00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00047 # define STATIC_LIB_EXT "lib"
00048 # define OBJECT_EXT "obj"
00049 # define LIBRARIAN "emxomfar"
00050 # else
00051
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
00388
00389
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
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
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
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
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 }