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
24 typedef char bool;
25 #define false 0
26 #define true (!false)
27
28 bool silent = false;
29 bool shared = false;
30 bool export_all = false;
31 enum mode_t { mCompile, mLink, mInstall };
32 enum 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
59 typedef 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
72 void parse_args(int argc, char *argv[], cmd_data_t *cmd_data);
73 bool parse_long_opt(char *arg, cmd_data_t *cmd_data);
74 int parse_short_opt(char *arg, cmd_data_t *cmd_data);
75 bool parse_input_file_name(char *arg, cmd_data_t *cmd_data);
76 bool parse_output_file_name(char *arg, cmd_data_t *cmd_data);
77 void post_parse_fixup(cmd_data_t *cmd_data);
78 bool explode_static_lib(char *lib, cmd_data_t *cmd_data);
79 int execute_command(cmd_data_t *cmd_data);
80 char *shell_esc(const char *str);
81 void cleanup_tmp_dirs(cmd_data_t *cmd_data);
82 void generate_def_file(cmd_data_t *cmd_data);
83 char *nameof(char *fullpath);
84 char *truncate_dll_name(char *path);
85
86
main(int argc,char * argv[])87 int 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
parse_args(int argc,char * argv[],cmd_data_t * cmd_data)109 void 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
parse_long_opt(char * arg,cmd_data_t * cmd_data)148 bool 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
parse_short_opt(char * arg,cmd_data_t * cmd_data)190 int 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
parse_input_file_name(char * arg,cmd_data_t * cmd_data)229 bool 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
parse_output_file_name(char * arg,cmd_data_t * cmd_data)305 bool 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
post_parse_fixup(cmd_data_t * cmd_data)379 void 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
execute_command(cmd_data_t * cmd_data)476 int 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
shell_esc(const char * str)518 char *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
explode_static_lib(char * lib,cmd_data_t * cmd_data)541 bool 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
cleanup_tmp_dir(char * dirname)590 void 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
cleanup_tmp_dirs(cmd_data_t * cmd_data)615 void 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
generate_def_file(cmd_data_t * cmd_data)626 void 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 */
nameof(char * fullpath)698 char *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
truncate_dll_name(char * path)727 char *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