diff options
Diffstat (limited to 'build/aplibtool.c')
-rw-r--r-- | build/aplibtool.c | 750 |
1 files changed, 750 insertions, 0 deletions
diff --git a/build/aplibtool.c b/build/aplibtool.c new file mode 100644 index 0000000..b5c6c3f --- /dev/null +++ b/build/aplibtool.c @@ -0,0 +1,750 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <process.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <dirent.h> + +typedef char bool; +#define false 0 +#define true (!false) + +bool silent = false; +bool shared = false; +bool export_all = false; +enum mode_t { mCompile, mLink, mInstall }; +enum output_type_t { otGeneral, otObject, otProgram, otStaticLibrary, otDynamicLibrary }; + +#ifdef __EMX__ +# define SHELL_CMD "sh" +# define CC "gcc" +# define GEN_EXPORTS "emxexp" +# define DEF2IMPLIB_CMD "emximp" +# define SHARE_SW "-Zdll -Zmtd" +# define USE_OMF true +# define TRUNCATE_DLL_NAME +# define DYNAMIC_LIB_EXT "dll" +# define EXE_EXT ".exe" + +# if USE_OMF + /* OMF is the native format under OS/2 */ +# define STATIC_LIB_EXT "lib" +# define OBJECT_EXT "obj" +# define LIBRARIAN "emxomfar" +# else + /* but the alternative, a.out, can fork() which is sometimes necessary */ +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# endif +#endif + + +typedef struct { + char *arglist[1024]; + int num_args; + enum mode_t mode; + enum output_type_t output_type; + char *output_name; + char *stub_name; + char *tmp_dirs[1024]; + int num_tmp_dirs; + char *obj_files[1024]; + int num_obj_files; +} cmd_data_t; + +void parse_args(int argc, char *argv[], cmd_data_t *cmd_data); +bool parse_long_opt(char *arg, cmd_data_t *cmd_data); +int parse_short_opt(char *arg, cmd_data_t *cmd_data); +bool parse_input_file_name(char *arg, cmd_data_t *cmd_data); +bool parse_output_file_name(char *arg, cmd_data_t *cmd_data); +void post_parse_fixup(cmd_data_t *cmd_data); +bool explode_static_lib(char *lib, cmd_data_t *cmd_data); +int execute_command(cmd_data_t *cmd_data); +char *shell_esc(const char *str); +void cleanup_tmp_dirs(cmd_data_t *cmd_data); +void generate_def_file(cmd_data_t *cmd_data); +char *nameof(char *fullpath); +char *truncate_dll_name(char *path); + + +int main(int argc, char *argv[]) +{ + int rc; + cmd_data_t cmd_data; + + memset(&cmd_data, 0, sizeof(cmd_data)); + cmd_data.mode = mCompile; + cmd_data.output_type = otGeneral; + + parse_args(argc, argv, &cmd_data); + rc = execute_command(&cmd_data); + + if (rc == 0 && cmd_data.stub_name) { + fopen(cmd_data.stub_name, "w"); + } + + cleanup_tmp_dirs(&cmd_data); + return rc; +} + + + +void parse_args(int argc, char *argv[], cmd_data_t *cmd_data) +{ + int a; + char *arg; + bool argused; + + for (a=1; a < argc; a++) { + arg = argv[a]; + argused = false; + + if (arg[0] == '-') { + if (arg[1] == '-') { + argused = parse_long_opt(arg + 2, cmd_data); + } else if (arg[1] == 'o' && a+1 < argc) { + cmd_data->arglist[cmd_data->num_args++] = arg; + arg = argv[++a]; + argused = parse_output_file_name(arg, cmd_data); + } else { + int num_used = parse_short_opt(arg + 1, cmd_data); + argused = num_used > 0; + + if (num_used > 1) { + a += num_used - 1; + } + } + } else { + argused = parse_input_file_name(arg, cmd_data); + } + + if (!argused) { + cmd_data->arglist[cmd_data->num_args++] = arg; + } + } + + post_parse_fixup(cmd_data); +} + + + +bool parse_long_opt(char *arg, cmd_data_t *cmd_data) +{ + char *equal_pos = strchr(arg, '='); + char var[50]; + char value[500]; + + if (equal_pos) { + strncpy(var, arg, equal_pos - arg); + var[equal_pos - arg] = 0; + strcpy(value, equal_pos + 1); + } else { + strcpy(var, arg); + } + + if (strcmp(var, "silent") == 0) { + silent = true; + } else if (strcmp(var, "mode") == 0) { + if (strcmp(value, "compile") == 0) { + cmd_data->mode = mCompile; + cmd_data->output_type = otObject; + } + + if (strcmp(value, "link") == 0) { + cmd_data->mode = mLink; + } + + if (strcmp(value, "install") == 0) { + cmd_data->mode = mInstall; + } + } else if (strcmp(var, "shared") == 0) { + shared = true; + } else if (strcmp(var, "export-all") == 0) { + export_all = true; + } else { + return false; + } + + return true; +} + + + +int parse_short_opt(char *arg, cmd_data_t *cmd_data) +{ + if (strcmp(arg, "export-dynamic") == 0) { + return 1; + } + + if (strcmp(arg, "module") == 0) { + return 1; + } + + if (strcmp(arg, "Zexe") == 0) { + return 1; + } + + if (strcmp(arg, "avoid-version") == 0) { + return 1; + } + + if (strcmp(arg, "prefer-pic") == 0) { + return 1; + } + + if (strcmp(arg, "prefer-non-pic") == 0) { + return 1; + } + + if (strcmp(arg, "version-info") == 0 ) { + return 2; + } + + if (strcmp(arg, "no-install") == 0) { + return 1; + } + + return 0; +} + + + +bool parse_input_file_name(char *arg, cmd_data_t *cmd_data) +{ + char *ext = strrchr(arg, '.'); + char *name = strrchr(arg, '/'); + char *newarg; + + if (!ext) { + return false; + } + + ext++; + + if (name == NULL) { + name = strrchr(arg, '\\'); + + if (name == NULL) { + name = arg; + } else { + name++; + } + } else { + name++; + } + + if (strcmp(ext, "lo") == 0) { + newarg = (char *)malloc(strlen(arg) + 10); + strcpy(newarg, arg); + strcpy(newarg + (ext - arg), OBJECT_EXT); + cmd_data->arglist[cmd_data->num_args++] = newarg; + cmd_data->obj_files[cmd_data->num_obj_files++] = newarg; + return true; + } + + if (strcmp(ext, "la") == 0) { + newarg = (char *)malloc(strlen(arg) + 10); + strcpy(newarg, arg); + newarg[pathlen] = 0; + strcat(newarg, ".libs/"); + + if (strncmp(name, "lib", 3) == 0) { + name += 3; + } + + strcat(newarg, name); + ext = strrchr(newarg, '.') + 1; + + if (shared && cmd_data->mode == mInstall) { + strcpy(ext, DYNAMIC_LIB_EXT); + newarg = truncate_dll_name(newarg); + } else { + strcpy(ext, STATIC_LIB_EXT); + } + + cmd_data->arglist[cmd_data->num_args++] = newarg; + return true; + } + + if (strcmp(ext, "c") == 0) { + if (cmd_data->stub_name == NULL) { + cmd_data->stub_name = (char *)malloc(strlen(arg) + 4); + strcpy(cmd_data->stub_name, arg); + strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo"); + } + } + + if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) { + if (cmd_data->output_type == otGeneral) { + cmd_data->output_type = otObject; + } + } + + return false; +} + + + +bool parse_output_file_name(char *arg, cmd_data_t *cmd_data) +{ + char *name = strrchr(arg, '/'); + char *ext = strrchr(arg, '.'); + char *newarg = NULL, *newext; + + if (name == NULL) { + name = strrchr(arg, '\\'); + + if (name == NULL) { + name = arg; + } else { + name++; + } + } else { + name++; + } + + if (!ext) { + cmd_data->stub_name = arg; + cmd_data->output_type = otProgram; + newarg = (char *)malloc(strlen(arg) + 5); + strcpy(newarg, arg); + strcat(newarg, EXE_EXT); + cmd_data->arglist[cmd_data->num_args++] = newarg; + cmd_data->output_name = newarg; + return true; + } + + ext++; + + if (strcmp(ext, "la") == 0) { + cmd_data->stub_name = arg; + cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary; + newarg = (char *)malloc(strlen(arg) + 10); + mkdir(".libs", 0); + strcpy(newarg, ".libs/"); + + if (strncmp(arg, "lib", 3) == 0) { + arg += 3; + } + + strcat(newarg, arg); + newext = strrchr(newarg, '.') + 1; + strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT); + +#ifdef TRUNCATE_DLL_NAME + if (shared) { + newarg = truncate_dll_name(newarg); + } +#endif + + cmd_data->arglist[cmd_data->num_args++] = newarg; + cmd_data->output_name = newarg; + return true; + } + + if (strcmp(ext, "lo") == 0) { + cmd_data->stub_name = arg; + cmd_data->output_type = otObject; + newarg = (char *)malloc(strlen(arg) + 2); + strcpy(newarg, arg); + ext = strrchr(newarg, '.') + 1; + strcpy(ext, OBJECT_EXT); + cmd_data->arglist[cmd_data->num_args++] = newarg; + cmd_data->output_name = newarg; + return true; + } + + return false; +} + + + +void post_parse_fixup(cmd_data_t *cmd_data) +{ + int a; + char *arg; + char *ext; + + if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) { + /* We do a real hatchet job on the args when making a static library + * removing all compiler switches & any other cruft that ar won't like + * We also need to explode any libraries listed + */ + + for (a=0; a < cmd_data->num_args; a++) { + arg = cmd_data->arglist[a]; + + if (arg) { + ext = strrchr(arg, '.'); + + if (ext) { + ext++; + } + + if (arg[0] == '-') { + cmd_data->arglist[a] = NULL; + + if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a+1] = NULL; + } + + if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a+1] = NULL; + } + + if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a+1] = NULL; + } + + if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a+1] = NULL; + } + + if (strcmp(arg, "-o") == 0) { + a++; + } + } + + if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) { + cmd_data->arglist[a] = LIBRARIAN " cr"; + } + + if (ext) { + if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) { + /* ignore source files, they don't belong in a library */ + cmd_data->arglist[a] = NULL; + } + + if (strcmp(ext, STATIC_LIB_EXT) == 0) { + cmd_data->arglist[a] = NULL; + explode_static_lib(arg, cmd_data); + } + } + } + } + } + + if (cmd_data->output_type == otDynamicLibrary) { + for (a=0; a < cmd_data->num_args; a++) { + arg = cmd_data->arglist[a]; + + if (arg) { + if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a] = NULL; + cmd_data->arglist[a+1] = NULL; + } + } + } + + if (export_all) { + generate_def_file(cmd_data); + } + } + +#if USE_OMF + if (cmd_data->output_type == otObject || + cmd_data->output_type == otProgram || + cmd_data->output_type == otDynamicLibrary) { + cmd_data->arglist[cmd_data->num_args++] = "-Zomf"; + } +#endif + + if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) { + cmd_data->arglist[cmd_data->num_args++] = SHARE_SW; + } +} + + + +int execute_command(cmd_data_t *cmd_data) +{ + int target = 0; + char *command; + int a, total_len = 0; + char *args[4]; + + for (a=0; a < cmd_data->num_args; a++) { + if (cmd_data->arglist[a]) { + total_len += strlen(cmd_data->arglist[a]) + 1; + } + } + + command = (char *)malloc( total_len ); + command[0] = 0; + + for (a=0; a < cmd_data->num_args; a++) { + if (cmd_data->arglist[a]) { + strcat(command, cmd_data->arglist[a]); + strcat(command, " "); + } + } + + command[strlen(command)-1] = 0; + + if (!silent) { + puts(command); + } + + cmd_data->num_args = target; + cmd_data->arglist[cmd_data->num_args] = NULL; + command = shell_esc(command); + + args[0] = SHELL_CMD; + args[1] = "-c"; + args[2] = command; + args[3] = NULL; + return spawnvp(P_WAIT, args[0], args); +} + + + +char *shell_esc(const char *str) +{ + char *cmd; + unsigned char *d; + const unsigned char *s; + + cmd = (char *)malloc(2 * strlen(str) + 1); + d = (unsigned char *)cmd; + s = (const unsigned char *)str; + + for (; *s; ++s) { + if (*s == '"' || *s == '\\') { + *d++ = '\\'; + } + *d++ = *s; + } + + *d = '\0'; + return cmd; +} + + + +bool explode_static_lib(char *lib, cmd_data_t *cmd_data) +{ + char tmpdir[1024]; + char savewd[1024]; + char cmd[1024]; + char *name; + DIR *dir; + struct dirent *entry; + + strcpy(tmpdir, lib); + strcat(tmpdir, ".exploded"); + + mkdir(tmpdir, 0); + cmd_data->tmp_dirs[cmd_data->num_tmp_dirs++] = strdup(tmpdir); + getcwd(savewd, sizeof(savewd)); + + if (chdir(tmpdir) != 0) + return false; + + strcpy(cmd, LIBRARIAN " x "); + name = strrchr(lib, '/'); + + if (name) { + name++; + } else { + name = lib; + } + + strcat(cmd, "../"); + strcat(cmd, name); + system(cmd); + chdir(savewd); + dir = opendir(tmpdir); + + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] != '.') { + strcpy(cmd, tmpdir); + strcat(cmd, "/"); + strcat(cmd, entry->d_name); + cmd_data->arglist[cmd_data->num_args++] = strdup(cmd); + } + } + + closedir(dir); + return true; +} + + + +void cleanup_tmp_dir(char *dirname) +{ + DIR *dir; + struct dirent *entry; + char fullname[1024]; + + dir = opendir(dirname); + + if (dir == NULL) + return; + + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] != '.') { + strcpy(fullname, dirname); + strcat(fullname, "/"); + strcat(fullname, entry->d_name); + remove(fullname); + } + } + + rmdir(dirname); +} + + + +void cleanup_tmp_dirs(cmd_data_t *cmd_data) +{ + int d; + + for (d=0; d < cmd_data->num_tmp_dirs; d++) { + cleanup_tmp_dir(cmd_data->tmp_dirs[d]); + } +} + + + +void generate_def_file(cmd_data_t *cmd_data) +{ + char def_file[1024]; + char implib_file[1024]; + char *ext; + FILE *hDef; + char *export_args[1024]; + int num_export_args = 0; + char *cmd; + int cmd_size = 0; + int a; + + if (cmd_data->output_name) { + strcpy(def_file, cmd_data->output_name); + strcat(def_file, ".def"); + hDef = fopen(def_file, "w"); + + if (hDef != NULL) { + fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name)); + fprintf(hDef, "DATA NONSHARED\n"); + fprintf(hDef, "EXPORTS\n"); + fclose(hDef); + + for (a=0; a < cmd_data->num_obj_files; a++) { + cmd_size += strlen(cmd_data->obj_files[a]) + 1; + } + + cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3; + cmd = (char *)malloc(cmd_size); + strcpy(cmd, GEN_EXPORTS); + + for (a=0; a < cmd_data->num_obj_files; a++) { + strcat(cmd, " "); + strcat(cmd, cmd_data->obj_files[a] ); + } + + strcat(cmd, ">>"); + strcat(cmd, def_file); + puts(cmd); + export_args[num_export_args++] = SHELL_CMD; + export_args[num_export_args++] = "-c"; + export_args[num_export_args++] = cmd; + export_args[num_export_args++] = NULL; + spawnvp(P_WAIT, export_args[0], export_args); + cmd_data->arglist[cmd_data->num_args++] = strdup(def_file); + + /* Now make an import library for the dll */ + num_export_args = 0; + export_args[num_export_args++] = DEF2IMPLIB_CMD; + export_args[num_export_args++] = "-o"; + + strcpy(implib_file, ".libs/"); + strcat(implib_file, cmd_data->stub_name); + ext = strrchr(implib_file, '.'); + + if (ext) + *ext = 0; + + strcat(implib_file, "."); + strcat(implib_file, STATIC_LIB_EXT); + + export_args[num_export_args++] = implib_file; + export_args[num_export_args++] = def_file; + export_args[num_export_args++] = NULL; + spawnvp(P_WAIT, export_args[0], export_args); + } + } +} + + + +/* returns just a file's name without path or extension */ +char *nameof(char *fullpath) +{ + char buffer[1024]; + char *ext; + char *name = strrchr(fullpath, '/'); + + if (name == NULL) { + name = strrchr(fullpath, '\\'); + } + + if (name == NULL) { + name = fullpath; + } else { + name++; + } + + strcpy(buffer, name); + ext = strrchr(buffer, '.'); + + if (ext) { + *ext = 0; + return strdup(buffer); + } + + return name; +} + + + +char *truncate_dll_name(char *path) +{ + /* Cut DLL name down to 8 characters after removing any mod_ prefix */ + char *tmppath = strdup(path); + char *newname = strrchr(tmppath, '/') + 1; + char *ext = strrchr(tmppath, '.'); + int len; + + if (ext == NULL) + return tmppath; + + len = ext - newname; + + if (strncmp(newname, "mod_", 4) == 0) { + strcpy(newname, newname + 4); + len -= 4; + } + + if (len > 8) { + strcpy(newname + 8, strchr(newname, '.')); + } + + return tmppath; +} |