1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18#include <process.h> 19#include <string.h> 20#include <stdlib.h> 21#include <sys/types.h> 22#include <dirent.h> 23 24typedef char bool; 25#define false 0 26#define true (!false) 27 28bool silent = false; 29bool shared = false; 30bool export_all = false; 31enum mode_t { mCompile, mLink, mInstall }; 32enum output_type_t { otGeneral, otObject, otProgram, otStaticLibrary, otDynamicLibrary }; 33 34#ifdef __EMX__ 35# define SHELL_CMD "sh" 36# define CC "gcc" 37# define GEN_EXPORTS "emxexp" 38# define DEF2IMPLIB_CMD "emximp" 39# define SHARE_SW "-Zdll -Zmtd" 40# define USE_OMF true 41# define TRUNCATE_DLL_NAME 42# define DYNAMIC_LIB_EXT "dll" 43# define EXE_EXT ".exe" 44 45# if USE_OMF 46 /* OMF is the native format under OS/2 */ 47# define STATIC_LIB_EXT "lib" 48# define OBJECT_EXT "obj" 49# define LIBRARIAN "emxomfar" 50# else 51 /* but the alternative, a.out, can fork() which is sometimes necessary */ 52# define STATIC_LIB_EXT "a" 53# define OBJECT_EXT "o" 54# define LIBRARIAN "ar" 55# endif 56#endif 57 58 59typedef struct { 60 char *arglist[1024]; 61 int num_args; 62 enum mode_t mode; 63 enum output_type_t output_type; 64 char *output_name; 65 char *stub_name; 66 char *tmp_dirs[1024]; 67 int num_tmp_dirs; 68 char *obj_files[1024]; 69 int num_obj_files; 70} cmd_data_t; 71 72void parse_args(int argc, char *argv[], cmd_data_t *cmd_data); 73bool parse_long_opt(char *arg, cmd_data_t *cmd_data); 74int parse_short_opt(char *arg, cmd_data_t *cmd_data); 75bool parse_input_file_name(char *arg, cmd_data_t *cmd_data); 76bool parse_output_file_name(char *arg, cmd_data_t *cmd_data); 77void post_parse_fixup(cmd_data_t *cmd_data); 78bool explode_static_lib(char *lib, cmd_data_t *cmd_data); 79int execute_command(cmd_data_t *cmd_data); 80char *shell_esc(const char *str); 81void cleanup_tmp_dirs(cmd_data_t *cmd_data); 82void generate_def_file(cmd_data_t *cmd_data); 83char *nameof(char *fullpath); 84char *truncate_dll_name(char *path); 85 86 87int main(int argc, char *argv[]) 88{ 89 int rc; 90 cmd_data_t cmd_data; 91 92 memset(&cmd_data, 0, sizeof(cmd_data)); 93 cmd_data.mode = mCompile; 94 cmd_data.output_type = otGeneral; 95 96 parse_args(argc, argv, &cmd_data); 97 rc = execute_command(&cmd_data); 98 99 if (rc == 0 && cmd_data.stub_name) { 100 fopen(cmd_data.stub_name, "w"); 101 } 102 103 cleanup_tmp_dirs(&cmd_data); 104 return rc; 105} 106 107 108 109void parse_args(int argc, char *argv[], cmd_data_t *cmd_data) 110{ 111 int a; 112 char *arg; 113 bool argused; 114 115 for (a=1; a < argc; a++) { 116 arg = argv[a]; 117 argused = false; 118 119 if (arg[0] == '-') { 120 if (arg[1] == '-') { 121 argused = parse_long_opt(arg + 2, cmd_data); 122 } else if (arg[1] == 'o' && a+1 < argc) { 123 cmd_data->arglist[cmd_data->num_args++] = arg; 124 arg = argv[++a]; 125 argused = parse_output_file_name(arg, cmd_data); 126 } else { 127 int num_used = parse_short_opt(arg + 1, cmd_data); 128 argused = num_used > 0; 129 130 if (num_used > 1) { 131 a += num_used - 1; 132 } 133 } 134 } else { 135 argused = parse_input_file_name(arg, cmd_data); 136 } 137 138 if (!argused) { 139 cmd_data->arglist[cmd_data->num_args++] = arg; 140 } 141 } 142 143 post_parse_fixup(cmd_data); 144} 145 146 147 148bool parse_long_opt(char *arg, cmd_data_t *cmd_data) 149{ 150 char *equal_pos = strchr(arg, '='); 151 char var[50]; 152 char value[500]; 153 154 if (equal_pos) { 155 strncpy(var, arg, equal_pos - arg); 156 var[equal_pos - arg] = 0; 157 strcpy(value, equal_pos + 1); 158 } else { 159 strcpy(var, arg); 160 } 161 162 if (strcmp(var, "silent") == 0) { 163 silent = true; 164 } else if (strcmp(var, "mode") == 0) { 165 if (strcmp(value, "compile") == 0) { 166 cmd_data->mode = mCompile; 167 cmd_data->output_type = otObject; 168 } 169 170 if (strcmp(value, "link") == 0) { 171 cmd_data->mode = mLink; 172 } 173 174 if (strcmp(value, "install") == 0) { 175 cmd_data->mode = mInstall; 176 } 177 } else if (strcmp(var, "shared") == 0) { 178 shared = true; 179 } else if (strcmp(var, "export-all") == 0) { 180 export_all = true; 181 } else { 182 return false; 183 } 184 185 return true; 186} 187 188 189 190int parse_short_opt(char *arg, cmd_data_t *cmd_data) 191{ 192 if (strcmp(arg, "export-dynamic") == 0) { 193 return 1; 194 } 195 196 if (strcmp(arg, "module") == 0) { 197 return 1; 198 } 199 200 if (strcmp(arg, "Zexe") == 0) { 201 return 1; 202 } 203 204 if (strcmp(arg, "avoid-version") == 0) { 205 return 1; 206 } 207 208 if (strcmp(arg, "prefer-pic") == 0) { 209 return 1; 210 } 211 212 if (strcmp(arg, "prefer-non-pic") == 0) { 213 return 1; 214 } 215 216 if (strcmp(arg, "version-info") == 0 ) { 217 return 2; 218 } 219 220 if (strcmp(arg, "no-install") == 0) { 221 return 1; 222 } 223 224 return 0; 225} 226 227 228 229bool parse_input_file_name(char *arg, cmd_data_t *cmd_data) 230{ 231 char *ext = strrchr(arg, '.'); 232 char *name = strrchr(arg, '/'); 233 int pathlen; 234 char *newarg; 235 236 if (!ext) { 237 return false; 238 } 239 240 ext++; 241 242 if (name == NULL) { 243 name = strrchr(arg, '\\'); 244 245 if (name == NULL) { 246 name = arg; 247 } else { 248 name++; 249 } 250 } else { 251 name++; 252 } 253 254 pathlen = name - arg; 255 256 if (strcmp(ext, "lo") == 0) { 257 newarg = (char *)malloc(strlen(arg) + 10); 258 strcpy(newarg, arg); 259 strcpy(newarg + (ext - arg), OBJECT_EXT); 260 cmd_data->arglist[cmd_data->num_args++] = newarg; 261 cmd_data->obj_files[cmd_data->num_obj_files++] = newarg; 262 return true; 263 } 264 265 if (strcmp(ext, "la") == 0) { 266 newarg = (char *)malloc(strlen(arg) + 10); 267 strcpy(newarg, arg); 268 newarg[pathlen] = 0; 269 strcat(newarg, ".libs/"); 270 271 if (strncmp(name, "lib", 3) == 0) { 272 name += 3; 273 } 274 275 strcat(newarg, name); 276 ext = strrchr(newarg, '.') + 1; 277 278 if (shared && cmd_data->mode == mInstall) { 279 strcpy(ext, DYNAMIC_LIB_EXT); 280 newarg = truncate_dll_name(newarg); 281 } else { 282 strcpy(ext, STATIC_LIB_EXT); 283 } 284 285 cmd_data->arglist[cmd_data->num_args++] = newarg; 286 return true; 287 } 288 289 if (strcmp(ext, "c") == 0) { 290 if (cmd_data->stub_name == NULL) { 291 cmd_data->stub_name = (char *)malloc(strlen(arg) + 4); 292 strcpy(cmd_data->stub_name, arg); 293 strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo"); 294 } 295 } 296 297 if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) { 298 if (cmd_data->output_type == otGeneral) { 299 cmd_data->output_type = otObject; 300 } 301 } 302 303 return false; 304} 305 306 307 308bool parse_output_file_name(char *arg, cmd_data_t *cmd_data) 309{ 310 char *name = strrchr(arg, '/'); 311 char *ext = strrchr(arg, '.'); 312 char *newarg = NULL, *newext; 313 int pathlen; 314 315 if (name == NULL) { 316 name = strrchr(arg, '\\'); 317 318 if (name == NULL) { 319 name = arg; 320 } else { 321 name++; 322 } 323 } else { 324 name++; 325 } 326 327 if (!ext) { 328 cmd_data->stub_name = arg; 329 cmd_data->output_type = otProgram; 330 newarg = (char *)malloc(strlen(arg) + 5); 331 strcpy(newarg, arg); 332 strcat(newarg, EXE_EXT); 333 cmd_data->arglist[cmd_data->num_args++] = newarg; 334 cmd_data->output_name = newarg; 335 return true; 336 } 337 338 ext++; 339 pathlen = name - arg; 340 341 if (strcmp(ext, "la") == 0) { 342 cmd_data->stub_name = arg; 343 cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary; 344 newarg = (char *)malloc(strlen(arg) + 10); 345 mkdir(".libs", 0); 346 strcpy(newarg, ".libs/"); 347 348 if (strncmp(arg, "lib", 3) == 0) { 349 arg += 3; 350 } 351 352 strcat(newarg, arg); 353 newext = strrchr(newarg, '.') + 1; 354 strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT); 355 356#ifdef TRUNCATE_DLL_NAME 357 if (shared) { 358 newarg = truncate_dll_name(newarg); 359 } 360#endif 361 362 cmd_data->arglist[cmd_data->num_args++] = newarg; 363 cmd_data->output_name = newarg; 364 return true; 365 } 366 367 if (strcmp(ext, "lo") == 0) { 368 cmd_data->stub_name = arg; 369 cmd_data->output_type = otObject; 370 newarg = (char *)malloc(strlen(arg) + 2); 371 strcpy(newarg, arg); 372 ext = strrchr(newarg, '.') + 1; 373 strcpy(ext, OBJECT_EXT); 374 cmd_data->arglist[cmd_data->num_args++] = newarg; 375 cmd_data->output_name = newarg; 376 return true; 377 } 378 379 return false; 380} 381 382 383 384void post_parse_fixup(cmd_data_t *cmd_data) 385{ 386 int a; 387 char *arg; 388 char *ext; 389 390 if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) { 391 /* We do a real hatchet job on the args when making a static library 392 * removing all compiler switches & any other cruft that ar won't like 393 * We also need to explode any libraries listed 394 */ 395 396 for (a=0; a < cmd_data->num_args; a++) { 397 arg = cmd_data->arglist[a]; 398 399 if (arg) { 400 ext = strrchr(arg, '.'); 401 402 if (ext) { 403 ext++; 404 } 405 406 if (arg[0] == '-') { 407 cmd_data->arglist[a] = NULL; 408 409 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { 410 cmd_data->arglist[a+1] = NULL; 411 } 412 413 if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) { 414 cmd_data->arglist[a+1] = NULL; 415 } 416 417 if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) { 418 cmd_data->arglist[a+1] = NULL; 419 } 420 421 if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) { 422 cmd_data->arglist[a+1] = NULL; 423 } 424 425 if (strcmp(arg, "-o") == 0) { 426 a++; 427 } 428 } 429 430 if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) { 431 cmd_data->arglist[a] = LIBRARIAN " cr"; 432 } 433 434 if (ext) { 435 if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) { 436 /* ignore source files, they don't belong in a library */ 437 cmd_data->arglist[a] = NULL; 438 } 439 440 if (strcmp(ext, STATIC_LIB_EXT) == 0) { 441 cmd_data->arglist[a] = NULL; 442 explode_static_lib(arg, cmd_data); 443 } 444 } 445 } 446 } 447 } 448 449 if (cmd_data->output_type == otDynamicLibrary) { 450 for (a=0; a < cmd_data->num_args; a++) { 451 arg = cmd_data->arglist[a]; 452 453 if (arg) { 454 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { 455 cmd_data->arglist[a] = NULL; 456 cmd_data->arglist[a+1] = NULL; 457 } 458 } 459 } 460 461 if (export_all) { 462 generate_def_file(cmd_data); 463 } 464 } 465 466#if USE_OMF 467 if (cmd_data->output_type == otObject || 468 cmd_data->output_type == otProgram || 469 cmd_data->output_type == otDynamicLibrary) { 470 cmd_data->arglist[cmd_data->num_args++] = "-Zomf"; 471 } 472#endif 473 474 if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) { 475 cmd_data->arglist[cmd_data->num_args++] = SHARE_SW; 476 } 477} 478 479 480 481int execute_command(cmd_data_t *cmd_data) 482{ 483 int target = 0; 484 char *command; 485 int a, total_len = 0; 486 char *args[4]; 487 488 for (a=0; a < cmd_data->num_args; a++) { 489 if (cmd_data->arglist[a]) { 490 total_len += strlen(cmd_data->arglist[a]) + 1; 491 } 492 } 493 494 command = (char *)malloc( total_len ); 495 command[0] = 0; 496 497 for (a=0; a < cmd_data->num_args; a++) { 498 if (cmd_data->arglist[a]) { 499 strcat(command, cmd_data->arglist[a]); 500 strcat(command, " "); 501 } 502 } 503 504 command[strlen(command)-1] = 0; 505 506 if (!silent) { 507 puts(command); 508 } 509 510 cmd_data->num_args = target; 511 cmd_data->arglist[cmd_data->num_args] = NULL; 512 command = shell_esc(command); 513 514 args[0] = SHELL_CMD; 515 args[1] = "-c"; 516 args[2] = command; 517 args[3] = NULL; 518 return spawnvp(P_WAIT, args[0], args); 519} 520 521 522 523char *shell_esc(const char *str) 524{ 525 char *cmd; 526 unsigned char *d; 527 const unsigned char *s; 528 529 cmd = (char *)malloc(2 * strlen(str) + 1); 530 d = (unsigned char *)cmd; 531 s = (const unsigned char *)str; 532 533 for (; *s; ++s) { 534 if (*s == '"' || *s == '\\') { 535 *d++ = '\\'; 536 } 537 *d++ = *s; 538 } 539 540 *d = '\0'; 541 return cmd; 542} 543 544 545 546bool explode_static_lib(char *lib, cmd_data_t *cmd_data) 547{ 548 char tmpdir[1024]; 549 char savewd[1024]; 550 char cmd[1024]; 551 char *name; 552 DIR *dir; 553 struct dirent *entry; 554 555 strcpy(tmpdir, lib); 556 strcat(tmpdir, ".exploded"); 557 558 mkdir(tmpdir, 0); 559 cmd_data->tmp_dirs[cmd_data->num_tmp_dirs++] = strdup(tmpdir); 560 getcwd(savewd, sizeof(savewd)); 561 562 if (chdir(tmpdir) != 0) 563 return false; 564 565 strcpy(cmd, LIBRARIAN " x "); 566 name = strrchr(lib, '/'); 567 568 if (name) { 569 name++; 570 } else { 571 name = lib; 572 } 573 574 strcat(cmd, "../"); 575 strcat(cmd, name); 576 system(cmd); 577 chdir(savewd); 578 dir = opendir(tmpdir); 579 580 while ((entry = readdir(dir)) != NULL) { 581 if (entry->d_name[0] != '.') { 582 strcpy(cmd, tmpdir); 583 strcat(cmd, "/"); 584 strcat(cmd, entry->d_name); 585 cmd_data->arglist[cmd_data->num_args++] = strdup(cmd); 586 } 587 } 588 589 closedir(dir); 590 return true; 591} 592 593 594 595void cleanup_tmp_dir(char *dirname) 596{ 597 DIR *dir; 598 struct dirent *entry; 599 char fullname[1024]; 600 601 dir = opendir(dirname); 602 603 if (dir == NULL) 604 return; 605 606 while ((entry = readdir(dir)) != NULL) { 607 if (entry->d_name[0] != '.') { 608 strcpy(fullname, dirname); 609 strcat(fullname, "/"); 610 strcat(fullname, entry->d_name); 611 remove(fullname); 612 } 613 } 614 615 rmdir(dirname); 616} 617 618 619 620void cleanup_tmp_dirs(cmd_data_t *cmd_data) 621{ 622 int d; 623 624 for (d=0; d < cmd_data->num_tmp_dirs; d++) { 625 cleanup_tmp_dir(cmd_data->tmp_dirs[d]); 626 } 627} 628 629 630 631void generate_def_file(cmd_data_t *cmd_data) 632{ 633 char def_file[1024]; 634 char implib_file[1024]; 635 char *ext; 636 FILE *hDef; 637 char *export_args[1024]; 638 int num_export_args = 0; 639 char *cmd; 640 int cmd_size = 0; 641 int a; 642 643 if (cmd_data->output_name) { 644 strcpy(def_file, cmd_data->output_name); 645 strcat(def_file, ".def"); 646 hDef = fopen(def_file, "w"); 647 648 if (hDef != NULL) { 649 fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name)); 650 fprintf(hDef, "DATA NONSHARED\n"); 651 fprintf(hDef, "EXPORTS\n"); 652 fclose(hDef); 653 654 for (a=0; a < cmd_data->num_obj_files; a++) { 655 cmd_size += strlen(cmd_data->obj_files[a]) + 1; 656 } 657 658 cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3; 659 cmd = (char *)malloc(cmd_size); 660 strcpy(cmd, GEN_EXPORTS); 661 662 for (a=0; a < cmd_data->num_obj_files; a++) { 663 strcat(cmd, " "); 664 strcat(cmd, cmd_data->obj_files[a] ); 665 } 666 667 strcat(cmd, ">>"); 668 strcat(cmd, def_file); 669 puts(cmd); 670 export_args[num_export_args++] = SHELL_CMD; 671 export_args[num_export_args++] = "-c"; 672 export_args[num_export_args++] = cmd; 673 export_args[num_export_args++] = NULL; 674 spawnvp(P_WAIT, export_args[0], export_args); 675 cmd_data->arglist[cmd_data->num_args++] = strdup(def_file); 676 677 /* Now make an import library for the dll */ 678 num_export_args = 0; 679 export_args[num_export_args++] = DEF2IMPLIB_CMD; 680 export_args[num_export_args++] = "-o"; 681 682 strcpy(implib_file, ".libs/"); 683 strcat(implib_file, cmd_data->stub_name); 684 ext = strrchr(implib_file, '.'); 685 686 if (ext) 687 *ext = 0; 688 689 strcat(implib_file, "."); 690 strcat(implib_file, STATIC_LIB_EXT); 691 692 export_args[num_export_args++] = implib_file; 693 export_args[num_export_args++] = def_file; 694 export_args[num_export_args++] = NULL; 695 spawnvp(P_WAIT, export_args[0], export_args); 696 } 697 } 698} 699 700 701 702/* returns just a file's name without path or extension */ 703char *nameof(char *fullpath) 704{ 705 char buffer[1024]; 706 char *ext; 707 char *name = strrchr(fullpath, '/'); 708 709 if (name == NULL) { 710 name = strrchr(fullpath, '\\'); 711 } 712 713 if (name == NULL) { 714 name = fullpath; 715 } else { 716 name++; 717 } 718 719 strcpy(buffer, name); 720 ext = strrchr(buffer, '.'); 721 722 if (ext) { 723 *ext = 0; 724 return strdup(buffer); 725 } 726 727 return name; 728} 729 730 731 732char *truncate_dll_name(char *path) 733{ 734 /* Cut DLL name down to 8 characters after removing any mod_ prefix */ 735 char *tmppath = strdup(path); 736 char *newname = strrchr(tmppath, '/') + 1; 737 char *ext = strrchr(tmppath, '.'); 738 int len; 739 740 if (ext == NULL) 741 return tmppath; 742 743 len = ext - newname; 744 745 if (strncmp(newname, "mod_", 4) == 0) { 746 strcpy(newname, newname + 4); 747 len -= 4; 748 } 749 750 if (len > 8) { 751 strcpy(newname + 8, strchr(newname, '.')); 752 } 753 754 return tmppath; 755} 756