Initial import.
[profile/ivi/apr.git] / build / aplibtool.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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 */
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
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 }