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