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 char *newarg; 234 235 if (!ext) { 236 return false; 237 } 238 239 ext++; 240 241 if (name == NULL) { 242 name = strrchr(arg, '\\'); 243 244 if (name == NULL) { 245 name = arg; 246 } else { 247 name++; 248 } 249 } else { 250 name++; 251 } 252 253 if (strcmp(ext, "lo") == 0) { 254 newarg = (char *)malloc(strlen(arg) + 10); 255 strcpy(newarg, arg); 256 strcpy(newarg + (ext - arg), OBJECT_EXT); 257 cmd_data->arglist[cmd_data->num_args++] = newarg; 258 cmd_data->obj_files[cmd_data->num_obj_files++] = newarg; 259 return true; 260 } 261 262 if (strcmp(ext, "la") == 0) { 263 newarg = (char *)malloc(strlen(arg) + 10); 264 strcpy(newarg, arg); 265 newarg[pathlen] = 0; 266 strcat(newarg, ".libs/"); 267 268 if (strncmp(name, "lib", 3) == 0) { 269 name += 3; 270 } 271 272 strcat(newarg, name); 273 ext = strrchr(newarg, '.') + 1; 274 275 if (shared && cmd_data->mode == mInstall) { 276 strcpy(ext, DYNAMIC_LIB_EXT); 277 newarg = truncate_dll_name(newarg); 278 } else { 279 strcpy(ext, STATIC_LIB_EXT); 280 } 281 282 cmd_data->arglist[cmd_data->num_args++] = newarg; 283 return true; 284 } 285 286 if (strcmp(ext, "c") == 0) { 287 if (cmd_data->stub_name == NULL) { 288 cmd_data->stub_name = (char *)malloc(strlen(arg) + 4); 289 strcpy(cmd_data->stub_name, arg); 290 strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo"); 291 } 292 } 293 294 if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) { 295 if (cmd_data->output_type == otGeneral) { 296 cmd_data->output_type = otObject; 297 } 298 } 299 300 return false; 301} 302 303 304 305bool parse_output_file_name(char *arg, cmd_data_t *cmd_data) 306{ 307 char *name = strrchr(arg, '/'); 308 char *ext = strrchr(arg, '.'); 309 char *newarg = NULL, *newext; 310 311 if (name == NULL) { 312 name = strrchr(arg, '\\'); 313 314 if (name == NULL) { 315 name = arg; 316 } else { 317 name++; 318 } 319 } else { 320 name++; 321 } 322 323 if (!ext) { 324 cmd_data->stub_name = arg; 325 cmd_data->output_type = otProgram; 326 newarg = (char *)malloc(strlen(arg) + 5); 327 strcpy(newarg, arg); 328 strcat(newarg, EXE_EXT); 329 cmd_data->arglist[cmd_data->num_args++] = newarg; 330 cmd_data->output_name = newarg; 331 return true; 332 } 333 334 ext++; 335 336 if (strcmp(ext, "la") == 0) { 337 cmd_data->stub_name = arg; 338 cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary; 339 newarg = (char *)malloc(strlen(arg) + 10); 340 mkdir(".libs", 0); 341 strcpy(newarg, ".libs/"); 342 343 if (strncmp(arg, "lib", 3) == 0) { 344 arg += 3; 345 } 346 347 strcat(newarg, arg); 348 newext = strrchr(newarg, '.') + 1; 349 strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT); 350 351#ifdef TRUNCATE_DLL_NAME 352 if (shared) { 353 newarg = truncate_dll_name(newarg); 354 } 355#endif 356 357 cmd_data->arglist[cmd_data->num_args++] = newarg; 358 cmd_data->output_name = newarg; 359 return true; 360 } 361 362 if (strcmp(ext, "lo") == 0) { 363 cmd_data->stub_name = arg; 364 cmd_data->output_type = otObject; 365 newarg = (char *)malloc(strlen(arg) + 2); 366 strcpy(newarg, arg); 367 ext = strrchr(newarg, '.') + 1; 368 strcpy(ext, OBJECT_EXT); 369 cmd_data->arglist[cmd_data->num_args++] = newarg; 370 cmd_data->output_name = newarg; 371 return true; 372 } 373 374 return false; 375} 376 377 378 379void post_parse_fixup(cmd_data_t *cmd_data) 380{ 381 int a; 382 char *arg; 383 char *ext; 384 385 if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) { 386 /* We do a real hatchet job on the args when making a static library 387 * removing all compiler switches & any other cruft that ar won't like 388 * We also need to explode any libraries listed 389 */ 390 391 for (a=0; a < cmd_data->num_args; a++) { 392 arg = cmd_data->arglist[a]; 393 394 if (arg) { 395 ext = strrchr(arg, '.'); 396 397 if (ext) { 398 ext++; 399 } 400 401 if (arg[0] == '-') { 402 cmd_data->arglist[a] = NULL; 403 404 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { 405 cmd_data->arglist[a+1] = NULL; 406 } 407 408 if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) { 409 cmd_data->arglist[a+1] = NULL; 410 } 411 412 if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) { 413 cmd_data->arglist[a+1] = NULL; 414 } 415 416 if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) { 417 cmd_data->arglist[a+1] = NULL; 418 } 419 420 if (strcmp(arg, "-o") == 0) { 421 a++; 422 } 423 } 424 425 if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) { 426 cmd_data->arglist[a] = LIBRARIAN " cr"; 427 } 428 429 if (ext) { 430 if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) { 431 /* ignore source files, they don't belong in a library */ 432 cmd_data->arglist[a] = NULL; 433 } 434 435 if (strcmp(ext, STATIC_LIB_EXT) == 0) { 436 cmd_data->arglist[a] = NULL; 437 explode_static_lib(arg, cmd_data); 438 } 439 } 440 } 441 } 442 } 443 444 if (cmd_data->output_type == otDynamicLibrary) { 445 for (a=0; a < cmd_data->num_args; a++) { 446 arg = cmd_data->arglist[a]; 447 448 if (arg) { 449 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { 450 cmd_data->arglist[a] = NULL; 451 cmd_data->arglist[a+1] = NULL; 452 } 453 } 454 } 455 456 if (export_all) { 457 generate_def_file(cmd_data); 458 } 459 } 460 461#if USE_OMF 462 if (cmd_data->output_type == otObject || 463 cmd_data->output_type == otProgram || 464 cmd_data->output_type == otDynamicLibrary) { 465 cmd_data->arglist[cmd_data->num_args++] = "-Zomf"; 466 } 467#endif 468 469 if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) { 470 cmd_data->arglist[cmd_data->num_args++] = SHARE_SW; 471 } 472} 473 474 475 476int execute_command(cmd_data_t *cmd_data) 477{ 478 int target = 0; 479 char *command; 480 int a, total_len = 0; 481 char *args[4]; 482 483 for (a=0; a < cmd_data->num_args; a++) { 484 if (cmd_data->arglist[a]) { 485 total_len += strlen(cmd_data->arglist[a]) + 1; 486 } 487 } 488 489 command = (char *)malloc( total_len ); 490 command[0] = 0; 491 492 for (a=0; a < cmd_data->num_args; a++) { 493 if (cmd_data->arglist[a]) { 494 strcat(command, cmd_data->arglist[a]); 495 strcat(command, " "); 496 } 497 } 498 499 command[strlen(command)-1] = 0; 500 501 if (!silent) { 502 puts(command); 503 } 504 505 cmd_data->num_args = target; 506 cmd_data->arglist[cmd_data->num_args] = NULL; 507 command = shell_esc(command); 508 509 args[0] = SHELL_CMD; 510 args[1] = "-c"; 511 args[2] = command; 512 args[3] = NULL; 513 return spawnvp(P_WAIT, args[0], args); 514} 515 516 517 518char *shell_esc(const char *str) 519{ 520 char *cmd; 521 unsigned char *d; 522 const unsigned char *s; 523 524 cmd = (char *)malloc(2 * strlen(str) + 1); 525 d = (unsigned char *)cmd; 526 s = (const unsigned char *)str; 527 528 for (; *s; ++s) { 529 if (*s == '"' || *s == '\\') { 530 *d++ = '\\'; 531 } 532 *d++ = *s; 533 } 534 535 *d = '\0'; 536 return cmd; 537} 538 539 540 541bool explode_static_lib(char *lib, cmd_data_t *cmd_data) 542{ 543 char tmpdir[1024]; 544 char savewd[1024]; 545 char cmd[1024]; 546 char *name; 547 DIR *dir; 548 struct dirent *entry; 549 550 strcpy(tmpdir, lib); 551 strcat(tmpdir, ".exploded"); 552 553 mkdir(tmpdir, 0); 554 cmd_data->tmp_dirs[cmd_data->num_tmp_dirs++] = strdup(tmpdir); 555 getcwd(savewd, sizeof(savewd)); 556 557 if (chdir(tmpdir) != 0) 558 return false; 559 560 strcpy(cmd, LIBRARIAN " x "); 561 name = strrchr(lib, '/'); 562 563 if (name) { 564 name++; 565 } else { 566 name = lib; 567 } 568 569 strcat(cmd, "../"); 570 strcat(cmd, name); 571 system(cmd); 572 chdir(savewd); 573 dir = opendir(tmpdir); 574 575 while ((entry = readdir(dir)) != NULL) { 576 if (entry->d_name[0] != '.') { 577 strcpy(cmd, tmpdir); 578 strcat(cmd, "/"); 579 strcat(cmd, entry->d_name); 580 cmd_data->arglist[cmd_data->num_args++] = strdup(cmd); 581 } 582 } 583 584 closedir(dir); 585 return true; 586} 587 588 589 590void cleanup_tmp_dir(char *dirname) 591{ 592 DIR *dir; 593 struct dirent *entry; 594 char fullname[1024]; 595 596 dir = opendir(dirname); 597 598 if (dir == NULL) 599 return; 600 601 while ((entry = readdir(dir)) != NULL) { 602 if (entry->d_name[0] != '.') { 603 strcpy(fullname, dirname); 604 strcat(fullname, "/"); 605 strcat(fullname, entry->d_name); 606 remove(fullname); 607 } 608 } 609 610 rmdir(dirname); 611} 612 613 614 615void cleanup_tmp_dirs(cmd_data_t *cmd_data) 616{ 617 int d; 618 619 for (d=0; d < cmd_data->num_tmp_dirs; d++) { 620 cleanup_tmp_dir(cmd_data->tmp_dirs[d]); 621 } 622} 623 624 625 626void generate_def_file(cmd_data_t *cmd_data) 627{ 628 char def_file[1024]; 629 char implib_file[1024]; 630 char *ext; 631 FILE *hDef; 632 char *export_args[1024]; 633 int num_export_args = 0; 634 char *cmd; 635 int cmd_size = 0; 636 int a; 637 638 if (cmd_data->output_name) { 639 strcpy(def_file, cmd_data->output_name); 640 strcat(def_file, ".def"); 641 hDef = fopen(def_file, "w"); 642 643 if (hDef != NULL) { 644 fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name)); 645 fprintf(hDef, "DATA NONSHARED\n"); 646 fprintf(hDef, "EXPORTS\n"); 647 fclose(hDef); 648 649 for (a=0; a < cmd_data->num_obj_files; a++) { 650 cmd_size += strlen(cmd_data->obj_files[a]) + 1; 651 } 652 653 cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3; 654 cmd = (char *)malloc(cmd_size); 655 strcpy(cmd, GEN_EXPORTS); 656 657 for (a=0; a < cmd_data->num_obj_files; a++) { 658 strcat(cmd, " "); 659 strcat(cmd, cmd_data->obj_files[a] ); 660 } 661 662 strcat(cmd, ">>"); 663 strcat(cmd, def_file); 664 puts(cmd); 665 export_args[num_export_args++] = SHELL_CMD; 666 export_args[num_export_args++] = "-c"; 667 export_args[num_export_args++] = cmd; 668 export_args[num_export_args++] = NULL; 669 spawnvp(P_WAIT, export_args[0], export_args); 670 cmd_data->arglist[cmd_data->num_args++] = strdup(def_file); 671 672 /* Now make an import library for the dll */ 673 num_export_args = 0; 674 export_args[num_export_args++] = DEF2IMPLIB_CMD; 675 export_args[num_export_args++] = "-o"; 676 677 strcpy(implib_file, ".libs/"); 678 strcat(implib_file, cmd_data->stub_name); 679 ext = strrchr(implib_file, '.'); 680 681 if (ext) 682 *ext = 0; 683 684 strcat(implib_file, "."); 685 strcat(implib_file, STATIC_LIB_EXT); 686 687 export_args[num_export_args++] = implib_file; 688 export_args[num_export_args++] = def_file; 689 export_args[num_export_args++] = NULL; 690 spawnvp(P_WAIT, export_args[0], export_args); 691 } 692 } 693} 694 695 696 697/* returns just a file's name without path or extension */ 698char *nameof(char *fullpath) 699{ 700 char buffer[1024]; 701 char *ext; 702 char *name = strrchr(fullpath, '/'); 703 704 if (name == NULL) { 705 name = strrchr(fullpath, '\\'); 706 } 707 708 if (name == NULL) { 709 name = fullpath; 710 } else { 711 name++; 712 } 713 714 strcpy(buffer, name); 715 ext = strrchr(buffer, '.'); 716 717 if (ext) { 718 *ext = 0; 719 return strdup(buffer); 720 } 721 722 return name; 723} 724 725 726 727char *truncate_dll_name(char *path) 728{ 729 /* Cut DLL name down to 8 characters after removing any mod_ prefix */ 730 char *tmppath = strdup(path); 731 char *newname = strrchr(tmppath, '/') + 1; 732 char *ext = strrchr(tmppath, '.'); 733 int len; 734 735 if (ext == NULL) 736 return tmppath; 737 738 len = ext - newname; 739 740 if (strncmp(newname, "mod_", 4) == 0) { 741 strcpy(newname, newname + 4); 742 len -= 4; 743 } 744 745 if (len > 8) { 746 strcpy(newname + 8, strchr(newname, '.')); 747 } 748 749 return tmppath; 750} 751