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