Main Page | Modules | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages | Examples

aplibtool.c

Go to the documentation of this file.
00001 /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
00002  * applicable.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <stdio.h>
00018 #include <process.h>
00019 #include <string.h>
00020 #include <stdlib.h>
00021 #include <sys/types.h>
00022 #include <dirent.h>
00023 
00024 typedef char bool;
00025 #define false 0
00026 #define true (!false)
00027 
00028 bool silent = false;
00029 bool shared = false;
00030 bool export_all = false;
00031 enum mode_t { mCompile, mLink, mInstall };
00032 enum output_type_t { otGeneral, otObject, otProgram, otStaticLibrary, otDynamicLibrary };
00033 
00034 #ifdef __EMX__
00035 #  define SHELL_CMD  "sh"
00036 #  define CC         "gcc"
00037 #  define GEN_EXPORTS "emxexp"
00038 #  define DEF2IMPLIB_CMD "emximp"
00039 #  define SHARE_SW   "-Zdll -Zmtd"
00040 #  define USE_OMF true
00041 #  define TRUNCATE_DLL_NAME
00042 #  define DYNAMIC_LIB_EXT "dll"
00043 #  define EXE_EXT ".exe"
00044 
00045 #  if USE_OMF
00046      /* OMF is the native format under OS/2 */
00047 #    define STATIC_LIB_EXT "lib"
00048 #    define OBJECT_EXT     "obj"
00049 #    define LIBRARIAN      "emxomfar"
00050 #  else
00051      /* but the alternative, a.out, can fork() which is sometimes necessary */
00052 #    define STATIC_LIB_EXT "a"
00053 #    define OBJECT_EXT     "o"
00054 #    define LIBRARIAN      "ar"
00055 #  endif
00056 #endif
00057 
00058 
00059 typedef struct {
00060     char *arglist[1024];
00061     int num_args;
00062     enum mode_t mode;
00063     enum output_type_t output_type;
00064     char *output_name;
00065     char *stub_name;
00066     char *tmp_dirs[1024];
00067     int num_tmp_dirs;
00068     char *obj_files[1024];
00069     int num_obj_files;
00070 } cmd_data_t;
00071 
00072 void parse_args(int argc, char *argv[], cmd_data_t *cmd_data);
00073 bool parse_long_opt(char *arg, cmd_data_t *cmd_data);
00074 int parse_short_opt(char *arg, cmd_data_t *cmd_data);
00075 bool parse_input_file_name(char *arg, cmd_data_t *cmd_data);
00076 bool parse_output_file_name(char *arg, cmd_data_t *cmd_data);
00077 void post_parse_fixup(cmd_data_t *cmd_data);
00078 bool explode_static_lib(char *lib, cmd_data_t *cmd_data);
00079 int execute_command(cmd_data_t *cmd_data);
00080 char *shell_esc(const char *str);
00081 void cleanup_tmp_dirs(cmd_data_t *cmd_data);
00082 void generate_def_file(cmd_data_t *cmd_data);
00083 char *nameof(char *fullpath);
00084 char *truncate_dll_name(char *path);
00085 
00086 
00087 int main(int argc, char *argv[])
00088 {
00089     int rc;
00090     cmd_data_t cmd_data;
00091 
00092     memset(&cmd_data, 0, sizeof(cmd_data));
00093     cmd_data.mode = mCompile;
00094     cmd_data.output_type = otGeneral;
00095 
00096     parse_args(argc, argv, &cmd_data);
00097     rc = execute_command(&cmd_data);
00098 
00099     if (rc == 0 && cmd_data.stub_name) {
00100         fopen(cmd_data.stub_name, "w");
00101     }
00102 
00103     cleanup_tmp_dirs(&cmd_data);
00104     return rc;
00105 }
00106 
00107 
00108 
00109 void parse_args(int argc, char *argv[], cmd_data_t *cmd_data)
00110 {
00111     int a;
00112     char *arg;
00113     bool argused;
00114 
00115     for (a=1; a < argc; a++) {
00116         arg = argv[a];
00117         argused = false;
00118 
00119         if (arg[0] == '-') {
00120             if (arg[1] == '-') {
00121                 argused = parse_long_opt(arg + 2, cmd_data);
00122             } else if (arg[1] == 'o' && a+1 < argc) {
00123                 cmd_data->arglist[cmd_data->num_args++] = arg;
00124                 arg = argv[++a];
00125                 argused = parse_output_file_name(arg, cmd_data);
00126             } else {
00127                 int num_used = parse_short_opt(arg + 1, cmd_data);
00128                 argused = num_used > 0;
00129 
00130                 if (num_used > 1) {
00131                     a += num_used - 1;
00132                 }
00133             }
00134         } else {
00135             argused = parse_input_file_name(arg, cmd_data);
00136         }
00137 
00138         if (!argused) {
00139             cmd_data->arglist[cmd_data->num_args++] = arg;
00140         }
00141     }
00142 
00143     post_parse_fixup(cmd_data);
00144 }
00145 
00146 
00147 
00148 bool parse_long_opt(char *arg, cmd_data_t *cmd_data)
00149 {
00150     char *equal_pos = strchr(arg, '=');
00151     char var[50];
00152     char value[500];
00153 
00154     if (equal_pos) {
00155         strncpy(var, arg, equal_pos - arg);
00156         var[equal_pos - arg] = 0;
00157         strcpy(value, equal_pos + 1);
00158     } else {
00159         strcpy(var, arg);
00160     }
00161 
00162     if (strcmp(var, "silent") == 0) {
00163         silent = true;
00164     } else if (strcmp(var, "mode") == 0) {
00165         if (strcmp(value, "compile") == 0) {
00166             cmd_data->mode = mCompile;
00167             cmd_data->output_type = otObject;
00168         }
00169 
00170         if (strcmp(value, "link") == 0) {
00171             cmd_data->mode = mLink;
00172         }
00173 
00174         if (strcmp(value, "install") == 0) {
00175             cmd_data->mode = mInstall;
00176         }
00177     } else if (strcmp(var, "shared") == 0) {
00178         shared = true;
00179     } else if (strcmp(var, "export-all") == 0) {
00180         export_all = true;
00181     } else {
00182         return false;
00183     }
00184 
00185     return true;
00186 }
00187 
00188 
00189 
00190 int parse_short_opt(char *arg, cmd_data_t *cmd_data)
00191 {
00192     if (strcmp(arg, "export-dynamic") == 0) {
00193         return 1;
00194     }
00195 
00196     if (strcmp(arg, "module") == 0) {
00197         return 1;
00198     }
00199 
00200     if (strcmp(arg, "Zexe") == 0) {
00201         return 1;
00202     }
00203 
00204     if (strcmp(arg, "avoid-version") == 0) {
00205         return 1;
00206     }
00207 
00208     if (strcmp(arg, "prefer-pic") == 0) {
00209         return 1;
00210     }
00211 
00212     if (strcmp(arg, "prefer-non-pic") == 0) {
00213         return 1;
00214     }
00215 
00216     if (strcmp(arg, "version-info") == 0 ) {
00217         return 2;
00218     }
00219 
00220     return 0;
00221 }
00222 
00223 
00224 
00225 bool parse_input_file_name(char *arg, cmd_data_t *cmd_data)
00226 {
00227     char *ext = strrchr(arg, '.');
00228     char *name = strrchr(arg, '/');
00229     int pathlen;
00230     char *newarg;
00231 
00232     if (!ext) {
00233         return false;
00234     }
00235 
00236     ext++;
00237 
00238     if (name == NULL) {
00239         name = strrchr(arg, '\\');
00240 
00241         if (name == NULL) {
00242             name = arg;
00243         } else {
00244             name++;
00245         }
00246     } else {
00247         name++;
00248     }
00249 
00250     pathlen = name - arg;
00251 
00252     if (strcmp(ext, "lo") == 0) {
00253         newarg = (char *)malloc(strlen(arg) + 10);
00254         strcpy(newarg, arg);
00255         strcpy(newarg + (ext - arg), OBJECT_EXT);
00256         cmd_data->arglist[cmd_data->num_args++] = newarg;
00257         cmd_data->obj_files[cmd_data->num_obj_files++] = newarg;
00258         return true;
00259     }
00260 
00261     if (strcmp(ext, "la") == 0) {
00262         newarg = (char *)malloc(strlen(arg) + 10);
00263         strcpy(newarg, arg);
00264         newarg[pathlen] = 0;
00265         strcat(newarg, ".libs/");
00266 
00267         if (strncmp(name, "lib", 3) == 0) {
00268             name += 3;
00269         }
00270 
00271         strcat(newarg, name);
00272         ext = strrchr(newarg, '.') + 1;
00273 
00274         if (shared && cmd_data->mode == mInstall) {
00275           strcpy(ext, DYNAMIC_LIB_EXT);
00276           newarg = truncate_dll_name(newarg);
00277         } else {
00278           strcpy(ext, STATIC_LIB_EXT);
00279         }
00280 
00281         cmd_data->arglist[cmd_data->num_args++] = newarg;
00282         return true;
00283     }
00284 
00285     if (strcmp(ext, "c") == 0) {
00286         if (cmd_data->stub_name == NULL) {
00287             cmd_data->stub_name = (char *)malloc(strlen(arg) + 4);
00288             strcpy(cmd_data->stub_name, arg);
00289             strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo");
00290         }
00291     }
00292 
00293     if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) {
00294         if (cmd_data->output_type == otGeneral) {
00295             cmd_data->output_type = otObject;
00296         }
00297     }
00298 
00299     return false;
00300 }
00301 
00302 
00303 
00304 bool parse_output_file_name(char *arg, cmd_data_t *cmd_data)
00305 {
00306     char *name = strrchr(arg, '/');
00307     char *ext = strrchr(arg, '.');
00308     char *newarg = NULL, *newext;
00309     int pathlen;
00310 
00311     if (name == NULL) {
00312         name = strrchr(arg, '\\');
00313 
00314         if (name == NULL) {
00315             name = arg;
00316         } else {
00317             name++;
00318         }
00319     } else {
00320         name++;
00321     }
00322 
00323     if (!ext) {
00324         cmd_data->stub_name = arg;
00325         cmd_data->output_type = otProgram;
00326         newarg = (char *)malloc(strlen(arg) + 5);
00327         strcpy(newarg, arg);
00328         strcat(newarg, EXE_EXT);
00329         cmd_data->arglist[cmd_data->num_args++] = newarg;
00330         cmd_data->output_name = newarg;
00331         return true;
00332     }
00333 
00334     ext++;
00335     pathlen = name - arg;
00336 
00337     if (strcmp(ext, "la") == 0) {
00338         cmd_data->stub_name = arg;
00339         cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary;
00340         newarg = (char *)malloc(strlen(arg) + 10);
00341         mkdir(".libs", 0);
00342         strcpy(newarg, ".libs/");
00343 
00344         if (strncmp(arg, "lib", 3) == 0) {
00345             arg += 3;
00346         }
00347 
00348         strcat(newarg, arg);
00349         newext = strrchr(newarg, '.') + 1;
00350         strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT);
00351 
00352 #ifdef TRUNCATE_DLL_NAME
00353         if (shared) {
00354           newarg = truncate_dll_name(newarg);
00355         }
00356 #endif
00357 
00358         cmd_data->arglist[cmd_data->num_args++] = newarg;
00359         cmd_data->output_name = newarg;
00360         return true;
00361     }
00362 
00363     if (strcmp(ext, "lo") == 0) {
00364         cmd_data->stub_name = arg;
00365         cmd_data->output_type = otObject;
00366         newarg = (char *)malloc(strlen(arg) + 2);
00367         strcpy(newarg, arg);
00368         ext = strrchr(newarg, '.') + 1;
00369         strcpy(ext, OBJECT_EXT);
00370         cmd_data->arglist[cmd_data->num_args++] = newarg;
00371         cmd_data->output_name = newarg;
00372         return true;
00373     }
00374 
00375     return false;
00376 }
00377 
00378 
00379 
00380 void post_parse_fixup(cmd_data_t *cmd_data)
00381 {
00382     int a;
00383     char *arg;
00384     char *ext;
00385 
00386     if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) {
00387         /* We do a real hatchet job on the args when making a static library
00388          * removing all compiler switches & any other cruft that ar won't like
00389          * We also need to explode any libraries listed
00390          */
00391 
00392         for (a=0; a < cmd_data->num_args; a++) {
00393             arg = cmd_data->arglist[a];
00394 
00395             if (arg) {
00396                 ext = strrchr(arg, '.');
00397 
00398                 if (ext) {
00399                     ext++;
00400                 }
00401 
00402                 if (arg[0] == '-') {
00403                     cmd_data->arglist[a] = NULL;
00404 
00405                     if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
00406                         cmd_data->arglist[a+1] = NULL;
00407                     }
00408 
00409                     if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) {
00410                         cmd_data->arglist[a+1] = NULL;
00411                     }
00412 
00413                     if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) {
00414                         cmd_data->arglist[a+1] = NULL;
00415                     }
00416 
00417                     if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) {
00418                         cmd_data->arglist[a+1] = NULL;
00419                     }
00420 
00421                     if (strcmp(arg, "-o") == 0) {
00422                         a++;
00423                     }
00424                 }
00425 
00426                 if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) {
00427                     cmd_data->arglist[a] = LIBRARIAN " cr";
00428                 }
00429 
00430                 if (ext) {
00431                     if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) {
00432                         /* ignore source files, they don't belong in a library */
00433                         cmd_data->arglist[a] = NULL;
00434                     }
00435 
00436                     if (strcmp(ext, STATIC_LIB_EXT) == 0) {
00437                         cmd_data->arglist[a] = NULL;
00438                         explode_static_lib(arg, cmd_data);
00439                     }
00440                 }
00441             }
00442         }
00443     }
00444 
00445     if (cmd_data->output_type == otDynamicLibrary) {
00446         for (a=0; a < cmd_data->num_args; a++) {
00447             arg = cmd_data->arglist[a];
00448 
00449             if (arg) {
00450                 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
00451                     cmd_data->arglist[a] = NULL;
00452                     cmd_data->arglist[a+1] = NULL;
00453                 }
00454             }
00455         }
00456 
00457         if (export_all) {
00458             generate_def_file(cmd_data);
00459         }
00460     }
00461 
00462 #if USE_OMF
00463     if (cmd_data->output_type == otObject ||
00464         cmd_data->output_type == otProgram ||
00465         cmd_data->output_type == otDynamicLibrary) {
00466         cmd_data->arglist[cmd_data->num_args++] = "-Zomf";
00467     }
00468 #endif
00469 
00470     if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) {
00471         cmd_data->arglist[cmd_data->num_args++] = SHARE_SW;
00472     }
00473 }
00474 
00475 
00476 
00477 int execute_command(cmd_data_t *cmd_data)
00478 {
00479     int target = 0;
00480     char *command;
00481     int a, total_len = 0;
00482     char *args[4];
00483 
00484     for (a=0; a < cmd_data->num_args; a++) {
00485         if (cmd_data->arglist[a]) {
00486             total_len += strlen(cmd_data->arglist[a]) + 1;
00487         }
00488     }
00489 
00490     command = (char *)malloc( total_len );
00491     command[0] = 0;
00492 
00493     for (a=0; a < cmd_data->num_args; a++) {
00494         if (cmd_data->arglist[a]) {
00495             strcat(command, cmd_data->arglist[a]);
00496             strcat(command, " ");
00497         }
00498     }
00499 
00500     command[strlen(command)-1] = 0;
00501 
00502     if (!silent) {
00503         puts(command);
00504     }
00505 
00506     cmd_data->num_args = target;
00507     cmd_data->arglist[cmd_data->num_args] = NULL;
00508     command = shell_esc(command);
00509 
00510     args[0] = SHELL_CMD;
00511     args[1] = "-c";
00512     args[2] = command;
00513     args[3] = NULL;
00514     return spawnvp(P_WAIT, args[0], args);
00515 }
00516 
00517 
00518 
00519 char *shell_esc(const char *str)
00520 {
00521     char *cmd;
00522     unsigned char *d;
00523     const unsigned char *s;
00524 
00525     cmd = (char *)malloc(2 * strlen(str) + 1);
00526     d = (unsigned char *)cmd;
00527     s = (const unsigned char *)str;
00528 
00529     for (; *s; ++s) {
00530         if (*s == '"' || *s == '\\') {
00531             *d++ = '\\';
00532         }
00533         *d++ = *s;
00534     }
00535 
00536     *d = '\0';
00537     return cmd;
00538 }
00539 
00540 
00541 
00542 bool explode_static_lib(char *lib, cmd_data_t *cmd_data)
00543 {
00544     char tmpdir[1024];
00545     char savewd[1024];
00546     char cmd[1024];
00547     char *name;
00548     DIR *dir;
00549     struct dirent *entry;
00550 
00551     strcpy(tmpdir, lib);
00552     strcat(tmpdir, ".exploded");
00553 
00554     mkdir(tmpdir, 0);
00555     cmd_data->tmp_dirs[cmd_data->num_tmp_dirs++] = strdup(tmpdir);
00556     getcwd(savewd, sizeof(savewd));
00557 
00558     if (chdir(tmpdir) != 0)
00559         return false;
00560 
00561     strcpy(cmd, LIBRARIAN " x ");
00562     name = strrchr(lib, '/');
00563 
00564     if (name) {
00565         name++;
00566     } else {
00567         name = lib;
00568     }
00569 
00570     strcat(cmd, "../");
00571     strcat(cmd, name);
00572     system(cmd);
00573     chdir(savewd);
00574     dir = opendir(tmpdir);
00575 
00576     while ((entry = readdir(dir)) != NULL) {
00577         if (entry->d_name[0] != '.') {
00578             strcpy(cmd, tmpdir);
00579             strcat(cmd, "/");
00580             strcat(cmd, entry->d_name);
00581             cmd_data->arglist[cmd_data->num_args++] = strdup(cmd);
00582         }
00583     }
00584 
00585     closedir(dir);
00586     return true;
00587 }
00588 
00589 
00590 
00591 void cleanup_tmp_dir(char *dirname)
00592 {
00593     DIR *dir;
00594     struct dirent *entry;
00595     char fullname[1024];
00596 
00597     dir = opendir(dirname);
00598 
00599     if (dir == NULL)
00600         return;
00601 
00602     while ((entry = readdir(dir)) != NULL) {
00603         if (entry->d_name[0] != '.') {
00604             strcpy(fullname, dirname);
00605             strcat(fullname, "/");
00606             strcat(fullname, entry->d_name);
00607             remove(fullname);
00608         }
00609     }
00610 
00611     rmdir(dirname);
00612 }
00613 
00614 
00615 
00616 void cleanup_tmp_dirs(cmd_data_t *cmd_data)
00617 {
00618     int d;
00619 
00620     for (d=0; d < cmd_data->num_tmp_dirs; d++) {
00621         cleanup_tmp_dir(cmd_data->tmp_dirs[d]);
00622     }
00623 }
00624 
00625 
00626 
00627 void generate_def_file(cmd_data_t *cmd_data)
00628 {
00629     char def_file[1024];
00630     char implib_file[1024];
00631     char *ext;
00632     FILE *hDef;
00633     char *export_args[1024];
00634     int num_export_args = 0;
00635     char *cmd;
00636     int cmd_size = 0;
00637     int a;
00638 
00639     if (cmd_data->output_name) {
00640         strcpy(def_file, cmd_data->output_name);
00641         strcat(def_file, ".def");
00642         hDef = fopen(def_file, "w");
00643 
00644         if (hDef != NULL) {
00645             fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
00646             fprintf(hDef, "DATA NONSHARED\n");
00647             fprintf(hDef, "EXPORTS\n");
00648             fclose(hDef);
00649 
00650             for (a=0; a < cmd_data->num_obj_files; a++) {
00651                 cmd_size += strlen(cmd_data->obj_files[a]) + 1;
00652             }
00653 
00654             cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
00655             cmd = (char *)malloc(cmd_size);
00656             strcpy(cmd, GEN_EXPORTS);
00657 
00658             for (a=0; a < cmd_data->num_obj_files; a++) {
00659                 strcat(cmd, " ");
00660                 strcat(cmd, cmd_data->obj_files[a] );
00661             }
00662 
00663             strcat(cmd, ">>");
00664             strcat(cmd, def_file);
00665             puts(cmd);
00666             export_args[num_export_args++] = SHELL_CMD;
00667             export_args[num_export_args++] = "-c";
00668             export_args[num_export_args++] = cmd;
00669             export_args[num_export_args++] = NULL;
00670             spawnvp(P_WAIT, export_args[0], export_args);
00671             cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
00672 
00673             /* Now make an import library for the dll */
00674             num_export_args = 0;
00675             export_args[num_export_args++] = DEF2IMPLIB_CMD;
00676             export_args[num_export_args++] = "-o";
00677 
00678             strcpy(implib_file, ".libs/");
00679             strcat(implib_file, cmd_data->stub_name);
00680             ext = strrchr(implib_file, '.');
00681 
00682             if (ext)
00683                 *ext = 0;
00684 
00685             strcat(implib_file, ".");
00686             strcat(implib_file, STATIC_LIB_EXT);
00687 
00688             export_args[num_export_args++] = implib_file;
00689             export_args[num_export_args++] = def_file;
00690             export_args[num_export_args++] = NULL;
00691             spawnvp(P_WAIT, export_args[0], export_args);
00692         }
00693     }
00694 }
00695 
00696 
00697 
00698 /* returns just a file's name without path or extension */
00699 char *nameof(char *fullpath)
00700 {
00701     char buffer[1024];
00702     char *ext;
00703     char *name = strrchr(fullpath, '/');
00704 
00705     if (name == NULL) {
00706         name = strrchr(fullpath, '\\');
00707     }
00708 
00709     if (name == NULL) {
00710         name = fullpath;
00711     } else {
00712         name++;
00713     }
00714 
00715     strcpy(buffer, name);
00716     ext = strrchr(buffer, '.');
00717 
00718     if (ext) {
00719         *ext = 0;
00720         return strdup(buffer);
00721     }
00722 
00723     return name;
00724 }
00725 
00726 
00727 
00728 char *truncate_dll_name(char *path)
00729 {
00730     /* Cut DLL name down to 8 characters after removing any mod_ prefix */
00731     char *tmppath = strdup(path);
00732     char *newname = strrchr(tmppath, '/') + 1;
00733     char *ext = strrchr(tmppath, '.');
00734     int len;
00735 
00736     if (ext == NULL)
00737         return tmppath;
00738 
00739     len = ext - newname;
00740 
00741     if (strncmp(newname, "mod_", 4) == 0) {
00742         strcpy(newname, newname + 4);
00743         len -= 4;
00744     }
00745 
00746     if (len > 8) {
00747         strcpy(newname + 8, strchr(newname, '.'));
00748     }
00749 
00750     return tmppath;
00751 }