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