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