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 <string.h>
19 #include <stdlib.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #if !defined(__MINGW32__)
23 #include <sys/wait.h>
24 #endif
25 #include <unistd.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <assert.h>
29 
30 #ifdef __EMX__
31 #  define SHELL_CMD  "sh"
32 #  define GEN_EXPORTS "emxexp"
33 #  define DEF2IMPLIB_CMD "emximp"
34 #  define SHARE_SW   "-Zdll -Zmtd"
35 #  define USE_OMF 1
36 #  define TRUNCATE_DLL_NAME
37 #  define DYNAMIC_LIB_EXT "dll"
38 #  define EXE_EXT ".exe"
39 
40 #  if USE_OMF
41      /* OMF is the native format under OS/2 */
42 #    define STATIC_LIB_EXT "lib"
43 #    define OBJECT_EXT     "obj"
44 #    define LIBRARIAN      "emxomfar"
45 #    define LIBRARIAN_OPTS "cr"
46 #  else
47      /* but the alternative, a.out, can fork() which is sometimes necessary */
48 #    define STATIC_LIB_EXT "a"
49 #    define OBJECT_EXT     "o"
50 #    define LIBRARIAN      "ar"
51 #    define LIBRARIAN_OPTS "cr"
52 #  endif
53 #endif
54 
55 #if defined(__APPLE__)
56 #  define SHELL_CMD  "/bin/sh"
57 #  define DYNAMIC_LIB_EXT "dylib"
58 #  define MODULE_LIB_EXT  "bundle"
59 #  define STATIC_LIB_EXT "a"
60 #  define OBJECT_EXT     "o"
61 #  define LIBRARIAN      "ar"
62 #  define LIBRARIAN_OPTS "cr"
63 /* man libtool(1) documents ranlib option of -c.  */
64 #  define RANLIB "ranlib"
65 #  define PIC_FLAG "-fPIC -fno-common"
66 #  define SHARED_OPTS "-dynamiclib"
67 #  define MODULE_OPTS "-bundle -dynamic"
68 #  define DYNAMIC_LINK_OPTS "-flat_namespace"
69 #  define DYNAMIC_LINK_UNDEFINED "-undefined suppress"
70 #  define dynamic_link_version_func darwin_dynamic_link_function
71 #  define DYNAMIC_INSTALL_NAME "-install_name"
72 #  define DYNAMIC_LINK_NO_INSTALL "-dylib_file"
73 #  define HAS_REALPATH
74 /*-install_name  /Users/jerenk/apache-2.0-cvs/lib/libapr.0.dylib -compatibility_version 1 -current_version 1.0 */
75 #  define LD_LIBRARY_PATH "DYLD_LIBRARY_PATH"
76 #endif
77 
78 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
79 #  define SHELL_CMD  "/bin/sh"
80 #  define DYNAMIC_LIB_EXT "so"
81 #  define MODULE_LIB_EXT  "so"
82 #  define STATIC_LIB_EXT "a"
83 #  define OBJECT_EXT     "o"
84 #  define LIBRARIAN      "ar"
85 #  define LIBRARIAN_OPTS "cr"
86 #  define RANLIB "ranlib"
87 #  define PIC_FLAG "-fPIC"
88 #  define RPATH "-rpath"
89 #  define SHARED_OPTS "-shared"
90 #  define MODULE_OPTS "-shared"
91 #  define DYNAMIC_LINK_OPTS "-export-dynamic"
92 #  define LINKER_FLAG_PREFIX "-Wl,"
93 #  define ADD_MINUS_L
94 #  define LD_RUN_PATH "LD_RUN_PATH"
95 #  define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
96 #endif
97 
98 #if defined(sun)
99 #  define SHELL_CMD  "/bin/sh"
100 #  define DYNAMIC_LIB_EXT "so"
101 #  define MODULE_LIB_EXT  "so"
102 #  define STATIC_LIB_EXT "a"
103 #  define OBJECT_EXT     "o"
104 #  define LIBRARIAN      "ar"
105 #  define LIBRARIAN_OPTS "cr"
106 #  define RANLIB "ranlib"
107 #  define PIC_FLAG "-KPIC"
108 #  define RPATH "-R"
109 #  define SHARED_OPTS "-G"
110 #  define MODULE_OPTS "-G"
111 #  define DYNAMIC_LINK_OPTS ""
112 #  define LINKER_FLAG_NO_EQUALS
113 #  define ADD_MINUS_L
114 #  define HAS_REALPATH
115 #  define LD_RUN_PATH "LD_RUN_PATH"
116 #  define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
117 #endif
118 
119 #if defined(_OSD_POSIX)
120 #  define SHELL_CMD  "/usr/bin/sh"
121 #  define DYNAMIC_LIB_EXT "so"
122 #  define MODULE_LIB_EXT  "so"
123 #  define STATIC_LIB_EXT "a"
124 #  define OBJECT_EXT     "o"
125 #  define LIBRARIAN      "ar"
126 #  define LIBRARIAN_OPTS "cr"
127 #  define SHARED_OPTS "-G"
128 #  define MODULE_OPTS "-G"
129 #  define LINKER_FLAG_PREFIX "-Wl,"
130 #  define NEED_SNPRINTF
131 #endif
132 
133 #if defined(sinix) && defined(mips) && defined(__SNI_TARG_UNIX)
134 #  define SHELL_CMD  "/usr/bin/sh"
135 #  define DYNAMIC_LIB_EXT "so"
136 #  define MODULE_LIB_EXT  "so"
137 #  define STATIC_LIB_EXT "a"
138 #  define OBJECT_EXT     "o"
139 #  define LIBRARIAN      "ar"
140 #  define LIBRARIAN_OPTS "cr"
141 #  define RPATH "-Brpath"
142 #  define SHARED_OPTS "-G"
143 #  define MODULE_OPTS "-G"
144 #  define DYNAMIC_LINK_OPTS "-Wl,-Blargedynsym"
145 #  define LINKER_FLAG_PREFIX "-Wl,"
146 #  define NEED_SNPRINTF
147 #  define LD_RUN_PATH "LD_RUN_PATH"
148 #  define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
149 #endif
150 
151 #if defined(__MINGW32__)
152 #  define SHELL_CMD "sh"
153 #  define DYNAMIC_LIB_EXT "dll"
154 #  define MODULE_LIB_EXT  "dll"
155 #  define STATIC_LIB_EXT "a"
156 #  define OBJECT_EXT     "o"
157 #  define LIBRARIAN      "ar"
158 #  define LIBRARIAN_OPTS "cr"
159 #  define RANLIB "ranlib"
160 #  define LINKER_FLAG_PREFIX "-Wl,"
161 #  define SHARED_OPTS "-shared"
162 #  define MODULE_OPTS "-shared"
163 #  define MKDIR_NO_UMASK
164 #  define EXE_EXT ".exe"
165 #endif
166 
167 #ifndef SHELL_CMD
168 #error Unsupported platform: Please add defines for SHELL_CMD etc. for your platform.
169 #endif
170 
171 #ifdef NEED_SNPRINTF
172 #include <stdarg.h>
173 #endif
174 
175 #ifdef __EMX__
176 #include <process.h>
177 #endif
178 
179 #ifndef PATH_MAX
180 #define PATH_MAX 1024
181 #endif
182 
183 
184 /* We want to say we are libtool 1.4 for shlibtool compatibility. */
185 #define VERSION "1.4"
186 
187 enum tool_mode_t {
188     mUnknown,
189     mCompile,
190     mLink,
191     mInstall,
192 };
193 
194 enum output_t {
195     otGeneral,
196     otObject,
197     otProgram,
198     otLibrary,
199     otStaticLibraryOnly,
200     otDynamicLibraryOnly,
201     otModule,
202 };
203 
204 enum pic_mode_e {
205     pic_UNKNOWN,
206     pic_PREFER,
207     pic_AVOID,
208 };
209 
210 enum shared_mode_e {
211     share_UNSET,
212     share_STATIC,
213     share_SHARED,
214 };
215 
216 enum lib_type {
217     type_UNKNOWN,
218     type_DYNAMIC_LIB,
219     type_STATIC_LIB,
220     type_MODULE_LIB,
221     type_OBJECT,
222 };
223 
224 typedef struct {
225     const char **vals;
226     int num;
227 } count_chars;
228 
229 typedef struct {
230     const char *normal;
231     const char *install;
232 } library_name;
233 
234 typedef struct {
235     count_chars *normal;
236     count_chars *install;
237     count_chars *dependencies;
238 } library_opts;
239 
240 typedef struct {
241     int silent;
242     enum shared_mode_e shared;
243     int export_all;
244     int dry_run;
245     enum pic_mode_e pic_mode;
246     int export_dynamic;
247     int no_install;
248 } options_t;
249 
250 typedef struct {
251     enum tool_mode_t mode;
252     enum output_t output;
253     options_t options;
254 
255     char *output_name;
256     char *fake_output_name;
257     char *basename;
258 
259     const char *install_path;
260     const char *compiler;
261     const char *program;
262     count_chars *program_opts;
263 
264     count_chars *arglist;
265     count_chars *tmp_dirs;
266     count_chars *obj_files;
267     count_chars *dep_rpaths;
268     count_chars *rpaths;
269 
270     library_name static_name;
271     library_name shared_name;
272     library_name module_name;
273 
274     library_opts static_opts;
275     library_opts shared_opts;
276 
277     const char *version_info;
278     const char *undefined_flag;
279 } command_t;
280 
281 #ifdef RPATH
282 void add_rpath(count_chars *cc, const char *path);
283 #endif
284 
285 #if defined(NEED_SNPRINTF)
286 /* Write at most n characters to the buffer in str, return the
287  * number of chars written or -1 if the buffer would have been
288  * overflowed.
289  *
290  * This is portable to any POSIX-compliant system has /dev/null
291  */
292 static FILE *f=NULL;
vsnprintf(char * str,size_t n,const char * fmt,va_list ap)293 static int vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
294 {
295        int res;
296 
297        if (f == NULL)
298                f = fopen("/dev/null","w");
299        if (f == NULL)
300                return -1;
301 
302        setvbuf( f, str, _IOFBF, n );
303 
304        res = vfprintf( f, fmt, ap );
305 
306        if ( res > 0 && res < n ) {
307                res = vsprintf( str, fmt, ap );
308        }
309        return res;
310 }
snprintf(char * str,size_t n,const char * fmt,...)311 static int snprintf( char *str, size_t n, const char *fmt, ... )
312 {
313         va_list ap;
314         int res;
315 
316         va_start( ap, fmt );
317         res = vsnprintf( str, n, fmt, ap );
318         va_end( ap );
319         return res;
320 }
321 #endif
322 
init_count_chars(count_chars * cc)323 void init_count_chars(count_chars *cc)
324 {
325     cc->vals = (const char**)malloc(PATH_MAX*sizeof(char*));
326     cc->num = 0;
327 }
328 
clear_count_chars(count_chars * cc)329 void clear_count_chars(count_chars *cc)
330 {
331     int i;
332     for (i = 0; i < cc->num; i++) {
333         cc->vals[i] = 0;
334     }
335 
336     cc->num = 0;
337 }
338 
push_count_chars(count_chars * cc,const char * newval)339 void push_count_chars(count_chars *cc, const char *newval)
340 {
341     cc->vals[cc->num++] = newval;
342 }
343 
pop_count_chars(count_chars * cc)344 void pop_count_chars(count_chars *cc)
345 {
346     cc->num--;
347 }
348 
insert_count_chars(count_chars * cc,const char * newval,int position)349 void insert_count_chars(count_chars *cc, const char *newval, int position)
350 {
351     int i;
352 
353     for (i = cc->num; i > position; i--) {
354         cc->vals[i] = cc->vals[i-1];
355     }
356 
357     cc->vals[position] = newval;
358     cc->num++;
359 }
360 
append_count_chars(count_chars * cc,count_chars * cctoadd)361 void append_count_chars(count_chars *cc, count_chars *cctoadd)
362 {
363     int i;
364     for (i = 0; i < cctoadd->num; i++) {
365         if (cctoadd->vals[i]) {
366             push_count_chars(cc, cctoadd->vals[i]);
367         }
368     }
369 }
370 
flatten_count_chars(count_chars * cc,int space)371 const char *flatten_count_chars(count_chars *cc, int space)
372 {
373     int i, size;
374     char *newval;
375 
376     size = 0;
377     for (i = 0; i < cc->num; i++) {
378         if (cc->vals[i]) {
379             size += strlen(cc->vals[i]) + 1;
380             if (space) {
381               size++;
382             }
383         }
384     }
385 
386     newval = (char*)malloc(size + 1);
387     newval[0] = 0;
388 
389     for (i = 0; i < cc->num; i++) {
390         if (cc->vals[i]) {
391             strcat(newval, cc->vals[i]);
392             if (space) {
393                 strcat(newval, " ");
394             }
395         }
396     }
397 
398     return newval;
399 }
400 
shell_esc(const char * str)401 char *shell_esc(const char *str)
402 {
403     int in_quote = 0;
404     char *cmd;
405     unsigned char *d;
406     const unsigned char *s;
407 
408     cmd = (char *)malloc(2 * strlen(str) + 3);
409     d = (unsigned char *)cmd;
410     s = (const unsigned char *)str;
411 
412 #ifdef __MINGW32__
413     *d++ = '\"';
414 #endif
415 
416     for (; *s; ++s) {
417         if (*s == '"') {
418             *d++ = '\\';
419             in_quote++;
420         }
421         else if (*s == '\\' || (*s == ' ' && (in_quote % 2))) {
422             *d++ = '\\';
423         }
424         *d++ = *s;
425     }
426 
427 #ifdef __MINGW32__
428     *d++ = '\"';
429 #endif
430 
431     *d = '\0';
432     return cmd;
433 }
434 
external_spawn(command_t * cmd,const char * file,const char ** argv)435 int external_spawn(command_t *cmd, const char *file, const char **argv)
436 {
437     if (!cmd->options.silent) {
438         const char **argument = argv;
439         printf("Executing: ");
440         while (*argument) {
441             printf("%s ", *argument);
442             argument++;
443         }
444         puts("");
445     }
446 
447     if (cmd->options.dry_run) {
448         return 0;
449     }
450 #if defined(__EMX__) || defined(__MINGW32__)
451     return spawnvp(P_WAIT, argv[0], argv);
452 #else
453     {
454         pid_t pid;
455         pid = fork();
456         if (pid == 0) {
457             return execvp(argv[0], (char**)argv);
458         }
459         else {
460             int statuscode;
461             waitpid(pid, &statuscode, 0);
462             if (WIFEXITED(statuscode)) {
463                 return WEXITSTATUS(statuscode);
464             }
465             return 0;
466         }
467     }
468 #endif
469 }
470 
run_command(command_t * cmd_data,count_chars * cc)471 int run_command(command_t *cmd_data, count_chars *cc)
472 {
473     char *command;
474     const char *spawn_args[4];
475     count_chars tmpcc;
476 
477     init_count_chars(&tmpcc);
478 
479     if (cmd_data->program) {
480         push_count_chars(&tmpcc, cmd_data->program);
481     }
482 
483     append_count_chars(&tmpcc, cmd_data->program_opts);
484 
485     append_count_chars(&tmpcc, cc);
486 
487     command = shell_esc(flatten_count_chars(&tmpcc, 1));
488 
489     spawn_args[0] = SHELL_CMD;
490     spawn_args[1] = "-c";
491     spawn_args[2] = command;
492     spawn_args[3] = NULL;
493     return external_spawn(cmd_data, spawn_args[0], (const char**)spawn_args);
494 }
495 
496 /*
497  * print configuration
498  * shlibpath_var is used in configure.
499  */
print_config()500 void print_config()
501 {
502 #ifdef LD_RUN_PATH
503     printf("runpath_var=%s\n", LD_RUN_PATH);
504 #endif
505 #ifdef LD_LIBRARY_PATH
506     printf("shlibpath_var=%s\n", LD_LIBRARY_PATH);
507 #endif
508 #ifdef SHELL_CMD
509     printf("SHELL=\"%s\"\n", SHELL_CMD);
510 #endif
511 }
512 /*
513  * Add a directory to the runtime library search path.
514  */
add_runtimedirlib(char * arg,command_t * cmd_data)515 void add_runtimedirlib(char *arg, command_t *cmd_data)
516 {
517 #ifdef RPATH
518     add_rpath(cmd_data->shared_opts.dependencies, arg);
519 #else
520 #endif
521 }
522 
parse_long_opt(char * arg,command_t * cmd_data)523 int parse_long_opt(char *arg, command_t *cmd_data)
524 {
525     char *equal_pos = strchr(arg, '=');
526     char var[50];
527     char value[500];
528 
529     if (equal_pos) {
530         strncpy(var, arg, equal_pos - arg);
531         var[equal_pos - arg] = 0;
532         strcpy(value, equal_pos + 1);
533     } else {
534         strcpy(var, arg);
535     }
536 
537     if (strcmp(var, "silent") == 0) {
538         cmd_data->options.silent = 1;
539     } else if (strcmp(var, "mode") == 0) {
540         if (strcmp(value, "compile") == 0) {
541             cmd_data->mode = mCompile;
542             cmd_data->output = otObject;
543         }
544 
545         if (strcmp(value, "link") == 0) {
546             cmd_data->mode = mLink;
547             cmd_data->output = otLibrary;
548         }
549 
550         if (strcmp(value, "install") == 0) {
551             cmd_data->mode = mInstall;
552         }
553     } else if (strcmp(var, "shared") == 0) {
554         if (cmd_data->mode == mLink) {
555             cmd_data->output = otDynamicLibraryOnly;
556         }
557         cmd_data->options.shared = share_SHARED;
558     } else if (strcmp(var, "export-all") == 0) {
559         cmd_data->options.export_all = 1;
560     } else if (strcmp(var, "dry-run") == 0) {
561         printf("Dry-run mode on!\n");
562         cmd_data->options.dry_run = 1;
563     } else if (strcmp(var, "version") == 0) {
564         printf("Version " VERSION "\n");
565     } else if (strcmp(var, "help") == 0) {
566         printf("Sorry.  No help available.\n");
567     } else if (strcmp(var, "config") == 0) {
568         print_config();
569     } else if (strcmp(var, "tag") == 0) {
570         if (strcmp(value, "CC") == 0) {
571             /* Do nothing. */
572         }
573         if (strcmp(value, "CXX") == 0) {
574             /* Do nothing. */
575         }
576     } else {
577         return 0;
578     }
579 
580     return 1;
581 }
582 
583 /* Return 1 if we eat it. */
parse_short_opt(char * arg,command_t * cmd_data)584 int parse_short_opt(char *arg, command_t *cmd_data)
585 {
586     if (strcmp(arg, "export-dynamic") == 0) {
587         cmd_data->options.export_dynamic = 1;
588         return 1;
589     }
590 
591     if (strcmp(arg, "module") == 0) {
592         cmd_data->output = otModule;
593         return 1;
594     }
595 
596     if (strcmp(arg, "shared") == 0) {
597         if (cmd_data->mode == mLink) {
598             cmd_data->output = otDynamicLibraryOnly;
599         }
600         cmd_data->options.shared = share_SHARED;
601         return 1;
602     }
603 
604     if (strcmp(arg, "Zexe") == 0) {
605         return 1;
606     }
607 
608     if (strcmp(arg, "avoid-version") == 0) {
609         return 1;
610     }
611 
612     if (strcmp(arg, "prefer-pic") == 0) {
613         cmd_data->options.pic_mode = pic_PREFER;
614         return 1;
615     }
616 
617     if (strcmp(arg, "prefer-non-pic") == 0) {
618         cmd_data->options.pic_mode = pic_AVOID;
619         return 1;
620     }
621 
622     if (strcmp(arg, "static") == 0) {
623         cmd_data->options.shared = share_STATIC;
624         return 1;
625     }
626 
627     if (cmd_data->mode == mLink) {
628         if (strcmp(arg, "no-install") == 0) {
629             cmd_data->options.no_install = 1;
630             return 1;
631         }
632         if (arg[0] == 'L' || arg[0] == 'l') {
633             /* Hack... */
634             arg--;
635             push_count_chars(cmd_data->shared_opts.dependencies, arg);
636             return 1;
637         } else if (arg[0] == 'R' && arg[1]) {
638             /* -Rdir Add dir to runtime library search path. */
639             add_runtimedirlib(&arg[1], cmd_data);
640             return 1;
641         }
642     }
643     return 0;
644 }
645 
truncate_dll_name(char * path)646 char *truncate_dll_name(char *path)
647 {
648     /* Cut DLL name down to 8 characters after removing any mod_ prefix */
649     char *tmppath = strdup(path);
650     char *newname = strrchr(tmppath, '/') + 1;
651     char *ext = strrchr(tmppath, '.');
652     int len;
653 
654     if (ext == NULL)
655         return tmppath;
656 
657     len = ext - newname;
658 
659     if (strncmp(newname, "mod_", 4) == 0) {
660         strcpy(newname, newname + 4);
661         len -= 4;
662     }
663 
664     if (len > 8) {
665         strcpy(newname + 8, strchr(newname, '.'));
666     }
667 
668     return tmppath;
669 }
670 
safe_strtol(const char * nptr,const char ** endptr,int base)671 long safe_strtol(const char *nptr, const char **endptr, int base)
672 {
673     long rv;
674 
675     errno = 0;
676 
677     rv = strtol(nptr, (char**)endptr, 10);
678 
679     if (errno == ERANGE) {
680         return 0;
681     }
682 
683     return rv;
684 }
685 
safe_mkdir(const char * path)686 void safe_mkdir(const char *path)
687 {
688     mode_t old_umask;
689 
690     old_umask = umask(0);
691     umask(old_umask);
692 
693 #ifdef MKDIR_NO_UMASK
694     mkdir(path);
695 #else
696     mkdir(path, ~old_umask);
697 #endif
698 }
699 
700 /* returns just a file's name without the path */
jlibtool_basename(const char * fullpath)701 const char *jlibtool_basename(const char *fullpath)
702 {
703     const char *name = strrchr(fullpath, '/');
704 
705     if (name == NULL) {
706         name = strrchr(fullpath, '\\');
707     }
708 
709     if (name == NULL) {
710         name = fullpath;
711     } else {
712         name++;
713     }
714 
715     return name;
716 }
717 
718 /* returns just a file's name without path or extension */
nameof(const char * fullpath)719 const char *nameof(const char *fullpath)
720 {
721     const char *name;
722     const char *ext;
723 
724     name = jlibtool_basename(fullpath);
725     ext = strrchr(name, '.');
726 
727     if (ext) {
728         char *trimmed;
729         trimmed = malloc(ext - name + 1);
730         strncpy(trimmed, name, ext - name);
731         trimmed[ext-name] = 0;
732         return trimmed;
733     }
734 
735     return name;
736 }
737 
738 /* version_info is in the form of MAJOR:MINOR:PATCH */
darwin_dynamic_link_function(const char * version_info)739 const char *darwin_dynamic_link_function(const char *version_info)
740 {
741     char *newarg;
742     long major, minor, patch;
743 
744     major = 0;
745     minor = 0;
746     patch = 0;
747 
748     if (version_info) {
749         major = safe_strtol(version_info, &version_info, 10);
750 
751         if (version_info) {
752             if (version_info[0] == ':') {
753                 version_info++;
754             }
755 
756             minor = safe_strtol(version_info, &version_info, 10);
757 
758             if (version_info) {
759                 if (version_info[0] == ':') {
760                     version_info++;
761                 }
762 
763                 patch = safe_strtol(version_info, &version_info, 10);
764 
765             }
766         }
767     }
768 
769     /* Avoid -dylib_compatibility_version must be greater than zero errors. */
770     if (major == 0) {
771         major = 1;
772     }
773     newarg = (char*)malloc(100);
774     snprintf(newarg, 99,
775              "-compatibility_version %ld -current_version %ld.%ld",
776              major, major, minor);
777 
778     return newarg;
779 }
780 
781 /* genlib values
782  * 0 - static
783  * 1 - dynamic
784  * 2 - module
785  */
gen_library_name(const char * name,int genlib)786 char *gen_library_name(const char *name, int genlib)
787 {
788     char *newarg, *newext;
789 
790     newarg = (char *)malloc(strlen(name) + 11);
791     strcpy(newarg, ".libs/");
792 
793     if (genlib == 2 && strncmp(name, "lib", 3) == 0) {
794         name += 3;
795     }
796 
797     if (genlib == 2) {
798         strcat(newarg, jlibtool_basename(name));
799     }
800     else {
801         strcat(newarg, name);
802     }
803 
804     newext = strrchr(newarg, '.') + 1;
805 
806     switch (genlib) {
807     case 0:
808         strcpy(newext, STATIC_LIB_EXT);
809         break;
810     case 1:
811         strcpy(newext, DYNAMIC_LIB_EXT);
812         break;
813     case 2:
814         strcpy(newext, MODULE_LIB_EXT);
815         break;
816     }
817 
818     return newarg;
819 }
820 
821 /* genlib values
822  * 0 - static
823  * 1 - dynamic
824  * 2 - module
825  */
gen_install_name(const char * name,int genlib)826 char *gen_install_name(const char *name, int genlib)
827 {
828     struct stat sb;
829     char *newname;
830     int rv;
831 
832     newname = gen_library_name(name, genlib);
833 
834     /* Check if it exists. If not, return NULL.  */
835     rv = stat(newname, &sb);
836 
837     if (rv) {
838         return NULL;
839     }
840 
841     return newname;
842 }
843 
check_object_exists(command_t * cmd,const char * arg,int arglen)844 char *check_object_exists(command_t *cmd, const char *arg, int arglen)
845 {
846     char *newarg, *ext;
847     int pass, rv;
848 
849     newarg = (char *)malloc(arglen + 10);
850     memcpy(newarg, arg, arglen);
851     newarg[arglen] = 0;
852     ext = newarg + arglen;
853 
854     pass = 0;
855 
856     do {
857         struct stat sb;
858 
859         switch (pass) {
860         case 0:
861             strcpy(ext, OBJECT_EXT);
862             break;
863 /*
864         case 1:
865             strcpy(ext, NO_PIC_EXT);
866             break;
867 */
868         default:
869             break;
870         }
871 
872         if (!cmd->options.silent) {
873             printf("Checking (obj): %s\n", newarg);
874         }
875         rv = stat(newarg, &sb);
876     }
877     while (rv != 0 && ++pass < 1);
878 
879     if (rv == 0) {
880         if (pass == 1) {
881             cmd->options.pic_mode = pic_AVOID;
882         }
883         return newarg;
884     }
885 
886     return NULL;
887 }
888 
889 /* libdircheck values:
890  * 0 - no .libs suffix
891  * 1 - .libs suffix
892  */
check_library_exists(command_t * cmd,const char * arg,int pathlen,int libdircheck,enum lib_type * libtype)893 char *check_library_exists(command_t *cmd, const char *arg, int pathlen,
894                            int libdircheck, enum lib_type *libtype)
895 {
896     char *newarg, *ext;
897     int pass, rv, newpathlen;
898 
899     newarg = (char *)malloc(strlen(arg) + 10);
900     strcpy(newarg, arg);
901     newarg[pathlen] = 0;
902 
903     newpathlen = pathlen;
904     if (libdircheck) {
905         strcat(newarg, ".libs/");
906         newpathlen += sizeof(".libs/") - 1;
907     }
908 
909     strcpy(newarg+newpathlen, arg+pathlen);
910     ext = strrchr(newarg, '.') + 1;
911 
912     pass = 0;
913 
914     do {
915         struct stat sb;
916 
917         switch (pass) {
918         case 0:
919             if (cmd->options.pic_mode != pic_AVOID &&
920                 cmd->options.shared != share_STATIC) {
921                 strcpy(ext, DYNAMIC_LIB_EXT);
922                 *libtype = type_DYNAMIC_LIB;
923                 break;
924             }
925             pass = 1;
926             /* Fall through */
927         case 1:
928             strcpy(ext, STATIC_LIB_EXT);
929             *libtype = type_STATIC_LIB;
930             break;
931         case 2:
932             strcpy(ext, MODULE_LIB_EXT);
933             *libtype = type_MODULE_LIB;
934             break;
935         case 3:
936             strcpy(ext, OBJECT_EXT);
937             *libtype = type_OBJECT;
938             break;
939         default:
940             *libtype = type_UNKNOWN;
941             break;
942         }
943 
944         if (!cmd->options.silent) {
945             printf("Checking (lib): %s\n", newarg);
946         }
947         rv = stat(newarg, &sb);
948     }
949     while (rv != 0 && ++pass < 4);
950 
951     if (rv == 0) {
952         return newarg;
953     }
954 
955     return NULL;
956 }
957 
load_install_path(const char * arg)958 char * load_install_path(const char *arg)
959 {
960     FILE *f;
961     char *path;
962 
963     path = malloc(PATH_MAX);
964 
965     f = fopen(arg,"r");
966     if (f == NULL) {
967         return NULL;
968     }
969     fgets(path, PATH_MAX, f);
970     fclose(f);
971     if (path[strlen(path)-1] == '\n') {
972         path[strlen(path)-1] = '\0';
973     }
974     /* Check that we have an absolute path.
975      * Otherwise the file could be a GNU libtool file.
976      */
977     if (path[0] != '/') {
978         return NULL;
979     }
980     return path;
981 }
982 
load_noinstall_path(const char * arg,int pathlen)983 char * load_noinstall_path(const char *arg, int pathlen)
984 {
985     char *newarg, *expanded_path;
986     int newpathlen;
987 
988     newarg = (char *)malloc(strlen(arg) + 10);
989     strcpy(newarg, arg);
990     newarg[pathlen] = 0;
991 
992     newpathlen = pathlen;
993     strcat(newarg, ".libs");
994     newpathlen += sizeof(".libs") - 1;
995     newarg[newpathlen] = 0;
996 
997 #ifdef HAS_REALPATH
998     expanded_path = malloc(PATH_MAX);
999     expanded_path = realpath(newarg, expanded_path);
1000     /* Uh, oh.  There was an error.  Fall back on our first guess. */
1001     if (!expanded_path) {
1002         expanded_path = newarg;
1003     }
1004 #else
1005     /* We might get ../ or something goofy.  Oh, well. */
1006     expanded_path = newarg;
1007 #endif
1008 
1009     return expanded_path;
1010 }
1011 
add_dynamic_link_opts(command_t * cmd_data,count_chars * args)1012 void add_dynamic_link_opts(command_t *cmd_data, count_chars *args)
1013 {
1014 #ifdef DYNAMIC_LINK_OPTS
1015     if (cmd_data->options.pic_mode != pic_AVOID) {
1016         if (!cmd_data->options.silent) {
1017            printf("Adding: %s\n", DYNAMIC_LINK_OPTS);
1018         }
1019         push_count_chars(args, DYNAMIC_LINK_OPTS);
1020         if (cmd_data->undefined_flag) {
1021             push_count_chars(args, "-undefined");
1022 #if defined(__APPLE__)
1023             /* -undefined dynamic_lookup is used by the bundled Python in
1024              * 10.4, but if we don't set MACOSX_DEPLOYMENT_TARGET to 10.3+,
1025              * we'll get a linker error if we pass this flag.
1026              */
1027             if (strcasecmp(cmd_data->undefined_flag,
1028                            "dynamic_lookup") == 0) {
1029                 insert_count_chars(cmd_data->program_opts,
1030                                    "MACOSX_DEPLOYMENT_TARGET=10.3", 0);
1031             }
1032 #endif
1033             push_count_chars(args, cmd_data->undefined_flag);
1034         }
1035         else {
1036 #ifdef DYNAMIC_LINK_UNDEFINED
1037             if (!cmd_data->options.silent) {
1038                 printf("Adding: %s\n", DYNAMIC_LINK_UNDEFINED);
1039             }
1040             push_count_chars(args, DYNAMIC_LINK_UNDEFINED);
1041 #endif
1042         }
1043     }
1044 #endif
1045 }
1046 
1047 /* Read the final install location and add it to runtime library search path. */
1048 #ifdef RPATH
add_rpath(count_chars * cc,const char * path)1049 void add_rpath(count_chars *cc, const char *path)
1050 {
1051     int size = 0;
1052     char *tmp;
1053 
1054 #ifdef LINKER_FLAG_PREFIX
1055     size = strlen(LINKER_FLAG_PREFIX);
1056 #endif
1057     size = size + strlen(path) + strlen(RPATH) + 2;
1058     tmp = malloc(size);
1059     if (tmp == NULL) {
1060         return;
1061     }
1062 #ifdef LINKER_FLAG_PREFIX
1063     strcpy(tmp, LINKER_FLAG_PREFIX);
1064     strcat(tmp, RPATH);
1065 #else
1066     strcpy(tmp, RPATH);
1067 #endif
1068 #ifndef LINKER_FLAG_NO_EQUALS
1069     strcat(tmp, "=");
1070 #endif
1071     strcat(tmp, path);
1072 
1073     push_count_chars(cc, tmp);
1074 }
1075 
add_rpath_file(count_chars * cc,const char * arg)1076 void add_rpath_file(count_chars *cc, const char *arg)
1077 {
1078     const char *path;
1079 
1080     path = load_install_path(arg);
1081     if (path) {
1082         add_rpath(cc, path);
1083     }
1084 }
1085 
add_rpath_noinstall(count_chars * cc,const char * arg,int pathlen)1086 void add_rpath_noinstall(count_chars *cc, const char *arg, int pathlen)
1087 {
1088     const char *path;
1089 
1090     path = load_noinstall_path(arg, pathlen);
1091     if (path) {
1092         add_rpath(cc, path);
1093     }
1094 }
1095 #endif
1096 
1097 #ifdef DYNAMIC_LINK_NO_INSTALL
add_dylink_noinstall(count_chars * cc,const char * arg,int pathlen,int extlen)1098 void add_dylink_noinstall(count_chars *cc, const char *arg, int pathlen,
1099                           int extlen)
1100 {
1101     const char *install_path, *current_path, *name;
1102     char *exp_argument;
1103     int i_p_len, c_p_len, name_len, dyext_len, cur_len;
1104 
1105     install_path = load_install_path(arg);
1106     current_path = load_noinstall_path(arg, pathlen);
1107 
1108     if (!install_path || !current_path) {
1109         return;
1110     }
1111 
1112     push_count_chars(cc, DYNAMIC_LINK_NO_INSTALL);
1113 
1114     i_p_len = strlen(install_path);
1115     c_p_len = strlen(current_path);
1116 
1117     name = arg+pathlen;
1118     name_len = extlen-pathlen;
1119     dyext_len = sizeof(DYNAMIC_LIB_EXT) - 1;
1120 
1121     /* No, we need to replace the extension. */
1122     exp_argument = (char *)malloc(i_p_len + c_p_len + (name_len*2) +
1123                                   (dyext_len*2) + 2);
1124 
1125     cur_len = 0;
1126     strcpy(exp_argument, install_path);
1127     cur_len += i_p_len;
1128     exp_argument[cur_len++] = '/';
1129     strncpy(exp_argument+cur_len, name, extlen-pathlen);
1130     cur_len += name_len;
1131     strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1132     cur_len += dyext_len;
1133     exp_argument[cur_len++] = ':';
1134     strcpy(exp_argument+cur_len, current_path);
1135     cur_len += c_p_len;
1136     exp_argument[cur_len++] = '/';
1137     strncpy(exp_argument+cur_len, name, extlen-pathlen);
1138     cur_len += name_len;
1139     strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1140     cur_len += dyext_len;
1141 
1142     push_count_chars(cc, exp_argument);
1143 }
1144 #endif
1145 
1146 /* use -L -llibname to allow to use installed libraries */
add_minus_l(count_chars * cc,const char * arg)1147 void add_minus_l(count_chars *cc, const char *arg)
1148 {
1149     char *newarg;
1150     char *name = strrchr(arg, '/');
1151     char *file = strrchr(arg, '.');
1152     char *lib  = strstr(name, "lib");
1153 
1154     if (name !=NULL && file != NULL && lib == name+1) {
1155         *name = '\0';
1156         *file = '\0';
1157         file = name;
1158         file = file+4;
1159         push_count_chars(cc, "-L");
1160         push_count_chars(cc, arg);
1161         /* we need one argument like -lapr-1 */
1162         newarg = malloc(strlen(file) + 3);
1163         strcpy(newarg, "-l");
1164         strcat(newarg, file);
1165         push_count_chars(cc, newarg);
1166     } else {
1167         push_count_chars(cc, arg);
1168     }
1169 }
1170 
add_linker_flag_prefix(count_chars * cc,const char * arg)1171 void add_linker_flag_prefix(count_chars *cc, const char *arg)
1172 {
1173 #ifndef LINKER_FLAG_PREFIX
1174     push_count_chars(cc, arg);
1175 #else
1176     char *newarg;
1177     newarg = (char*)malloc(strlen(arg) + sizeof(LINKER_FLAG_PREFIX) + 1);
1178     strcpy(newarg, LINKER_FLAG_PREFIX);
1179     strcat(newarg, arg);
1180     push_count_chars(cc, newarg);
1181 #endif
1182 }
1183 
explode_static_lib(command_t * cmd_data,const char * lib)1184 int explode_static_lib(command_t *cmd_data, const char *lib)
1185 {
1186     count_chars tmpdir_cc, libname_cc;
1187     const char *tmpdir, *libname;
1188     char savewd[PATH_MAX];
1189     const char *name;
1190     DIR *dir;
1191     struct dirent *entry;
1192     const char *lib_args[4];
1193 
1194     /* Bah! */
1195     if (cmd_data->options.dry_run) {
1196         return 0;
1197     }
1198 
1199     name = jlibtool_basename(lib);
1200 
1201     init_count_chars(&tmpdir_cc);
1202     push_count_chars(&tmpdir_cc, ".libs/");
1203     push_count_chars(&tmpdir_cc, name);
1204     push_count_chars(&tmpdir_cc, ".exploded/");
1205     tmpdir = flatten_count_chars(&tmpdir_cc, 0);
1206 
1207     if (!cmd_data->options.silent) {
1208         printf("Making: %s\n", tmpdir);
1209     }
1210     safe_mkdir(tmpdir);
1211 
1212     push_count_chars(cmd_data->tmp_dirs, tmpdir);
1213 
1214     getcwd(savewd, sizeof(savewd));
1215 
1216     if (chdir(tmpdir) != 0) {
1217         if (!cmd_data->options.silent) {
1218             printf("Warning: could not explode %s\n", lib);
1219         }
1220         return 1;
1221     }
1222 
1223     if (lib[0] == '/') {
1224         libname = lib;
1225     }
1226     else {
1227         init_count_chars(&libname_cc);
1228         push_count_chars(&libname_cc, "../../");
1229         push_count_chars(&libname_cc, lib);
1230         libname = flatten_count_chars(&libname_cc, 0);
1231     }
1232 
1233     lib_args[0] = LIBRARIAN;
1234     lib_args[1] = "x";
1235     lib_args[2] = libname;
1236     lib_args[3] = NULL;
1237 
1238     external_spawn(cmd_data, LIBRARIAN, lib_args);
1239 
1240     chdir(savewd);
1241     dir = opendir(tmpdir);
1242 
1243     while ((entry = readdir(dir)) != NULL) {
1244 #if defined(__APPLE__) && defined(RANLIB)
1245         /* Apple inserts __.SYMDEF which isn't needed.
1246          * Leopard (10.5+) can also add '__.SYMDEF SORTED' which isn't
1247          * much fun either.  Just skip them.
1248          */
1249         if (strstr(entry->d_name, "__.SYMDEF") != NULL) {
1250             continue;
1251         }
1252 #endif
1253         if (entry->d_name[0] != '.') {
1254             push_count_chars(&tmpdir_cc, entry->d_name);
1255             name = flatten_count_chars(&tmpdir_cc, 0);
1256             if (!cmd_data->options.silent) {
1257                 printf("Adding: %s\n", name);
1258             }
1259             push_count_chars(cmd_data->obj_files, name);
1260             pop_count_chars(&tmpdir_cc);
1261         }
1262     }
1263 
1264     closedir(dir);
1265     return 0;
1266 }
1267 
parse_input_file_name(char * arg,command_t * cmd_data)1268 int parse_input_file_name(char *arg, command_t *cmd_data)
1269 {
1270     char *ext = strrchr(arg, '.');
1271     char *name = strrchr(arg, '/');
1272     int pathlen;
1273     enum lib_type libtype;
1274     char *newarg;
1275 
1276     if (!ext) {
1277         return 0;
1278     }
1279 
1280     ext++;
1281 
1282     if (name == NULL) {
1283         name = strrchr(arg, '\\');
1284 
1285         if (name == NULL) {
1286             name = arg;
1287         } else {
1288             name++;
1289         }
1290     } else {
1291         name++;
1292     }
1293 
1294     pathlen = name - arg;
1295 
1296     if (strcmp(ext, "lo") == 0) {
1297         newarg = check_object_exists(cmd_data, arg, ext - arg);
1298         if (!newarg) {
1299             printf("Can not find suitable object file for %s\n", arg);
1300             exit(1);
1301         }
1302         if (cmd_data->mode != mLink) {
1303             push_count_chars(cmd_data->arglist, newarg);
1304         }
1305         else {
1306             push_count_chars(cmd_data->obj_files, newarg);
1307         }
1308         return 1;
1309     }
1310 
1311     if (strcmp(ext, "la") == 0) {
1312         switch (cmd_data->mode) {
1313         case mLink:
1314             /* Try the .libs dir first! */
1315             newarg = check_library_exists(cmd_data, arg, pathlen, 1, &libtype);
1316             if (!newarg) {
1317                 /* Try the normal dir next. */
1318                 newarg = check_library_exists(cmd_data, arg, pathlen, 0, &libtype);
1319                 if (!newarg) {
1320                     printf("Can not find suitable library for %s\n", arg);
1321                     exit(1);
1322                 }
1323             }
1324 
1325             /* It is not ok to just add the file: a library may added with:
1326                1 - -L path library_name. (For *.so in Linux).
1327                2 - library_name.
1328              */
1329 #ifdef ADD_MINUS_L
1330             if (libtype == type_DYNAMIC_LIB) {
1331                  add_minus_l(cmd_data->shared_opts.dependencies, newarg);
1332             } else if (cmd_data->output == otLibrary &&
1333                        libtype == type_STATIC_LIB) {
1334                 explode_static_lib(cmd_data, newarg);
1335             } else {
1336                  push_count_chars(cmd_data->shared_opts.dependencies, newarg);
1337             }
1338 #else
1339             if (cmd_data->output == otLibrary && libtype == type_STATIC_LIB) {
1340                 explode_static_lib(cmd_data, newarg);
1341             }
1342             else {
1343                 push_count_chars(cmd_data->shared_opts.dependencies, newarg);
1344             }
1345 #endif
1346             if (libtype == type_DYNAMIC_LIB) {
1347                 if (cmd_data->options.no_install) {
1348 #ifdef RPATH
1349                     add_rpath_noinstall(cmd_data->shared_opts.dependencies,
1350                                         arg, pathlen);
1351 #endif
1352 #ifdef DYNAMIC_LINK_NO_INSTALL
1353                     /*
1354                      * This doesn't work as Darwin's linker has no way to
1355                      * override at link-time the search paths for a
1356                      * non-installed library.
1357                      */
1358                     /*
1359                     add_dylink_noinstall(cmd_data->shared_opts.dependencies,
1360                                          arg, pathlen, ext - arg);
1361                     */
1362 #endif
1363                 }
1364                 else {
1365 #ifdef RPATH
1366                     add_rpath_file(cmd_data->shared_opts.dependencies, arg);
1367 #endif
1368                 }
1369             }
1370             break;
1371         case mInstall:
1372             /* If we've already recorded a library to install, we're most
1373              * likely getting the .la file that we want to install as.
1374              * The problem is that we need to add it as the directory,
1375              * not the .la file itself.  Otherwise, we'll do odd things.
1376              */
1377             if (cmd_data->output == otLibrary) {
1378                 arg[pathlen] = '\0';
1379                 push_count_chars(cmd_data->arglist, arg);
1380             }
1381             else {
1382                 cmd_data->output = otLibrary;
1383                 cmd_data->output_name = arg;
1384                 cmd_data->static_name.install = gen_install_name(arg, 0);
1385                 cmd_data->shared_name.install = gen_install_name(arg, 1);
1386                 cmd_data->module_name.install = gen_install_name(arg, 2);
1387             }
1388             break;
1389         default:
1390             break;
1391         }
1392         return 1;
1393     }
1394 
1395     if (strcmp(ext, "c") == 0) {
1396         /* If we don't already have an idea what our output name will be. */
1397         if (cmd_data->basename == NULL) {
1398             cmd_data->basename = (char *)malloc(strlen(arg) + 4);
1399             strcpy(cmd_data->basename, arg);
1400             strcpy(strrchr(cmd_data->basename, '.') + 1, "lo");
1401 
1402             cmd_data->fake_output_name = strrchr(cmd_data->basename, '/');
1403             if (cmd_data->fake_output_name) {
1404                 cmd_data->fake_output_name++;
1405             }
1406             else {
1407                 cmd_data->fake_output_name = cmd_data->basename;
1408             }
1409         }
1410     }
1411 
1412     return 0;
1413 }
1414 
parse_output_file_name(char * arg,command_t * cmd_data)1415 int parse_output_file_name(char *arg, command_t *cmd_data)
1416 {
1417     char *name = strrchr(arg, '/');
1418     char *ext = strrchr(arg, '.');
1419     char *newarg = NULL;
1420     int pathlen;
1421 
1422     cmd_data->fake_output_name = arg;
1423 
1424     if (name) {
1425         name++;
1426     }
1427     else {
1428         name = strrchr(arg, '\\');
1429 
1430         if (name == NULL) {
1431             name = arg;
1432         }
1433         else {
1434             name++;
1435         }
1436     }
1437 
1438 #ifdef EXE_EXT
1439     if (!ext || strcmp(ext, EXE_EXT) == 0) {
1440 #else
1441     if (!ext) {
1442 #endif
1443         cmd_data->basename = arg;
1444         cmd_data->output = otProgram;
1445 #if defined(_OSD_POSIX)
1446         cmd_data->options.pic_mode = pic_AVOID;
1447 #endif
1448         newarg = (char *)malloc(strlen(arg) + 5);
1449         strcpy(newarg, arg);
1450 #ifdef EXE_EXT
1451         if (!ext) {
1452             strcat(newarg, EXE_EXT);
1453         }
1454 #endif
1455         cmd_data->output_name = newarg;
1456         return 1;
1457     }
1458 
1459     ext++;
1460     pathlen = name - arg;
1461 
1462     if (strcmp(ext, "la") == 0) {
1463         assert(cmd_data->mode == mLink);
1464 
1465         cmd_data->basename = arg;
1466         cmd_data->static_name.normal = gen_library_name(arg, 0);
1467         cmd_data->shared_name.normal = gen_library_name(arg, 1);
1468         cmd_data->module_name.normal = gen_library_name(arg, 2);
1469         cmd_data->static_name.install = gen_install_name(arg, 0);
1470         cmd_data->shared_name.install = gen_install_name(arg, 1);
1471         cmd_data->module_name.install = gen_install_name(arg, 2);
1472 
1473 #ifdef TRUNCATE_DLL_NAME
1474         if (shared) {
1475           arg = truncate_dll_name(arg);
1476         }
1477 #endif
1478 
1479         cmd_data->output_name = arg;
1480         return 1;
1481     }
1482 
1483     if (strcmp(ext, "lo") == 0) {
1484         cmd_data->basename = arg;
1485         cmd_data->output = otObject;
1486         newarg = (char *)malloc(strlen(arg) + 2);
1487         strcpy(newarg, arg);
1488         ext = strrchr(newarg, '.') + 1;
1489         strcpy(ext, OBJECT_EXT);
1490         cmd_data->output_name = newarg;
1491         return 1;
1492     }
1493 
1494     return 0;
1495 }
1496 
1497 void parse_args(int argc, char *argv[], command_t *cmd_data)
1498 {
1499     int a;
1500     char *arg;
1501     int argused;
1502 
1503     for (a = 1; a < argc; a++) {
1504         arg = argv[a];
1505         argused = 1;
1506 
1507         if (arg[0] == '-') {
1508             if (arg[1] == '-') {
1509                 argused = parse_long_opt(arg + 2, cmd_data);
1510             }
1511             else {
1512                 argused = parse_short_opt(arg + 1, cmd_data);
1513             }
1514 
1515             /* We haven't done anything with it yet, try some of the
1516              * more complicated short opts... */
1517             if (argused == 0 && a + 1 < argc) {
1518                 if (arg[1] == 'o' && !arg[2]) {
1519                     arg = argv[++a];
1520                     argused = parse_output_file_name(arg, cmd_data);
1521                 } else if (strcmp(arg+1, "MT") == 0) {
1522                     if (!cmd_data->options.silent) {
1523                         printf("Adding: %s\n", arg);
1524                     }
1525                     push_count_chars(cmd_data->arglist, arg);
1526                     arg = argv[++a];
1527                     if (!cmd_data->options.silent) {
1528                         printf(" %s\n", arg);
1529                     }
1530                     push_count_chars(cmd_data->arglist, arg);
1531                     argused = 1;
1532                 } else if (strcmp(arg+1, "rpath") == 0) {
1533                     /* Aha, we should try to link both! */
1534                     cmd_data->install_path = argv[++a];
1535                     argused = 1;
1536                 } else if (strcmp(arg+1, "release") == 0) {
1537                     /* Store for later deciphering */
1538                     cmd_data->version_info = argv[++a];
1539                     argused = 1;
1540                 } else if (strcmp(arg+1, "version-info") == 0) {
1541                     /* Store for later deciphering */
1542                     cmd_data->version_info = argv[++a];
1543                     argused = 1;
1544                 } else if (strcmp(arg+1, "export-symbols-regex") == 0) {
1545                     /* Skip the argument. */
1546                     ++a;
1547                     argused = 1;
1548                 } else if (strcmp(arg+1, "release") == 0) {
1549                     /* Skip the argument. */
1550                     ++a;
1551                     argused = 1;
1552                 } else if (strcmp(arg+1, "undefined") == 0) {
1553                     cmd_data->undefined_flag = argv[++a];
1554                     argused = 1;
1555                 } else if (arg[1] == 'R' && !arg[2]) {
1556                     /* -R dir Add dir to runtime library search path. */
1557                     add_runtimedirlib(argv[++a], cmd_data);
1558                     argused = 1;
1559                 }
1560             }
1561         } else {
1562             argused = parse_input_file_name(arg, cmd_data);
1563         }
1564 
1565         if (!argused) {
1566             if (!cmd_data->options.silent) {
1567                 printf("Adding: %s\n", arg);
1568             }
1569             push_count_chars(cmd_data->arglist, arg);
1570         }
1571     }
1572 
1573 }
1574 
1575 #ifdef GEN_EXPORTS
1576 void generate_def_file(command_t *cmd_data)
1577 {
1578     char def_file[1024];
1579     char implib_file[1024];
1580     char *ext;
1581     FILE *hDef;
1582     char *export_args[1024];
1583     int num_export_args = 0;
1584     char *cmd;
1585     int cmd_size = 0;
1586     int a;
1587 
1588     if (cmd_data->output_name) {
1589         strcpy(def_file, cmd_data->output_name);
1590         strcat(def_file, ".def");
1591         hDef = fopen(def_file, "w");
1592 
1593         if (hDef != NULL) {
1594             fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
1595             fprintf(hDef, "DATA NONSHARED\n");
1596             fprintf(hDef, "EXPORTS\n");
1597             fclose(hDef);
1598 
1599             for (a = 0; a < cmd_data->num_obj_files; a++) {
1600                 cmd_size += strlen(cmd_data->obj_files[a]) + 1;
1601             }
1602 
1603             cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
1604             cmd = (char *)malloc(cmd_size);
1605             strcpy(cmd, GEN_EXPORTS);
1606 
1607             for (a=0; a < cmd_data->num_obj_files; a++) {
1608                 strcat(cmd, " ");
1609                 strcat(cmd, cmd_data->obj_files[a] );
1610             }
1611 
1612             strcat(cmd, ">>");
1613             strcat(cmd, def_file);
1614             puts(cmd);
1615             export_args[num_export_args++] = SHELL_CMD;
1616             export_args[num_export_args++] = "-c";
1617             export_args[num_export_args++] = cmd;
1618             export_args[num_export_args++] = NULL;
1619             external_spawn(cmd_data, export_args[0], (const char**)export_args);
1620             cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
1621 
1622             /* Now make an import library for the dll */
1623             num_export_args = 0;
1624             export_args[num_export_args++] = DEF2IMPLIB_CMD;
1625             export_args[num_export_args++] = "-o";
1626 
1627             strcpy(implib_file, ".libs/");
1628             strcat(implib_file, cmd_data->basename);
1629             ext = strrchr(implib_file, '.');
1630 
1631             if (ext)
1632                 *ext = 0;
1633 
1634             strcat(implib_file, ".");
1635             strcat(implib_file, STATIC_LIB_EXT);
1636 
1637             export_args[num_export_args++] = implib_file;
1638             export_args[num_export_args++] = def_file;
1639             export_args[num_export_args++] = NULL;
1640             external_spawn(cmd_data, export_args[0], (const char**)export_args);
1641 
1642         }
1643     }
1644 }
1645 #endif
1646 
1647 const char* expand_path(const char *relpath)
1648 {
1649     char foo[PATH_MAX], *newpath;
1650 
1651     getcwd(foo, PATH_MAX-1);
1652     newpath = (char*)malloc(strlen(foo)+strlen(relpath)+2);
1653     strcpy(newpath, foo);
1654     strcat(newpath, "/");
1655     strcat(newpath, relpath);
1656     return newpath;
1657 }
1658 
1659 void link_fixup(command_t *c)
1660 {
1661     /* If we were passed an -rpath directive, we need to build
1662      * shared objects too.  Otherwise, we should only create static
1663      * libraries.
1664      */
1665     if (!c->install_path && (c->output == otDynamicLibraryOnly ||
1666         c->output == otModule || c->output == otLibrary)) {
1667         c->output = otStaticLibraryOnly;
1668     }
1669 
1670     if (c->output == otDynamicLibraryOnly ||
1671         c->output == otModule ||
1672         c->output == otLibrary) {
1673 
1674         push_count_chars(c->shared_opts.normal, "-o");
1675         if (c->output == otModule) {
1676             push_count_chars(c->shared_opts.normal, c->module_name.normal);
1677         }
1678         else {
1679             char *tmp;
1680             push_count_chars(c->shared_opts.normal, c->shared_name.normal);
1681 #ifdef DYNAMIC_INSTALL_NAME
1682             push_count_chars(c->shared_opts.normal, DYNAMIC_INSTALL_NAME);
1683 
1684             tmp = (char*)malloc(PATH_MAX);
1685             strcpy(tmp, c->install_path);
1686             strcat(tmp, strrchr(c->shared_name.normal, '/'));
1687             push_count_chars(c->shared_opts.normal, tmp);
1688 #endif
1689         }
1690 
1691         append_count_chars(c->shared_opts.normal, c->obj_files);
1692         append_count_chars(c->shared_opts.normal, c->shared_opts.dependencies);
1693 
1694         if (c->options.export_all) {
1695 #ifdef GEN_EXPORTS
1696             generate_def_file(c);
1697 #endif
1698         }
1699     }
1700 
1701     if (c->output == otLibrary || c->output == otStaticLibraryOnly) {
1702         push_count_chars(c->static_opts.normal, "-o");
1703         push_count_chars(c->static_opts.normal, c->output_name);
1704     }
1705 
1706     if (c->output == otProgram) {
1707         if (c->output_name) {
1708             push_count_chars(c->arglist, "-o");
1709             push_count_chars(c->arglist, c->output_name);
1710             append_count_chars(c->arglist, c->obj_files);
1711             append_count_chars(c->arglist, c->shared_opts.dependencies);
1712             add_dynamic_link_opts(c, c->arglist);
1713         }
1714     }
1715 }
1716 
1717 void post_parse_fixup(command_t *cmd_data)
1718 {
1719     switch (cmd_data->mode)
1720     {
1721     case mCompile:
1722 #ifdef PIC_FLAG
1723         if (cmd_data->options.pic_mode != pic_AVOID) {
1724             push_count_chars(cmd_data->arglist, PIC_FLAG);
1725         }
1726 #endif
1727         if (cmd_data->output_name) {
1728             push_count_chars(cmd_data->arglist, "-o");
1729             push_count_chars(cmd_data->arglist, cmd_data->output_name);
1730         }
1731         break;
1732     case mLink:
1733         link_fixup(cmd_data);
1734         break;
1735     case mInstall:
1736         if (cmd_data->output == otLibrary) {
1737             link_fixup(cmd_data);
1738         }
1739     default:
1740         break;
1741     }
1742 
1743 #if USE_OMF
1744     if (cmd_data->output == otObject ||
1745         cmd_data->output == otProgram ||
1746         cmd_data->output == otLibrary ||
1747         cmd_data->output == otDynamicLibraryOnly) {
1748         push_count_chars(cmd_data->arglist, "-Zomf");
1749     }
1750 #endif
1751 
1752     if (cmd_data->options.shared &&
1753             (cmd_data->output == otObject ||
1754              cmd_data->output == otLibrary ||
1755              cmd_data->output == otDynamicLibraryOnly)) {
1756 #ifdef SHARE_SW
1757         push_count_chars(cmd_data->arglist, SHARE_SW);
1758 #endif
1759     }
1760 }
1761 
1762 int run_mode(command_t *cmd_data)
1763 {
1764     int rv;
1765     count_chars *cctemp;
1766 
1767     cctemp = (count_chars*)malloc(sizeof(count_chars));
1768     init_count_chars(cctemp);
1769 
1770     switch (cmd_data->mode)
1771     {
1772     case mCompile:
1773         rv = run_command(cmd_data, cmd_data->arglist);
1774         if (rv) {
1775             return rv;
1776         }
1777         break;
1778     case mInstall:
1779         /* Well, we'll assume it's a file going to a directory... */
1780         /* For brain-dead install-sh based scripts, we have to repeat
1781          * the command N-times.  install-sh should die.
1782          */
1783         if (!cmd_data->output_name) {
1784             rv = run_command(cmd_data, cmd_data->arglist);
1785             if (rv) {
1786                 return rv;
1787             }
1788         }
1789         if (cmd_data->output_name) {
1790             append_count_chars(cctemp, cmd_data->arglist);
1791             insert_count_chars(cctemp,
1792                                cmd_data->output_name,
1793                                cctemp->num - 1);
1794             rv = run_command(cmd_data, cctemp);
1795             if (rv) {
1796                 return rv;
1797             }
1798             clear_count_chars(cctemp);
1799         }
1800         if (cmd_data->static_name.install) {
1801             append_count_chars(cctemp, cmd_data->arglist);
1802             insert_count_chars(cctemp,
1803                                cmd_data->static_name.install,
1804                                cctemp->num - 1);
1805             rv = run_command(cmd_data, cctemp);
1806             if (rv) {
1807                 return rv;
1808             }
1809 #if defined(__APPLE__) && defined(RANLIB)
1810             /* From the Apple libtool(1) manpage on Tiger/10.4:
1811              * ----
1812              * With  the way libraries used to be created, errors were possible
1813              * if the library was modified with ar(1) and  the  table  of
1814              * contents  was  not updated  by  rerunning ranlib(1).  Thus the
1815              * link editor, ld, warns when the modification date of a library
1816              * is more  recent  than  the  creation date  of its table of
1817              * contents.  Unfortunately, this means that you get the warning
1818              * even if you only copy the library.
1819              * ----
1820              *
1821              * This means that when we install the static archive, we need to
1822              * rerun ranlib afterwards.
1823              */
1824             const char *lib_args[3], *static_lib_name;
1825             char *tmp;
1826             size_t len1, len2;
1827             len1 = strlen(cmd_data->arglist->vals[cmd_data->arglist->num - 1]);
1828 
1829             static_lib_name = jlibtool_basename(cmd_data->static_name.install);
1830             len2 = strlen(static_lib_name);
1831 
1832             tmp = malloc(len1 + len2 + 2);
1833 
1834             snprintf(tmp, len1 + len2 + 2, "%s/%s",
1835                     cmd_data->arglist->vals[cmd_data->arglist->num - 1],
1836                     static_lib_name);
1837 
1838             lib_args[0] = RANLIB;
1839             lib_args[1] = tmp;
1840             lib_args[2] = NULL;
1841             external_spawn(cmd_data, RANLIB, lib_args);
1842             free(tmp);
1843 #endif
1844             clear_count_chars(cctemp);
1845         }
1846         if (cmd_data->shared_name.install) {
1847             append_count_chars(cctemp, cmd_data->arglist);
1848             insert_count_chars(cctemp,
1849                                cmd_data->shared_name.install,
1850                                cctemp->num - 1);
1851             rv = run_command(cmd_data, cctemp);
1852             if (rv) {
1853                 return rv;
1854             }
1855             clear_count_chars(cctemp);
1856         }
1857         if (cmd_data->module_name.install) {
1858             append_count_chars(cctemp, cmd_data->arglist);
1859             insert_count_chars(cctemp,
1860                                cmd_data->module_name.install,
1861                                cctemp->num - 1);
1862             rv = run_command(cmd_data, cctemp);
1863             if (rv) {
1864                 return rv;
1865             }
1866             clear_count_chars(cctemp);
1867         }
1868         break;
1869     case mLink:
1870         if (!cmd_data->options.dry_run) {
1871             /* Check first to see if the dir already exists! */
1872             safe_mkdir(".libs");
1873         }
1874 
1875         if (cmd_data->output == otStaticLibraryOnly ||
1876             cmd_data->output == otLibrary) {
1877 #ifdef RANLIB
1878             const char *lib_args[3];
1879 #endif
1880             /* Removes compiler! */
1881             cmd_data->program = LIBRARIAN;
1882             push_count_chars(cmd_data->program_opts, LIBRARIAN_OPTS);
1883             push_count_chars(cmd_data->program_opts,
1884                              cmd_data->static_name.normal);
1885 
1886             rv = run_command(cmd_data, cmd_data->obj_files);
1887             if (rv) {
1888                 return rv;
1889             }
1890 
1891 #ifdef RANLIB
1892             lib_args[0] = RANLIB;
1893             lib_args[1] = cmd_data->static_name.normal;
1894             lib_args[2] = NULL;
1895             external_spawn(cmd_data, RANLIB, lib_args);
1896 #endif
1897         }
1898 
1899         if (cmd_data->output == otDynamicLibraryOnly ||
1900             cmd_data->output == otModule ||
1901             cmd_data->output == otLibrary) {
1902             cmd_data->program = NULL;
1903             clear_count_chars(cmd_data->program_opts);
1904 
1905             append_count_chars(cmd_data->program_opts, cmd_data->arglist);
1906             if (cmd_data->output == otModule) {
1907 #ifdef MODULE_OPTS
1908                 push_count_chars(cmd_data->program_opts, MODULE_OPTS);
1909 #endif
1910             } else {
1911 #ifdef SHARED_OPTS
1912                 push_count_chars(cmd_data->program_opts, SHARED_OPTS);
1913 #endif
1914 #ifdef dynamic_link_version_func
1915                 push_count_chars(cmd_data->program_opts,
1916                              dynamic_link_version_func(cmd_data->version_info));
1917 #endif
1918             }
1919             add_dynamic_link_opts(cmd_data, cmd_data->program_opts);
1920 
1921             rv = run_command(cmd_data, cmd_data->shared_opts.normal);
1922             if (rv) {
1923                 return rv;
1924             }
1925         }
1926         if (cmd_data->output == otProgram) {
1927             rv = run_command(cmd_data, cmd_data->arglist);
1928             if (rv) {
1929                 return rv;
1930             }
1931         }
1932         break;
1933     default:
1934         break;
1935     }
1936 
1937     return 0;
1938 }
1939 
1940 void cleanup_tmp_dir(const char *dirname)
1941 {
1942     DIR *dir;
1943     struct dirent *entry;
1944     char fullname[1024];
1945 
1946     dir = opendir(dirname);
1947 
1948     if (dir == NULL)
1949         return;
1950 
1951     while ((entry = readdir(dir)) != NULL) {
1952         if (entry->d_name[0] != '.') {
1953             strcpy(fullname, dirname);
1954             strcat(fullname, "/");
1955             strcat(fullname, entry->d_name);
1956             remove(fullname);
1957         }
1958     }
1959 
1960     rmdir(dirname);
1961 }
1962 
1963 void cleanup_tmp_dirs(command_t *cmd_data)
1964 {
1965     int d;
1966 
1967     for (d = 0; d < cmd_data->tmp_dirs->num; d++) {
1968         cleanup_tmp_dir(cmd_data->tmp_dirs->vals[d]);
1969     }
1970 }
1971 
1972 int ensure_fake_uptodate(command_t *cmd_data)
1973 {
1974     /* FIXME: could do the stat/touch here, but nah... */
1975     const char *touch_args[3];
1976 
1977     if (cmd_data->mode == mInstall) {
1978         return 0;
1979     }
1980     if (!cmd_data->fake_output_name) {
1981         return 0;
1982     }
1983 
1984     touch_args[0] = "touch";
1985     touch_args[1] = cmd_data->fake_output_name;
1986     touch_args[2] = NULL;
1987     return external_spawn(cmd_data, "touch", touch_args);
1988 }
1989 
1990 /* Store the install path in the *.la file */
1991 int add_for_runtime(command_t *cmd_data)
1992 {
1993     if (cmd_data->mode == mInstall) {
1994         return 0;
1995     }
1996     if (cmd_data->output == otDynamicLibraryOnly ||
1997         cmd_data->output == otLibrary) {
1998         FILE *f=fopen(cmd_data->fake_output_name,"w");
1999         if (f == NULL) {
2000             return -1;
2001         }
2002         fprintf(f,"%s\n", cmd_data->install_path);
2003         fclose(f);
2004         return(0);
2005     } else {
2006         return(ensure_fake_uptodate(cmd_data));
2007     }
2008 }
2009 
2010 int main(int argc, char *argv[])
2011 {
2012     int rc;
2013     command_t cmd_data;
2014 
2015     memset(&cmd_data, 0, sizeof(cmd_data));
2016 
2017     cmd_data.options.pic_mode = pic_UNKNOWN;
2018 
2019     cmd_data.program_opts = (count_chars*)malloc(sizeof(count_chars));
2020     init_count_chars(cmd_data.program_opts);
2021     cmd_data.arglist = (count_chars*)malloc(sizeof(count_chars));
2022     init_count_chars(cmd_data.arglist);
2023     cmd_data.tmp_dirs = (count_chars*)malloc(sizeof(count_chars));
2024     init_count_chars(cmd_data.tmp_dirs);
2025     cmd_data.obj_files = (count_chars*)malloc(sizeof(count_chars));
2026     init_count_chars(cmd_data.obj_files);
2027     cmd_data.dep_rpaths = (count_chars*)malloc(sizeof(count_chars));
2028     init_count_chars(cmd_data.dep_rpaths);
2029     cmd_data.rpaths = (count_chars*)malloc(sizeof(count_chars));
2030     init_count_chars(cmd_data.rpaths);
2031     cmd_data.static_opts.normal = (count_chars*)malloc(sizeof(count_chars));
2032     init_count_chars(cmd_data.static_opts.normal);
2033     cmd_data.shared_opts.normal = (count_chars*)malloc(sizeof(count_chars));
2034     init_count_chars(cmd_data.shared_opts.normal);
2035     cmd_data.shared_opts.dependencies = (count_chars*)malloc(sizeof(count_chars));
2036     init_count_chars(cmd_data.shared_opts.dependencies);
2037 
2038     cmd_data.mode = mUnknown;
2039     cmd_data.output = otGeneral;
2040 
2041     parse_args(argc, argv, &cmd_data);
2042     post_parse_fixup(&cmd_data);
2043 
2044     if (cmd_data.mode == mUnknown) {
2045         exit(0);
2046     }
2047 
2048     rc = run_mode(&cmd_data);
2049 
2050     if (!rc) {
2051        add_for_runtime(&cmd_data);
2052     }
2053 
2054     cleanup_tmp_dirs(&cmd_data);
2055     return rc;
2056 }
2057