forked from Mirrors/freeswitch
0488a5109a
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3733 d0543943-73ff-0310-b7d9-9358b9ac24b2
1858 lines
47 KiB
C
1858 lines
47 KiB
C
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
|
|
#ifdef __EMX__
|
|
# define SHELL_CMD "sh"
|
|
# define GEN_EXPORTS "emxexp"
|
|
# define DEF2IMPLIB_CMD "emximp"
|
|
# define SHARE_SW "-Zdll -Zmtd"
|
|
# define USE_OMF 1
|
|
# define TRUNCATE_DLL_NAME
|
|
# define DYNAMIC_LIB_EXT "dll"
|
|
# define EXE_EXT ".exe"
|
|
|
|
# if USE_OMF
|
|
/* OMF is the native format under OS/2 */
|
|
# define STATIC_LIB_EXT "lib"
|
|
# define OBJECT_EXT "obj"
|
|
# define LIBRARIAN "emxomfar"
|
|
# define LIBRARIAN_OPTS "cr"
|
|
# else
|
|
/* but the alternative, a.out, can fork() which is sometimes necessary */
|
|
# define STATIC_LIB_EXT "a"
|
|
# define OBJECT_EXT "o"
|
|
# define LIBRARIAN "ar"
|
|
# define LIBRARIAN_OPTS "cr"
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(__APPLE__)
|
|
# define SHELL_CMD "/bin/sh"
|
|
# define DYNAMIC_LIB_EXT "dylib"
|
|
# define MODULE_LIB_EXT "so"
|
|
# define STATIC_LIB_EXT "a"
|
|
# define OBJECT_EXT "o"
|
|
# define LIBRARIAN "ar"
|
|
# define LIBRARIAN_OPTS "cr"
|
|
/* man libtool(1) documents ranlib option of -c. */
|
|
# define RANLIB "ranlib"
|
|
# define PIC_FLAG "-fPIC -fno-common"
|
|
# define SHARED_OPTS "-dynamiclib"
|
|
# define MODULE_OPTS "-bundle"
|
|
# define DYNAMIC_LINK_OPTS "-flat_namespace -undefined suppress"
|
|
# define dynamic_link_version_func darwin_dynamic_link_function
|
|
# define DYNAMIC_INSTALL_NAME "-install_name"
|
|
# define DYNAMIC_LINK_NO_INSTALL "-dylib_file"
|
|
# define HAS_REALPATH
|
|
/*-install_name /Users/jerenk/apache-2.0-cvs/lib/libapr.0.dylib -compatibility_version 1 -current_version 1.0 */
|
|
# define LD_LIBRARY_PATH "DYLD_LIBRARY_PATH"
|
|
#endif
|
|
|
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
|
# define SHELL_CMD "/bin/sh"
|
|
# define DYNAMIC_LIB_EXT "so"
|
|
# define MODULE_LIB_EXT "so"
|
|
# define STATIC_LIB_EXT "a"
|
|
# define OBJECT_EXT "o"
|
|
# define LIBRARIAN "ar"
|
|
# define LIBRARIAN_OPTS "cr"
|
|
# define RANLIB "ranlib"
|
|
# define PIC_FLAG "-fPIC"
|
|
# define RPATH "-rpath"
|
|
# define SHARED_OPTS "-shared"
|
|
# define MODULE_OPTS "-shared"
|
|
# define DYNAMIC_LINK_OPTS "-export-dynamic"
|
|
# define LINKER_FLAG_PREFIX "-Wl,"
|
|
# define ADD_MINUS_L
|
|
# define LD_RUN_PATH "LD_RUN_PATH"
|
|
# define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
|
|
#endif
|
|
|
|
#if defined(sun)
|
|
# define SHELL_CMD "/bin/sh"
|
|
# define DYNAMIC_LIB_EXT "so"
|
|
# define MODULE_LIB_EXT "so"
|
|
# define STATIC_LIB_EXT "a"
|
|
# define OBJECT_EXT "o"
|
|
# define LIBRARIAN "ar"
|
|
# define LIBRARIAN_OPTS "cr"
|
|
# define RANLIB "ranlib"
|
|
# define PIC_FLAG "-KPIC"
|
|
# define RPATH "-R"
|
|
# define SHARED_OPTS "-G"
|
|
# define MODULE_OPTS "-G"
|
|
# define DYNAMIC_LINK_OPTS ""
|
|
# define LINKER_FLAG_NO_EQUALS
|
|
# define ADD_MINUS_L
|
|
# define HAS_REALPATH
|
|
# define LD_RUN_PATH "LD_RUN_PATH"
|
|
# define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
|
|
#endif
|
|
|
|
#if defined(_OSD_POSIX)
|
|
# define SHELL_CMD "/usr/bin/sh"
|
|
# define DYNAMIC_LIB_EXT "so"
|
|
# define MODULE_LIB_EXT "so"
|
|
# define STATIC_LIB_EXT "a"
|
|
# define OBJECT_EXT "o"
|
|
# define LIBRARIAN "ar"
|
|
# define LIBRARIAN_OPTS "cr"
|
|
# define SHARED_OPTS "-G"
|
|
# define MODULE_OPTS "-G"
|
|
# define LINKER_FLAG_PREFIX "-Wl,"
|
|
# define NEED_SNPRINTF
|
|
#endif
|
|
|
|
#if defined(sinix) && defined(mips) && defined(__SNI_TARG_UNIX)
|
|
# define SHELL_CMD "/usr/bin/sh"
|
|
# define DYNAMIC_LIB_EXT "so"
|
|
# define MODULE_LIB_EXT "so"
|
|
# define STATIC_LIB_EXT "a"
|
|
# define OBJECT_EXT "o"
|
|
# define LIBRARIAN "ar"
|
|
# define LIBRARIAN_OPTS "cr"
|
|
# define RPATH "-Brpath"
|
|
# define SHARED_OPTS "-G"
|
|
# define MODULE_OPTS "-G"
|
|
# define DYNAMIC_LINK_OPTS "-Wl,-Blargedynsym"
|
|
# define LINKER_FLAG_PREFIX "-Wl,"
|
|
# define NEED_SNPRINTF
|
|
# define LD_RUN_PATH "LD_RUN_PATH"
|
|
# define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
|
|
#endif
|
|
|
|
#ifndef SHELL_CMD
|
|
#error Unsupported platform: Please add defines for SHELL_CMD etc. for your platform.
|
|
#endif
|
|
|
|
#ifdef NEED_SNPRINTF
|
|
#include <stdarg.h>
|
|
#endif
|
|
|
|
#ifdef __EMX__
|
|
#include <process.h>
|
|
#endif
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 1024
|
|
#endif
|
|
|
|
|
|
/* We want to say we are libtool 1.4 for shlibtool compatibility. */
|
|
#define VERSION "1.4"
|
|
|
|
enum tool_mode_t {
|
|
mUnknown,
|
|
mCompile,
|
|
mLink,
|
|
mInstall,
|
|
};
|
|
|
|
enum output_t {
|
|
otGeneral,
|
|
otObject,
|
|
otProgram,
|
|
otLibrary,
|
|
otStaticLibraryOnly,
|
|
otDynamicLibraryOnly,
|
|
otModule,
|
|
};
|
|
|
|
enum pic_mode_e {
|
|
pic_UNKNOWN,
|
|
pic_PREFER,
|
|
pic_AVOID,
|
|
};
|
|
|
|
enum lib_type {
|
|
type_UNKNOWN,
|
|
type_DYNAMIC_LIB,
|
|
type_STATIC_LIB,
|
|
type_MODULE_LIB,
|
|
type_OBJECT,
|
|
};
|
|
|
|
typedef struct {
|
|
const char **vals;
|
|
int num;
|
|
} count_chars;
|
|
|
|
typedef struct {
|
|
const char *normal;
|
|
const char *install;
|
|
} library_name;
|
|
|
|
typedef struct {
|
|
count_chars *normal;
|
|
count_chars *install;
|
|
count_chars *dependencies;
|
|
} library_opts;
|
|
|
|
typedef struct {
|
|
int silent;
|
|
int shared;
|
|
int export_all;
|
|
int dry_run;
|
|
enum pic_mode_e pic_mode;
|
|
int export_dynamic;
|
|
int no_install;
|
|
} options_t;
|
|
|
|
typedef struct {
|
|
enum tool_mode_t mode;
|
|
enum output_t output;
|
|
options_t options;
|
|
|
|
char *output_name;
|
|
char *fake_output_name;
|
|
char *basename;
|
|
|
|
const char *install_path;
|
|
const char *compiler;
|
|
const char *program;
|
|
count_chars *program_opts;
|
|
|
|
count_chars *arglist;
|
|
count_chars *tmp_dirs;
|
|
count_chars *obj_files;
|
|
count_chars *dep_rpaths;
|
|
count_chars *rpaths;
|
|
|
|
library_name static_name;
|
|
library_name shared_name;
|
|
library_name module_name;
|
|
|
|
library_opts static_opts;
|
|
library_opts shared_opts;
|
|
|
|
const char *version_info;
|
|
} command_t;
|
|
|
|
#ifdef RPATH
|
|
void add_rpath(count_chars *cc, const char *path);
|
|
#endif
|
|
|
|
#if defined(NEED_SNPRINTF)
|
|
/* Write at most n characters to the buffer in str, return the
|
|
* number of chars written or -1 if the buffer would have been
|
|
* overflowed.
|
|
*
|
|
* This is portable to any POSIX-compliant system has /dev/null
|
|
*/
|
|
static FILE *f=NULL;
|
|
static int vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
|
|
{
|
|
int res;
|
|
|
|
if (f == NULL)
|
|
f = fopen("/dev/null","w");
|
|
if (f == NULL)
|
|
return -1;
|
|
|
|
setvbuf( f, str, _IOFBF, n );
|
|
|
|
res = vfprintf( f, fmt, ap );
|
|
|
|
if ( res > 0 && res < n ) {
|
|
res = vsprintf( str, fmt, ap );
|
|
}
|
|
return res;
|
|
}
|
|
static int snprintf( char *str, size_t n, const char *fmt, ... )
|
|
{
|
|
va_list ap;
|
|
int res;
|
|
|
|
va_start( ap, fmt );
|
|
res = vsnprintf( str, n, fmt, ap );
|
|
va_end( ap );
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
void init_count_chars(count_chars *cc)
|
|
{
|
|
cc->vals = (const char**)malloc(PATH_MAX);
|
|
cc->num = 0;
|
|
}
|
|
|
|
void clear_count_chars(count_chars *cc)
|
|
{
|
|
int i;
|
|
for (i = 0; i < cc->num; i++) {
|
|
cc->vals[i] = 0;
|
|
}
|
|
|
|
cc->num = 0;
|
|
}
|
|
|
|
void push_count_chars(count_chars *cc, const char *newval)
|
|
{
|
|
cc->vals[cc->num++] = newval;
|
|
}
|
|
|
|
void insert_count_chars(count_chars *cc, const char *newval, int position)
|
|
{
|
|
int i;
|
|
|
|
for (i = cc->num; i > position; i--) {
|
|
cc->vals[i] = cc->vals[i-1];
|
|
}
|
|
|
|
cc->vals[position] = newval;
|
|
cc->num++;
|
|
}
|
|
|
|
void append_count_chars(count_chars *cc, count_chars *cctoadd)
|
|
{
|
|
int i;
|
|
for (i = 0; i < cctoadd->num; i++) {
|
|
if (cctoadd->vals[i]) {
|
|
push_count_chars(cc, cctoadd->vals[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *flatten_count_chars(count_chars *cc)
|
|
{
|
|
int i, size;
|
|
char *newval;
|
|
|
|
size = 0;
|
|
for (i = 0; i < cc->num; i++) {
|
|
if (cc->vals[i]) {
|
|
size += strlen(cc->vals[i]) + 1;
|
|
}
|
|
}
|
|
|
|
newval = (char*)malloc(size + 1);
|
|
newval[0] = 0;
|
|
|
|
for (i = 0; i < cc->num; i++) {
|
|
if (cc->vals[i]) {
|
|
strcat(newval, cc->vals[i]);
|
|
strcat(newval, " ");
|
|
}
|
|
}
|
|
|
|
return newval;
|
|
}
|
|
|
|
char *shell_esc(const char *str)
|
|
{
|
|
int in_quote = 0;
|
|
char *cmd;
|
|
unsigned char *d;
|
|
const unsigned char *s;
|
|
|
|
cmd = (char *)malloc(2 * strlen(str) + 1);
|
|
d = (unsigned char *)cmd;
|
|
s = (const unsigned char *)str;
|
|
|
|
for (; *s; ++s) {
|
|
if (*s == '"') {
|
|
*d++ = '\\';
|
|
in_quote++;
|
|
}
|
|
else if (*s == '\\' || (*s == ' ' && (in_quote % 2))) {
|
|
*d++ = '\\';
|
|
}
|
|
*d++ = *s;
|
|
}
|
|
|
|
*d = '\0';
|
|
return cmd;
|
|
}
|
|
|
|
int external_spawn(command_t *cmd, const char *file, const char **argv)
|
|
{
|
|
if (!cmd->options.silent) {
|
|
const char **argument = argv;
|
|
printf("Executing: ");
|
|
while (*argument) {
|
|
printf("%s ", *argument);
|
|
argument++;
|
|
}
|
|
puts("");
|
|
}
|
|
|
|
if (cmd->options.dry_run) {
|
|
return 0;
|
|
}
|
|
#ifdef __EMX__
|
|
return spawnvp(P_WAIT, file, argv);
|
|
#else
|
|
{
|
|
pid_t pid;
|
|
pid = fork();
|
|
if (pid == 0) {
|
|
return execvp(argv[0], (char**)argv);
|
|
}
|
|
else {
|
|
int statuscode;
|
|
waitpid(pid, &statuscode, 0);
|
|
if (WIFEXITED(statuscode)) {
|
|
return WEXITSTATUS(statuscode);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int run_command(command_t *cmd_data, count_chars *cc)
|
|
{
|
|
char *command;
|
|
const char *spawn_args[4];
|
|
count_chars tmpcc;
|
|
|
|
init_count_chars(&tmpcc);
|
|
|
|
if (cmd_data->program) {
|
|
push_count_chars(&tmpcc, cmd_data->program);
|
|
}
|
|
|
|
append_count_chars(&tmpcc, cmd_data->program_opts);
|
|
|
|
append_count_chars(&tmpcc, cc);
|
|
|
|
command = shell_esc(flatten_count_chars(&tmpcc));
|
|
|
|
spawn_args[0] = SHELL_CMD;
|
|
spawn_args[1] = "-c";
|
|
spawn_args[2] = command;
|
|
spawn_args[3] = NULL;
|
|
return external_spawn(cmd_data, spawn_args[0], (const char**)spawn_args);
|
|
}
|
|
|
|
/*
|
|
* print configuration
|
|
* shlibpath_var is used in configure.
|
|
*/
|
|
void print_config()
|
|
{
|
|
#ifdef LD_RUN_PATH
|
|
printf("runpath_var=%s\n", LD_RUN_PATH);
|
|
#endif
|
|
#ifdef LD_LIBRARY_PATH
|
|
printf("shlibpath_var=%s\n", LD_LIBRARY_PATH);
|
|
#endif
|
|
#ifdef SHELL_CMD
|
|
printf("SHELL=\"%s\"\n", SHELL_CMD);
|
|
#endif
|
|
}
|
|
/*
|
|
* Add a directory to the runtime library search path.
|
|
*/
|
|
void add_runtimedirlib(char *arg, command_t *cmd_data)
|
|
{
|
|
#ifdef RPATH
|
|
add_rpath(cmd_data->shared_opts.dependencies, arg);
|
|
#else
|
|
#endif
|
|
}
|
|
|
|
int parse_long_opt(char *arg, command_t *cmd_data)
|
|
{
|
|
char *equal_pos = strchr(arg, '=');
|
|
char var[50];
|
|
char value[500];
|
|
|
|
if (equal_pos) {
|
|
strncpy(var, arg, equal_pos - arg);
|
|
var[equal_pos - arg] = 0;
|
|
strcpy(value, equal_pos + 1);
|
|
} else {
|
|
strcpy(var, arg);
|
|
}
|
|
|
|
if (strcmp(var, "silent") == 0) {
|
|
cmd_data->options.silent = 1;
|
|
} else if (strcmp(var, "mode") == 0) {
|
|
if (strcmp(value, "compile") == 0) {
|
|
cmd_data->mode = mCompile;
|
|
cmd_data->output = otObject;
|
|
}
|
|
|
|
if (strcmp(value, "link") == 0) {
|
|
cmd_data->mode = mLink;
|
|
cmd_data->output = otLibrary;
|
|
}
|
|
|
|
if (strcmp(value, "install") == 0) {
|
|
cmd_data->mode = mInstall;
|
|
}
|
|
} else if (strcmp(var, "shared") == 0) {
|
|
if (cmd_data->mode == mLink) {
|
|
cmd_data->output = otDynamicLibraryOnly;
|
|
}
|
|
cmd_data->options.shared = 1;
|
|
} else if (strcmp(var, "export-all") == 0) {
|
|
cmd_data->options.export_all = 1;
|
|
} else if (strcmp(var, "dry-run") == 0) {
|
|
printf("Dry-run mode on!\n");
|
|
cmd_data->options.dry_run = 1;
|
|
} else if (strcmp(var, "version") == 0) {
|
|
printf("Version " VERSION "\n");
|
|
} else if (strcmp(var, "help") == 0) {
|
|
printf("Sorry. No help available.\n");
|
|
} else if (strcmp(var, "config") == 0) {
|
|
print_config();
|
|
} else if (strcmp(var, "tag") == 0) {
|
|
if (strcmp(value, "CC") == 0) {
|
|
/* Do nothing. */
|
|
}
|
|
if (strcmp(value, "CXX") == 0) {
|
|
/* Do nothing. */
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Return 1 if we eat it. */
|
|
int parse_short_opt(char *arg, command_t *cmd_data)
|
|
{
|
|
if (strcmp(arg, "export-dynamic") == 0) {
|
|
cmd_data->options.export_dynamic = 1;
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(arg, "module") == 0) {
|
|
cmd_data->output = otModule;
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(arg, "Zexe") == 0) {
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(arg, "avoid-version") == 0) {
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(arg, "prefer-pic") == 0) {
|
|
cmd_data->options.pic_mode = pic_PREFER;
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(arg, "prefer-non-pic") == 0) {
|
|
cmd_data->options.pic_mode = pic_AVOID;
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(arg, "static") == 0) {
|
|
/* Don't respect it for now. */
|
|
return 1;
|
|
}
|
|
|
|
if (cmd_data->mode == mLink) {
|
|
if (strcmp(arg, "no-install") == 0) {
|
|
cmd_data->options.no_install = 1;
|
|
return 1;
|
|
}
|
|
if (arg[0] == 'L' || arg[0] == 'l') {
|
|
/* Hack... */
|
|
arg--;
|
|
push_count_chars(cmd_data->shared_opts.dependencies, arg);
|
|
return 1;
|
|
} else if (arg[0] == 'R' && arg[1]) {
|
|
/* -Rdir Add dir to runtime library search path. */
|
|
add_runtimedirlib(&arg[1], cmd_data);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *truncate_dll_name(char *path)
|
|
{
|
|
/* Cut DLL name down to 8 characters after removing any mod_ prefix */
|
|
char *tmppath = strdup(path);
|
|
char *newname = strrchr(tmppath, '/') + 1;
|
|
char *ext = strrchr(tmppath, '.');
|
|
int len;
|
|
|
|
if (ext == NULL)
|
|
return tmppath;
|
|
|
|
len = ext - newname;
|
|
|
|
if (strncmp(newname, "mod_", 4) == 0) {
|
|
strcpy(newname, newname + 4);
|
|
len -= 4;
|
|
}
|
|
|
|
if (len > 8) {
|
|
strcpy(newname + 8, strchr(newname, '.'));
|
|
}
|
|
|
|
return tmppath;
|
|
}
|
|
|
|
long safe_strtol(const char *nptr, const char **endptr, int base)
|
|
{
|
|
long rv;
|
|
|
|
errno = 0;
|
|
|
|
rv = strtol(nptr, (char**)endptr, 10);
|
|
|
|
if (errno == ERANGE) {
|
|
return 0;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* version_info is in the form of MAJOR:MINOR:PATCH */
|
|
const char *darwin_dynamic_link_function(const char *version_info)
|
|
{
|
|
char *newarg;
|
|
long major, minor, patch;
|
|
|
|
major = 0;
|
|
minor = 0;
|
|
patch = 0;
|
|
|
|
if (version_info) {
|
|
major = safe_strtol(version_info, &version_info, 10);
|
|
|
|
if (version_info) {
|
|
if (version_info[0] == ':') {
|
|
version_info++;
|
|
}
|
|
|
|
minor = safe_strtol(version_info, &version_info, 10);
|
|
|
|
if (version_info) {
|
|
if (version_info[0] == ':') {
|
|
version_info++;
|
|
}
|
|
|
|
patch = safe_strtol(version_info, &version_info, 10);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Avoid -dylib_compatibility_version must be greater than zero errors. */
|
|
if (major == 0) {
|
|
major = 1;
|
|
}
|
|
newarg = (char*)malloc(100);
|
|
snprintf(newarg, 99,
|
|
"-compatibility_version %ld -current_version %ld.%ld",
|
|
major, major, minor);
|
|
|
|
return newarg;
|
|
}
|
|
|
|
/* genlib values
|
|
* 0 - static
|
|
* 1 - dynamic
|
|
* 2 - module
|
|
*/
|
|
char *gen_library_name(const char *name, int genlib)
|
|
{
|
|
char *newarg, *newext;
|
|
|
|
newarg = (char *)malloc(strlen(name) + 10);
|
|
strcpy(newarg, ".libs/");
|
|
|
|
if (genlib == 2 && strncmp(name, "lib", 3) == 0) {
|
|
name += 3;
|
|
}
|
|
|
|
strcat(newarg, name);
|
|
|
|
newext = strrchr(newarg, '.') + 1;
|
|
|
|
switch (genlib) {
|
|
case 0:
|
|
strcpy(newext, STATIC_LIB_EXT);
|
|
break;
|
|
case 1:
|
|
strcpy(newext, DYNAMIC_LIB_EXT);
|
|
break;
|
|
case 2:
|
|
strcpy(newext, MODULE_LIB_EXT);
|
|
break;
|
|
}
|
|
|
|
return newarg;
|
|
}
|
|
|
|
/* genlib values
|
|
* 0 - static
|
|
* 1 - dynamic
|
|
* 2 - module
|
|
*/
|
|
char *gen_install_name(const char *name, int genlib)
|
|
{
|
|
struct stat sb;
|
|
char *newname;
|
|
int rv;
|
|
|
|
newname = gen_library_name(name, genlib);
|
|
|
|
/* Check if it exists. If not, return NULL. */
|
|
rv = stat(newname, &sb);
|
|
|
|
if (rv) {
|
|
return NULL;
|
|
}
|
|
|
|
return newname;
|
|
}
|
|
|
|
char *check_object_exists(command_t *cmd, const char *arg, int arglen)
|
|
{
|
|
char *newarg, *ext;
|
|
int pass, rv;
|
|
|
|
newarg = (char *)malloc(arglen + 10);
|
|
memcpy(newarg, arg, arglen);
|
|
newarg[arglen] = 0;
|
|
ext = newarg + arglen;
|
|
|
|
pass = 0;
|
|
|
|
do {
|
|
struct stat sb;
|
|
|
|
switch (pass) {
|
|
case 0:
|
|
strcpy(ext, OBJECT_EXT);
|
|
break;
|
|
/*
|
|
case 1:
|
|
strcpy(ext, NO_PIC_EXT);
|
|
break;
|
|
*/
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!cmd->options.silent) {
|
|
printf("Checking (obj): %s\n", newarg);
|
|
}
|
|
rv = stat(newarg, &sb);
|
|
}
|
|
while (rv != 0 && ++pass < 1);
|
|
|
|
if (rv == 0) {
|
|
if (pass == 1) {
|
|
cmd->options.pic_mode = pic_AVOID;
|
|
}
|
|
return newarg;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* libdircheck values:
|
|
* 0 - no .libs suffix
|
|
* 1 - .libs suffix
|
|
*/
|
|
char *check_library_exists(command_t *cmd, const char *arg, int pathlen,
|
|
int libdircheck, enum lib_type *libtype)
|
|
{
|
|
char *newarg, *ext;
|
|
int pass, rv, newpathlen;
|
|
|
|
newarg = (char *)malloc(strlen(arg) + 10);
|
|
strcpy(newarg, arg);
|
|
newarg[pathlen] = 0;
|
|
|
|
newpathlen = pathlen;
|
|
if (libdircheck) {
|
|
strcat(newarg, ".libs/");
|
|
newpathlen += sizeof(".libs/") - 1;
|
|
}
|
|
|
|
strcpy(newarg+newpathlen, arg+pathlen);
|
|
ext = strrchr(newarg, '.') + 1;
|
|
|
|
pass = 0;
|
|
|
|
do {
|
|
struct stat sb;
|
|
|
|
switch (pass) {
|
|
case 0:
|
|
if (cmd->options.pic_mode != pic_AVOID || cmd->options.shared) {
|
|
strcpy(ext, DYNAMIC_LIB_EXT);
|
|
*libtype = type_DYNAMIC_LIB;
|
|
break;
|
|
}
|
|
pass = 1;
|
|
case 1:
|
|
strcpy(ext, STATIC_LIB_EXT);
|
|
*libtype = type_STATIC_LIB;
|
|
break;
|
|
case 2:
|
|
strcpy(ext, MODULE_LIB_EXT);
|
|
*libtype = type_MODULE_LIB;
|
|
break;
|
|
case 3:
|
|
strcpy(ext, OBJECT_EXT);
|
|
*libtype = type_OBJECT;
|
|
break;
|
|
default:
|
|
*libtype = type_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
if (!cmd->options.silent) {
|
|
printf("Checking (lib): %s\n", newarg);
|
|
}
|
|
rv = stat(newarg, &sb);
|
|
}
|
|
while (rv != 0 && ++pass < 4);
|
|
|
|
if (rv == 0) {
|
|
return newarg;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char * load_install_path(const char *arg)
|
|
{
|
|
FILE *f;
|
|
char *path;
|
|
|
|
path = malloc(PATH_MAX);
|
|
|
|
f = fopen(arg,"r");
|
|
if (f == NULL) {
|
|
return NULL;
|
|
}
|
|
fgets(path, PATH_MAX, f);
|
|
fclose(f);
|
|
if (path[strlen(path)-1] == '\n') {
|
|
path[strlen(path)-1] = '\0';
|
|
}
|
|
/* Check that we have an absolute path.
|
|
* Otherwise the file could be a GNU libtool file.
|
|
*/
|
|
if (path[0] != '/') {
|
|
return NULL;
|
|
}
|
|
return path;
|
|
}
|
|
|
|
char * load_noinstall_path(const char *arg, int pathlen)
|
|
{
|
|
char *newarg, *expanded_path;
|
|
int newpathlen;
|
|
|
|
newarg = (char *)malloc(strlen(arg) + 10);
|
|
strcpy(newarg, arg);
|
|
newarg[pathlen] = 0;
|
|
|
|
newpathlen = pathlen;
|
|
strcat(newarg, ".libs");
|
|
newpathlen += sizeof(".libs") - 1;
|
|
newarg[newpathlen] = 0;
|
|
|
|
#ifdef HAS_REALPATH
|
|
expanded_path = malloc(PATH_MAX);
|
|
expanded_path = realpath(newarg, expanded_path);
|
|
/* Uh, oh. There was an error. Fall back on our first guess. */
|
|
if (!expanded_path) {
|
|
expanded_path = newarg;
|
|
}
|
|
#else
|
|
/* We might get ../ or something goofy. Oh, well. */
|
|
expanded_path = newarg;
|
|
#endif
|
|
|
|
return expanded_path;
|
|
}
|
|
|
|
/* Read the final install location and add it to runtime library search path. */
|
|
#ifdef RPATH
|
|
void add_rpath(count_chars *cc, const char *path)
|
|
{
|
|
int size = 0;
|
|
char *tmp;
|
|
|
|
#ifdef LINKER_FLAG_PREFIX
|
|
size = strlen(LINKER_FLAG_PREFIX);
|
|
#endif
|
|
size = size + strlen(path) + strlen(RPATH) + 2;
|
|
tmp = malloc(size);
|
|
if (tmp == NULL) {
|
|
return;
|
|
}
|
|
#ifdef LINKER_FLAG_PREFIX
|
|
strcpy(tmp, LINKER_FLAG_PREFIX);
|
|
strcat(tmp, RPATH);
|
|
#else
|
|
strcpy(tmp, RPATH);
|
|
#endif
|
|
#ifndef LINKER_FLAG_NO_EQUALS
|
|
strcat(tmp, "=");
|
|
#endif
|
|
strcat(tmp, path);
|
|
|
|
push_count_chars(cc, tmp);
|
|
}
|
|
|
|
void add_rpath_file(count_chars *cc, const char *arg)
|
|
{
|
|
const char *path;
|
|
|
|
path = load_install_path(arg);
|
|
if (path) {
|
|
add_rpath(cc, path);
|
|
}
|
|
}
|
|
|
|
void add_rpath_noinstall(count_chars *cc, const char *arg, int pathlen)
|
|
{
|
|
const char *path;
|
|
|
|
path = load_noinstall_path(arg, pathlen);
|
|
if (path) {
|
|
add_rpath(cc, path);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef DYNAMIC_LINK_NO_INSTALL
|
|
void add_dylink_noinstall(count_chars *cc, const char *arg, int pathlen,
|
|
int extlen)
|
|
{
|
|
const char *install_path, *current_path, *name;
|
|
char *exp_argument;
|
|
int i_p_len, c_p_len, name_len, dyext_len, cur_len;
|
|
|
|
install_path = load_install_path(arg);
|
|
current_path = load_noinstall_path(arg, pathlen);
|
|
|
|
if (!install_path || !current_path) {
|
|
return;
|
|
}
|
|
|
|
push_count_chars(cc, DYNAMIC_LINK_NO_INSTALL);
|
|
|
|
i_p_len = strlen(install_path);
|
|
c_p_len = strlen(current_path);
|
|
|
|
name = arg+pathlen;
|
|
name_len = extlen-pathlen;
|
|
dyext_len = sizeof(DYNAMIC_LIB_EXT) - 1;
|
|
|
|
/* No, we need to replace the extension. */
|
|
exp_argument = (char *)malloc(i_p_len + c_p_len + (name_len*2) +
|
|
(dyext_len*2) + 2);
|
|
|
|
cur_len = 0;
|
|
strcpy(exp_argument, install_path);
|
|
cur_len += i_p_len;
|
|
exp_argument[cur_len++] = '/';
|
|
strncpy(exp_argument+cur_len, name, extlen-pathlen);
|
|
cur_len += name_len;
|
|
strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
|
|
cur_len += dyext_len;
|
|
exp_argument[cur_len++] = ':';
|
|
strcpy(exp_argument+cur_len, current_path);
|
|
cur_len += c_p_len;
|
|
exp_argument[cur_len++] = '/';
|
|
strncpy(exp_argument+cur_len, name, extlen-pathlen);
|
|
cur_len += name_len;
|
|
strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
|
|
cur_len += dyext_len;
|
|
|
|
push_count_chars(cc, exp_argument);
|
|
}
|
|
#endif
|
|
|
|
/* use -L -llibname to allow to use installed libraries */
|
|
void add_minus_l(count_chars *cc, const char *arg)
|
|
{
|
|
char *newarg;
|
|
char *name = strrchr(arg, '/');
|
|
char *file = strrchr(arg, '.');
|
|
char *lib = strstr(name, "lib");
|
|
|
|
if (name !=NULL && file != NULL && lib == name+1) {
|
|
*name = '\0';
|
|
*file = '\0';
|
|
file = name;
|
|
file = file+4;
|
|
push_count_chars(cc, "-L");
|
|
push_count_chars(cc, arg);
|
|
/* we need one argument like -lapr-1 */
|
|
newarg = malloc(strlen(file) + 3);
|
|
strcpy(newarg, "-l");
|
|
strcat(newarg, file);
|
|
push_count_chars(cc, newarg);
|
|
} else {
|
|
push_count_chars(cc, arg);
|
|
}
|
|
}
|
|
|
|
void add_linker_flag_prefix(count_chars *cc, const char *arg)
|
|
{
|
|
#ifndef LINKER_FLAG_PREFIX
|
|
push_count_chars(cc, arg);
|
|
#else
|
|
char *newarg;
|
|
newarg = (char*)malloc(strlen(arg) + sizeof(LINKER_FLAG_PREFIX) + 1);
|
|
strcpy(newarg, LINKER_FLAG_PREFIX);
|
|
strcat(newarg, arg);
|
|
push_count_chars(cc, newarg);
|
|
#endif
|
|
}
|
|
|
|
int parse_input_file_name(char *arg, command_t *cmd_data)
|
|
{
|
|
char *ext = strrchr(arg, '.');
|
|
char *name = strrchr(arg, '/');
|
|
int pathlen;
|
|
enum lib_type libtype;
|
|
char *newarg;
|
|
|
|
if (!ext) {
|
|
return 0;
|
|
}
|
|
|
|
ext++;
|
|
|
|
if (name == NULL) {
|
|
name = strrchr(arg, '\\');
|
|
|
|
if (name == NULL) {
|
|
name = arg;
|
|
} else {
|
|
name++;
|
|
}
|
|
} else {
|
|
name++;
|
|
}
|
|
|
|
pathlen = name - arg;
|
|
|
|
if (strcmp(ext, "lo") == 0) {
|
|
newarg = check_object_exists(cmd_data, arg, ext - arg);
|
|
if (!newarg) {
|
|
printf("Can not find suitable object file for %s\n", arg);
|
|
exit(1);
|
|
}
|
|
if (cmd_data->mode != mLink) {
|
|
push_count_chars(cmd_data->arglist, newarg);
|
|
}
|
|
else {
|
|
push_count_chars(cmd_data->obj_files, newarg);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(ext, "la") == 0) {
|
|
switch (cmd_data->mode) {
|
|
case mLink:
|
|
/* Try the .libs dir first! */
|
|
newarg = check_library_exists(cmd_data, arg, pathlen, 1, &libtype);
|
|
if (!newarg) {
|
|
/* Try the normal dir next. */
|
|
newarg = check_library_exists(cmd_data, arg, pathlen, 0, &libtype);
|
|
if (!newarg) {
|
|
printf("Can not find suitable library for %s\n", arg);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* It is not ok to just add the file: a library may added with:
|
|
1 - -L path library_name. (For *.so in Linux).
|
|
2 - library_name.
|
|
*/
|
|
#ifdef ADD_MINUS_L
|
|
if (libtype == type_DYNAMIC_LIB) {
|
|
add_minus_l(cmd_data->shared_opts.dependencies, newarg);
|
|
} else {
|
|
push_count_chars(cmd_data->shared_opts.dependencies, newarg);
|
|
}
|
|
#else
|
|
push_count_chars(cmd_data->shared_opts.dependencies, newarg);
|
|
#endif
|
|
if (libtype == type_DYNAMIC_LIB) {
|
|
if (cmd_data->options.no_install) {
|
|
#ifdef RPATH
|
|
add_rpath_noinstall(cmd_data->shared_opts.dependencies,
|
|
arg, pathlen);
|
|
#endif
|
|
#ifdef DYNAMIC_LINK_NO_INSTALL
|
|
/*
|
|
* This doesn't work as Darwin's linker has no way to
|
|
* override at link-time the search paths for a
|
|
* non-installed library.
|
|
*/
|
|
/*
|
|
add_dylink_noinstall(cmd_data->shared_opts.dependencies,
|
|
arg, pathlen, ext - arg);
|
|
*/
|
|
#endif
|
|
}
|
|
else {
|
|
#ifdef RPATH
|
|
add_rpath_file(cmd_data->shared_opts.dependencies, arg);
|
|
#endif
|
|
}
|
|
}
|
|
break;
|
|
case mInstall:
|
|
/* If we've already recorded a library to install, we're most
|
|
* likely getting the .la file that we want to install as.
|
|
* The problem is that we need to add it as the directory,
|
|
* not the .la file itself. Otherwise, we'll do odd things.
|
|
*/
|
|
if (cmd_data->output == otLibrary) {
|
|
arg[pathlen] = '\0';
|
|
push_count_chars(cmd_data->arglist, arg);
|
|
}
|
|
else {
|
|
cmd_data->output = otLibrary;
|
|
cmd_data->output_name = arg;
|
|
cmd_data->static_name.install = gen_install_name(arg, 0);
|
|
cmd_data->shared_name.install = gen_install_name(arg, 1);
|
|
cmd_data->module_name.install = gen_install_name(arg, 2);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(ext, "c") == 0) {
|
|
/* If we don't already have an idea what our output name will be. */
|
|
if (cmd_data->basename == NULL) {
|
|
cmd_data->basename = (char *)malloc(strlen(arg) + 4);
|
|
strcpy(cmd_data->basename, arg);
|
|
strcpy(strrchr(cmd_data->basename, '.') + 1, "lo");
|
|
|
|
cmd_data->fake_output_name = strrchr(cmd_data->basename, '/');
|
|
if (cmd_data->fake_output_name) {
|
|
cmd_data->fake_output_name++;
|
|
}
|
|
else {
|
|
cmd_data->fake_output_name = cmd_data->basename;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int parse_output_file_name(char *arg, command_t *cmd_data)
|
|
{
|
|
char *name = strrchr(arg, '/');
|
|
char *ext = strrchr(arg, '.');
|
|
char *newarg = NULL;
|
|
int pathlen;
|
|
|
|
cmd_data->fake_output_name = arg;
|
|
|
|
if (name) {
|
|
name++;
|
|
}
|
|
else {
|
|
name = strrchr(arg, '\\');
|
|
|
|
if (name == NULL) {
|
|
name = arg;
|
|
}
|
|
else {
|
|
name++;
|
|
}
|
|
}
|
|
|
|
if (!ext) {
|
|
cmd_data->basename = arg;
|
|
cmd_data->output = otProgram;
|
|
#if defined(_OSD_POSIX)
|
|
cmd_data->options.pic_mode = pic_AVOID;
|
|
#endif
|
|
newarg = (char *)malloc(strlen(arg) + 5);
|
|
strcpy(newarg, arg);
|
|
#ifdef EXE_EXT
|
|
strcat(newarg, EXE_EXT);
|
|
#endif
|
|
cmd_data->output_name = newarg;
|
|
return 1;
|
|
}
|
|
|
|
ext++;
|
|
pathlen = name - arg;
|
|
|
|
if (strcmp(ext, "la") == 0) {
|
|
assert(cmd_data->mode == mLink);
|
|
|
|
cmd_data->basename = arg;
|
|
cmd_data->static_name.normal = gen_library_name(arg, 0);
|
|
cmd_data->shared_name.normal = gen_library_name(arg, 1);
|
|
cmd_data->module_name.normal = gen_library_name(arg, 2);
|
|
cmd_data->static_name.install = gen_install_name(arg, 0);
|
|
cmd_data->shared_name.install = gen_install_name(arg, 1);
|
|
cmd_data->module_name.install = gen_install_name(arg, 2);
|
|
|
|
#ifdef TRUNCATE_DLL_NAME
|
|
if (shared) {
|
|
arg = truncate_dll_name(arg);
|
|
}
|
|
#endif
|
|
|
|
cmd_data->output_name = arg;
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(ext, "lo") == 0) {
|
|
cmd_data->basename = arg;
|
|
cmd_data->output = otObject;
|
|
newarg = (char *)malloc(strlen(arg) + 2);
|
|
strcpy(newarg, arg);
|
|
ext = strrchr(newarg, '.') + 1;
|
|
strcpy(ext, OBJECT_EXT);
|
|
cmd_data->output_name = newarg;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* returns just a file's name without path or extension */
|
|
char *nameof(char *fullpath)
|
|
{
|
|
char buffer[1024];
|
|
char *ext;
|
|
char *name = strrchr(fullpath, '/');
|
|
|
|
if (name == NULL) {
|
|
name = strrchr(fullpath, '\\');
|
|
}
|
|
|
|
if (name == NULL) {
|
|
name = fullpath;
|
|
} else {
|
|
name++;
|
|
}
|
|
|
|
strcpy(buffer, name);
|
|
ext = strrchr(buffer, '.');
|
|
|
|
if (ext) {
|
|
*ext = 0;
|
|
return strdup(buffer);
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
void parse_args(int argc, char *argv[], command_t *cmd_data)
|
|
{
|
|
int a;
|
|
char *arg;
|
|
int argused;
|
|
|
|
for (a = 1; a < argc; a++) {
|
|
arg = argv[a];
|
|
argused = 1;
|
|
|
|
if (arg[0] == '-') {
|
|
if (arg[1] == '-') {
|
|
argused = parse_long_opt(arg + 2, cmd_data);
|
|
}
|
|
else {
|
|
argused = parse_short_opt(arg + 1, cmd_data);
|
|
}
|
|
|
|
/* We haven't done anything with it yet, try some of the
|
|
* more complicated short opts... */
|
|
if (argused == 0 && a + 1 < argc) {
|
|
if (arg[1] == 'o' && !arg[2]) {
|
|
arg = argv[++a];
|
|
argused = parse_output_file_name(arg, cmd_data);
|
|
} else if (strcmp(arg+1, "MT") == 0) {
|
|
if (!cmd_data->options.silent) {
|
|
printf("Adding: %s", arg);
|
|
}
|
|
push_count_chars(cmd_data->arglist, arg);
|
|
arg = argv[++a];
|
|
if (!cmd_data->options.silent) {
|
|
printf(" %s\n", arg);
|
|
}
|
|
push_count_chars(cmd_data->arglist, arg);
|
|
argused = 1;
|
|
} else if (strcmp(arg+1, "rpath") == 0) {
|
|
/* Aha, we should try to link both! */
|
|
cmd_data->install_path = argv[++a];
|
|
argused = 1;
|
|
} else if (strcmp(arg+1, "version-info") == 0) {
|
|
/* Store for later deciphering */
|
|
cmd_data->version_info = argv[++a];
|
|
argused = 1;
|
|
} else if (strcmp(arg+1, "export-symbols-regex") == 0) {
|
|
/* Skip the argument. */
|
|
++a;
|
|
argused = 1;
|
|
} else if (arg[1] == 'R' && !arg[2]) {
|
|
/* -R dir Add dir to runtime library search path. */
|
|
add_runtimedirlib(argv[++a], cmd_data);
|
|
argused = 1;
|
|
}
|
|
}
|
|
} else {
|
|
argused = parse_input_file_name(arg, cmd_data);
|
|
}
|
|
|
|
if (!argused) {
|
|
if (!cmd_data->options.silent) {
|
|
printf("Adding: %s\n", arg);
|
|
}
|
|
push_count_chars(cmd_data->arglist, arg);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int explode_static_lib(const char *lib, command_t *cmd_data)
|
|
{
|
|
char tmpdir[1024];
|
|
char savewd[1024];
|
|
char cmd[1024];
|
|
const char *name;
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
|
|
/* Bah! */
|
|
if (cmd_data->options.dry_run) {
|
|
return 0;
|
|
}
|
|
|
|
strcpy(tmpdir, lib);
|
|
strcat(tmpdir, ".exploded");
|
|
|
|
mkdir(tmpdir, 0);
|
|
push_count_chars(cmd_data->tmp_dirs, strdup(tmpdir));
|
|
getcwd(savewd, sizeof(savewd));
|
|
|
|
if (chdir(tmpdir) != 0)
|
|
return 1;
|
|
|
|
strcpy(cmd, LIBRARIAN " x ");
|
|
name = strrchr(lib, '/');
|
|
|
|
if (name) {
|
|
name++;
|
|
} else {
|
|
name = lib;
|
|
}
|
|
|
|
strcat(cmd, "../");
|
|
strcat(cmd, name);
|
|
system(cmd);
|
|
chdir(savewd);
|
|
dir = opendir(tmpdir);
|
|
|
|
while ((entry = readdir(dir)) != NULL) {
|
|
if (entry->d_name[0] != '.') {
|
|
strcpy(cmd, tmpdir);
|
|
strcat(cmd, "/");
|
|
strcat(cmd, entry->d_name);
|
|
push_count_chars(cmd_data->arglist, strdup(cmd));
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef GEN_EXPORTS
|
|
void generate_def_file(command_t *cmd_data)
|
|
{
|
|
char def_file[1024];
|
|
char implib_file[1024];
|
|
char *ext;
|
|
FILE *hDef;
|
|
char *export_args[1024];
|
|
int num_export_args = 0;
|
|
char *cmd;
|
|
int cmd_size = 0;
|
|
int a;
|
|
|
|
if (cmd_data->output_name) {
|
|
strcpy(def_file, cmd_data->output_name);
|
|
strcat(def_file, ".def");
|
|
hDef = fopen(def_file, "w");
|
|
|
|
if (hDef != NULL) {
|
|
fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
|
|
fprintf(hDef, "DATA NONSHARED\n");
|
|
fprintf(hDef, "EXPORTS\n");
|
|
fclose(hDef);
|
|
|
|
for (a = 0; a < cmd_data->num_obj_files; a++) {
|
|
cmd_size += strlen(cmd_data->obj_files[a]) + 1;
|
|
}
|
|
|
|
cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
|
|
cmd = (char *)malloc(cmd_size);
|
|
strcpy(cmd, GEN_EXPORTS);
|
|
|
|
for (a=0; a < cmd_data->num_obj_files; a++) {
|
|
strcat(cmd, " ");
|
|
strcat(cmd, cmd_data->obj_files[a] );
|
|
}
|
|
|
|
strcat(cmd, ">>");
|
|
strcat(cmd, def_file);
|
|
puts(cmd);
|
|
export_args[num_export_args++] = SHELL_CMD;
|
|
export_args[num_export_args++] = "-c";
|
|
export_args[num_export_args++] = cmd;
|
|
export_args[num_export_args++] = NULL;
|
|
external_spawn(cmd_data, export_args[0], (const char**)export_args);
|
|
cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
|
|
|
|
/* Now make an import library for the dll */
|
|
num_export_args = 0;
|
|
export_args[num_export_args++] = DEF2IMPLIB_CMD;
|
|
export_args[num_export_args++] = "-o";
|
|
|
|
strcpy(implib_file, ".libs/");
|
|
strcat(implib_file, cmd_data->basename);
|
|
ext = strrchr(implib_file, '.');
|
|
|
|
if (ext)
|
|
*ext = 0;
|
|
|
|
strcat(implib_file, ".");
|
|
strcat(implib_file, STATIC_LIB_EXT);
|
|
|
|
export_args[num_export_args++] = implib_file;
|
|
export_args[num_export_args++] = def_file;
|
|
export_args[num_export_args++] = NULL;
|
|
external_spawn(cmd_data, export_args[0], (const char**)export_args);
|
|
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
const char* expand_path(const char *relpath)
|
|
{
|
|
char foo[PATH_MAX], *newpath;
|
|
|
|
getcwd(foo, PATH_MAX-1);
|
|
newpath = (char*)malloc(strlen(foo)+strlen(relpath)+2);
|
|
strcat(newpath, foo);
|
|
strcat(newpath, "/");
|
|
strcat(newpath, relpath);
|
|
return newpath;
|
|
}
|
|
|
|
void link_fixup(command_t *c)
|
|
{
|
|
/* If we were passed an -rpath directive, we need to build
|
|
* shared objects too. Otherwise, we should only create static
|
|
* libraries.
|
|
*/
|
|
if (!c->install_path && (c->output == otDynamicLibraryOnly ||
|
|
c->output == otModule || c->output == otLibrary)) {
|
|
c->output = otStaticLibraryOnly;
|
|
}
|
|
|
|
if (c->output == otDynamicLibraryOnly ||
|
|
c->output == otModule ||
|
|
c->output == otLibrary) {
|
|
|
|
push_count_chars(c->shared_opts.normal, "-o");
|
|
if (c->output == otModule) {
|
|
push_count_chars(c->shared_opts.normal, c->module_name.normal);
|
|
}
|
|
else {
|
|
char *tmp;
|
|
push_count_chars(c->shared_opts.normal, c->shared_name.normal);
|
|
#ifdef DYNAMIC_INSTALL_NAME
|
|
push_count_chars(c->shared_opts.normal, DYNAMIC_INSTALL_NAME);
|
|
|
|
tmp = (char*)malloc(PATH_MAX);
|
|
strcat(tmp, c->install_path);
|
|
strcat(tmp, strrchr(c->shared_name.normal, '/'));
|
|
push_count_chars(c->shared_opts.normal, tmp);
|
|
#endif
|
|
}
|
|
|
|
append_count_chars(c->shared_opts.normal, c->obj_files);
|
|
append_count_chars(c->shared_opts.normal, c->shared_opts.dependencies);
|
|
|
|
if (c->options.export_all) {
|
|
#ifdef GEN_EXPORTS
|
|
generate_def_file(c);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (c->output == otLibrary || c->output == otStaticLibraryOnly) {
|
|
push_count_chars(c->static_opts.normal, "-o");
|
|
push_count_chars(c->static_opts.normal, c->output_name);
|
|
}
|
|
|
|
if (c->output == otProgram) {
|
|
if (c->output_name) {
|
|
push_count_chars(c->arglist, "-o");
|
|
push_count_chars(c->arglist, c->output_name);
|
|
append_count_chars(c->arglist, c->obj_files);
|
|
append_count_chars(c->arglist, c->shared_opts.dependencies);
|
|
#ifdef DYNAMIC_LINK_OPTS
|
|
if (c->options.pic_mode != pic_AVOID) {
|
|
push_count_chars(c->arglist, DYNAMIC_LINK_OPTS);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void post_parse_fixup(command_t *cmd_data)
|
|
{
|
|
switch (cmd_data->mode)
|
|
{
|
|
case mCompile:
|
|
#ifdef PIC_FLAG
|
|
if (cmd_data->options.pic_mode != pic_AVOID) {
|
|
push_count_chars(cmd_data->arglist, PIC_FLAG);
|
|
}
|
|
#endif
|
|
if (cmd_data->output_name) {
|
|
push_count_chars(cmd_data->arglist, "-o");
|
|
push_count_chars(cmd_data->arglist, cmd_data->output_name);
|
|
}
|
|
break;
|
|
case mLink:
|
|
link_fixup(cmd_data);
|
|
break;
|
|
case mInstall:
|
|
if (cmd_data->output == otLibrary) {
|
|
link_fixup(cmd_data);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#if USE_OMF
|
|
if (cmd_data->output == otObject ||
|
|
cmd_data->output == otProgram ||
|
|
cmd_data->output == otLibrary ||
|
|
cmd_data->output == otDynamicLibraryOnly) {
|
|
push_count_chars(cmd_data->arglist, "-Zomf");
|
|
}
|
|
#endif
|
|
|
|
if (cmd_data->options.shared &&
|
|
(cmd_data->output == otObject ||
|
|
cmd_data->output == otLibrary ||
|
|
cmd_data->output == otDynamicLibraryOnly)) {
|
|
#ifdef SHARE_SW
|
|
push_count_chars(cmd_data->arglist, SHARE_SW);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int run_mode(command_t *cmd_data)
|
|
{
|
|
int rv;
|
|
count_chars *cctemp;
|
|
|
|
cctemp = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cctemp);
|
|
|
|
switch (cmd_data->mode)
|
|
{
|
|
case mCompile:
|
|
rv = run_command(cmd_data, cmd_data->arglist);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
break;
|
|
case mInstall:
|
|
/* Well, we'll assume it's a file going to a directory... */
|
|
/* For brain-dead install-sh based scripts, we have to repeat
|
|
* the command N-times. install-sh should die.
|
|
*/
|
|
if (!cmd_data->output_name) {
|
|
rv = run_command(cmd_data, cmd_data->arglist);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
}
|
|
if (cmd_data->output_name) {
|
|
append_count_chars(cctemp, cmd_data->arglist);
|
|
insert_count_chars(cctemp,
|
|
cmd_data->output_name,
|
|
cctemp->num - 1);
|
|
rv = run_command(cmd_data, cctemp);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
clear_count_chars(cctemp);
|
|
}
|
|
if (cmd_data->static_name.install) {
|
|
append_count_chars(cctemp, cmd_data->arglist);
|
|
insert_count_chars(cctemp,
|
|
cmd_data->static_name.install,
|
|
cctemp->num - 1);
|
|
rv = run_command(cmd_data, cctemp);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
clear_count_chars(cctemp);
|
|
}
|
|
if (cmd_data->shared_name.install) {
|
|
append_count_chars(cctemp, cmd_data->arglist);
|
|
insert_count_chars(cctemp,
|
|
cmd_data->shared_name.install,
|
|
cctemp->num - 1);
|
|
rv = run_command(cmd_data, cctemp);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
clear_count_chars(cctemp);
|
|
}
|
|
if (cmd_data->module_name.install) {
|
|
append_count_chars(cctemp, cmd_data->arglist);
|
|
insert_count_chars(cctemp,
|
|
cmd_data->module_name.install,
|
|
cctemp->num - 1);
|
|
rv = run_command(cmd_data, cctemp);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
clear_count_chars(cctemp);
|
|
}
|
|
break;
|
|
case mLink:
|
|
if (!cmd_data->options.dry_run) {
|
|
/* Check first to see if the dir already exists! */
|
|
mode_t old_umask;
|
|
|
|
old_umask = umask(0);
|
|
umask(old_umask);
|
|
|
|
mkdir(".libs", ~old_umask);
|
|
}
|
|
|
|
if (cmd_data->output == otStaticLibraryOnly ||
|
|
cmd_data->output == otLibrary) {
|
|
#ifdef RANLIB
|
|
const char *lib_args[3];
|
|
#endif
|
|
/* Removes compiler! */
|
|
cmd_data->program = LIBRARIAN;
|
|
push_count_chars(cmd_data->program_opts, LIBRARIAN_OPTS);
|
|
push_count_chars(cmd_data->program_opts,
|
|
cmd_data->static_name.normal);
|
|
|
|
rv = run_command(cmd_data, cmd_data->obj_files);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
|
|
#ifdef RANLIB
|
|
lib_args[0] = RANLIB;
|
|
lib_args[1] = cmd_data->static_name.normal;
|
|
lib_args[2] = NULL;
|
|
external_spawn(cmd_data, RANLIB, lib_args);
|
|
#endif
|
|
}
|
|
|
|
if (cmd_data->output == otDynamicLibraryOnly ||
|
|
cmd_data->output == otModule ||
|
|
cmd_data->output == otLibrary) {
|
|
cmd_data->program = NULL;
|
|
clear_count_chars(cmd_data->program_opts);
|
|
|
|
append_count_chars(cmd_data->program_opts, cmd_data->arglist);
|
|
if (cmd_data->output != otModule) {
|
|
#ifdef SHARED_OPTS
|
|
push_count_chars(cmd_data->program_opts, SHARED_OPTS);
|
|
#endif
|
|
#ifdef dynamic_link_version_func
|
|
push_count_chars(cmd_data->program_opts,
|
|
dynamic_link_version_func(cmd_data->version_info));
|
|
#endif
|
|
}
|
|
if (cmd_data->output == otModule) {
|
|
#ifdef MODULE_OPTS
|
|
push_count_chars(cmd_data->program_opts, MODULE_OPTS);
|
|
#endif
|
|
}
|
|
#ifdef DYNAMIC_LINK_OPTS
|
|
if (cmd_data->options.pic_mode != pic_AVOID) {
|
|
push_count_chars(cmd_data->program_opts,
|
|
DYNAMIC_LINK_OPTS);
|
|
}
|
|
#endif
|
|
rv = run_command(cmd_data, cmd_data->shared_opts.normal);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
}
|
|
if (cmd_data->output == otProgram) {
|
|
rv = run_command(cmd_data, cmd_data->arglist);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void cleanup_tmp_dir(const char *dirname)
|
|
{
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
char fullname[1024];
|
|
|
|
dir = opendir(dirname);
|
|
|
|
if (dir == NULL)
|
|
return;
|
|
|
|
while ((entry = readdir(dir)) != NULL) {
|
|
if (entry->d_name[0] != '.') {
|
|
strcpy(fullname, dirname);
|
|
strcat(fullname, "/");
|
|
strcat(fullname, entry->d_name);
|
|
remove(fullname);
|
|
}
|
|
}
|
|
|
|
rmdir(dirname);
|
|
}
|
|
|
|
void cleanup_tmp_dirs(command_t *cmd_data)
|
|
{
|
|
int d;
|
|
|
|
for (d = 0; d < cmd_data->tmp_dirs->num; d++) {
|
|
cleanup_tmp_dir(cmd_data->tmp_dirs->vals[d]);
|
|
}
|
|
}
|
|
|
|
int ensure_fake_uptodate(command_t *cmd_data)
|
|
{
|
|
/* FIXME: could do the stat/touch here, but nah... */
|
|
const char *touch_args[3];
|
|
|
|
if (cmd_data->mode == mInstall) {
|
|
return 0;
|
|
}
|
|
|
|
touch_args[0] = "touch";
|
|
touch_args[1] = cmd_data->fake_output_name;
|
|
touch_args[2] = NULL;
|
|
return external_spawn(cmd_data, "touch", touch_args);
|
|
}
|
|
|
|
/* Store the install path in the *.la file */
|
|
int add_for_runtime(command_t *cmd_data)
|
|
{
|
|
if (cmd_data->mode == mInstall) {
|
|
return 0;
|
|
}
|
|
if (cmd_data->output == otDynamicLibraryOnly ||
|
|
cmd_data->output == otLibrary) {
|
|
FILE *f=fopen(cmd_data->fake_output_name,"w");
|
|
if (f == NULL) {
|
|
return -1;
|
|
}
|
|
fprintf(f,"%s\n", cmd_data->install_path);
|
|
fclose(f);
|
|
return(0);
|
|
} else {
|
|
return(ensure_fake_uptodate(cmd_data));
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int rc;
|
|
command_t cmd_data;
|
|
|
|
memset(&cmd_data, 0, sizeof(cmd_data));
|
|
|
|
cmd_data.options.pic_mode = pic_UNKNOWN;
|
|
|
|
cmd_data.program_opts = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.program_opts);
|
|
cmd_data.arglist = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.arglist);
|
|
cmd_data.tmp_dirs = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.tmp_dirs);
|
|
cmd_data.obj_files = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.obj_files);
|
|
cmd_data.dep_rpaths = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.dep_rpaths);
|
|
cmd_data.rpaths = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.rpaths);
|
|
cmd_data.static_opts.normal = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.static_opts.normal);
|
|
cmd_data.shared_opts.normal = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.shared_opts.normal);
|
|
cmd_data.shared_opts.dependencies = (count_chars*)malloc(sizeof(count_chars));
|
|
init_count_chars(cmd_data.shared_opts.dependencies);
|
|
|
|
cmd_data.mode = mUnknown;
|
|
cmd_data.output = otGeneral;
|
|
|
|
parse_args(argc, argv, &cmd_data);
|
|
post_parse_fixup(&cmd_data);
|
|
|
|
if (cmd_data.mode == mUnknown) {
|
|
exit(0);
|
|
}
|
|
|
|
rc = run_mode(&cmd_data);
|
|
|
|
if (!rc) {
|
|
add_for_runtime(&cmd_data);
|
|
}
|
|
|
|
cleanup_tmp_dirs(&cmd_data);
|
|
return rc;
|
|
}
|