Use Painless Security signing key
[freeradius.git] / scripts / jlibtool.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23
24 #if !defined(__MINGW32__)
25 #  include <sys/wait.h>
26 #endif
27
28 #include <unistd.h>
29 #include <dirent.h>
30 #include <errno.h>
31 #include <assert.h>
32
33 #ifdef __EMX__
34 #  define SHELL_CMD                     "sh"
35 #  define GEN_EXPORTS                   "emxexp"
36 #  define DEF2IMPLIB_CMD                "emximp"
37 #  define SHARE_SW                      "-Zdll -Zmtd"
38 #  define USE_OMF 1
39 #  define TRUNCATE_DLL_NAME
40 #  define DYNAMIC_LIB_EXT               "dll"
41 #  define EXE_EX                        ".exe"
42 /* OMF is the native format under OS/2 */
43 #  if USE_OMF
44
45 #    define STATIC_LIB_EXT              "lib"
46 #    define OBJECT_EXT                  "obj"
47 #    define LIBRARIAN                   "emxomfar"
48 #    define LIBRARIAN_OPTS              "cr"
49 #  else
50 /* but the alternative, a.out, can fork() which is sometimes necessary */
51 #    define STATIC_LIB_EXT              "a"
52 #    define OBJECT_EXT                  "o"
53 #    define LIBRARIAN                   "ar"
54 #    define LIBRARIAN_OPTS              "cr"
55 #  endif
56 #endif
57
58 #if defined(__APPLE__)
59 #  define SHELL_CMD                     "/bin/sh"
60 #  define DYNAMIC_LIB_EXT               "dylib"
61 #  define MODULE_LIB_EXT                "bundle"
62 #  define STATIC_LIB_EXT                "a"
63 #  define OBJECT_EXT                    "o"
64 #  define LIBRARIAN                     "ar"
65 #  define LIBRARIAN_OPTS                "cr"
66 /* man libtool(1) documents ranlib option of -c.  */
67 #  define RANLIB                        "ranlib"
68 #  define PIC_FLAG                      "-fPIC -fno-common"
69 #  define SHARED_OPTS                   "-dynamiclib"
70 #  define MODULE_OPTS                   "-bundle -dynamic"
71 #  define DYNAMIC_LINK_OPTS             "-flat_namespace"
72 #  define DYNAMIC_LINK_UNDEFINED        "-undefined suppress"
73 #  define dynamic_link_version_func     darwin_dynamic_link_function
74 #  define DYNAMIC_INSTALL_NAME          "-install_name"
75 #  define DYNAMIC_LINK_NO_INSTALL       "-dylib_file"
76 #  define HAS_REALPATH
77 /*-install_name  /Users/jerenk/apache-2.0-cvs/lib/libapr.0.dylib -compatibility_version 1 -current_version 1.0 */
78 #  define LD_LIBRARY_PATH               "DYLD_LIBRARY_PATH"
79 #  define LD_LIBRARY_PATH_LOCAL         "DYLD_FALLBACK_LIBRARY_PATH"
80 #endif
81
82 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || (defined(__sun) && defined(__GNUC__))
83 #  define SHELL_CMD                     "/bin/sh"
84 #  define DYNAMIC_LIB_EXT               "so"
85 #  define MODULE_LIB_EXT                "so"
86 #  define STATIC_LIB_EXT                "a"
87 #  define OBJECT_EXT                    "o"
88 #  define LIBRARIAN                     "ar"
89 #  define LIBRARIAN_OPTS                "cr"
90 #  define RANLIB                        "ranlib"
91 #  define PIC_FLAG                      "-fPIC"
92 #  define RPATH                         "-rpath"
93 #  define SHARED_OPTS                   "-shared"
94 #  define MODULE_OPTS                   "-shared"
95 #  define LINKER_FLAG_PREFIX            "-Wl,"
96 #if !defined(__sun)
97 #  define DYNAMIC_LINK_OPTS             LINKER_FLAG_PREFIX "-export-dynamic"
98 #else
99 #  define DYNAMIC_LINK_OPTS             ""
100 #endif
101 #  define ADD_MINUS_L
102 #  define LD_RUN_PATH                   "LD_RUN_PATH"
103 #  define LD_LIBRARY_PATH               "LD_LIBRARY_PATH"
104 #  define LD_LIBRARY_PATH_LOCAL         LD_LIBRARY_PATH
105 #endif
106
107 #if defined(__sun) && !defined(__GNUC__)
108 #  define SHELL_CMD                     "/bin/sh"
109 #  define DYNAMIC_LIB_EXT               "so"
110 #  define MODULE_LIB_EXT                "so"
111 #  define STATIC_LIB_EXT                "a"
112 #  define OBJECT_EXT                    "o"
113 #  define LIBRARIAN                     "ar"
114 #  define LIBRARIAN_OPTS                "cr"
115 #  define RANLIB                        "ranlib"
116 #  define PIC_FLAG                      "-fPIC"
117 #  define RPATH                         "-R"
118 #  define SHARED_OPTS                   "-G"
119 #  define MODULE_OPTS                   "-G"
120 #  define DYNAMIC_LINK_OPTS             ""
121 #  define LINKER_FLAG_NO_EQUALS
122 #  define ADD_MINUS_L
123 #  define HAS_REALPATH
124 #  define LD_RUN_PATH                   "LD_RUN_PATH"
125 #  define LD_LIBRARY_PATH               "LD_LIBRARY_PATH"
126 #  define LD_LIBRARY_PATH_LOCAL         LD_LIBRARY_PATH
127 #endif
128
129 #if defined(_OSD_POSIX)
130 #  define SHELL_CMD                     "/usr/bin/sh"
131 #  define DYNAMIC_LIB_EXT               "so"
132 #  define MODULE_LIB_EXT                "so"
133 #  define STATIC_LIB_EXT                "a"
134 #  define OBJECT_EXT                    "o"
135 #  define LIBRARIAN                     "ar"
136 #  define LIBRARIAN_OPTS                "cr"
137 #  define SHARED_OPTS                   "-G"
138 #  define MODULE_OPTS                   "-G"
139 #  define LINKER_FLAG_PREFIX            "-Wl,"
140 #  define NEED_SNPRINTF
141 #endif
142
143 #if defined(sinix) && defined(mips) && defined(__SNI_TARG_UNIX)
144 #  define SHELL_CMD                     "/usr/bin/sh"
145 #  define DYNAMIC_LIB_EXT               "so"
146 #  define MODULE_LIB_EXT                "so"
147 #  define STATIC_LIB_EXT                "a"
148 #  define OBJECT_EXT                    "o"
149 #  define LIBRARIAN                     "ar"
150 #  define LIBRARIAN_OPTS                "cr"
151 #  define RPATH                         "-Brpath"
152 #  define SHARED_OPTS                   "-G"
153 #  define MODULE_OPTS                   "-G"
154 #  define LINKER_FLAG_PREFIX            "-Wl,"
155 #  define DYNAMIC_LINK_OPTS             LINKER_FLAG_PREFIX "-Blargedynsym"
156
157 #  define NEED_SNPRINTF
158 #  define LD_RUN_PATH                   "LD_RUN_PATH"
159 #  define LD_LIBRARY_PATH               "LD_LIBRARY_PATH"
160 #  define LD_LIBRARY_PATH_LOCAL         LD_LIBRARY_PATH
161 #endif
162
163 #if defined(__MINGW32__)
164 #  define SHELL_CMD                     "sh"
165 #  define DYNAMIC_LIB_EXT               "dll"
166 #  define MODULE_LIB_EXT                "dll"
167 #  define STATIC_LIB_EXT                "a"
168 #  define OBJECT_EXT                    "o"
169 #  define LIBRARIAN                     "ar"
170 #  define LIBRARIAN_OPTS                "cr"
171 #  define RANLIB                        "ranlib"
172 #  define LINKER_FLAG_PREFIX            "-Wl,"
173 #  define SHARED_OPTS                   "-shared"
174 #  define MODULE_OPTS                   "-shared"
175 #  define MKDIR_NO_UMASK
176 #  define EXE_EXT                       ".exe"
177 #endif
178
179 #ifndef CC
180 #define CC                              "gcc"
181 #endif
182
183 #ifndef CXX
184 #define CXX                             "g++"
185 #endif
186
187 #ifndef LINK_C
188 #define LINK_C                          "gcc"
189 #endif
190
191 #ifndef LINK_CXX
192 #define LINK_CXX                        "g++"
193 #endif
194
195 #ifndef LIBDIR
196 #define LIBDIR                          "/usr/local/lib"
197 #endif
198
199 #define OBJDIR                          ".libs"
200
201 #ifndef SHELL_CMD
202 #error Unsupported platform: Please add defines for SHELL_CMD etc. for your platform.
203 #endif
204
205 #ifdef NEED_SNPRINTF
206 #include <stdarg.h>
207 #endif
208
209 #ifdef __EMX__
210 #include <process.h>
211 #endif
212
213 #ifndef PATH_MAX
214 #define PATH_MAX 1024
215 #endif
216
217
218 /* We want to say we are libtool 1.4 for shlibtool compatibility. */
219 #define VERSION "1.4"
220
221 #define DEBUG(fmt, ...) if(cmd->options.debug) printf(fmt, ## __VA_ARGS__)
222 #define NOTICE(fmt, ...) if(!cmd->options.silent) printf(fmt, ## __VA_ARGS__)
223 #define ERROR(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
224
225 enum tool_mode {
226         MODE_UNKNOWN,
227         MODE_COMPILE,
228         MODE_LINK,
229         MODE_EXECUTE,
230         MODE_INSTALL,
231 };
232
233 enum output_type {
234         OUT_GENERAL,
235         OUT_OBJECT,
236         OUT_PROGRAM,
237         OUT_LIB,
238         OUT_STATIC_LIB_ONLY,
239         OUT_DYNAMIC_LIB_ONLY,
240         OUT_MODULE,
241 };
242
243 enum pic_mode {
244         PIC_UNKNOWN,
245         PIC_PREFER,
246         PIC_AVOID,
247 };
248
249 enum shared_mode {
250         SHARE_UNSET,
251         SHARE_STATIC,
252         SHARE_SHARED,
253 };
254
255 enum lib_type {
256         TYPE_UKNOWN,
257         TYPE_STATIC_LIB,
258         TYPE_DYNAMIC_LIB,
259         TYPE_MODULE_LIB,
260         TYPE_OBJECT,
261 };
262
263 typedef struct {
264         char const **vals;
265         int num;
266 } count_chars;
267
268 typedef struct {
269         char const *normal;
270         char const *install;
271 } library_name;
272
273 typedef struct {
274         count_chars *normal;
275         count_chars *install;
276         count_chars *dependencies;
277 } library_opts;
278
279 typedef struct {
280         int silent;
281         int debug;
282         enum shared_mode shared;
283         int export_all;
284         int dry_run;
285         enum pic_mode pic_mode;
286         int export_dynamic;
287         int no_install;
288 } options_t;
289
290 typedef struct {
291         enum tool_mode mode;
292         enum output_type output;
293         options_t options;
294
295         char const *output_name;
296         char const *fake_output_name;
297         char const *basename;
298
299         char const *install_path;
300         char const *compiler;
301         char const *program;
302         count_chars *program_opts;
303
304         count_chars *arglist;
305         count_chars *tmp_dirs;
306         count_chars *obj_files;
307         count_chars *dep_rpaths;
308         count_chars *rpaths;
309
310         library_name static_name;
311         library_name shared_name;
312         library_name module_name;
313
314         library_opts static_opts;
315         library_opts shared_opts;
316
317         char const *version_info;
318         char const *undefined_flag;
319 } command_t;
320
321 #ifdef RPATH
322 static void add_rpath(count_chars *cc, char const *path);
323 #endif
324
325 static void usage(int code)
326 {
327         printf("Usage: jlibtool [OPTIONS...] COMMANDS...\n");
328         printf("jlibtool is a replacement for GNU libtool with similar functionality.\n\n");
329
330         printf("  --config       show all configuration variables\n");
331         printf("  --debug         enable verbose shell tracing\n");
332         printf("  --dry-run     display commands without modifying any files\n");
333         printf("  --help           display this help message and exit\n");
334         printf("  --mode=MODE      use operational mode MODE (you *must* set mode)\n");
335
336         printf("  --silent       don't print informational messages\n");
337         printf("  --tag=TAG     Ignored for libtool compatibility\n");
338         printf("  --version     print version information\n");
339
340
341         printf("  --shared       Build shared libraries when using --mode=link\n");
342         printf("  --export-all     Try to export 'def' file on some platforms\n");
343
344         printf("\nMODE must be one of the following:\n\n");
345         printf("  compile         compile a source file into a jlibtool object\n");
346         printf("  execute         automatically set library path, then run a program\n");
347         printf("  install         install libraries or executables\n");
348         printf("  link       create a library or an executable\n");
349
350         printf("\nMODE-ARGS can be the following:\n\n");
351         printf("  -export-dynamic  accepted and ignored\n");
352         printf("  -module         create a module when linking\n");
353         printf("  -shared         create a shared library when linking\n");
354         printf("  -prefer-pic      prefer position-independent-code when compiling\n");
355         printf("  -prefer-non-pic  prefer non position-independent-code when compiling\n");
356         printf("  -static         create a static library when linking\n");
357         printf("  -no-install      link libraries locally\n");
358         printf("  -rpath arg       Set install path for shared libraries\n");
359         printf("  -l arg           pass '-l arg' to the link stage\n");
360         printf("  -L arg           pass '-L arg' to the link stage\n");
361         printf("  -R dir           add 'dir' to runtime library search path.\n");
362         printf("  -Zexe     accepted and ignored\n");
363         printf("  -avoid-version   accepted and ignored\n");
364
365         exit(code);
366 }
367
368 #if defined(NEED_SNPRINTF)
369 /* Write at most n characters to the buffer in str, return the
370  * number of chars written or -1 if the buffer would have been
371  * overflowed.
372  *
373  * This is portable to any POSIX-compliant system has /dev/null
374  */
375 static FILE *f = NULL;
376 static int vsnprintf(char *str, size_t n, char const *fmt, va_list ap)
377 {
378         int res;
379
380         if (!f) {
381                 f = fopen("/dev/null","w");
382         }
383
384         if (!f) {
385                 return -1;
386         }
387
388         setvbuf(f, str, _IOFBF, n);
389
390         res = vfprintf(f, fmt, ap);
391
392         if ((res > 0) && (res < n)) {
393                 res = vsprintf( str, fmt, ap );
394         }
395         return res;
396 }
397
398 static int snprintf(char *str, size_t n, char const *fmt, ...)
399 {
400         va_list ap;
401         int res;
402
403         va_start(ap, fmt);
404         res = vsnprintf(str, n, fmt, ap);
405         va_end(ap);
406         return res;
407 }
408 #endif
409
410 static void *lt_malloc(size_t size)
411 {
412         void *out;
413
414         out = malloc(size);
415         if (!out) {
416                 ERROR("Failed allocating %zu bytes, OOM", size);
417                 exit(1);
418         }
419
420         return out;
421 }
422
423 static void lt_const_free(const void *ptr)
424 {
425         void *tmp;
426
427         memcpy(&tmp, &ptr, sizeof(tmp));
428         free(tmp);
429 }
430
431 static void init_count_chars(count_chars *cc)
432 {
433         cc->vals = (char const**) lt_malloc(PATH_MAX*sizeof(char*));
434         cc->num = 0;
435 }
436
437 static count_chars *alloc_countchars(void)
438 {
439         count_chars *out;
440         out = lt_malloc(sizeof(count_chars));
441         if (!out) {
442                 exit(1);
443         }
444         init_count_chars(out);
445
446         return out;
447 }
448
449 static void clear_count_chars(count_chars *cc)
450 {
451         int i;
452         for (i = 0; i < cc->num; i++) {
453                 cc->vals[i] = NULL;
454         }
455
456         cc->num = 0;
457 }
458
459 static void push_count_chars(count_chars *cc, char const *newval)
460 {
461         cc->vals[cc->num++] = newval;
462 }
463
464 static char const *pop_count_chars(count_chars *cc)
465 {
466         if (!cc->num) {
467                 return NULL;
468         }
469         return cc->vals[--cc->num];
470 }
471
472 static void insert_count_chars(count_chars *cc, char const *newval, int position)
473 {
474         int i;
475
476         for (i = cc->num; i > position; i--) {
477                 cc->vals[i] = cc->vals[i-1];
478         }
479
480         cc->vals[position] = newval;
481         cc->num++;
482 }
483
484 static void append_count_chars(count_chars *cc, count_chars *cctoadd)
485 {
486         int i;
487         for (i = 0; i < cctoadd->num; i++) {
488                 if (cctoadd->vals[i]) {
489                         push_count_chars(cc, cctoadd->vals[i]);
490                 }
491         }
492 }
493
494 static char const *flatten_count_chars(count_chars *cc, char delim)
495 {
496         int i, size;
497         char *newval;
498
499         size = 0;
500         for (i = 0; i < cc->num; i++) {
501                 if (cc->vals[i]) {
502                         size += strlen(cc->vals[i]) + 1;
503                         if (delim) {
504                                 size++;
505                         }
506                 }
507         }
508
509         newval = (char*)lt_malloc(size + 1);
510         newval[0] = '\0';
511
512         for (i = 0; i < cc->num; i++) {
513                 if (cc->vals[i]) {
514                         strcat(newval, cc->vals[i]);
515                         if (delim) {
516                                 size_t len = strlen(newval);
517                                 newval[len] = delim;
518                                 newval[len + 1] = '\0';
519                         }
520                 }
521         }
522
523         return newval;
524 }
525
526 static char *shell_esc(char const *str)
527 {
528         int in_quote = 0;
529         char *cmd;
530         uint8_t *d;
531         uint8_t const *s;
532
533         cmd = (char *)lt_malloc(2 * strlen(str) + 3);
534         d = (unsigned char *)cmd;
535         s = (const unsigned char *)str;
536
537 #ifdef __MINGW32__
538         *d++ = '\"';
539 #endif
540
541         for (; *s; ++s) {
542                 if (*s == '"') {
543                         *d++ = '\\';
544                         in_quote++;
545                 }
546                 else if (*s == '\\' || (*s == ' ' && (in_quote % 2))) {
547                         *d++ = '\\';
548                 }
549                 *d++ = *s;
550         }
551
552 #ifdef __MINGW32__
553         *d++ = '\"';
554 #endif
555
556         *d = '\0';
557         return cmd;
558 }
559
560 static int external_spawn(command_t *cmd, char const *file, char const **argv)
561 {
562         file = file;            /* -Wunused */
563
564         if (!cmd->options.silent) {
565                 char const **argument = argv;
566                 NOTICE("Executing: ");
567                 while (*argument) {
568                         NOTICE("%s ", *argument);
569                         argument++;
570                 }
571                 puts("");
572         }
573
574         if (cmd->options.dry_run) {
575                 return 0;
576         }
577 #if defined(__EMX__) || defined(__MINGW32__)
578         return spawnvp(P_WAIT, argv[0], argv);
579 #else
580         {
581                 pid_t pid;
582                 pid = fork();
583                 if (pid == 0) {
584                         return execvp(argv[0], (char**)argv);
585                 }
586                 else {
587                         int status;
588                         waitpid(pid, &status, 0);
589
590                         /*
591                          *      Exited via exit(status)
592                          */
593                         if (WIFEXITED(status)) {
594                                 return WEXITSTATUS(status);
595                         }
596
597 #ifdef WTERMSIG
598                         if (WIFSIGNALED(status)) {
599                                 return WTERMSIG(status);
600                         }
601 #endif
602
603                         /*
604                          *      Some other failure.
605                          */
606                         return 1;
607                 }
608         }
609 #endif
610 }
611
612 static int run_command(command_t *cmd, count_chars *cc)
613 {
614         int ret;
615         char *command;
616         char *tmp;
617         char const *raw;
618         char const *spawn_args[4];
619         count_chars tmpcc;
620
621         init_count_chars(&tmpcc);
622
623         if (cmd->program) {
624                 push_count_chars(&tmpcc, cmd->program);
625         }
626
627         append_count_chars(&tmpcc, cmd->program_opts);
628
629         append_count_chars(&tmpcc, cc);
630
631         raw = flatten_count_chars(&tmpcc, ' ');
632         command = shell_esc(raw);
633
634         memcpy(&tmp, &raw, sizeof(tmp));
635         free(tmp);
636
637         spawn_args[0] = SHELL_CMD;
638         spawn_args[1] = "-c";
639         spawn_args[2] = command;
640         spawn_args[3] = NULL;
641         ret = external_spawn(cmd, spawn_args[0], spawn_args);
642
643         free(command);
644
645         return ret;
646 }
647
648 /*
649  * print configuration
650  * shlibpath_var is used in configure.
651  */
652 #define printc(_x,_y) if (!value || !strcmp(value, _x)) printf(_x "=\"%s\"\n", _y)
653
654 static void print_config(char const *value)
655 {
656 #ifdef LD_RUN_PATH
657         printc("runpath_var", LD_RUN_PATH);
658 #endif
659 #ifdef LD_LIBRARY_PATH
660         printc("shlibpath_var", LD_LIBRARY_PATH);
661 #endif
662 #ifdef LD_LIBRARY_PATH_LOCAL
663         printc("shlocallibpath_var", LD_LIBRARY_PATH_LOCAL);
664 #endif
665 #ifdef SHELL_CMD
666         printc("SHELL", SHELL_CMD);
667 #endif
668 #ifdef OBJECT_EXT
669         printc("objext", OBJECT_EXT);
670 #endif
671 #ifdef OBJDIR
672         printc("objdir", OBJDIR);
673 #endif
674 #ifdef DYNAMIC_LIB_EXT
675         /* add a '.' prefix because libtool does that. */
676         printc("shrext_cmds", "echo ." DYNAMIC_LIB_EXT);
677         /* add a '.' prefix because libtool does that. */
678         printc("shrext", "." DYNAMIC_LIB_EXT);
679 #endif
680 #ifdef EXE_EXT
681         printc("exeext", EXE_EXT);
682 #endif
683 #ifdef STATIC_LIB_EXT
684         printc("libext", STATIC_LIB_EXT);
685 #endif
686 #ifdef LIBRARIAN
687         printc("AR", LIBRARIAN);
688 #endif
689 #ifdef LIBRARIAN_OPTS
690         printc("AR_FLAGS", LIBRARIAN_OPTS);
691 #endif
692 #ifdef LINKER_FLAG_PREFIX
693         printc("wl", LINKER_FLAG_PREFIX);
694 #endif
695 #ifdef RANLIB
696         printc("ranlib", RANLIB);
697 #endif
698
699 }
700 /*
701  * Add a directory to the runtime library search path.
702  */
703 static void add_runtime_dir_lib(char const *arg, command_t *cmd)
704 {
705 #ifdef RPATH
706         add_rpath(cmd->shared_opts.dependencies, arg);
707 #else
708         (void) arg;                     /* -Wunused */
709         (void) cmd;
710 #endif
711 }
712
713 static int parse_long_opt(char const *arg, command_t *cmd)
714 {
715         char *equal_pos = strchr(arg, '=');
716         char var[50];
717         char value[500];
718
719         if (equal_pos) {
720                 strncpy(var, arg, equal_pos - arg);
721                 var[equal_pos - arg] = 0;
722                 if (strlen(equal_pos + 1) >= sizeof(var)) {
723                         return 0;
724                 }
725                 strcpy(value, equal_pos + 1);
726         } else {
727                 strncpy(var, arg, sizeof(var) - 1);
728                 var[sizeof(var) - 1] = '\0';
729
730                 value[0] = '\0';
731         }
732
733         if (strcmp(var, "silent") == 0) {
734                 cmd->options.silent = 1;
735         } else if (strcmp(var, "quiet") == 0) {
736                 cmd->options.silent = 1;
737         } else if (strcmp(var, "debug") == 0) {
738                 cmd->options.debug = 1;
739         } else if (strcmp(var, "mode") == 0) {
740                 if (cmd->mode != MODE_UNKNOWN) {
741                         ERROR("Cannot set --mode twice\n");
742                         exit(1);
743                 }
744
745                 if (strcmp(value, "compile") == 0) {
746                         cmd->mode = MODE_COMPILE;
747                         cmd->output = OUT_OBJECT;
748
749                 } else if (strcmp(value, "link") == 0) {
750                         cmd->mode = MODE_LINK;
751                         cmd->output = OUT_LIB;
752
753                 } else if (strcmp(value, "install") == 0) {
754                         cmd->mode = MODE_INSTALL;
755
756                 } else if (strcmp(value, "execute") == 0) {
757                         cmd->mode = MODE_EXECUTE;
758
759                 } else {
760                         ERROR("Unknown mode \"%s\"\n", value);
761                         exit(1);
762                 }
763
764         } else if (strcmp(var, "shared") == 0) {
765                 if ((cmd->mode == MODE_LINK) && (cmd->output == OUT_GENERAL)) {
766                         cmd->output = OUT_DYNAMIC_LIB_ONLY;
767                 }
768                 cmd->options.shared = SHARE_SHARED;
769
770         } else if (strcmp(var, "export-all") == 0) {
771                 cmd->options.export_all = 1;
772
773         } else if (strcmp(var, "dry-run") == 0) {
774                 NOTICE("Dry-run mode on!\n");
775                 cmd->options.dry_run = 1;
776
777         } else if (strcmp(var, "version") == 0) {
778                 NOTICE("Version " VERSION "\n");
779
780         } else if (strcmp(var, "help") == 0) {
781                 usage(0);
782
783         } else if (strcmp(var, "config") == 0) {
784                 print_config(value);
785
786                 exit(0);
787         } else {
788                 return 0;
789         }
790
791         return 1;
792 }
793
794 /* Return 1 if we eat it. */
795 static int parse_short_opt(char const *arg, command_t *cmd)
796 {
797         if (strcmp(arg, "export-dynamic") == 0) {
798                 cmd->options.export_dynamic = 1;
799                 return 1;
800         }
801
802         if (strcmp(arg, "module") == 0) {
803                 cmd->output = OUT_MODULE;
804                 return 1;
805         }
806
807         if (strcmp(arg, "shared") == 0) {
808                 if (cmd->mode == MODE_LINK) {
809                         cmd->output = OUT_DYNAMIC_LIB_ONLY;
810                 }
811                 cmd->options.shared = SHARE_SHARED;
812                 return 1;
813         }
814
815         if (strcmp(arg, "Zexe") == 0) {
816                 return 1;
817         }
818
819         if (strcmp(arg, "avoid-version") == 0) {
820                 return 1;
821         }
822
823         if (strcmp(arg, "prefer-pic") == 0) {
824                 cmd->options.pic_mode = PIC_PREFER;
825                 return 1;
826         }
827
828         if (strcmp(arg, "prefer-non-pic") == 0) {
829                 cmd->options.pic_mode = PIC_AVOID;
830                 return 1;
831         }
832
833         if (strcmp(arg, "static") == 0) {
834                 if ((cmd->mode == MODE_LINK) && (cmd->output == OUT_LIB)) {
835                         cmd->output = OUT_STATIC_LIB_ONLY;
836                 }
837                 cmd->options.shared = SHARE_STATIC;
838                 return 1;
839         }
840
841         if (cmd->mode == MODE_LINK) {
842                 if (strcmp(arg, "no-install") == 0) {
843                         cmd->options.no_install = 1;
844                         return 1;
845                 }
846                 if (arg[0] == 'L' || arg[0] == 'l') {
847                         /* Hack... */
848                         arg--;
849                         push_count_chars(cmd->shared_opts.dependencies, arg);
850                         return 1;
851                 } else if (arg[0] == 'R' && arg[1]) {
852                         /* -Rdir Add dir to runtime library search path. */
853                         add_runtime_dir_lib(&arg[1], cmd);
854                         return 1;
855                 }
856         }
857         return 0;
858 }
859
860 #ifdef TRUNCATE_DLL_NAME
861 static char *truncate_dll_name(char *path)
862 {
863         /* Cut DLL name down to 8 characters after removing any mod_ prefix */
864         char *tmppath = strdup(path);
865         char *newname = strrchr(tmppath, '/') + 1;
866         char *ext = strrchr(newname, '.');
867         int len;
868
869         if (ext == NULL) {
870                 return tmppath;
871         }
872
873         len = ext - newname;
874
875         if (strncmp(newname, "mod_", 4) == 0) {
876                 strcpy(newname, newname + 4);
877                 len -= 4;
878         }
879
880         if (len > 8) {
881                 strcpy(newname + 8, strchr(newname, '.'));
882         }
883
884         return tmppath;
885 }
886 #endif
887
888 static long safe_strtol(char const *nptr, char const **endptr, int base)
889 {
890         long rv;
891
892         errno = 0;
893
894         rv = strtol(nptr, (char**)endptr, 10);
895
896         if (errno == ERANGE) {
897                 return 0;
898         }
899
900         return rv;
901 }
902
903 static void safe_mkdir(command_t *cmd, char const *path)
904 {
905         int status;
906         mode_t old_umask;
907
908         old_umask = umask(0);
909         umask(old_umask);
910
911 #ifdef MKDIR_NO_UMASK
912         status = mkdir(path);
913 #else
914         status = mkdir(path, ~old_umask);
915 #endif
916         if ((status < 0) && (errno != EEXIST)) {
917                 NOTICE("Warning: mkdir of %s failed\n", path);
918         }
919 }
920
921 /** Returns a file's name without the path
922  *
923  * @param path to break apart.
924  * @return pointer in path.
925  */
926 static char const *file_name(char const *path)
927 {
928         char const *name;
929
930         name = strrchr(path, '/');
931         if (!name) {
932                 name = strrchr(path, '\\');     /* eww windows? */
933         }
934         if (!name) {
935                 name = path;
936         } else {
937                 name++;
938         }
939
940         return name;
941 }
942
943 #ifdef GEN_EXPORTS
944
945 /** Returns a file's name without path or extension
946  *
947  * @param path to check
948  * @return pointer in path.
949  */
950 static char const *file_name_stripped(char const *path)
951 {
952         char const *name;
953         char const *ext;
954
955         name = file_name(path);
956         ext = strrchr(name, '.');
957
958         if (ext) {
959                 char *trimmed;
960
961                 trimmed = lt_malloc(ext - name + 1);
962                 strncpy(trimmed, name, ext - name);
963                 trimmed[ext-name] = 0;
964
965                 return trimmed;
966         }
967
968         return name;
969 }
970 #endif
971
972 /* version_info is in the form of MAJOR:MINOR:PATCH */
973 static char const *darwin_dynamic_link_function(char const *version_info)
974 {
975         char *newarg;
976         long major, minor, patch;
977
978         major = 0;
979         minor = 0;
980         patch = 0;
981
982         if (version_info) {
983                 major = safe_strtol(version_info, &version_info, 10);
984
985                 if (version_info) {
986                         if (version_info[0] == ':') {
987                                 version_info++;
988                         }
989
990                         minor = safe_strtol(version_info, &version_info, 10);
991
992                         if (version_info) {
993                                 if (version_info[0] == ':') {
994                                         version_info++;
995                                 }
996
997                                 patch = safe_strtol(version_info, &version_info, 10);
998
999                         }
1000                 }
1001         }
1002
1003         /* Avoid -dylib_compatibility_version must be greater than zero errors. */
1004         if (major == 0) {
1005                 major = 1;
1006         }
1007         newarg = (char*)lt_malloc(100);
1008         snprintf(newarg, 99,
1009                          "-compatibility_version %ld -current_version %ld.%ld",
1010                          major, major, minor);
1011
1012         return newarg;
1013 }
1014
1015
1016 /*
1017  *      Add a '.libs/' to the buffer.  The caller ensures that
1018  *      The buffer is large enough to handle 6 extra characters.
1019  */
1020 static void add_dotlibs(char *buffer)
1021 {
1022         char *name = strrchr(buffer, '/');
1023
1024         if (!name) {
1025                 if (!buffer[0]) {
1026                         strcpy(buffer, ".libs/");
1027                         return;
1028                 }
1029                 name = buffer;
1030         } else {
1031                 name++;
1032         }
1033         memmove(name + 6, name, strlen(name));
1034         memcpy(name, ".libs/", 6);
1035 }
1036
1037 static char *gen_library_name(char const *name, enum lib_type genlib)
1038 {
1039         char *newarg, *newext;
1040
1041         newarg = (char *)calloc(strlen(name) + 11, 1);
1042
1043         if (genlib == TYPE_MODULE_LIB && strncmp(name, "lib", 3) == 0) {
1044                 name += 3;
1045         }
1046
1047         if (genlib == TYPE_MODULE_LIB) {
1048                 strcpy(newarg, file_name(name));
1049         }
1050         else {
1051                 strcpy(newarg, name);
1052         }
1053
1054         newext = strrchr(newarg, '.');
1055         if (!newext) {
1056                 ERROR("Library path does not have an extension");
1057         free(newarg);
1058
1059         return NULL;
1060         }
1061         newext++;
1062
1063         switch (genlib) {
1064         case TYPE_STATIC_LIB:
1065                 strcpy(newext, STATIC_LIB_EXT);
1066                 break;
1067         case TYPE_DYNAMIC_LIB:
1068                 strcpy(newext, DYNAMIC_LIB_EXT);
1069                 break;
1070         case TYPE_MODULE_LIB:
1071                 strcpy(newext, MODULE_LIB_EXT);
1072                 break;
1073
1074         default:
1075                 break;
1076         }
1077
1078         add_dotlibs(newarg);
1079
1080         return newarg;
1081 }
1082
1083 static char *gen_install_name(char const *name, enum lib_type genlib)
1084 {
1085         char *newname;
1086         int rv;
1087         struct stat sb;
1088
1089         newname = gen_library_name(name, genlib);
1090         if (!newname) return NULL;
1091
1092         /* Check if it exists. If not, return NULL.  */
1093         rv = stat(newname, &sb);
1094
1095         if (rv) {
1096                 free(newname);
1097                 return NULL;
1098         }
1099
1100         return newname;
1101 }
1102
1103 static char const *check_object_exists(command_t *cmd, char const *arg, int arglen)
1104 {
1105         char *newarg, *ext;
1106         struct stat sb;
1107
1108         newarg = (char *)lt_malloc(arglen + 10);
1109         memcpy(newarg, arg, arglen);
1110         newarg[arglen] = 0;
1111         ext = newarg + arglen;
1112
1113         strcpy(ext, OBJECT_EXT);
1114
1115         DEBUG("Checking (obj): %s\n", newarg);
1116         if (stat(newarg, &sb) == 0) {
1117                 return newarg;
1118         }
1119
1120         free(newarg);
1121
1122         return NULL;
1123 }
1124
1125 /* libdircheck values:
1126  * 0 - no .libs suffix
1127  * 1 - .libs suffix
1128  */
1129 static char *check_library_exists(command_t *cmd, char const *arg, int pathlen,
1130                                   int libdircheck, enum lib_type *libtype)
1131 {
1132         char *newarg, *ext;
1133         int pass, rv, newpathlen;
1134
1135         newarg = (char *)lt_malloc(strlen(arg) + 10);
1136         strcpy(newarg, arg);
1137         newarg[pathlen] = '\0';
1138
1139         newpathlen = pathlen;
1140         if (libdircheck) {
1141                 add_dotlibs(newarg);
1142                 newpathlen += sizeof(".libs/") - 1;
1143         }
1144
1145         strcpy(newarg + newpathlen, arg + pathlen);
1146         ext = strrchr(newarg, '.');
1147         if (!ext) {
1148                 ERROR("Error: Library path does not have an extension");
1149                 free(newarg);
1150
1151                 return NULL;
1152         }
1153         ext++;
1154
1155         pass = 0;
1156
1157         do {
1158                 struct stat sb;
1159
1160                 switch (pass) {
1161                 case 0:
1162                         if (cmd->options.pic_mode != PIC_AVOID &&
1163                                 cmd->options.shared != SHARE_STATIC) {
1164                                 strcpy(ext, DYNAMIC_LIB_EXT);
1165                                 *libtype = TYPE_DYNAMIC_LIB;
1166                                 break;
1167                         }
1168                         pass = 1;
1169                         /* Fall through */
1170                 case 1:
1171                         strcpy(ext, STATIC_LIB_EXT);
1172                         *libtype = TYPE_STATIC_LIB;
1173                         break;
1174                 case 2:
1175                         strcpy(ext, MODULE_LIB_EXT);
1176                         *libtype = TYPE_MODULE_LIB;
1177                         break;
1178                 case 3:
1179                         strcpy(ext, OBJECT_EXT);
1180                         *libtype = TYPE_OBJECT;
1181                         break;
1182                 default:
1183                         *libtype = TYPE_UKNOWN;
1184                         break;
1185                 }
1186
1187                 DEBUG("Checking (lib): %s\n", newarg);
1188                 rv = stat(newarg, &sb);
1189         }
1190         while (rv != 0 && ++pass < 4);
1191
1192         if (rv == 0) {
1193                 return newarg;
1194         }
1195
1196         free(newarg);
1197
1198         return NULL;
1199 }
1200
1201 static char * load_install_path(char const *arg)
1202 {
1203         FILE *f;
1204         char *path;
1205
1206         f = fopen(arg,"r");
1207         if (f == NULL) {
1208                 return NULL;
1209         }
1210
1211         path = lt_malloc(PATH_MAX);
1212
1213         fgets(path, PATH_MAX, f);
1214         fclose(f);
1215
1216         if (path[strlen(path)-1] == '\n') {
1217                 path[strlen(path)-1] = '\0';
1218         }
1219
1220         /* Check that we have an absolute path.
1221          * Otherwise the file could be a GNU libtool file.
1222          */
1223         if (path[0] != '/') {
1224                 free(path);
1225
1226                 return NULL;
1227         }
1228         return path;
1229 }
1230
1231 static char *load_noinstall_path(char const *arg, int pathlen)
1232 {
1233         char *newarg, *expanded_path;
1234         int newpathlen;
1235
1236         newarg = (char *)lt_malloc(strlen(arg) + 10);
1237         strcpy(newarg, arg);
1238         newarg[pathlen] = 0;
1239
1240         newpathlen = pathlen;
1241         strcat(newarg, ".libs");
1242         newpathlen += sizeof(".libs") - 1;
1243         newarg[newpathlen] = 0;
1244
1245 #ifdef HAS_REALPATH
1246         expanded_path = lt_malloc(PATH_MAX);
1247         expanded_path = realpath(newarg, expanded_path);
1248         /* Uh, oh.  There was an error.  Fall back on our first guess. */
1249         if (!expanded_path) {
1250                 expanded_path = newarg;
1251         }
1252 #else
1253         /* We might get ../ or something goofy.  Oh, well. */
1254         expanded_path = newarg;
1255 #endif
1256
1257         return expanded_path;
1258 }
1259
1260 static void add_dynamic_link_opts(command_t *cmd, count_chars *args)
1261 {
1262 #ifdef DYNAMIC_LINK_OPTS
1263         if (cmd->options.pic_mode != PIC_AVOID) {
1264                 DEBUG("Adding linker opt: %s\n", DYNAMIC_LINK_OPTS);
1265
1266                 push_count_chars(args, DYNAMIC_LINK_OPTS);
1267                 if (cmd->undefined_flag) {
1268                         push_count_chars(args, "-undefined");
1269 #if defined(__APPLE__)
1270                         /* -undefined dynamic_lookup is used by the bundled Python in
1271                          * 10.4, but if we don't set MACOSX_DEPLOYMENT_TARGET to 10.3+,
1272                          * we'll get a linker error if we pass this flag.
1273                          */
1274                         if (strcasecmp(cmd->undefined_flag, "dynamic_lookup") == 0) {
1275                                 insert_count_chars(cmd->program_opts, "MACOSX_DEPLOYMENT_TARGET=10.3", 0);
1276                         }
1277 #endif
1278                         push_count_chars(args, cmd->undefined_flag);
1279                 }
1280                 else {
1281 #ifdef DYNAMIC_LINK_UNDEFINED
1282                         DEBUG("Adding linker opt: %s\n", DYNAMIC_LINK_UNDEFINED);
1283
1284                         push_count_chars(args, DYNAMIC_LINK_UNDEFINED);
1285 #endif
1286                 }
1287         }
1288 #endif
1289 }
1290
1291 /* Read the final install location and add it to runtime library search path. */
1292 #ifdef RPATH
1293 static void add_rpath(count_chars *cc, char const *path)
1294 {
1295         int size = 0;
1296         char *tmp;
1297
1298 #ifdef LINKER_FLAG_PREFIX
1299         size = strlen(LINKER_FLAG_PREFIX);
1300 #endif
1301         size = size + strlen(path) + strlen(RPATH) + 2;
1302         tmp = lt_malloc(size);
1303
1304 #ifdef LINKER_FLAG_PREFIX
1305         strcpy(tmp, LINKER_FLAG_PREFIX);
1306         strcat(tmp, RPATH);
1307 #else
1308         strcpy(tmp, RPATH);
1309 #endif
1310 #ifndef LINKER_FLAG_NO_EQUALS
1311         strcat(tmp, "=");
1312 #endif
1313         strcat(tmp, path);
1314
1315         push_count_chars(cc, tmp);
1316 }
1317
1318 static void add_rpath_file(count_chars *cc, char const *arg)
1319 {
1320         char const *path;
1321
1322         path = load_install_path(arg);
1323         if (path) {
1324                 add_rpath(cc, path);
1325                 lt_const_free(path);
1326         }
1327 }
1328
1329 static void add_rpath_noinstall(count_chars *cc, char const *arg, int pathlen)
1330 {
1331         char const *path;
1332
1333         path = load_noinstall_path(arg, pathlen);
1334         if (path) {
1335                 add_rpath(cc, path);
1336                 lt_const_free(path);
1337         }
1338 }
1339 #endif
1340
1341 #ifdef DYNAMIC_LINK_NO_INSTALL
1342 static void add_dylink_noinstall(count_chars *cc, char const *arg, int pathlen,
1343                                                   int extlen)
1344 {
1345         char const *install_path, *current_path, *name;
1346         char *exp_argument;
1347         int i_p_len, c_p_len, name_len, dyext_len, cur_len;
1348
1349         install_path = load_install_path(arg);
1350         current_path = load_noinstall_path(arg, pathlen);
1351
1352         if (!install_path || !current_path) {
1353                 return;
1354         }
1355
1356         push_count_chars(cc, DYNAMIC_LINK_NO_INSTALL);
1357
1358         i_p_len = strlen(install_path);
1359         c_p_len = strlen(current_path);
1360
1361         name = arg+pathlen;
1362         name_len = extlen-pathlen;
1363         dyext_len = sizeof(DYNAMIC_LIB_EXT) - 1;
1364
1365         /* No, we need to replace the extension. */
1366         exp_argument = (char *)lt_malloc(i_p_len + c_p_len + (name_len*2) +
1367                                                                   (dyext_len*2) + 2);
1368
1369         cur_len = 0;
1370         strcpy(exp_argument, install_path);
1371         cur_len += i_p_len;
1372         exp_argument[cur_len++] = '/';
1373         strncpy(exp_argument+cur_len, name, extlen-pathlen);
1374         cur_len += name_len;
1375         strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1376         cur_len += dyext_len;
1377         exp_argument[cur_len++] = ':';
1378         strcpy(exp_argument+cur_len, current_path);
1379         cur_len += c_p_len;
1380         exp_argument[cur_len++] = '/';
1381         strncpy(exp_argument+cur_len, name, extlen-pathlen);
1382         cur_len += name_len;
1383         strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1384         cur_len += dyext_len;
1385
1386         push_count_chars(cc, exp_argument);
1387 }
1388 #endif
1389
1390 #ifdef ADD_MINUS_L
1391 /* use -L -llibname to allow to use installed libraries */
1392 static void add_minus_l(count_chars *cc, char const *arg)
1393 {
1394         char *newarg;
1395         char *name = strrchr(arg, '/');
1396         char *file = strrchr(arg, '.');
1397
1398         if ((name != NULL) && (file != NULL) &&
1399                 (strstr(name, "lib") == (name + 1))) {
1400                 *name = '\0';
1401                 *file = '\0';
1402                 file = name;
1403                 file = file+4;
1404                 push_count_chars(cc, "-L");
1405                 push_count_chars(cc, arg);
1406                 /* we need one argument like -lapr-1 */
1407                 newarg = lt_malloc(strlen(file) + 3);
1408                 strcpy(newarg, "-l");
1409                 strcat(newarg, file);
1410                 push_count_chars(cc, newarg);
1411         } else {
1412                 push_count_chars(cc, arg);
1413         }
1414 }
1415 #endif
1416
1417 #if 0
1418 static void add_linker_flag_prefix(count_chars *cc, char const *arg)
1419 {
1420 #ifndef LINKER_FLAG_PREFIX
1421         push_count_chars(cc, arg);
1422 #else
1423         char *newarg;
1424         newarg = (char*)lt_malloc(strlen(arg) + sizeof(LINKER_FLAG_PREFIX) + 1);
1425         strcpy(newarg, LINKER_FLAG_PREFIX);
1426         strcat(newarg, arg);
1427         push_count_chars(cc, newarg);
1428 #endif
1429 }
1430 #endif
1431
1432 static int explode_static_lib(command_t *cmd, char const *lib)
1433 {
1434         count_chars tmpdir_cc, libname_cc;
1435         char const *tmpdir, *libname;
1436         char savewd[PATH_MAX];
1437         char const *name;
1438         DIR *dir;
1439         struct dirent *entry;
1440         char const *lib_args[4];
1441
1442         /* Bah! */
1443         if (cmd->options.dry_run) {
1444                 return 0;
1445         }
1446
1447         name = file_name(lib);
1448
1449         init_count_chars(&tmpdir_cc);
1450         push_count_chars(&tmpdir_cc, ".libs/");
1451         push_count_chars(&tmpdir_cc, name);
1452         push_count_chars(&tmpdir_cc, ".exploded/");
1453         tmpdir = flatten_count_chars(&tmpdir_cc, 0);
1454
1455         NOTICE("Making: %s\n", tmpdir);
1456
1457         safe_mkdir(cmd, tmpdir);
1458
1459         push_count_chars(cmd->tmp_dirs, tmpdir);
1460
1461         getcwd(savewd, sizeof(savewd));
1462
1463         if (chdir(tmpdir) != 0) {
1464                 NOTICE("Warning: could not explode %s\n", lib);
1465
1466                 return 1;
1467         }
1468
1469         if (lib[0] == '/') {
1470                 libname = lib;
1471         }
1472         else {
1473                 init_count_chars(&libname_cc);
1474                 push_count_chars(&libname_cc, "../../");
1475                 push_count_chars(&libname_cc, lib);
1476                 libname = flatten_count_chars(&libname_cc, 0);
1477         }
1478
1479         lib_args[0] = LIBRARIAN;
1480         lib_args[1] = "x";
1481         lib_args[2] = libname;
1482         lib_args[3] = NULL;
1483
1484         external_spawn(cmd, LIBRARIAN, lib_args);
1485
1486         chdir(savewd);
1487         dir = opendir(tmpdir);
1488
1489         while ((entry = readdir(dir)) != NULL) {
1490 #if defined(__APPLE__) && defined(RANLIB)
1491                 /* Apple inserts __.SYMDEF which isn't needed.
1492                  * Leopard (10.5+) can also add '__.SYMDEF SORTED' which isn't
1493                  * much fun either.  Just skip them.
1494                  */
1495                 if (strstr(entry->d_name, "__.SYMDEF") != NULL) {
1496                         continue;
1497                 }
1498 #endif
1499                 if (entry->d_name[0] != '.') {
1500                         push_count_chars(&tmpdir_cc, entry->d_name);
1501                         name = flatten_count_chars(&tmpdir_cc, 0);
1502
1503                         DEBUG("Adding object: %s\n", name);
1504                         push_count_chars(cmd->obj_files, name);
1505                         pop_count_chars(&tmpdir_cc);
1506                 }
1507         }
1508
1509         closedir(dir);
1510         return 0;
1511 }
1512
1513 static int parse_input_file_name(char const *arg, command_t *cmd)
1514 {
1515         char const *ext = strrchr(arg, '.');
1516         char const *name;
1517         int pathlen;
1518         enum lib_type libtype;
1519         char const *newarg;
1520
1521         /* Can't guess the extension */
1522         if (!ext) {
1523                 return 0;
1524         }
1525
1526         ext++;
1527         name = file_name(arg);
1528         pathlen = name - arg;
1529
1530         /*
1531          *      Were linking and have an archived object or object file
1532          *      push it onto the list of object files which'll get used
1533          *      to create the input files list for the linker.
1534          *
1535          *      We assume that these are outside of the project were building,
1536          *      as there's no reason to create .a files as part of the build
1537          *      process.
1538          */
1539         if (!strcmp(ext, STATIC_LIB_EXT) && (cmd->mode == MODE_LINK)) {
1540                 struct stat sb;
1541
1542                 if (!stat(arg, &sb)) {
1543                         DEBUG("Adding object: %s\n", arg);
1544
1545                         push_count_chars(cmd->obj_files, arg);
1546
1547                         return 1;
1548                 }
1549         }
1550
1551         /*
1552          *      More object files, if were linking they get set as input
1553          *      files.
1554          */
1555         if (!strcmp(ext, "lo") || !strcmp(ext, OBJECT_EXT)) {
1556                 newarg = check_object_exists(cmd, arg, ext - arg);
1557                 if (!newarg) {
1558                         ERROR("Can not find suitable object file for %s\n", arg);
1559                         exit(1);
1560                 }
1561
1562                 if (cmd->mode == MODE_LINK) {
1563                         DEBUG("Adding object: %s\n", newarg);
1564
1565                         push_count_chars(cmd->obj_files, newarg);
1566                 } else {
1567                         push_count_chars(cmd->arglist, newarg);
1568                 }
1569
1570                 return 1;
1571         }
1572
1573         if (!strcmp(ext, "la")) {
1574                 switch (cmd->mode) {
1575                 case MODE_LINK:
1576                         /* Try the .libs dir first! */
1577                         newarg = check_library_exists(cmd, arg, pathlen, 1, &libtype);
1578                         if (!newarg) {
1579                                 /* Try the normal dir next. */
1580                                 newarg = check_library_exists(cmd, arg, pathlen, 0, &libtype);
1581                                 if (!newarg) {
1582                                         ERROR("Can not find suitable library for %s\n", arg);
1583                                         exit(1);
1584                                 }
1585                         }
1586
1587                         /* It is not ok to just add the file: a library may added with:
1588                            1 - -L path library_name. (For *.so in Linux).
1589                            2 - library_name.
1590                          */
1591 #ifdef ADD_MINUS_L
1592                         if (libtype == TYPE_DYNAMIC_LIB) {
1593                                 add_minus_l(cmd->shared_opts.dependencies, newarg);
1594                         } else if (cmd->output == OUT_LIB &&
1595                                            libtype == TYPE_STATIC_LIB) {
1596                                 explode_static_lib(cmd, newarg);
1597                         } else {
1598                                 push_count_chars(cmd->shared_opts.dependencies, newarg);
1599                         }
1600 #else
1601                         if (cmd->output == OUT_LIB && libtype == TYPE_STATIC_LIB) {
1602                                 explode_static_lib(cmd, newarg);
1603                         }
1604                         else {
1605                                 push_count_chars(cmd->shared_opts.dependencies, newarg);
1606                         }
1607 #endif
1608                         if (libtype == TYPE_DYNAMIC_LIB) {
1609                                 if (cmd->options.no_install) {
1610 #ifdef RPATH
1611                                         add_rpath_noinstall(cmd->shared_opts.dependencies,
1612                                                                                 arg, pathlen);
1613 #endif
1614                                 }
1615                                 else {
1616 #ifdef RPATH
1617                                         add_rpath_file(cmd->shared_opts.dependencies, arg);
1618 #endif
1619                                 }
1620                         }
1621                         break;
1622                 case MODE_INSTALL:
1623                         /*
1624                          *      If we've already recorded a library to
1625                          *      install, we're most likely getting the .la
1626                          *      file that we want to install as.
1627                          *
1628                          *      The problem is that we need to add it as the
1629                          *      directory, not the .la file itself.
1630                          *      Otherwise, we'll do odd things.
1631                          */
1632                         if (cmd->output == OUT_LIB) {
1633                                 char *tmp;
1634
1635                                 tmp = strdup(arg);
1636                                 tmp[pathlen] = '\0';
1637                                 push_count_chars(cmd->arglist, tmp);
1638
1639                         } else {
1640                                 cmd->output = OUT_LIB;
1641                                 cmd->output_name = arg;
1642                                 cmd->static_name.install = gen_install_name(arg, 0);
1643                                 cmd->shared_name.install = gen_install_name(arg, 1);
1644                                 cmd->module_name.install = gen_install_name(arg, 2);
1645
1646                                 if (!cmd->static_name.install &&
1647                                         !cmd->shared_name.install &&
1648                                         !cmd->module_name.install) {
1649                                         ERROR("Files to install do not exist\n");
1650                                         exit(1);
1651                                 }
1652
1653                         }
1654                         break;
1655                 default:
1656                         break;
1657                 }
1658
1659                 return 1;
1660         }
1661
1662         if (!strcmp(ext, "c")) {
1663                 /* If we don't already have an idea what our output name will be. */
1664                 if (!cmd->basename) {
1665                         char *tmp = lt_malloc(strlen(arg) + 4);
1666                         strcpy(tmp, arg);
1667                         strcpy(strrchr(tmp, '.') + 1, "lo");
1668
1669                         cmd->basename = tmp;
1670
1671                         cmd->fake_output_name = strrchr(cmd->basename, '/');
1672                         if (cmd->fake_output_name) {
1673                                 cmd->fake_output_name++;
1674                         } else {
1675                                 cmd->fake_output_name = cmd->basename;
1676                         }
1677                 }
1678         }
1679
1680         return 0;
1681 }
1682
1683 static int parse_output_file_name(char const *arg, command_t *cmd)
1684 {
1685         char const *name;
1686         char const *ext;
1687         char *newarg = NULL;
1688         size_t pathlen;
1689
1690         cmd->fake_output_name = arg;
1691
1692         name = file_name(arg);
1693         ext = strrchr(name, '.');
1694
1695 #ifdef EXE_EXT
1696         if (!ext || strcmp(ext, EXE_EXT) == 0) {
1697 #else
1698         if (!ext) {
1699 #endif
1700                 cmd->basename = arg;
1701                 cmd->output = OUT_PROGRAM;
1702 #if defined(_OSD_POSIX)
1703                 cmd->options.pic_mode = PIC_AVOID;
1704 #endif
1705                 newarg = (char *)lt_malloc(strlen(arg) + 5);
1706                 strcpy(newarg, arg);
1707 #ifdef EXE_EXT
1708         if (!ext) {
1709           strcat(newarg, EXE_EXT);
1710         }
1711 #endif
1712                 cmd->output_name = newarg;
1713                 return 1;
1714         }
1715
1716         ext++;
1717         pathlen = name - arg;
1718
1719         if (strcmp(ext, "la") == 0) {
1720                 assert(cmd->mode == MODE_LINK);
1721
1722                 cmd->basename = arg;
1723                 cmd->static_name.normal = gen_library_name(arg, TYPE_STATIC_LIB);
1724                 cmd->shared_name.normal = gen_library_name(arg, TYPE_DYNAMIC_LIB);
1725                 cmd->module_name.normal = gen_library_name(arg, TYPE_MODULE_LIB);
1726                 cmd->static_name.install = gen_install_name(arg, TYPE_STATIC_LIB);
1727                 cmd->shared_name.install = gen_install_name(arg, TYPE_DYNAMIC_LIB);
1728                 cmd->module_name.install = gen_install_name(arg, TYPE_MODULE_LIB);
1729
1730                 if (!cmd->options.dry_run) {
1731                         char *newname;
1732                         char *newext;
1733                         newname = lt_malloc(strlen(cmd->static_name.normal) + 1);
1734
1735                         strcpy(newname, cmd->static_name.normal);
1736                         newext = strrchr(newname, '/');
1737                         if (!newext) {
1738                                 /* Check first to see if the dir already exists! */
1739                                 safe_mkdir(cmd, ".libs");
1740                         } else {
1741                                 *newext = '\0';
1742                                 safe_mkdir(cmd, newname);
1743                         }
1744                         free(newname);
1745                 }
1746
1747 #ifdef TRUNCATE_DLL_NAME
1748                 if (shared) {
1749                         arg = truncate_dll_name(arg);
1750                 }
1751 #endif
1752
1753                 cmd->output_name = arg;
1754                 return 1;
1755         }
1756
1757         if (strcmp(ext, STATIC_LIB_EXT) == 0) {
1758                 assert(cmd->mode == MODE_LINK);
1759
1760                 cmd->basename = arg;
1761                 cmd->options.shared = SHARE_STATIC;
1762                 cmd->output = OUT_STATIC_LIB_ONLY;
1763                 cmd->static_name.normal = gen_library_name(arg, TYPE_STATIC_LIB);
1764                 cmd->static_name.install = gen_install_name(arg, TYPE_STATIC_LIB);
1765
1766                 if (!cmd->options.dry_run) {
1767                         char *newname;
1768                         char *newext;
1769                         newname = lt_malloc(strlen(cmd->static_name.normal) + 1);
1770
1771                         strcpy(newname, cmd->static_name.normal);
1772                         newext = strrchr(newname, '/');
1773                         if (!newext) {
1774                                 /* Check first to see if the dir already exists! */
1775                                 safe_mkdir(cmd, ".libs");
1776                         } else {
1777                                 *newext = '\0';
1778                                 safe_mkdir(cmd, newname);
1779                         }
1780                         free(newname);
1781                 }
1782
1783                 cmd->output_name = arg;
1784                 return 1;
1785         }
1786
1787         if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
1788                 assert(cmd->mode == MODE_LINK);
1789
1790                 cmd->basename = arg;
1791                 cmd->options.shared = SHARE_SHARED;
1792                 cmd->output = OUT_DYNAMIC_LIB_ONLY;
1793                 cmd->shared_name.normal = gen_library_name(arg, TYPE_DYNAMIC_LIB);
1794                 cmd->module_name.normal = gen_library_name(arg, TYPE_MODULE_LIB);
1795                 cmd->shared_name.install = gen_install_name(arg, TYPE_DYNAMIC_LIB);
1796                 cmd->module_name.install = gen_install_name(arg, TYPE_MODULE_LIB);
1797
1798                 if (!cmd->options.dry_run) {
1799                         char *newname;
1800                         char *newext;
1801                         newname = lt_malloc(strlen(cmd->shared_name.normal) + 1);
1802
1803                         strcpy(newname, cmd->shared_name.normal);
1804                         newext = strrchr(newname, '/');
1805                         if (!newext) {
1806                                 /* Check first to see if the dir already exists! */
1807                                 safe_mkdir(cmd, ".libs");
1808                         } else {
1809                                 *newext = '\0';
1810                                 safe_mkdir(cmd, newname);
1811                         }
1812                         free(newname);
1813                 }
1814
1815                 cmd->output_name = arg;
1816                 return 1;
1817         }
1818
1819         if (strcmp(ext, "lo") == 0) {
1820                 char *newext;
1821                 cmd->basename = arg;
1822                 cmd->output = OUT_OBJECT;
1823                 newarg = (char *)lt_malloc(strlen(arg) + 2);
1824                 strcpy(newarg, arg);
1825                 newext = strrchr(newarg, '.') + 1;
1826                 strcpy(newext, OBJECT_EXT);
1827                 cmd->output_name = newarg;
1828                 return 1;
1829         }
1830
1831         if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
1832                 ERROR("Please build libraries with .la target, not ."
1833                       DYNAMIC_LIB_EXT "\n");
1834
1835                 exit(1);
1836         }
1837
1838         if (strcmp(ext, STATIC_LIB_EXT) == 0) {
1839                 ERROR("Please build libraries with .la target, not ."
1840                       STATIC_LIB_EXT "\n");
1841
1842                 exit(1);
1843         }
1844
1845         return 0;
1846 }
1847
1848 static char const *automode(char const *arg, command_t *cmd)
1849 {
1850         if (cmd->mode != MODE_UNKNOWN) return arg;
1851
1852         if (!strcmp(arg, "CC") ||
1853             !strcmp(arg, "CXX")) {
1854                 DEBUG("Now in compile mode, guessed from: %s\n", arg);
1855                 arg = CC;
1856                 cmd->mode = MODE_COMPILE;
1857
1858         } else if (!strcmp(arg, "LINK") ||
1859                    !strcmp(arg, "LINK.c") ||
1860                    !strcmp(arg, "LINK.cxx")) {
1861                 DEBUG("Now in linker mode, guessed from: %s\n", arg);
1862                 arg = LINK_C;
1863                 cmd->mode = MODE_LINK;
1864         }
1865
1866         return arg;
1867 }
1868
1869
1870 #ifdef GEN_EXPORTS
1871 static void generate_def_file(command_t *cmd)
1872 {
1873         char def_file[1024];
1874         char implib_file[1024];
1875         char *ext;
1876         FILE *hDef;
1877         char *export_args[1024];
1878         int num_export_args = 0;
1879         char *cmd;
1880         int cmd_size = 0;
1881         int a;
1882
1883         if (cmd->output_name) {
1884                 strcpy(def_file, cmd->output_name);
1885                 strcat(def_file, ".def");
1886                 hDef = fopen(def_file, "w");
1887
1888                 if (hDef != NULL) {
1889                         fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", file_name_stripped(cmd->output_name));
1890                         fprintf(hDef, "DATA NONSHARED\n");
1891                         fprintf(hDef, "EXPORTS\n");
1892                         fclose(hDef);
1893
1894                         for (a = 0; a < cmd->num_obj_files; a++) {
1895                                 cmd_size += strlen(cmd->obj_files[a]) + 1;
1896                         }
1897
1898                         cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
1899                         cmd = (char *)lt_malloc(cmd_size);
1900                         strcpy(cmd, GEN_EXPORTS);
1901
1902                         for (a=0; a < cmd->num_obj_files; a++) {
1903                                 strcat(cmd, " ");
1904                                 strcat(cmd, cmd->obj_files[a] );
1905                         }
1906
1907                         strcat(cmd, ">>");
1908                         strcat(cmd, def_file);
1909                         puts(cmd);
1910                         export_args[num_export_args++] = SHELL_CMD;
1911                         export_args[num_export_args++] = "-c";
1912                         export_args[num_export_args++] = cmd;
1913                         export_args[num_export_args++] = NULL;
1914                         external_spawn(cmd, export_args[0], (char const**)export_args);
1915                         cmd->arglist[cmd->num_args++] = strdup(def_file);
1916
1917                         /* Now make an import library for the dll */
1918                         num_export_args = 0;
1919                         export_args[num_export_args++] = DEF2IMPLIB_CMD;
1920                         export_args[num_export_args++] = "-o";
1921
1922                         strcpy(implib_file, ".libs/");
1923                         strcat(implib_file, cmd->basename);
1924                         ext = strrchr(implib_file, '.');
1925
1926                         if (ext) {
1927                                 *ext = '\0';
1928                         }
1929
1930                         strcat(implib_file, ".");
1931                         strcat(implib_file, STATIC_LIB_EXT);
1932
1933                         export_args[num_export_args++] = implib_file;
1934                         export_args[num_export_args++] = def_file;
1935                         export_args[num_export_args++] = NULL;
1936                         external_spawn(cmd, export_args[0], (char const**)export_args);
1937
1938                 }
1939         }
1940 }
1941 #endif
1942
1943 #if 0
1944 static char const* expand_path(char const *relpath)
1945 {
1946         char foo[PATH_MAX], *newpath;
1947
1948         getcwd(foo, PATH_MAX-1);
1949         newpath = (char*)lt_malloc(strlen(foo)+strlen(relpath)+2);
1950         strcpy(newpath, foo);
1951         strcat(newpath, "/");
1952         strcat(newpath, relpath);
1953         return newpath;
1954 }
1955 #endif
1956
1957 static void link_fixup(command_t *cmd)
1958 {
1959         /* If we were passed an -rpath directive, we need to build
1960          * shared objects too.  Otherwise, we should only create static
1961          * libraries.
1962          */
1963         if (!cmd->install_path && (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
1964                 cmd->output == OUT_MODULE || cmd->output == OUT_LIB)) {
1965                 if (cmd->options.shared == SHARE_SHARED) {
1966                         cmd->install_path = LIBDIR;
1967                 }
1968         }
1969
1970         if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
1971                 cmd->output == OUT_MODULE ||
1972                 cmd->output == OUT_LIB) {
1973
1974                 push_count_chars(cmd->shared_opts.normal, "-o");
1975                 if (cmd->output == OUT_MODULE) {
1976                         push_count_chars(cmd->shared_opts.normal, cmd->module_name.normal);
1977                 } else {
1978                         push_count_chars(cmd->shared_opts.normal, cmd->shared_name.normal);
1979 #ifdef DYNAMIC_INSTALL_NAME
1980                         push_count_chars(cmd->shared_opts.normal, DYNAMIC_INSTALL_NAME);
1981
1982                         if (!cmd->install_path) {
1983                                 ERROR("Installation mode requires -rpath\n");
1984                                 exit(1);
1985                         }
1986
1987                         {
1988                                 char *tmp = lt_malloc(PATH_MAX);
1989                                 strcpy(tmp, cmd->install_path);
1990
1991                                 if (cmd->shared_name.install) {
1992                                         strcat(tmp, strrchr(cmd->shared_name.install, '/'));
1993                                 } else {
1994                                         strcat(tmp, strrchr(cmd->shared_name.normal, '/'));
1995                                 }
1996
1997                                 push_count_chars(cmd->shared_opts.normal, tmp);
1998                         }
1999 #endif
2000                 }
2001
2002                 append_count_chars(cmd->shared_opts.normal, cmd->obj_files);
2003                 append_count_chars(cmd->shared_opts.normal, cmd->shared_opts.dependencies);
2004
2005                 if (cmd->options.export_all) {
2006 #ifdef GEN_EXPORTS
2007                         generate_def_file(cmd);
2008 #endif
2009                 }
2010         }
2011
2012         if (cmd->output == OUT_LIB || cmd->output == OUT_STATIC_LIB_ONLY) {
2013                 push_count_chars(cmd->static_opts.normal, "-o");
2014                 push_count_chars(cmd->static_opts.normal, cmd->output_name);
2015         }
2016
2017         if (cmd->output == OUT_PROGRAM) {
2018                 if (cmd->output_name) {
2019                         push_count_chars(cmd->arglist, "-o");
2020                         push_count_chars(cmd->arglist, cmd->output_name);
2021                         append_count_chars(cmd->arglist, cmd->obj_files);
2022                         append_count_chars(cmd->arglist, cmd->shared_opts.dependencies);
2023                         add_dynamic_link_opts(cmd, cmd->arglist);
2024                 }
2025         }
2026 }
2027
2028 static void post_parse_fixup(command_t *cmd)
2029 {
2030         switch (cmd->mode) {
2031         case MODE_COMPILE:
2032 #ifdef PIC_FLAG
2033                 if (cmd->options.pic_mode != PIC_AVOID) {
2034                         push_count_chars(cmd->arglist, PIC_FLAG);
2035                 }
2036 #endif
2037                 if (cmd->output_name) {
2038                         push_count_chars(cmd->arglist, "-o");
2039                         push_count_chars(cmd->arglist, cmd->output_name);
2040                 }
2041                 break;
2042         case MODE_LINK:
2043                 link_fixup(cmd);
2044                 break;
2045         case MODE_INSTALL:
2046                 if (cmd->output == OUT_LIB) {
2047                         link_fixup(cmd);
2048                 }
2049         default:
2050                 break;
2051         }
2052
2053 #ifdef USE_OMF
2054         if (cmd->output == OUT_OBJECT ||
2055                 cmd->output == OUT_PROGRAM ||
2056                 cmd->output == OUT_LIB ||
2057                 cmd->output == OUT_DYNAMIC_LIB_ONLY) {
2058                 push_count_chars(cmd->arglist, "-Zomf");
2059         }
2060 #endif
2061
2062         if (cmd->options.shared &&
2063                         (cmd->output == OUT_OBJECT ||
2064                          cmd->output == OUT_LIB ||
2065                          cmd->output == OUT_DYNAMIC_LIB_ONLY)) {
2066 #ifdef SHARE_SW
2067                 push_count_chars(cmd->arglist, SHARE_SW);
2068 #endif
2069         }
2070 }
2071
2072 static int run_mode(command_t *cmd)
2073 {
2074         int rv = 0;
2075         count_chars *cctemp;
2076
2077         cctemp = (count_chars*)lt_malloc(sizeof(count_chars));
2078         init_count_chars(cctemp);
2079
2080         switch (cmd->mode) {
2081         case MODE_COMPILE:
2082                 rv = run_command(cmd, cmd->arglist);
2083                 if (rv) goto finish;
2084                 break;
2085         case MODE_INSTALL:
2086                 /* Well, we'll assume it's a file going to a directory... */
2087                 /* For brain-dead install-sh based scripts, we have to repeat
2088                  * the command N-times.  install-sh should die.
2089                  */
2090                 if (!cmd->output_name) {
2091                         rv = run_command(cmd, cmd->arglist);
2092                         if (rv) goto finish;
2093                 }
2094                 if (cmd->output_name) {
2095                         append_count_chars(cctemp, cmd->arglist);
2096                         insert_count_chars(cctemp,
2097                                                            cmd->output_name,
2098                                                            cctemp->num - 1);
2099                         rv = run_command(cmd, cctemp);
2100                         if (rv) goto finish;
2101                         clear_count_chars(cctemp);
2102                 }
2103                 if (cmd->static_name.install) {
2104                         append_count_chars(cctemp, cmd->arglist);
2105                         insert_count_chars(cctemp,
2106                                                            cmd->static_name.install,
2107                                                            cctemp->num - 1);
2108                         rv = run_command(cmd, cctemp);
2109                         if (rv) goto finish;
2110 #if defined(__APPLE__) && defined(RANLIB)
2111                         /* From the Apple libtool(1) manpage on Tiger/10.4:
2112                          * ----
2113                          * With  the way libraries used to be created, errors were possible
2114                          * if the library was modified with ar(1) and  the  table  of
2115                          * contents  was  not updated  by  rerunning ranlib(1).  Thus the
2116                          * link editor, ld, warns when the modification date of a library
2117                          * is more  recent  than  the  creation date  of its table of
2118                          * contents.  Unfortunately, this means that you get the warning
2119                          * even if you only copy the library.
2120                          * ----
2121                          *
2122                          * This means that when we install the static archive, we need to
2123                          * rerun ranlib afterwards.
2124                          */
2125                         char const *lib_args[3], *static_lib_name;
2126
2127                         {
2128                                 char *tmp;
2129                                 size_t len1, len2;
2130
2131                                 len1 = strlen(cmd->arglist->vals[cmd->arglist->num - 1]);
2132
2133                                 static_lib_name = file_name(cmd->static_name.install);
2134                                 len2 = strlen(static_lib_name);
2135
2136                                 tmp = lt_malloc(len1 + len2 + 2);
2137
2138                                 snprintf(tmp, len1 + len2 + 2, "%s/%s",
2139                                                 cmd->arglist->vals[cmd->arglist->num - 1],
2140                                                 static_lib_name);
2141
2142                                 lib_args[0] = RANLIB;
2143                                 lib_args[1] = tmp;
2144                                 lib_args[2] = NULL;
2145
2146                                 external_spawn(cmd, RANLIB, lib_args);
2147
2148                                 free(tmp);
2149                         }
2150 #endif
2151                         clear_count_chars(cctemp);
2152                 }
2153                 if (cmd->shared_name.install) {
2154                         append_count_chars(cctemp, cmd->arglist);
2155                         insert_count_chars(cctemp, cmd->shared_name.install,
2156                                            cctemp->num - 1);
2157                         rv = run_command(cmd, cctemp);
2158                         if (rv) goto finish;
2159                         clear_count_chars(cctemp);
2160                 }
2161                 if (cmd->module_name.install) {
2162                         append_count_chars(cctemp, cmd->arglist);
2163                         insert_count_chars(cctemp, cmd->module_name.install,
2164                                            cctemp->num - 1);
2165                         rv = run_command(cmd, cctemp);
2166                         if (rv) goto finish;
2167                         clear_count_chars(cctemp);
2168                 }
2169                 break;
2170         case MODE_LINK:
2171                 if (cmd->output == OUT_STATIC_LIB_ONLY ||
2172                         cmd->output == OUT_LIB) {
2173 #ifdef RANLIB
2174                         char const *lib_args[3];
2175 #endif
2176                         /* Removes compiler! */
2177                         cmd->program = LIBRARIAN;
2178                         push_count_chars(cmd->program_opts, LIBRARIAN_OPTS);
2179                         push_count_chars(cmd->program_opts, cmd->static_name.normal);
2180
2181                         rv = run_command(cmd, cmd->obj_files);
2182                         if (rv) goto finish;
2183
2184 #ifdef RANLIB
2185                         lib_args[0] = RANLIB;
2186                         lib_args[1] = cmd->static_name.normal;
2187                         lib_args[2] = NULL;
2188                         external_spawn(cmd, RANLIB, lib_args);
2189 #endif
2190                 }
2191
2192                 if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
2193                         cmd->output == OUT_MODULE ||
2194                         cmd->output == OUT_LIB) {
2195                         cmd->program = NULL;
2196                         clear_count_chars(cmd->program_opts);
2197
2198                         append_count_chars(cmd->program_opts, cmd->arglist);
2199                         if (cmd->output == OUT_MODULE) {
2200 #ifdef MODULE_OPTS
2201                                 push_count_chars(cmd->program_opts, MODULE_OPTS);
2202 #endif
2203                         } else {
2204 #ifdef SHARED_OPTS
2205                                 push_count_chars(cmd->program_opts, SHARED_OPTS);
2206 #endif
2207 #ifdef dynamic_link_version_func
2208                                 push_count_chars(cmd->program_opts,
2209                                                  dynamic_link_version_func(cmd->version_info));
2210 #endif
2211                         }
2212                         add_dynamic_link_opts(cmd, cmd->program_opts);
2213
2214                         rv = run_command(cmd, cmd->shared_opts.normal);
2215                         if (rv) goto finish;
2216                 }
2217                 if (cmd->output == OUT_PROGRAM) {
2218                         rv = run_command(cmd, cmd->arglist);
2219                         if (rv) goto finish;
2220                 }
2221                 break;
2222         case MODE_EXECUTE:
2223         {
2224                 char *l, libpath[PATH_MAX];
2225
2226                 if (strlen(cmd->arglist->vals[0]) >= PATH_MAX) {
2227                         ERROR("Libpath too long no buffer space");
2228                         rv = 1;
2229
2230                         goto finish;
2231                 }
2232
2233                 strcpy(libpath, cmd->arglist->vals[0]);
2234                 add_dotlibs(libpath);
2235                 l = strrchr(libpath, '/');
2236                 if (!l) l = strrchr(libpath, '\\');
2237                 if (l) {
2238                         *l = '\0';
2239                         l = libpath;
2240                 } else {
2241                         l = ".libs/";
2242                 }
2243
2244                 l = "./build/lib/.libs";
2245                 setenv(LD_LIBRARY_PATH_LOCAL, l, 1);
2246 #ifdef __APPLE__
2247                 setenv("DYLD_FALLBACK_LIBRARY_PATH", l, 1);
2248 #endif
2249                 setenv("FR_LIBRARY_PATH", "./build/lib/local/.libs", 1);
2250                 rv = run_command(cmd, cmd->arglist);
2251                 if (rv) goto finish;
2252         }
2253                 break;
2254
2255         default:
2256                 break;
2257         }
2258
2259         finish:
2260
2261         free(cctemp);
2262         return rv;
2263 }
2264
2265 static void cleanup_tmp_dir(char const *dirname)
2266 {
2267         DIR *dir;
2268         struct dirent *entry;
2269         char fullname[1024];
2270
2271         dir = opendir(dirname);
2272         if (!dir) {
2273                 return;
2274         }
2275
2276         if ((strlen(dirname) + 1 + sizeof(entry->d_name)) >= sizeof(fullname)) {
2277                 ERROR("Dirname too long, out of buffer space");
2278
2279                 (void) closedir(dir);
2280                 return;
2281         }
2282
2283         while ((entry = readdir(dir)) != NULL) {
2284                 if (entry->d_name[0] != '.') {
2285                         strcpy(fullname, dirname);
2286                         strcat(fullname, "/");
2287                         strcat(fullname, entry->d_name);
2288                         (void) remove(fullname);
2289                 }
2290         }
2291
2292         rmdir(dirname);
2293
2294         (void) closedir(dir);
2295 }
2296
2297 static void cleanup_tmp_dirs(command_t *cmd)
2298 {
2299         int d;
2300
2301         for (d = 0; d < cmd->tmp_dirs->num; d++) {
2302                 cleanup_tmp_dir(cmd->tmp_dirs->vals[d]);
2303         }
2304 }
2305
2306 static int ensure_fake_uptodate(command_t *cmd)
2307 {
2308         /* FIXME: could do the stat/touch here, but nah... */
2309         char const *touch_args[3];
2310
2311         if (cmd->mode == MODE_INSTALL) {
2312                 return 0;
2313         }
2314         if (!cmd->fake_output_name) {
2315                 return 0;
2316         }
2317
2318         touch_args[0] = "touch";
2319         touch_args[1] = cmd->fake_output_name;
2320         touch_args[2] = NULL;
2321         return external_spawn(cmd, "touch", touch_args);
2322 }
2323
2324 /* Store the install path in the *.la file */
2325 static int add_for_runtime(command_t *cmd)
2326 {
2327         if (cmd->mode == MODE_INSTALL) {
2328                 return 0;
2329         }
2330         if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
2331                 cmd->output == OUT_LIB) {
2332                 FILE *f=fopen(cmd->fake_output_name,"w");
2333                 if (f == NULL) {
2334                         return -1;
2335                 }
2336                 fprintf(f,"%s\n", cmd->install_path);
2337                 fclose(f);
2338                 return(0);
2339         } else {
2340                 return(ensure_fake_uptodate(cmd));
2341         }
2342 }
2343
2344 static void parse_args(int argc, char *argv[], command_t *cmd)
2345 {
2346         int a;
2347         char const *arg, *base;
2348         int arg_used;
2349
2350         /*
2351          *      We now take a major step past libtool.
2352          *
2353          *      IF there's no "--mode=...", AND we recognise
2354          *      the binary as a "special" name, THEN replace it
2355          *      with the correct one, and set the correct mode.
2356          *
2357          *      For example if were called 'CC' then we know we should
2358          *      probably be compiling stuff.
2359          */
2360         base = file_name(argv[0]);
2361         arg = automode(base, cmd);
2362         if (arg != base) {
2363                 push_count_chars(cmd->arglist, arg);
2364
2365                 assert(cmd->mode != MODE_UNKNOWN);
2366         }
2367
2368         /*
2369          *      We first pass over the command-line arguments looking for
2370          *      "--mode", etc.  If so, then use the libtool compatibility
2371          *      method for building the software.  Otherwise, auto-detect it
2372          *      via "-o" and the extensions.
2373          */
2374         base = NULL;
2375         if (cmd->mode == MODE_UNKNOWN) for (a = 1; a < argc; a++) {
2376                 arg = argv[a];
2377
2378                 if (strncmp(arg, "--mode=", 7) == 0) {
2379                         base = NULL;
2380                         break;
2381                 }
2382
2383                 /*
2384                  *      Stop if we get another magic method
2385                  */
2386                 if ((a == 1) &&
2387                     ((strncmp(arg, "LINK", 4) == 0) ||
2388                      (strcmp(arg, "CC") == 0) ||
2389                      (strcmp(arg, "CXX") == 0))) {
2390                         base = NULL;
2391                         break;
2392                 }
2393
2394                 if (strncmp(arg, "-o", 2) == 0) {
2395                         base = argv[++a];
2396                 }
2397         }
2398
2399         /*
2400          *      There were no magic args or an explicit --mode= but we did
2401          *      find an output file, so guess what mode were meant to be in
2402          *      from its extension.
2403          */
2404         if (base) {
2405                 arg = strrchr(base, '.');
2406                 if (!arg) {
2407                         cmd->mode = MODE_LINK;
2408                         push_count_chars(cmd->arglist, LINK_C);
2409                 }
2410 #ifdef EXE_EXT
2411                 else if (strcmp(arg, EXE_EXT) == 0) {
2412                         cmd->mode = MODE_LINK;
2413                         push_count_chars(cmd->arglist, LINK_C);
2414                 }
2415 #endif
2416                 else if (strcmp(arg + 1, DYNAMIC_LIB_EXT) == 0) {
2417                         cmd->mode = MODE_LINK;
2418                         push_count_chars(cmd->arglist, LINK_C);
2419                 }
2420                 else if (strcmp(arg + 1, STATIC_LIB_EXT) == 0) {
2421                         cmd->mode = MODE_LINK;
2422                         push_count_chars(cmd->arglist, LINK_C);
2423                 }
2424                 else if (strcmp(arg + 1, "la") == 0) {
2425                         cmd->mode = MODE_LINK;
2426                         push_count_chars(cmd->arglist, LINK_C);
2427                 }
2428                 else if ((strcmp(arg + 1, "lo") == 0) ||
2429                          (strcmp(arg + 1, "o") == 0)) {
2430                         cmd->mode = MODE_COMPILE;
2431                         push_count_chars(cmd->arglist, CC);
2432                 }
2433         }
2434
2435         for (a = 1; a < argc; a++) {
2436                 arg = argv[a];
2437                 arg_used = 1;
2438
2439                 if (cmd->mode == MODE_EXECUTE) {
2440                         push_count_chars(cmd->arglist, arg);
2441                         continue;
2442                 }
2443
2444                 if (arg[0] == '-') {
2445                         /*
2446                          *      Double dashed (long) single dash (short)
2447                          */
2448                         arg_used = (arg[1] == '-') ?
2449                                 parse_long_opt(arg + 2, cmd) :
2450                                 parse_short_opt(arg + 1, cmd);
2451
2452                         if (arg_used) continue;
2453
2454                         /*
2455                          *      Ignore all options after the '--execute'
2456                          */
2457                         if (cmd->mode == MODE_EXECUTE) continue;
2458
2459                         /*
2460                          *      We haven't done anything with it yet, but
2461                          *      there are still some arg/value pairs.
2462                          *
2463                          *      Try some of the more complicated short opts...
2464                          */
2465                         if (a + 1 < argc) {
2466                                 /*
2467                                  *      We found an output file!
2468                                  */
2469                                 if ((arg[1] == 'o') && (arg[2] == '\0')) {
2470                                         arg = argv[++a];
2471                                         arg_used = parse_output_file_name(arg,
2472                                                                           cmd);
2473                                 /*
2474                                  *      -MT literal dependency
2475                                  */
2476                                 } else if (!strcmp(arg + 1, "MT")) {
2477                                         DEBUG("Adding: %s\n", arg);
2478
2479                                         push_count_chars(cmd->arglist, arg);
2480                                         arg = argv[++a];
2481
2482                                         NOTICE(" %s\n", arg);
2483
2484                                         push_count_chars(cmd->arglist, arg);
2485                                         arg_used = 1;
2486                                 /*
2487                                  *      Runtime library search path
2488                                  */
2489                                 } else if (!strcmp(arg + 1, "rpath")) {
2490                                         /* Aha, we should try to link both! */
2491                                         cmd->install_path = argv[++a];
2492                                         arg_used = 1;
2493
2494                                 } else if (!strcmp(arg + 1, "release")) {
2495                                         /* Store for later deciphering */
2496                                         cmd->version_info = argv[++a];
2497                                         arg_used = 1;
2498
2499                                 } else if (!strcmp(arg + 1, "version-info")) {
2500                                         /* Store for later deciphering */
2501                                         cmd->version_info = argv[++a];
2502                                         arg_used = 1;
2503
2504                                 } else if (!strcmp(arg + 1,
2505                                                    "export-symbols-regex")) {
2506                                         /* Skip the argument. */
2507                                         ++a;
2508                                         arg_used = 1;
2509
2510                                 } else if (!strcmp(arg + 1, "undefined")) {
2511                                         cmd->undefined_flag = argv[++a];
2512                                         arg_used = 1;
2513                                 /*
2514                                  *      Add dir to runtime library search path.
2515                                  */
2516                                 } else if ((arg[1] == 'R') && !arg[2]) {
2517
2518                                         add_runtime_dir_lib(argv[++a], cmd);
2519                                         arg_used = 1;
2520                                 }
2521                         }
2522                 /*
2523                  *      Ok.. the argument doesn't begin with a dash
2524                  *      maybe it's an input file.
2525                  *
2526                  *      Check its extension to see if it's a known input
2527                  *      file and verify it exists.
2528                  */
2529                 } else {
2530                         arg_used = parse_input_file_name(arg, cmd);
2531                 }
2532
2533                 /*
2534                  *      If we still don't have a run mode, look for a magic
2535                  *      program name CC, LINK, or whatever.  Then replace that
2536                  *      with the name of the real program we want to run.
2537                  */
2538                 if (!arg_used) {
2539                         if ((cmd->arglist->num == 0) &&
2540                                 (cmd->mode == MODE_UNKNOWN)) {
2541                                 arg = automode(arg, cmd);
2542                         }
2543
2544                         DEBUG("Adding: %s\n", arg);
2545
2546                         push_count_chars(cmd->arglist, arg);
2547                 }
2548         }
2549
2550 }
2551
2552 int main(int argc, char *argv[])
2553 {
2554         int rc;
2555         command_t cmd;
2556
2557         memset(&cmd, 0, sizeof(cmd));
2558
2559         cmd.options.pic_mode = PIC_UNKNOWN;
2560         cmd.mode = MODE_UNKNOWN;
2561         cmd.output = OUT_GENERAL;
2562
2563         /*
2564          *      Initialise the various argument lists
2565          */
2566         cmd.program_opts                = alloc_countchars();
2567         cmd.arglist                     = alloc_countchars();
2568         cmd.tmp_dirs                    = alloc_countchars();
2569         cmd.obj_files                   = alloc_countchars();
2570         cmd.dep_rpaths                  = alloc_countchars();
2571         cmd.rpaths                      = alloc_countchars();
2572         cmd.static_opts.normal          = alloc_countchars();
2573         cmd.shared_opts.normal          = alloc_countchars();
2574         cmd.shared_opts.dependencies    = alloc_countchars();
2575
2576         /*
2577          *      Fill up the various argument lists
2578          */
2579         parse_args(argc, argv, &cmd);
2580         post_parse_fixup(&cmd);
2581
2582         /*
2583          *      We couldn't figure out which mode to operate in
2584          */
2585         if (cmd.mode == MODE_UNKNOWN) {
2586                 usage(1);
2587         }
2588
2589         rc = run_mode(&cmd);
2590         if (!rc) {
2591                 add_for_runtime(&cmd);
2592         }
2593
2594         cleanup_tmp_dirs(&cmd);
2595
2596         return rc;
2597 }