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