xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/build/aplibtool.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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