Blame src/driver/slbt_driver_ctx.c

9ca8c4
/*******************************************************************/
9ca8c4
/*  slibtool: a skinny libtool implementation, written in C        */
6803d8
/*  Copyright (C) 2016--2018  Z. Gilboa                            */
9ca8c4
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
9ca8c4
/*******************************************************************/
9ca8c4
9ca8c4
#include <stdint.h>
0cbb20
#include <string.h>
9ca8c4
#include <unistd.h>
d5e3ae
#include <stdlib.h>
d5e3ae
#include <stdbool.h>
9ca8c4
#include <fcntl.h>
d5e3ae
#include <spawn.h>
d5e3ae
#include <sys/wait.h>
9ca8c4
9ca8c4
#define ARGV_DRIVER
9ca8c4
9ca8c4
#include <slibtool/slibtool.h>
9f24d2
#include "slibtool_version.h"
9ca8c4
#include "slibtool_driver_impl.h"
8069c3
#include "slibtool_errinfo_impl.h"
499a71
#include "slibtool_lconf_impl.h"
9ca8c4
#include "argv/argv.h"
9ca8c4
d5e3ae
extern char ** environ;
d5e3ae
9f24d2
/* package info */
9f24d2
static const struct slbt_source_version slbt_src_version = {
9f24d2
	SLBT_TAG_VER_MAJOR,
9f24d2
	SLBT_TAG_VER_MINOR,
9f24d2
	SLBT_TAG_VER_PATCH,
9f24d2
	SLIBTOOL_GIT_VERSION
9f24d2
};
5a9161
358030
/* default fd context */
358030
static const struct slbt_fd_ctx slbt_default_fdctx = {
358030
	.fdin  = STDIN_FILENO,
358030
	.fdout = STDOUT_FILENO,
358030
	.fderr = STDERR_FILENO,
358030
	.fdcwd = AT_FDCWD,
358030
	.fddst = AT_FDCWD,
358030
	.fdlog = (-1),
358030
};
358030
a66d34
/* flavor settings */
b9fe97
#define SLBT_FLAVOR_SETTINGS(flavor,          \
b9fe97
		bfmt,pic,                     \
339022
		arp,ars,dsop,dsos,osds,osdf,  \
b9fe97
		exep,exes,impp,imps,          \
b9fe97
		ldenv)                        \
b9fe97
	static const struct slbt_flavor_settings flavor = {  \
339022
		bfmt,arp,ars,dsop,dsos,osds,osdf,           \
b9fe97
		exep,exes,impp,imps,                       \
b9fe97
		ldenv,pic}
b9fe97
b9fe97
SLBT_FLAVOR_SETTINGS(host_flavor_default,       \
b9fe97
	"elf","-fPIC",                          \
339022
	"lib",".a","lib",".so",".so","",        \
b9fe97
	"","","","",                            \
b9fe97
	"LD_LIBRARY_PATH");
b9fe97
b9fe97
SLBT_FLAVOR_SETTINGS(host_flavor_midipix,       \
b9fe97
	"pe","-fPIC",                           \
339022
	"lib",".a","lib",".so",".so","",        \
b9fe97
	"","","lib",".lib.a",                   \
b9fe97
	"LD_LIBRARY_PATH");
b9fe97
b9fe97
SLBT_FLAVOR_SETTINGS(host_flavor_mingw,         \
b9fe97
	"pe",0,                                 \
339022
	"lib",".a","lib",".dll","",".dll",      \
b9fe97
	"",".exe","lib",".dll.a",               \
b9fe97
	"PATH");
b9fe97
b9fe97
SLBT_FLAVOR_SETTINGS(host_flavor_cygwin,        \
b9fe97
	"pe",0,                                 \
339022
	"lib",".a","lib",".dll","",".dll",      \
b9fe97
	"",".exe","lib",".dll.a",               \
b9fe97
	"PATH");
b9fe97
b9fe97
SLBT_FLAVOR_SETTINGS(host_flavor_darwin,        \
b9fe97
	"macho","-fPIC",                        \
339022
	"lib",".a","lib",".dylib","",".dylib",  \
b9fe97
	"","","","",                            \
b9fe97
	"DYLD_LIBRARY_PATH");
a66d34
a66d34
f10958
/* annotation strings */
46ea99
static const char cfgexplicit[] = "command-line argument";
46ea99
static const char cfghost[]     = "derived from <host>";
46ea99
static const char cfgtarget[]   = "derived from <target>";
46ea99
static const char cfgcompiler[] = "derived from <compiler>";
c7857f
static const char cfgnmachine[] = "native (derived from -dumpmachine)";
c7857f
static const char cfgxmachine[] = "foreign (derived from -dumpmachine)";
46ea99
static const char cfgnative[]   = "native";
46ea99
23b101
23b101
/* default compiler argv */
23b101
static char * slbt_default_cargv[] = {"cc",0};
23b101
af7db9
/* elf rpath */
af7db9
static const char*ldrpath_elf[] = {
af7db9
	"/lib",
af7db9
	"/lib/64",
af7db9
	"/usr/lib",
af7db9
	"/usr/lib64",
af7db9
	"/usr/local/lib",
bf2850
	"/usr/local/lib64",
af7db9
	0};
af7db9
caf7d0
static const char aclr_reset [] = "\x1b[0m";
caf7d0
static const char aclr_bold  [] = "\x1b[1m";
caf7d0
static const char aclr_red   [] = "\x1b[31m";
caf7d0
static const char aclr_green [] = "\x1b[32m";
caf7d0
static const char aclr_yellow[] = "\x1b[33m";
caf7d0
static const char aclr_blue  [] = "\x1b[34m";
caf7d0
static const char aclr_cyan  [] = "\x1b[36m";
caf7d0
static const char aclr_white [] = "\x1b[37m";
caf7d0
9ca8c4
struct slbt_driver_ctx_alloc {
9ca8c4
	struct argv_meta *		meta;
9ca8c4
	struct slbt_driver_ctx_impl	ctx;
9ca8c4
	uint64_t			guard;
9ca8c4
};
9ca8c4
d4c3e3
static void slbt_output_raw_vector(int fderr, char ** argv, char ** envp, bool fcolor)
caf7d0
{
caf7d0
	char **		parg;
caf7d0
	char *		dot;
caf7d0
	const char *	color;
caf7d0
d3ca02
	(void)envp;
d3ca02
d4c3e3
	if (fcolor)
a82cc2
		slbt_dprintf(fderr,"%s%s",aclr_bold,aclr_red);
caf7d0
a82cc2
	slbt_dprintf(fderr,"\n\n\n%s",argv[0]);
caf7d0
caf7d0
	for (parg=&argv[1]; *parg; parg++) {
caf7d0
		if (!fcolor)
caf7d0
			color = "";
caf7d0
		else if (*parg[0] == '-')
caf7d0
			color = aclr_blue;
caf7d0
		else if (!(dot = strrchr(*parg,'.')))
caf7d0
			color = aclr_green;
caf7d0
		else if (!(strcmp(dot,".lo")))
caf7d0
			color = aclr_cyan;
caf7d0
		else if (!(strcmp(dot,".la")))
caf7d0
			color = aclr_yellow;
caf7d0
		else
caf7d0
			color = aclr_white;
caf7d0
a82cc2
		slbt_dprintf(fderr," %s%s",color,*parg);
caf7d0
	}
caf7d0
a82cc2
	slbt_dprintf(fderr,"%s\n\n",fcolor ? aclr_reset : "");
caf7d0
}
caf7d0
9ca8c4
static uint32_t slbt_argv_flags(uint32_t flags)
9ca8c4
{
9ca8c4
	uint32_t ret = 0;
9ca8c4
9ca8c4
	if (flags & SLBT_DRIVER_VERBOSITY_NONE)
9ca8c4
		ret |= ARGV_VERBOSITY_NONE;
9ca8c4
9ca8c4
	if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
9ca8c4
		ret |= ARGV_VERBOSITY_ERRORS;
9ca8c4
9ca8c4
	if (flags & SLBT_DRIVER_VERBOSITY_STATUS)
9ca8c4
		ret |= ARGV_VERBOSITY_STATUS;
9ca8c4
9ca8c4
	return ret;
9ca8c4
}
9ca8c4
0cbb20
static int slbt_free_argv_buffer(struct slbt_split_vector * sargv)
0cbb20
{
0cbb20
	if (sargv->dargs)
0cbb20
		free(sargv->dargs);
0cbb20
0cbb20
	if (sargv->dargv)
0cbb20
		free(sargv->dargv);
0cbb20
0cbb20
	if (sargv->targv)
0cbb20
		free(sargv->targv);
0cbb20
0cbb20
	return -1;
0cbb20
}
0cbb20
9ca8c4
static int slbt_driver_usage(
a82cc2
	int				fdout,
9ca8c4
	const char *			program,
9ca8c4
	const char *			arg,
d58d2f
	const struct argv_option **	optv,
0cbb20
	struct argv_meta *		meta,
d4c3e3
	struct slbt_split_vector *	sargv,
d4c3e3
	int				noclr)
9ca8c4
{
9ca8c4
	char header[512];
9ca8c4
9ca8c4
	snprintf(header,sizeof(header),
9ca8c4
		"Usage: %s [options] <file>...\n" "Options:\n",
9ca8c4
		program);
9ca8c4
d4c3e3
	switch (noclr) {
d4c3e3
		case 0:
d4c3e3
			argv_usage(fdout,header,optv,arg);
d4c3e3
			break;
d4c3e3
d4c3e3
		default:
d4c3e3
			argv_usage_plain(fdout,header,optv,arg);
d4c3e3
			break;
d4c3e3
	}
d4c3e3
9ca8c4
	argv_free(meta);
0cbb20
	slbt_free_argv_buffer(sargv);
9ca8c4
9ca8c4
	return SLBT_USAGE;
9ca8c4
}
9ca8c4
9ca8c4
static struct slbt_driver_ctx_impl * slbt_driver_ctx_alloc(
9ca8c4
	struct argv_meta *		meta,
a82cc2
	const struct slbt_fd_ctx *	fdctx,
0cbb20
	const struct slbt_common_ctx *	cctx,
684b80
	struct slbt_split_vector *	sargv,
684b80
	char **				envp)
9ca8c4
{
9ca8c4
	struct slbt_driver_ctx_alloc *	ictx;
9ca8c4
	size_t				size;
41c05b
	int				elements;
9ca8c4
9ca8c4
	size =  sizeof(struct slbt_driver_ctx_alloc);
9ca8c4
0cbb20
	if (!(ictx = calloc(1,size))) {
0cbb20
		slbt_free_argv_buffer(sargv);
9ca8c4
		return 0;
0cbb20
	}
0cbb20
0cbb20
	ictx->ctx.dargs = sargv->dargs;
0cbb20
	ictx->ctx.dargv = sargv->dargv;
0cbb20
	ictx->ctx.targv = sargv->targv;
0cbb20
	ictx->ctx.cargv = sargv->cargv;
684b80
	ictx->ctx.envp  = envp;
9ca8c4
a82cc2
	memcpy(&ictx->ctx.fdctx,fdctx,sizeof(*fdctx));
a82cc2
	memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
9ca8c4
41c05b
	elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf);
41c05b
41c05b
	ictx->ctx.errinfp  = &ictx->ctx.erriptr[0];
41c05b
	ictx->ctx.erricap  = &ictx->ctx.erriptr[--elements];
41c05b
9ca8c4
	ictx->meta = meta;
41c05b
	ictx->ctx.ctx.errv  = ictx->ctx.errinfp;
9ca8c4
	return &ictx->ctx;
9ca8c4
}
9ca8c4
38b351
static int slbt_get_driver_ctx_fail(
38b351
	struct slbt_driver_ctx * dctx,
38b351
	struct argv_meta *       meta)
9ca8c4
{
38b351
	if (dctx) {
38b351
		slbt_output_error_vector(dctx);
38b351
		slbt_free_driver_ctx(dctx);
38b351
	} else {
38b351
		argv_free(meta);
38b351
	}
38b351
9ca8c4
	return -1;
9ca8c4
}
9ca8c4
56cab3
static int slbt_split_argv(
56cab3
	char **				argv,
56cab3
	uint32_t			flags,
a82cc2
	struct slbt_split_vector *	sargv,
a82cc2
	int				fderr)
56cab3
{
56cab3
	int				i;
56cab3
	int				argc;
56cab3
	const char *			program;
56cab3
	char *				compiler;
17e18a
	char *				csysroot;
0cbb20
	char **				dargv;
56cab3
	char **				targv;
56cab3
	char **				cargv;
0cbb20
	char *				dst;
0cbb20
	bool				flast;
0cbb20
	bool				fcopy;
0cbb20
	size_t				size;
34988f
	const char *			base;
56cab3
	struct argv_meta *		meta;
56cab3
	struct argv_entry *		entry;
56cab3
	struct argv_entry *		mode;
37ff4a
	struct argv_entry *		config;
b9575f
	struct argv_entry *		finish;
23b101
	struct argv_entry *		features;
34988f
	struct argv_entry *		ccwrap;
d58d2f
	const struct argv_option **	popt;
d58d2f
	const struct argv_option **	optout;
d58d2f
	const struct argv_option *	optv[SLBT_OPTV_ELEMENTS];
56cab3
	struct argv_ctx			ctx = {ARGV_VERBOSITY_NONE,
56cab3
						ARGV_MODE_SCAN,
56cab3
						0,0,0,0,0,0,0};
56cab3
56cab3
	program = argv_program_name(argv[0]);
56cab3
56cab3
	/* missing arguments? */
d58d2f
	argv_optv_init(slbt_default_options,optv);
d58d2f
56cab3
	if (!argv[1] && (flags & SLBT_DRIVER_VERBOSITY_USAGE))
a82cc2
		return slbt_driver_usage(
a82cc2
			fderr,program,
d4c3e3
			0,optv,0,sargv,
d4c3e3
			!!getenv("NO_COLOR"));
56cab3
56cab3
	/* initial argv scan: ... --mode=xxx ... <compiler> ... */
d58d2f
	argv_scan(argv,optv,&ctx,0);
56cab3
56cab3
	/* invalid slibtool arguments? */
56cab3
	if (ctx.erridx && !ctx.unitidx) {
56cab3
		if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
56cab3
			argv_get(
d58d2f
				argv,optv,
93f9e4
				slbt_argv_flags(flags),
a82cc2
				fderr);
56cab3
		return -1;
56cab3
	}
56cab3
56cab3
	/* obtain slibtool's own arguments */
23b101
	if (ctx.unitidx) {
23b101
		compiler = argv[ctx.unitidx];
23b101
		argv[ctx.unitidx] = 0;
23b101
a82cc2
		meta = argv_get(argv,optv,ARGV_VERBOSITY_NONE,fderr);
23b101
		argv[ctx.unitidx] = compiler;
23b101
	} else {
a82cc2
		meta = argv_get(argv,optv,ARGV_VERBOSITY_NONE,fderr);
23b101
	}
56cab3
23b101
	/* missing all of --mode, --config, --features, and --finish? */
34988f
	mode = config = finish = features = ccwrap = 0;
56cab3
23b101
	for (entry=meta->entries; entry->fopt; entry++)
56cab3
		if (entry->tag == TAG_MODE)
56cab3
			mode = entry;
37ff4a
		else if (entry->tag == TAG_CONFIG)
37ff4a
			config = entry;
b9575f
		else if (entry->tag == TAG_FINISH)
b9575f
			finish = entry;
23b101
		else if (entry->tag == TAG_FEATURES)
23b101
			features = entry;
34988f
		else if (entry->tag == TAG_CCWRAP)
34988f
			ccwrap = entry;
56cab3
56cab3
	argv_free(meta);
56cab3
23b101
	if (!mode && !config && !finish && !features) {
a82cc2
		slbt_dprintf(fderr,
56cab3
			"%s: error: --mode must be specified.\n",
56cab3
			program);
56cab3
		return -1;
56cab3
	}
56cab3
b9575f
	/* missing compiler? */
23b101
	if (!ctx.unitidx && !finish && !features) {
b9575f
		if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
a82cc2
			slbt_dprintf(fderr,
b9575f
				"%s: error: <compiler> is missing.\n",
b9575f
				program);
b9575f
		return -1;
b9575f
	}
b9575f
0cbb20
	/* clone and normalize the argv vector (-l, --library) */
0cbb20
	for (argc=0,size=0,dargv=argv; *dargv; argc++,dargv++)
0cbb20
		size += strlen(*dargv) + 1;
0cbb20
0cbb20
	if (!(sargv->dargv = calloc(argc+1,sizeof(char *))))
0cbb20
		return -1;
56cab3
0cbb20
	else if (!(sargv->dargs = calloc(1,size+1)))
0cbb20
		return -1;
0cbb20
17e18a
	csysroot = 0;
17e18a
0cbb20
	for (i=0,flast=false,dargv=sargv->dargv,dst=sargv->dargs; i
0cbb20
		if ((fcopy = flast)) {
0cbb20
			(void)0;
0cbb20
0cbb20
		} else if (!strcmp(argv[i],"--")) {
0cbb20
			flast = true;
0cbb20
			fcopy = true;
0cbb20
0cbb20
		} else if (!strcmp(argv[i],"-l")) {
0cbb20
			*dargv++ = dst;
0cbb20
			*dst++ = '-';
0cbb20
			*dst++ = 'l';
0cbb20
			strcpy(dst,argv[++i]);
0cbb20
			dst += strlen(dst)+1;
0cbb20
0cbb20
		} else if (!strncmp(argv[i],"-l",2)) {
0cbb20
			fcopy = true;
0cbb20
0cbb20
		} else if (!strcmp(argv[i],"--library")) {
0cbb20
			*dargv++ = dst;
0cbb20
			*dst++ = '-';
0cbb20
			*dst++ = 'l';
0cbb20
			strcpy(dst,argv[++i]);
0cbb20
			dst += strlen(dst)+1;
0cbb20
0cbb20
		} else if (!strncmp(argv[i],"--library=",10)) {
0cbb20
			*dargv++ = dst;
0cbb20
			*dst++ = '-';
0cbb20
			*dst++ = 'l';
0cbb20
			strcpy(dst,&argv[++i][10]);
0cbb20
			dst += strlen(dst)+1;
0cbb20
0cbb20
		} else if (!strcmp(argv[i],"-L")) {
0cbb20
			*dargv++ = dst;
0cbb20
			*dst++ = '-';
0cbb20
			*dst++ = 'L';
0cbb20
			strcpy(dst,argv[++i]);
0cbb20
			dst += strlen(dst)+1;
0cbb20
0cbb20
		} else if (!strncmp(argv[i],"-L",2)) {
0cbb20
			fcopy = true;
0cbb20
2c4e5f
		} else if (!strcmp(argv[i],"-Xlinker")) {
2c4e5f
			*dargv++ = dst;
2c4e5f
			*dst++ = '-';
2c4e5f
			*dst++ = 'W';
2c4e5f
			*dst++ = 'l';
2c4e5f
			*dst++ = ',';
2c4e5f
			strcpy(dst,argv[++i]);
2c4e5f
			dst += strlen(dst)+1;
2c4e5f
0cbb20
		} else if (!strcmp(argv[i],"--library-path")) {
0cbb20
			*dargv++ = dst;
0cbb20
			*dst++ = '-';
0cbb20
			*dst++ = 'L';
0cbb20
			strcpy(dst,argv[++i]);
0cbb20
			dst += strlen(dst)+1;
0cbb20
0cbb20
		} else if (!strncmp(argv[i],"--library-path=",15)) {
0cbb20
			*dargv++ = dst;
0cbb20
			*dst++ = '-';
0cbb20
			*dst++ = 'L';
3ead95
			strcpy(dst,&argv[i][15]);
0cbb20
			dst += strlen(dst)+1;
17e18a
17e18a
		} else if (!strcmp(argv[i],"--sysroot") && (i
17e18a
			*dargv++ = dst;
17e18a
			csysroot = dst;
17e18a
			strcpy(dst,argv[i]);
17e18a
			dst[9] = '=';
17e18a
			strcpy(&dst[10],argv[++i]);
17e18a
			dst += strlen(dst)+1;
17e18a
			ctx.unitidx--;
17e18a
17e18a
		} else if (!strncmp(argv[i],"--sysroot=",10) && (i
17e18a
			*dargv++ = dst;
17e18a
			csysroot = dst;
17e18a
			strcpy(dst,argv[i]);
17e18a
			dst += strlen(dst)+1;
17e18a
0cbb20
		} else {
0cbb20
			fcopy = true;
0cbb20
		}
0cbb20
0cbb20
		if (fcopy) {
0cbb20
			*dargv++ = dst;
0cbb20
			strcpy(dst,argv[i]);
0cbb20
			dst += strlen(dst)+1;
0cbb20
		}
0cbb20
	}
0cbb20
0cbb20
	/* update argc,argv */
0cbb20
	argc = dargv - sargv->dargv;
0cbb20
	argv = sargv->dargv;
0cbb20
17e18a
	/* allocate split vectors, account for cargv's added sysroot */
17e18a
	if ((sargv->targv = calloc(2*(argc+3),sizeof(char *))))
34988f
		sargv->cargv = sargv->targv + argc + 2;
56cab3
	else
56cab3
		return -1;
56cab3
23b101
	/* --features and no <compiler>? */
23b101
	if (features && !ctx.unitidx) {
23b101
		for (i=0; i
23b101
			sargv->targv[i] = argv[i];
23b101
23b101
		sargv->cargv = slbt_default_cargv;
23b101
23b101
		return 0;
23b101
	}
23b101
56cab3
	/* split vectors: slibtool's own options */
56cab3
	for (i=0; i
56cab3
		sargv->targv[i] = argv[i];
56cab3
34988f
	/* split vector marks */
34988f
	targv = sargv->targv + i;
34988f
	cargv = sargv->cargv;
34988f
34988f
	/* known wrappers */
34988f
	if (ctx.unitidx && !ccwrap) {
34988f
		if ((base = strrchr(argv[i],'/')))
34988f
			base++;
34988f
		else if ((base = strrchr(argv[i],'\\')))
34988f
			base++;
34988f
		else
34988f
			base = argv[i];
34988f
34988f
		if (!strcmp(base,"ccache")
34988f
				|| !strcmp(base,"distcc")
34988f
				|| !strcmp(base,"compiler")
34988f
				|| !strcmp(base,"purify")) {
34988f
			*targv++ = "--ccwrap";
34988f
			*targv++ = argv[i++];
34988f
		}
34988f
	}
34988f
56cab3
	/* split vectors: legacy mixture */
d58d2f
	for (optout=optv; optout[0]->tag != TAG_OUTPUT; optout++)
d58d2f
		(void)0;
56cab3
17e18a
	/* compiler */
17e18a
	*cargv++ = argv[i++];
17e18a
17e18a
	/* sysroot */
17e18a
	if (csysroot)
17e18a
		*cargv++ = csysroot;
17e18a
17e18a
	/* remaining vector */
56cab3
	for (; i
70c446
		if (argv[i][0] != '-') {
70c446
			if (argv[i+1] && (argv[i+1][0] == '+')
70c446
					&& (argv[i+1][1] == '=')
70c446
					&& (argv[i+1][2] == 0)
70c446
					&& !(strrchr(argv[i],'.')))
70c446
				/* libfoo_la_LDFLAGS += -Wl,.... */
70c446
				i++;
70c446
			else
70c446
				*cargv++ = argv[i];
70c446
70c446
		} else if (argv[i][1] == 'o') {
56cab3
			*targv++ = argv[i];
56cab3
a87fd1
			if (argv[i][2] == 0)
a288c4
				*targv++ = argv[++i];
a797c9
		} else if ((argv[i][1] == 'W')  && (argv[i][2] == 'c')) {
56cab3
			*cargv++ = argv[i];
56cab3
a797c9
		} else if (!(strcmp("Xcompiler",&argv[i][1]))) {
56cab3
			*cargv++ = argv[++i];
56cab3
0d693e
		} else if (!(strcmp("XCClinker",&argv[i][1]))) {
0d693e
			*cargv++ = argv[++i];
0d693e
a797c9
		} else if ((argv[i][1] == 'R')  && (argv[i][2] == 0)) {
523027
			*targv++ = argv[i++];
523027
			*targv++ = argv[i];
523027
523027
		} else if (argv[i][1] == 'R') {
523027
			*targv++ = argv[i];
523027
66a3c2
		} else if (!(strncmp("-target=",&argv[i][1],8))) {
66a3c2
			*cargv++ = argv[i];
66a3c2
			*targv++ = argv[i];
66a3c2
66a3c2
		} else if (!(strcmp("-target",&argv[i][1]))) {
66a3c2
			*cargv++ = argv[i];
66a3c2
			*targv++ = argv[i++];
66a3c2
66a3c2
			*cargv++ = argv[i];
66a3c2
			*targv++ = argv[i];
66a3c2
17e18a
		} else if (!(strncmp("-sysroot=",&argv[i][1],9))) {
17e18a
			*cargv++ = argv[i];
17e18a
			*targv++ = argv[i];
17e18a
17e18a
		} else if (!(strcmp("-sysroot",&argv[i][1]))) {
17e18a
			*cargv++ = argv[i];
17e18a
			*targv++ = argv[i++];
17e18a
17e18a
			*cargv++ = argv[i];
17e18a
			*targv++ = argv[i];
17e18a
63a1b4
		} else if (!(strcmp("bindir",&argv[i][1]))) {
63a1b4
			*targv++ = argv[i++];
63a1b4
			*targv++ = argv[i];
63a1b4
bfa8ca
		} else if (!(strcmp("shrext",&argv[i][1]))) {
bfa8ca
			*targv++ = argv[i++];
bfa8ca
			*targv++ = argv[i];
bfa8ca
9c664d
		} else if (!(strcmp("rpath",&argv[i][1]))) {
9c664d
			*targv++ = argv[i++];
666296
			*targv++ = argv[i];
5a9161
9aa1f4
		} else if (!(strcmp("release",&argv[i][1]))) {
9aa1f4
			*targv++ = argv[i++];
9aa1f4
			*targv++ = argv[i];
9aa1f4
05ca7e
		} else if (!(strcmp("dlopen",&argv[i][1]))) {
05ca7e
			*targv++ = argv[i++];
05ca7e
			*targv++ = argv[i];
05ca7e
56f236
		} else if (!(strcmp("static-libtool-libs",&argv[i][1]))) {
56f236
			*targv++ = argv[i];
56f236
916050
		} else if (!(strcmp("export-dynamic",&argv[i][1]))) {
916050
			*targv++ = argv[i];
916050
873ecb
		} else if (!(strcmp("export-symbols",&argv[i][1]))) {
873ecb
			*targv++ = argv[i++];
873ecb
			*targv++ = argv[i];
873ecb
73ca78
		} else if (!(strcmp("export-symbols-regex",&argv[i][1]))) {
73ca78
			*targv++ = argv[i++];
73ca78
			*targv++ = argv[i];
73ca78
5a9161
		} else if (!(strcmp("version-info",&argv[i][1]))) {
5a9161
			*targv++ = argv[i++];
5a9161
			*targv++ = argv[i];
5a9161
cd3d41
		} else if (!(strcmp("version-number",&argv[i][1]))) {
cd3d41
			*targv++ = argv[i++];
cd3d41
			*targv++ = argv[i];
cd3d41
bb5843
		} else if (!(strcmp("dlpreopen",&argv[i][1]))) {
bb5843
			(void)0;
bb5843
411564
		} else {
d58d2f
			for (popt=optout; popt[0] && popt[0]->long_name; popt++)
d58d2f
				if (!(strcmp(popt[0]->long_name,&argv[i][1])))
56cab3
					break;
56cab3
d58d2f
			if (popt[0] && popt[0]->long_name)
56cab3
				*targv++ = argv[i];
56cab3
			else
56cab3
				*cargv++ = argv[i];
56cab3
		}
56cab3
	}
56cab3
56cab3
	return 0;
56cab3
}
56cab3
d7eb71
static void slbt_get_host_quad(
d7eb71
	char *	hostbuf,
d7eb71
	char ** hostquad)
d7eb71
{
d7eb71
	char *	mark;
d7eb71
	char *	ch;
d7eb71
	int	i;
d7eb71
d7eb71
	for (i=0, ch=hostbuf, mark=hostbuf; *ch && i<4; ch++) {
d7eb71
		if (*ch == '-') {
d7eb71
			*ch = 0;
d7eb71
			hostquad[i++] = mark;
d7eb71
			mark = &ch[1];
d7eb71
		}
d7eb71
	}
d7eb71
d7eb71
	if (i<4)
d7eb71
		hostquad[i] = mark;
d7eb71
d7eb71
	if (i==3) {
d7eb71
		hostquad[1] = hostquad[2];
d7eb71
		hostquad[2] = hostquad[3];
d7eb71
		hostquad[3] = 0;
d7eb71
	}
d7eb71
}
d7eb71
a62f90
static void slbt_spawn_ar(char ** argv, int * ecode)
a62f90
{
a62f90
	int	estatus;
a62f90
	pid_t	pid;
a62f90
a62f90
	*ecode = 127;
a62f90
a62f90
	if ((pid = fork()) < 0) {
a62f90
		return;
a62f90
a62f90
	} else if (pid == 0) {
a62f90
		execvp(argv[0],argv);
a62f90
		_exit(errno);
a62f90
a62f90
	} else {
a62f90
		waitpid(pid,&estatus,0);
a62f90
a62f90
		if (WIFEXITED(estatus))
a62f90
			*ecode = WEXITSTATUS(estatus);
a62f90
	}
a62f90
}
a62f90
f0921b
static int slbt_init_host_params(
56f2d4
	const struct slbt_driver_ctx *	dctx,
46ea99
	const struct slbt_common_ctx *	cctx,
46ea99
	struct slbt_host_strs *		drvhost,
46ea99
	struct slbt_host_params *	host,
46ea99
	struct slbt_host_params *	cfgmeta)
46ea99
{
d38565
	int		fdcwd;
d5e3ae
	int		arprobe;
d5e3ae
	int		arfd;
a62f90
	int		ecode;
46ea99
	size_t		toollen;
a07c9b
	char *		dash;
a21ac1
	char *		base;
c67e64
	char *		mark;
46ea99
	const char *	machine;
46ea99
	bool		ftarget       = false;
46ea99
	bool		fhost         = false;
46ea99
	bool		fcompiler     = false;
46ea99
	bool		fnative       = false;
663ef2
	bool		fdumpmachine  = false;
d7eb71
	char		buf        [256];
d7eb71
	char		hostbuf    [256];
d7eb71
	char		machinebuf [256];
d7eb71
	char *		hostquad   [4];
d7eb71
	char *		machinequad[4];
d5e3ae
	char *		arprobeargv[4];
d5e3ae
	char		archivename[] = "/tmp/slibtool.ar.probe.XXXXXXXXXXXXXXXX";
46ea99
a21ac1
	/* base */
a21ac1
	if ((base = strrchr(cctx->cargv[0],'/')))
a21ac1
		base++;
a21ac1
	else
a21ac1
		base = cctx->cargv[0];
a21ac1
0bfff4
	fdumpmachine  = (cctx->mode == SLBT_MODE_COMPILE)
3c1679
			|| (cctx->mode == SLBT_MODE_LINK)
3c1679
			|| (cctx->mode == SLBT_MODE_INFO);
663ef2
0bfff4
	fdumpmachine &= (!strcmp(base,"xgcc")
0bfff4
			|| !strcmp(base,"xg++"));
0bfff4
c67e64
	/* support the portbld <--> unknown synonym */
c67e64
	if (!(drvhost->machine = strdup(SLBT_MACHINE)))
c67e64
		return -1;
c67e64
c67e64
	if ((mark = strstr(drvhost->machine,"-portbld-")))
c67e64
		memcpy(mark,"-unknown",8);
c67e64
46ea99
	/* host */
46ea99
	if (host->host) {
46ea99
		cfgmeta->host = cfgexplicit;
46ea99
		fhost         = true;
56f2d4
46ea99
	} else if (cctx->target) {
46ea99
		host->host    = cctx->target;
46ea99
		cfgmeta->host = cfgtarget;
46ea99
		ftarget       = true;
56f2d4
a21ac1
	} else if (strrchr(base,'-')) {
46ea99
		if (!(drvhost->host = strdup(cctx->cargv[0])))
46ea99
			return -1;
46ea99
a07c9b
		dash          = strrchr(drvhost->host,'-');
a07c9b
		*dash         = 0;
46ea99
		host->host    = drvhost->host;
46ea99
		cfgmeta->host = cfgcompiler;
46ea99
		fcompiler     = true;
56f2d4
56f2d4
	} else if (!fdumpmachine) {
56f2d4
		host->host    = drvhost->machine;
56f2d4
		cfgmeta->host = cfgnmachine;
56f2d4
56f2d4
	} else if (slbt_dump_machine(cctx->cargv[0],buf,sizeof(buf)) < 0) {
56f2d4
		if (dctx)
56f2d4
			slbt_dprintf(
56f2d4
				slbt_driver_fderr(dctx),
56f2d4
				"%s: could not determine host "
56f2d4
				"via -dumpmachine\n",
56f2d4
				dctx->program);
56f2d4
		return -1;
56f2d4
56f2d4
	} else {
663ef2
		if (!(drvhost->host = strdup(buf)))
663ef2
			return -1;
663ef2
663ef2
		host->host    = drvhost->host;
663ef2
		fcompiler     = true;
d7eb71
		fnative       = !strcmp(host->host,drvhost->machine);
c7857f
		cfgmeta->host = fnative ? cfgnmachine : cfgxmachine;
d7eb71
d7eb71
		if (!fnative) {
d7eb71
			strcpy(hostbuf,host->host);
d7eb71
			strcpy(machinebuf,drvhost->machine);
d7eb71
d7eb71
			slbt_get_host_quad(hostbuf,hostquad);
d7eb71
			slbt_get_host_quad(machinebuf,machinequad);
d7eb71
d7eb71
			if (hostquad[2] && machinequad[2])
d7eb71
				fnative = !strcmp(hostquad[0],machinequad[0])
d7eb71
					&& !strcmp(hostquad[1],machinequad[1])
d7eb71
					&& !strcmp(hostquad[2],machinequad[2]);
d7eb71
		}
46ea99
	}
46ea99
46ea99
	/* flavor */
46ea99
	if (host->flavor) {
46ea99
		cfgmeta->flavor = cfgexplicit;
46ea99
	} else {
46ea99
		if (fhost) {
46ea99
			machine         = host->host;
46ea99
			cfgmeta->flavor = cfghost;
46ea99
		} else if (ftarget) {
46ea99
			machine         = cctx->target;
46ea99
			cfgmeta->flavor = cfgtarget;
46ea99
		} else if (fcompiler) {
46ea99
			machine         = drvhost->host;
46ea99
			cfgmeta->flavor = cfgcompiler;
46ea99
		} else {
c67e64
			machine         = drvhost->machine;
c7857f
			cfgmeta->flavor = cfgnmachine;
46ea99
		}
46ea99
a07c9b
		dash = strrchr(machine,'-');
46ea99
		cfgmeta->flavor = cfghost;
46ea99
a07c9b
		if ((dash && !strcmp(dash,"-bsd")) || strstr(machine,"-bsd-"))
46ea99
			host->flavor = "bsd";
a07c9b
		else if ((dash && !strcmp(dash,"-cygwin")) || strstr(machine,"-cygwin-"))
46ea99
			host->flavor = "cygwin";
9ff9ad
		else if ((dash && !strcmp(dash,"-darwin")) || strstr(machine,"-darwin"))
46ea99
			host->flavor = "darwin";
a07c9b
		else if ((dash && !strcmp(dash,"-linux")) || strstr(machine,"-linux-"))
46ea99
			host->flavor = "linux";
a07c9b
		else if ((dash && !strcmp(dash,"-midipix")) || strstr(machine,"-midipix-"))
46ea99
			host->flavor = "midipix";
a07c9b
		else if ((dash && !strcmp(dash,"-mingw")) || strstr(machine,"-mingw-"))
46ea99
			host->flavor = "mingw";
a07c9b
		else if ((dash && !strcmp(dash,"-mingw32")) || strstr(machine,"-mingw32-"))
46ea99
			host->flavor = "mingw";
a07c9b
		else if ((dash && !strcmp(dash,"-mingw64")) || strstr(machine,"-mingw64-"))
46ea99
			host->flavor = "mingw";
ae6854
		else if ((dash && !strcmp(dash,"-windows")) || strstr(machine,"-windows-"))
ae6854
			host->flavor = "mingw";
46ea99
		else {
46ea99
			host->flavor   = "default";
46ea99
			cfgmeta->flavor = "fallback, unverified";
46ea99
		}
34a96e
34a96e
		if (fcompiler && !fnative)
34a96e
			if ((mark = strstr(drvhost->machine,host->flavor)))
34a96e
				if (mark > drvhost->machine)
34a96e
					fnative = (*--mark == '-');
46ea99
	}
46ea99
46ea99
	/* toollen */
46ea99
	toollen =  fnative ? 0 : strlen(host->host);
46ea99
	toollen += strlen("-utility-name");
46ea99
46ea99
	/* ar */
46ea99
	if (host->ar)
46ea99
		cfgmeta->ar = cfgexplicit;
46ea99
	else {
46ea99
		if (!(drvhost->ar = calloc(1,toollen)))
46ea99
			return -1;
46ea99
46ea99
		if (fnative) {
46ea99
			strcpy(drvhost->ar,"ar");
46ea99
			cfgmeta->ar = cfgnative;
d5e3ae
			arprobe = 0;
d5e3ae
		} else if (cctx->mode == SLBT_MODE_LINK) {
d5e3ae
			arprobe = true;
d5e3ae
		} else if (cctx->mode == SLBT_MODE_INFO) {
d5e3ae
			arprobe = true;
46ea99
		} else {
d5e3ae
			arprobe = false;
d5e3ae
		}
d5e3ae
d5e3ae
		/* arprobe */
d5e3ae
		if (arprobe) {
46ea99
			sprintf(drvhost->ar,"%s-ar",host->host);
46ea99
			cfgmeta->ar = cfghost;
315645
			ecode       = 127;
d5e3ae
d5e3ae
			/* empty archive */
d5e3ae
			if ((arfd = mkstemp(archivename)) >= 0) {
d5e3ae
				slbt_dprintf(arfd,"!<arch>\n");
d5e3ae
d5e3ae
				arprobeargv[0] = drvhost->ar;
d5e3ae
				arprobeargv[1] = "-t";
d5e3ae
				arprobeargv[2] = archivename;
d5e3ae
				arprobeargv[3] = 0;
d5e3ae
d5e3ae
				/* <target>-ar */
a62f90
				slbt_spawn_ar(
a62f90
					arprobeargv,
a62f90
					&ecode);
d5e3ae
			}
d5e3ae
d5e3ae
			/* <target>-<compiler>-ar */
a62f90
			if (ecode && !strchr(base,'-')) {
d5e3ae
				sprintf(drvhost->ar,"%s-%s-ar",host->host,base);
d5e3ae
a62f90
				slbt_spawn_ar(
a62f90
					arprobeargv,
a62f90
					&ecode);
d5e3ae
			}
d5e3ae
d5e3ae
			/* <compiler>-ar */
a62f90
			if (ecode && !strchr(base,'-')) {
d5e3ae
				sprintf(drvhost->ar,"%s-ar",base);
d5e3ae
a62f90
				slbt_spawn_ar(
a62f90
					arprobeargv,
a62f90
					&ecode);
d5e3ae
			}
d5e3ae
d5e3ae
			/* if target is the native target, fallback to native ar */
a62f90
			if (ecode && !strcmp(host->host,SLBT_MACHINE)) {
d5e3ae
				strcpy(drvhost->ar,"ar");
d5e3ae
				cfgmeta->ar = cfgnative;
d5e3ae
			}
d5e3ae
d38565
			/* fdcwd */
d38565
			fdcwd = slbt_driver_fdcwd(dctx);
d38565
d5e3ae
			/* clean up */
d5e3ae
			if (arfd >= 0) {
d38565
				unlinkat(fdcwd,archivename,0);
d5e3ae
				close(arfd);
d5e3ae
			}
46ea99
		}
46ea99
46ea99
		host->ar = drvhost->ar;
46ea99
	}
46ea99
46ea99
	/* ranlib */
46ea99
	if (host->ranlib)
46ea99
		cfgmeta->ranlib = cfgexplicit;
46ea99
	else {
46ea99
		if (!(drvhost->ranlib = calloc(1,toollen)))
46ea99
			return -1;
46ea99
46ea99
		if (fnative) {
46ea99
			strcpy(drvhost->ranlib,"ranlib");
46ea99
			cfgmeta->ranlib = cfgnative;
46ea99
		} else {
46ea99
			sprintf(drvhost->ranlib,"%s-ranlib",host->host);
46ea99
			cfgmeta->ranlib = cfghost;
46ea99
		}
46ea99
46ea99
		host->ranlib = drvhost->ranlib;
46ea99
	}
46ea99
9a02e2
	/* windres */
9a02e2
	if (host->windres)
9a02e2
		cfgmeta->windres = cfgexplicit;
9a02e2
9a02e2
	else if (strcmp(host->flavor,"cygwin")
9a02e2
			&& strcmp(host->flavor,"midipix")
9a02e2
			&& strcmp(host->flavor,"mingw")) {
9a02e2
		host->windres    = "";
9a02e2
		cfgmeta->windres = "not applicable";
9a02e2
9a02e2
	} else {
9a02e2
		if (!(drvhost->windres = calloc(1,toollen)))
9a02e2
			return -1;
9a02e2
9a02e2
		if (fnative) {
9a02e2
			strcpy(drvhost->windres,"windres");
9a02e2
			cfgmeta->windres = cfgnative;
9a02e2
		} else {
9a02e2
			sprintf(drvhost->windres,"%s-windres",host->host);
9a02e2
			cfgmeta->windres = cfghost;
9a02e2
		}
9a02e2
9a02e2
		host->windres = drvhost->windres;
9a02e2
	}
9a02e2
46ea99
	/* dlltool */
46ea99
	if (host->dlltool)
46ea99
		cfgmeta->dlltool = cfgexplicit;
46ea99
46ea99
	else if (strcmp(host->flavor,"cygwin")
46ea99
			&& strcmp(host->flavor,"midipix")
46ea99
			&& strcmp(host->flavor,"mingw")) {
46ea99
		host->dlltool = "";
46ea99
		cfgmeta->dlltool = "not applicable";
46ea99
46ea99
	} else {
46ea99
		if (!(drvhost->dlltool = calloc(1,toollen)))
46ea99
			return -1;
46ea99
46ea99
		if (fnative) {
46ea99
			strcpy(drvhost->dlltool,"dlltool");
46ea99
			cfgmeta->dlltool = cfgnative;
46ea99
		} else {
46ea99
			sprintf(drvhost->dlltool,"%s-dlltool",host->host);
46ea99
			cfgmeta->dlltool = cfghost;
46ea99
		}
46ea99
46ea99
		host->dlltool = drvhost->dlltool;
46ea99
	}
46ea99
fbda3a
	/* mdso */
fbda3a
	if (host->mdso)
fbda3a
		cfgmeta->mdso = cfgexplicit;
fbda3a
fbda3a
	else if (strcmp(host->flavor,"cygwin")
fbda3a
			&& strcmp(host->flavor,"midipix")
fbda3a
			&& strcmp(host->flavor,"mingw")) {
fbda3a
		host->mdso = "";
fbda3a
		cfgmeta->mdso = "not applicable";
fbda3a
fbda3a
	} else {
fbda3a
		if (!(drvhost->mdso = calloc(1,toollen)))
fbda3a
			return -1;
fbda3a
fbda3a
		if (fnative) {
fbda3a
			strcpy(drvhost->mdso,"mdso");
fbda3a
			cfgmeta->mdso = cfgnative;
fbda3a
		} else {
fbda3a
			sprintf(drvhost->mdso,"%s-mdso",host->host);
fbda3a
			cfgmeta->mdso = cfghost;
fbda3a
		}
fbda3a
fbda3a
		host->mdso = drvhost->mdso;
fbda3a
	}
fbda3a
46ea99
	return 0;
46ea99
}
46ea99
52556c
static void slbt_free_host_params(struct slbt_host_strs * host)
52556c
{
c67e64
	if (host->machine)
c67e64
		free(host->machine);
c67e64
52556c
	if (host->host)
52556c
		free(host->host);
52556c
52556c
	if (host->flavor)
52556c
		free(host->flavor);
52556c
52556c
	if (host->ar)
52556c
		free(host->ar);
52556c
52556c
	if (host->ranlib)
52556c
		free(host->ranlib);
52556c
9a02e2
	if (host->windres)
9a02e2
		free(host->windres);
9a02e2
52556c
	if (host->dlltool)
52556c
		free(host->dlltool);
a313a4
fbda3a
	if (host->mdso)
fbda3a
		free(host->mdso);
fbda3a
a313a4
	memset(host,0,sizeof(*host));
52556c
}
52556c
0b68ad
static void slbt_init_flavor_settings(
0b68ad
	struct slbt_common_ctx *	cctx,
1f442f
	const struct slbt_host_params * ahost,
0b68ad
	struct slbt_flavor_settings *	psettings)
a66d34
{
1f442f
	const struct slbt_host_params *     host;
a66d34
	const struct slbt_flavor_settings * settings;
a66d34
1f442f
	host = ahost ? ahost : &cctx->host;
1f442f
1f442f
	if (!strcmp(host->flavor,"midipix"))
a66d34
		settings = &host_flavor_midipix;
1f442f
	else if (!strcmp(host->flavor,"mingw"))
a66d34
		settings = &host_flavor_mingw;
1f442f
	else if (!strcmp(host->flavor,"cygwin"))
a66d34
		settings = &host_flavor_cygwin;
1f442f
	else if (!strcmp(host->flavor,"darwin"))
a66d34
		settings = &host_flavor_darwin;
a66d34
	else
a66d34
		settings = &host_flavor_default;
a66d34
1f442f
	if (!ahost) {
1f442f
		if (!strcmp(settings->imagefmt,"elf"))
1f442f
			cctx->drvflags |= SLBT_DRIVER_IMAGE_ELF;
1f442f
		else if (!strcmp(settings->imagefmt,"pe"))
1f442f
			cctx->drvflags |= SLBT_DRIVER_IMAGE_PE;
1f442f
		else if (!strcmp(settings->imagefmt,"macho"))
1573d0
			cctx->drvflags |= SLBT_DRIVER_IMAGE_MACHO;
1f442f
	}
bcd5af
0b68ad
	memcpy(psettings,settings,sizeof(*settings));
bfa8ca
bfa8ca
	if (cctx->shrext)
eecdab
		psettings->dsosuffix = cctx->shrext;
a66d34
}
a66d34
af7db9
static int slbt_init_ldrpath(
af7db9
	struct slbt_common_ctx *  cctx,
af7db9
	struct slbt_host_params * host)
af7db9
{
af7db9
	char *         buf;
af7db9
	const char **  ldrpath;
af7db9
af7db9
	if (!cctx->rpath || !(cctx->drvflags & SLBT_DRIVER_IMAGE_ELF)) {
af7db9
		host->ldrpath = 0;
af7db9
		return 0;
af7db9
	}
af7db9
af7db9
	/* common? */
af7db9
	for (ldrpath=ldrpath_elf; *ldrpath; ldrpath ++)
af7db9
		if (!(strcmp(cctx->rpath,*ldrpath))) {
af7db9
			host->ldrpath = 0;
af7db9
			return 0;
af7db9
		}
af7db9
af7db9
	/* buf */
af7db9
	if (!(buf = malloc(12 + strlen(cctx->host.host))))
af7db9
		return -1;
af7db9
af7db9
	/* /usr/{host}/lib */
af7db9
	sprintf(buf,"/usr/%s/lib",cctx->host.host);
af7db9
af7db9
	if (!(strcmp(cctx->rpath,buf))) {
af7db9
		host->ldrpath = 0;
af7db9
		free(buf);
af7db9
		return 0;
af7db9
	}
af7db9
af7db9
	/* /usr/{host}/lib64 */
af7db9
	sprintf(buf,"/usr/%s/lib64",cctx->host.host);
af7db9
af7db9
	if (!(strcmp(cctx->rpath,buf))) {
af7db9
		host->ldrpath = 0;
af7db9
		free(buf);
af7db9
		return 0;
af7db9
	}
af7db9
af7db9
	host->ldrpath = cctx->rpath;
af7db9
af7db9
	free(buf);
af7db9
	return 0;
af7db9
}
af7db9
5a9161
static int slbt_init_version_info(
5a9161
	struct slbt_driver_ctx_impl *	ictx,
5a9161
	struct slbt_version_info *	verinfo)
5a9161
{
5a9161
	int	current;
5a9161
	int	revision;
5a9161
	int	age;
5a9161
dcb453
	if (!verinfo->verinfo && !verinfo->vernumber)
dcb453
		return 0;
dcb453
cd3d41
	if (verinfo->vernumber) {
cd3d41
		sscanf(verinfo->vernumber,"%d:%d:%d",
cd3d41
			&verinfo->major,
cd3d41
			&verinfo->minor,
cd3d41
			&verinfo->revision);
cd3d41
		return 0;
cd3d41
	}
cd3d41
f22545
	current = revision = age = 0;
f22545
5a9161
	sscanf(verinfo->verinfo,"%d:%d:%d",
5a9161
		&current,&revision,&age;;
5a9161
5a9161
	if (current < age) {
5a9161
		if (ictx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
a82cc2
			slbt_dprintf(ictx->fdctx.fderr,
5a9161
				"%s: error: invalid version info: "
5a9161
				"<current> may not be smaller than <age>.\n",
5a9161
				argv_program_name(ictx->cctx.targv[0]));
5a9161
		return -1;
5a9161
	}
5a9161
5a9161
	verinfo->major    = current - age;
5a9161
	verinfo->minor    = age;
5a9161
	verinfo->revision = revision;
5a9161
5a9161
	return 0;
5a9161
}
5a9161
f8e27e
static int slbt_init_link_params(struct slbt_driver_ctx_impl * ctx)
f8e27e
{
f8e27e
	const char * program;
f8e27e
	const char * libname;
f8e27e
	const char * prefix;
965661
	const char * base;
f8e27e
	char *       dot;
a943fc
	bool         fmodule;
a82cc2
	int          fderr;
f8e27e
a82cc2
	fderr   = ctx->fdctx.fderr;
f8e27e
	program = argv_program_name(ctx->cctx.targv[0]);
f8e27e
	libname = 0;
146916
	prefix  = 0;
a943fc
	fmodule = false;
f8e27e
f8e27e
	/* output */
f8e27e
	if (!(ctx->cctx.output)) {
f8e27e
		if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
a82cc2
			slbt_dprintf(fderr,
f8e27e
				"%s: error: output file must be "
f8e27e
				"specified in link mode.\n",
f8e27e
				program);
f8e27e
		return -1;
f8e27e
	}
f8e27e
f8e27e
	/* executable? */
f8e27e
	if (!(dot = strrchr(ctx->cctx.output,'.')))
712060
		if (!(ctx->cctx.drvflags & SLBT_DRIVER_MODULE))
712060
			return 0;
f8e27e
f8e27e
	/* todo: archive? library? wrapper? inlined function, avoid repetition */
965661
	if ((base = strrchr(ctx->cctx.output,'/')))
965661
		base++;
965661
	else
965661
		base = ctx->cctx.output;
f8e27e
f8e27e
	/* archive? */
712060
	if (dot && !strcmp(dot,ctx->cctx.settings.arsuffix)) {
f8e27e
		prefix = ctx->cctx.settings.arprefix;
f8e27e
965661
		if (!strncmp(prefix,base,strlen(prefix)))
4f7984
			libname = base;
f8e27e
		else {
f8e27e
			if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
a82cc2
				slbt_dprintf(fderr,
f8e27e
					"%s: error: output file prefix does "
f8e27e
					"not match its (archive) suffix; "
f8e27e
					"the expected prefix was '%s'\n",
f8e27e
					program,prefix);
f8e27e
			return -1;
f8e27e
		}
f8e27e
	}
f8e27e
f8e27e
	/* library? */
712060
	else if (dot && !strcmp(dot,ctx->cctx.settings.dsosuffix)) {
f8e27e
		prefix = ctx->cctx.settings.dsoprefix;
f8e27e
712060
		if (!strncmp(prefix,base,strlen(prefix))) {
4f7984
			libname = base;
712060
712060
		} else if (ctx->cctx.drvflags & SLBT_DRIVER_MODULE) {
712060
			libname = base;
712060
			fmodule = true;
712060
712060
		} else {
f8e27e
			if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
a82cc2
				slbt_dprintf(fderr,
f8e27e
					"%s: error: output file prefix does "
f8e27e
					"not match its (shared library) suffix; "
f8e27e
					"the expected prefix was '%s'\n",
f8e27e
					program,prefix);
f8e27e
			return -1;
f8e27e
		}
f8e27e
	}
f8e27e
f8e27e
	/* wrapper? */
712060
	else if (dot && !strcmp(dot,".la")) {
f8e27e
		prefix = ctx->cctx.settings.dsoprefix;
f8e27e
f9dfdb
		if (!strncmp(prefix,base,strlen(prefix))) {
4f7984
			libname = base;
f9dfdb
			fmodule = !!(ctx->cctx.drvflags & SLBT_DRIVER_MODULE);
f9dfdb
		} else if (ctx->cctx.drvflags & SLBT_DRIVER_MODULE) {
a943fc
			libname = base;
a943fc
			fmodule = true;
a943fc
		} else {
f8e27e
			if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
a82cc2
				slbt_dprintf(fderr,
f8e27e
					"%s: error: output file prefix does "
f8e27e
					"not match its (libtool wrapper) suffix; "
f8e27e
					"the expected prefix was '%s'\n",
f8e27e
					program,prefix);
f8e27e
			return -1;
f8e27e
		}
82142f
	} else
f8e27e
		return 0;
f8e27e
f8e27e
	/* libname alloc */
a943fc
	if (!fmodule)
a943fc
		libname += strlen(prefix);
a943fc
a943fc
	if (!(ctx->libname = strdup(libname)))
f8e27e
		return -1;
f8e27e
712060
	if ((dot  = strrchr(ctx->libname,'.')))
712060
		*dot = 0;
f8e27e
f8e27e
	ctx->cctx.libname = ctx->libname;
f8e27e
f8e27e
	return 0;
f8e27e
}
f8e27e
b54f55
static int slbt_driver_fail_incompatible_args(
89f5ab
	int				fderr,
89f5ab
	uint64_t			drvflags,
89f5ab
	struct argv_meta *		meta,
89f5ab
	const char *			program,
89f5ab
	const char *			afirst,
89f5ab
	const char *			asecond)
89f5ab
{
89f5ab
	int fcolor;
89f5ab
d4c3e3
	fcolor = (drvflags & SLBT_DRIVER_ANNOTATE_NEVER)
d4c3e3
		? 0 : isatty(fderr);
d4c3e3
89f5ab
	if (drvflags & SLBT_DRIVER_VERBOSITY_ERRORS){
d4c3e3
		if (fcolor)
89f5ab
			slbt_dprintf(
89f5ab
				fderr,"%s%s",
89f5ab
				aclr_bold,aclr_red);
89f5ab
89f5ab
		slbt_dprintf(fderr,
89f5ab
			"%s: error: incompatible arguments: "
89f5ab
			"at the most one of %s and %s "
89f5ab
			"may be used.\n",
89f5ab
			program,afirst,asecond);
89f5ab
89f5ab
		if (fcolor)
89f5ab
			slbt_dprintf(
89f5ab
				fderr,"%s",
89f5ab
				aclr_reset);
89f5ab
	}
89f5ab
89f5ab
	return slbt_get_driver_ctx_fail(0,meta);
89f5ab
}
89f5ab
9ca8c4
int slbt_get_driver_ctx(
9ca8c4
	char **				argv,
9ca8c4
	char **				envp,
9ca8c4
	uint32_t			flags,
a82cc2
	const struct slbt_fd_ctx *	fdctx,
9ca8c4
	struct slbt_driver_ctx **	pctx)
9ca8c4
{
56cab3
	struct slbt_split_vector	sargv;
9ca8c4
	struct slbt_driver_ctx_impl *	ctx;
9ca8c4
	struct slbt_common_ctx		cctx;
d58d2f
	const struct argv_option *	optv[SLBT_OPTV_ELEMENTS];
9ca8c4
	struct argv_meta *		meta;
9ca8c4
	struct argv_entry *		entry;
89f5ab
	struct argv_entry *		cmdstatic;
89f5ab
	struct argv_entry *		cmdshared;
89f5ab
	struct argv_entry *		cmdnostatic;
89f5ab
	struct argv_entry *		cmdnoshared;
9ca8c4
	const char *			program;
499a71
	const char *			lconf;
499a71
	uint64_t			lflags;
9ca8c4
d58d2f
	argv_optv_init(slbt_default_options,optv);
9ca8c4
358030
	if (!fdctx)
358030
		fdctx = &slbt_default_fdctx;
a82cc2
0cbb20
	sargv.dargs = 0;
0cbb20
	sargv.dargv = 0;
0cbb20
	sargv.targv = 0;
0cbb20
	sargv.cargv = 0;
0cbb20
a82cc2
	if (slbt_split_argv(argv,flags,&sargv,fdctx->fderr))
0cbb20
		return slbt_free_argv_buffer(&sargv);
56cab3
93f9e4
	if (!(meta = argv_get(
93f9e4
			sargv.targv,optv,
0cbb20
			slbt_argv_flags(flags),
a82cc2
			fdctx->fderr)))
0cbb20
		return slbt_free_argv_buffer(&sargv);
9ca8c4
499a71
	lconf   = 0;
9ca8c4
	program = argv_program_name(argv[0]);
499a71
9ca8c4
	memset(&cctx,0,sizeof(cctx));
9ca8c4
341c87
	/* shared and static objects: enable by default, disable by ~switch */
340eda
	cctx.drvflags = flags | SLBT_DRIVER_SHARED | SLBT_DRIVER_STATIC;
341c87
2bc175
	/* full annotation when annotation is on; */
d4c3e3
	if (!(cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER))
d4c3e3
		cctx.drvflags |= SLBT_DRIVER_ANNOTATE_FULL;
2bc175
89f5ab
	/* track incompatible command-line arguments */
89f5ab
	cmdstatic   = 0;
89f5ab
	cmdshared   = 0;
89f5ab
	cmdnostatic = 0;
89f5ab
	cmdnoshared = 0;
89f5ab
1379f7
	/* get options */
9ca8c4
	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
9ca8c4
		if (entry->fopt) {
9ca8c4
			switch (entry->tag) {
9ca8c4
				case TAG_HELP:
949677
				case TAG_HELP_ALL:
50a552
					return (flags & SLBT_DRIVER_VERBOSITY_USAGE)
50a552
						? slbt_driver_usage(
a82cc2
							fdctx->fdout,program,
0cbb20
							entry->arg,optv,
d4c3e3
							meta,&sargv,
d4c3e3
							(cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER))
50a552
						: SLBT_USAGE;
9ca8c4
9ca8c4
				case TAG_VERSION:
9ca8c4
					cctx.drvflags |= SLBT_DRIVER_VERSION;
9ca8c4
					break;
667ce2
499a71
				case TAG_HEURISTICS:
499a71
					cctx.drvflags |= SLBT_DRIVER_HEURISTICS;
499a71
					lconf = entry->arg;
499a71
					break;
499a71
667ce2
				case TAG_MODE:
667ce2
					if (!strcmp("clean",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_CLEAN;
667ce2
667ce2
					else if (!strcmp("compile",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_COMPILE;
667ce2
667ce2
					else if (!strcmp("execute",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_EXECUTE;
667ce2
667ce2
					else if (!strcmp("finish",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_FINISH;
667ce2
667ce2
					else if (!strcmp("install",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_INSTALL;
667ce2
667ce2
					else if (!strcmp("link",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_LINK;
667ce2
667ce2
					else if (!strcmp("uninstall",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_UNINSTALL;
667ce2
					break;
071d14
b9575f
				case TAG_FINISH:
b9575f
					cctx.mode = SLBT_MODE_FINISH;
b9575f
					break;
b9575f
071d14
				case TAG_DRY_RUN:
071d14
					cctx.drvflags |= SLBT_DRIVER_DRY_RUN;
071d14
					break;
53f4ec
53f4ec
				case TAG_TAG:
53f4ec
					if (!strcmp("CC",entry->arg))
53f4ec
						cctx.tag = SLBT_TAG_CC;
53f4ec
53f4ec
					else if (!strcmp("CXX",entry->arg))
53f4ec
						cctx.tag = SLBT_TAG_CXX;
62b4bb
6e6b0f
					else if (!strcmp("FC",entry->arg))
6e6b0f
						cctx.tag = SLBT_TAG_FC;
6e6b0f
1bd7a3
					else if (!strcmp("F77",entry->arg))
1bd7a3
						cctx.tag = SLBT_TAG_F77;
1bd7a3
62b4bb
					else if (!strcmp("NASM",entry->arg))
62b4bb
						cctx.tag = SLBT_TAG_NASM;
0e609b
4127b5
					else if (!strcmp("RC",entry->arg))
4127b5
						cctx.tag = SLBT_TAG_RC;
4127b5
0e609b
					else if (!strcmp("disable-static",entry->arg))
89f5ab
						cmdnostatic = entry;
f5fa4c
f5fa4c
					else if (!strcmp("disable-shared",entry->arg))
89f5ab
						cmdnoshared = entry;
53f4ec
					break;
173b54
173b54
				case TAG_CONFIG:
173b54
					cctx.drvflags |= SLBT_DRIVER_CONFIG;
173b54
					break;
173b54
fea1b8
				case TAG_DEBUG:
fea1b8
					cctx.drvflags |= SLBT_DRIVER_DEBUG;
fea1b8
					break;
d03fbc
d03fbc
				case TAG_FEATURES:
d03fbc
					cctx.drvflags |= SLBT_DRIVER_FEATURES;
d03fbc
					break;
6376f0
0a9bff
				case TAG_LEGABITS:
0a9bff
					if (!entry->arg)
0a9bff
						cctx.drvflags |= SLBT_DRIVER_LEGABITS;
0a9bff
0a9bff
					else if (!strcmp("enabled",entry->arg))
0a9bff
						cctx.drvflags |= SLBT_DRIVER_LEGABITS;
0a9bff
0a9bff
					else
0a9bff
						cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_LEGABITS;
0a9bff
614d85
					break;
614d85
34988f
				case TAG_CCWRAP:
34988f
					cctx.ccwrap = entry->arg;
34988f
					break;
34988f
fbda3a
				case TAG_IMPLIB:
fbda3a
					if (!strcmp("idata",entry->arg)) {
fbda3a
						cctx.drvflags |= SLBT_DRIVER_IMPLIB_IDATA;
fbda3a
						cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_IMPLIB_DSOMETA;
fbda3a
fbda3a
					} else if (!strcmp("never",entry->arg)) {
fbda3a
						cctx.drvflags |= SLBT_DRIVER_IMPLIB_DSOMETA;
fbda3a
						cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_IMPLIB_IDATA;
fbda3a
					}
fbda3a
fbda3a
					break;
fbda3a
6376f0
				case TAG_WARNINGS:
6376f0
					if (!strcmp("all",entry->arg))
1142bf
						cctx.warnings = SLBT_WARNING_LEVEL_ALL;
6376f0
6376f0
					else if (!strcmp("error",entry->arg))
1142bf
						cctx.warnings = SLBT_WARNING_LEVEL_ERROR;
6376f0
6376f0
					else if (!strcmp("none",entry->arg))
1142bf
						cctx.warnings = SLBT_WARNING_LEVEL_NONE;
6376f0
					break;
40fabb
2bc175
				case TAG_ANNOTATE:
2bc175
					if (!strcmp("always",entry->arg)) {
2bc175
						cctx.drvflags |= SLBT_DRIVER_ANNOTATE_ALWAYS;
2bc175
						cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_ANNOTATE_NEVER;
2bc175
2bc175
					} else if (!strcmp("never",entry->arg)) {
2bc175
						cctx.drvflags |= SLBT_DRIVER_ANNOTATE_NEVER;
2bc175
						cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_ANNOTATE_ALWAYS;
2bc175
2bc175
					} else if (!strcmp("minimal",entry->arg)) {
2bc175
						cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_ANNOTATE_FULL;
2bc175
2bc175
					} else if (!strcmp("full",entry->arg)) {
2bc175
						cctx.drvflags |= SLBT_DRIVER_ANNOTATE_FULL;
2bc175
					}
2bc175
2bc175
					break;
2bc175
40fabb
				case TAG_DEPS:
40fabb
					cctx.drvflags |= SLBT_DRIVER_DEPS;
40fabb
					break;
40fabb
398419
				case TAG_SILENT:
398419
					cctx.drvflags |= SLBT_DRIVER_SILENT;
398419
					break;
25956b
25956b
				case TAG_VERBOSE:
25956b
					cctx.drvflags |= SLBT_DRIVER_VERBOSE;
25956b
					break;
b83b64
db67ad
				case TAG_HOST:
db67ad
					cctx.host.host = entry->arg;
db67ad
					break;
db67ad
db67ad
				case TAG_FLAVOR:
db67ad
					cctx.host.flavor = entry->arg;
db67ad
					break;
db67ad
db67ad
				case TAG_AR:
db67ad
					cctx.host.ar = entry->arg;
db67ad
					break;
db67ad
db67ad
				case TAG_RANLIB:
db67ad
					cctx.host.ranlib = entry->arg;
db67ad
					break;
db67ad
9a02e2
				case TAG_WINDRES:
9a02e2
					cctx.host.windres = entry->arg;
9a02e2
					break;
9a02e2
db67ad
				case TAG_DLLTOOL:
db67ad
					cctx.host.dlltool = entry->arg;
db67ad
					break;
db67ad
fbda3a
				case TAG_MDSO:
fbda3a
					cctx.host.mdso = entry->arg;
fbda3a
					break;
fbda3a
b83b64
				case TAG_OUTPUT:
b83b64
					cctx.output = entry->arg;
b83b64
					break;
4f1b20
bfa8ca
				case TAG_SHREXT:
bfa8ca
					cctx.shrext = entry->arg;
bfa8ca
					break;
bfa8ca
9c664d
				case TAG_RPATH:
9c664d
					cctx.rpath = entry->arg;
9c664d
					break;
9c664d
17e18a
				case TAG_SYSROOT:
17e18a
					cctx.sysroot = entry->arg;
17e18a
					break;
17e18a
9aa1f4
				case TAG_RELEASE:
9aa1f4
					cctx.release = entry->arg;
9aa1f4
					break;
9aa1f4
05ca7e
				case TAG_DLOPEN:
05ca7e
					break;
05ca7e
56f236
				case TAG_STATIC_LIBTOOL_LIBS:
56f236
					cctx.drvflags |= SLBT_DRIVER_STATIC_LIBTOOL_LIBS;
56f236
					break;
56f236
916050
				case TAG_EXPORT_DYNAMIC:
916050
					cctx.drvflags |= SLBT_DRIVER_EXPORT_DYNAMIC;
916050
					break;
916050
873ecb
				case TAG_EXPSYM_FILE:
873ecb
					cctx.symfile = entry->arg;
873ecb
					break;
873ecb
73ca78
				case TAG_EXPSYM_REGEX:
73ca78
					cctx.regex = entry->arg;
73ca78
					break;
73ca78
5a9161
				case TAG_VERSION_INFO:
5a9161
					cctx.verinfo.verinfo = entry->arg;
5a9161
					break;
5a9161
cd3d41
				case TAG_VERSION_NUMBER:
cd3d41
					cctx.verinfo.vernumber = entry->arg;
cd3d41
					break;
cd3d41
4df790
				case TAG_TARGET:
4df790
					cctx.target = entry->arg;
4df790
					break;
4df790
4f1b20
				case TAG_PREFER_PIC:
4f1b20
					cctx.drvflags |= SLBT_DRIVER_PRO_PIC;
4f1b20
					break;
4f1b20
4f1b20
				case TAG_PREFER_NON_PIC:
4f1b20
					cctx.drvflags |= SLBT_DRIVER_ANTI_PIC;
4f1b20
					break;
9c25c7
93b62c
				case TAG_NO_UNDEFINED:
93b62c
					cctx.drvflags |= SLBT_DRIVER_NO_UNDEFINED;
93b62c
					break;
93b62c
a943fc
				case TAG_MODULE:
a943fc
					cctx.drvflags |= SLBT_DRIVER_MODULE;
a943fc
					break;
a943fc
f7645c
				case TAG_ALL_STATIC:
f7645c
					cctx.drvflags |= SLBT_DRIVER_ALL_STATIC;
f7645c
					break;
f7645c
0e609b
				case TAG_DISABLE_STATIC:
89f5ab
					cmdnostatic = entry;
0e609b
					break;
0e609b
f5fa4c
				case TAG_DISABLE_SHARED:
89f5ab
					cmdnoshared = entry;
f5fa4c
					break;
f5fa4c
68f313
				case TAG_AVOID_VERSION:
68f313
					cctx.drvflags |= SLBT_DRIVER_AVOID_VERSION;
68f313
					break;
68f313
9c25c7
				case TAG_SHARED:
89f5ab
					cmdshared = entry;
9c25c7
					break;
9c25c7
9c25c7
				case TAG_STATIC:
89f5ab
					cmdstatic = entry;
9c25c7
					break;
9ca8c4
			}
1379f7
		}
9ca8c4
	}
9ca8c4
89f5ab
	/* incompatible command-line arguments? */
89f5ab
	if (cmdstatic && cmdshared)
89f5ab
		return slbt_driver_fail_incompatible_args(
89f5ab
			fdctx->fderr,
89f5ab
			cctx.drvflags,
89f5ab
			meta,program,
89f5ab
			"-static",
89f5ab
			"-shared");
89f5ab
89f5ab
	if (cmdstatic && cmdnostatic)
89f5ab
		return slbt_driver_fail_incompatible_args(
89f5ab
			fdctx->fderr,
89f5ab
			cctx.drvflags,
89f5ab
			meta,program,
89f5ab
			"-static",
89f5ab
			"--disable-static");
89f5ab
89f5ab
	if (cmdshared && cmdnoshared)
89f5ab
		return slbt_driver_fail_incompatible_args(
89f5ab
			fdctx->fderr,
89f5ab
			cctx.drvflags,
89f5ab
			meta,program,
89f5ab
			"-shared",
89f5ab
			"--disable-shared");
89f5ab
89f5ab
	if (cmdnostatic && cmdnoshared)
89f5ab
		return slbt_driver_fail_incompatible_args(
89f5ab
			fdctx->fderr,
89f5ab
			cctx.drvflags,
89f5ab
			meta,program,
89f5ab
			"--disable-static",
89f5ab
			"--disable-shared");
89f5ab
89f5ab
	/* -static? */
89f5ab
	if (cmdstatic) {
89f5ab
		cctx.drvflags |= SLBT_DRIVER_STATIC;
89f5ab
		cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED;
89f5ab
		cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC;
89f5ab
	}
89f5ab
89f5ab
	/* shared? */
89f5ab
	if (cmdshared) {
89f5ab
		cctx.drvflags |= SLBT_DRIVER_SHARED;
89f5ab
		cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC;
89f5ab
		cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_SHARED;
89f5ab
	}
89f5ab
005b65
	/* -disable-static? */
89f5ab
	if (cmdnostatic) {
89f5ab
		cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC;
005b65
		cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_STATIC;
89f5ab
	}
005b65
005b65
	/* -disable-shared? */
89f5ab
	if (cmdnoshared) {
89f5ab
		cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED;
005b65
		cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_SHARED;
89f5ab
	}
005b65
caf7d0
	/* debug: raw argument vector */
caf7d0
	if (cctx.drvflags & SLBT_DRIVER_DEBUG)
d4c3e3
		slbt_output_raw_vector(
d4c3e3
			fdctx->fderr,argv,envp,
d4c3e3
			(cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER)
d4c3e3
				? 0 : isatty(fdctx->fderr));
caf7d0
9b5eec
	/* -o in install mode means USER */
9b5eec
	if ((cctx.mode == SLBT_MODE_INSTALL) && cctx.output) {
9b5eec
		cctx.user   = cctx.output;
9b5eec
		cctx.output = 0;
9b5eec
	}
9b5eec
3c1679
	/* info mode */
3c1679
	if (cctx.drvflags & (SLBT_DRIVER_CONFIG | SLBT_DRIVER_FEATURES))
3c1679
		cctx.mode = SLBT_MODE_INFO;
3c1679
a9abe3
	/* --tag */
a9abe3
	if (cctx.mode == SLBT_MODE_COMPILE)
a9abe3
		if (cctx.tag == SLBT_TAG_UNKNOWN)
a9abe3
			cctx.tag = SLBT_TAG_CC;
a9abe3
c778cc
	/* driver context */
684b80
	if (!(ctx = slbt_driver_ctx_alloc(meta,fdctx,&cctx,&sargv,envp)))
38b351
		return slbt_get_driver_ctx_fail(0,meta);
38b351
38b351
	/* ctx */
38b351
	ctx->ctx.program	= program;
38b351
	ctx->ctx.cctx		= &ctx->cctx;
38b351
38b351
	ctx->cctx.targv		= sargv.targv;
38b351
	ctx->cctx.cargv		= sargv.cargv;
9ca8c4
499a71
	/* heuristics */
499a71
	if (cctx.drvflags & SLBT_DRIVER_HEURISTICS) {
38b351
		if (slbt_get_lconf_flags(&ctx->ctx,lconf,&lflags) < 0)
38b351
			return slbt_get_driver_ctx_fail(&ctx->ctx,0);
499a71
9582b2
		if (cmdnoshared)
9582b2
			lflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC;
9582b2
c9788a
		if (cmdnostatic)
c9788a
			if (lflags & SLBT_DRIVER_DISABLE_SHARED)
c9788a
				cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC;
c9788a
499a71
		cctx.drvflags |= lflags;
499a71
		cctx.drvflags |= SLBT_DRIVER_SHARED;
499a71
		cctx.drvflags |= SLBT_DRIVER_STATIC;
499a71
89f5ab
		if (cmdstatic) {
89f5ab
			cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED;
89f5ab
			cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC;
89f5ab
		}
89f5ab
89f5ab
		if (cmdshared) {
89f5ab
			cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC;
89f5ab
			cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_SHARED;
89f5ab
		}
89f5ab
499a71
		/* -disable-static? */
499a71
		if (cctx.drvflags & SLBT_DRIVER_DISABLE_STATIC)
499a71
			cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_STATIC;
499a71
499a71
		/* -disable-shared? */
499a71
		if (cctx.drvflags & SLBT_DRIVER_DISABLE_SHARED)
499a71
			cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_SHARED;
499a71
499a71
		ctx->cctx.drvflags = cctx.drvflags;
499a71
	}
499a71
46ea99
	/* host params */
11e277
	if (slbt_init_host_params(
11e277
			&ctx->ctx,
11e277
			&ctx->cctx,
11e277
			&ctx->host,
11e277
			&ctx->cctx.host,
38b351
			&ctx->cctx.cfgmeta))
38b351
		return slbt_get_driver_ctx_fail(&ctx->ctx,0);
46ea99
11e277
	/* flavor settings */
11e277
	slbt_init_flavor_settings(
11e277
		&ctx->cctx,0,
11e277
		&ctx->cctx.settings);
11e277
af7db9
	/* ldpath */
38b351
	if (slbt_init_ldrpath(&ctx->cctx,&ctx->cctx.host))
38b351
		return slbt_get_driver_ctx_fail(&ctx->ctx,0);
af7db9
5a9161
	/* version info */
38b351
	if (slbt_init_version_info(ctx,&ctx->cctx.verinfo))
38b351
		return slbt_get_driver_ctx_fail(&ctx->ctx,0);
5a9161
f8e27e
	/* link params */
f8e27e
	if (cctx.mode == SLBT_MODE_LINK)
38b351
		if (slbt_init_link_params(ctx))
38b351
			return slbt_get_driver_ctx_fail(&ctx->ctx,0);
f8e27e
9ca8c4
	*pctx = &ctx->ctx;
38b351
38b351
	return 0;
9ca8c4
}
9ca8c4
9ca8c4
static void slbt_free_driver_ctx_impl(struct slbt_driver_ctx_alloc * ictx)
9ca8c4
{
6beda1
	struct slbt_error_info ** perr;
6beda1
	struct slbt_error_info *  erri;
6beda1
6beda1
	for (perr=ictx->ctx.errinfp; *perr; perr++) {
6beda1
		erri = *perr;
6beda1
6beda1
		if (erri->eany && (erri->esyscode == ENOENT))
6beda1
			free(erri->eany);
6beda1
	}
6beda1
6beda1
f8e27e
	if (ictx->ctx.libname)
f8e27e
		free(ictx->ctx.libname);
f8e27e
0cbb20
	free(ictx->ctx.dargs);
0cbb20
	free(ictx->ctx.dargv);
0cbb20
	free(ictx->ctx.targv);
0cbb20
52556c
	slbt_free_host_params(&ictx->ctx.host);
77b97b
	slbt_free_host_params(&ictx->ctx.ahost);
9ca8c4
	argv_free(ictx->meta);
9ca8c4
	free(ictx);
9ca8c4
}
9ca8c4
9ca8c4
void slbt_free_driver_ctx(struct slbt_driver_ctx * ctx)
9ca8c4
{
9ca8c4
	struct slbt_driver_ctx_alloc *	ictx;
9ca8c4
	uintptr_t			addr;
9ca8c4
9ca8c4
	if (ctx) {
a13661
		addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_impl,ctx);
a13661
		addr = addr - offsetof(struct slbt_driver_ctx_alloc,ctx);
9ca8c4
		ictx = (struct slbt_driver_ctx_alloc *)addr;
9ca8c4
		slbt_free_driver_ctx_impl(ictx);
9ca8c4
	}
9ca8c4
}
a313a4
a313a4
void slbt_reset_alternate_host(const struct slbt_driver_ctx * ctx)
a313a4
{
a313a4
	struct slbt_driver_ctx_alloc *	ictx;
a313a4
	uintptr_t			addr;
a313a4
a313a4
	addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_alloc,ctx);
a313a4
	addr = addr - offsetof(struct slbt_driver_ctx_impl,ctx);
a313a4
	ictx = (struct slbt_driver_ctx_alloc *)addr;
a313a4
a313a4
	slbt_free_host_params(&ictx->ctx.ahost);
a313a4
}
a313a4
a313a4
int  slbt_set_alternate_host(
a313a4
	const struct slbt_driver_ctx *	ctx,
a313a4
	const char *			host,
a313a4
	const char *			flavor)
a313a4
{
a313a4
	struct slbt_driver_ctx_alloc *	ictx;
a313a4
	uintptr_t			addr;
a313a4
a313a4
	addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_alloc,ctx);
a313a4
	addr = addr - offsetof(struct slbt_driver_ctx_impl,ctx);
a313a4
	ictx = (struct slbt_driver_ctx_alloc *)addr;
a313a4
	slbt_free_host_params(&ictx->ctx.ahost);
a313a4
a313a4
	if (!(ictx->ctx.ahost.host = strdup(host)))
6beda1
		return SLBT_SYSTEM_ERROR(ctx,0);
a313a4
a313a4
	if (!(ictx->ctx.ahost.flavor = strdup(flavor))) {
a313a4
		slbt_free_host_params(&ictx->ctx.ahost);
6beda1
		return SLBT_SYSTEM_ERROR(ctx,0);
a313a4
	}
a313a4
a313a4
	ictx->ctx.cctx.ahost.host   = ictx->ctx.ahost.host;
a313a4
	ictx->ctx.cctx.ahost.flavor = ictx->ctx.ahost.flavor;
a313a4
a313a4
	if (slbt_init_host_params(
56f2d4
			0,
a313a4
			ctx->cctx,
a313a4
			&ictx->ctx.ahost,
a313a4
			&ictx->ctx.cctx.ahost,
a313a4
			&ictx->ctx.cctx.acfgmeta)) {
a313a4
		slbt_free_host_params(&ictx->ctx.ahost);
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(ctx,SLBT_ERR_HOST_INIT);
a313a4
	}
a313a4
a313a4
	slbt_init_flavor_settings(
a313a4
		&ictx->ctx.cctx,
a313a4
		&ictx->ctx.cctx.ahost,
a313a4
		&ictx->ctx.cctx.asettings);
a313a4
af7db9
	if (slbt_init_ldrpath(
af7db9
			&ictx->ctx.cctx,
af7db9
			&ictx->ctx.cctx.ahost)) {
af7db9
		slbt_free_host_params(&ictx->ctx.ahost);
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(ctx,SLBT_ERR_LDRPATH_INIT);
af7db9
	}
af7db9
a313a4
	return 0;
a313a4
}
9f24d2
1f2c01
int slbt_get_flavor_settings(
1f2c01
	const char *                            flavor,
1f2c01
	const struct slbt_flavor_settings **    settings)
1f2c01
{
1f2c01
	if (!strcmp(flavor,"midipix"))
1f2c01
		*settings = &host_flavor_midipix;
1f2c01
	else if (!strcmp(flavor,"mingw"))
1f2c01
		*settings = &host_flavor_mingw;
1f2c01
	else if (!strcmp(flavor,"cygwin"))
1f2c01
		*settings = &host_flavor_cygwin;
1f2c01
	else if (!strcmp(flavor,"darwin"))
1f2c01
		*settings = &host_flavor_darwin;
1f2c01
	else if (!strcmp(flavor,"default"))
1f2c01
		*settings = &host_flavor_default;
1f2c01
	else
1f2c01
		*settings = 0;
1f2c01
1f2c01
	return *settings ? 0 : -1;
1f2c01
}
1f2c01
9f24d2
const struct slbt_source_version * slbt_source_version(void)
9f24d2
{
9f24d2
	return &slbt_src_version;
9f24d2
}
a82cc2
a82cc2
int slbt_get_driver_fdctx(
a82cc2
	const struct slbt_driver_ctx *	dctx,
a82cc2
	struct slbt_fd_ctx *		fdctx)
a82cc2
{
a82cc2
	struct slbt_driver_ctx_impl *	ictx;
a82cc2
a82cc2
	ictx = slbt_get_driver_ictx(dctx);
a82cc2
a82cc2
	fdctx->fdin  = ictx->fdctx.fdin;
a82cc2
	fdctx->fdout = ictx->fdctx.fdout;
a82cc2
	fdctx->fderr = ictx->fdctx.fderr;
a82cc2
	fdctx->fdlog = ictx->fdctx.fdlog;
ca72f5
	fdctx->fdcwd = ictx->fdctx.fdcwd;
ca72f5
	fdctx->fddst = ictx->fdctx.fddst;
a82cc2
a82cc2
	return 0;
a82cc2
}
a82cc2
a82cc2
int slbt_set_driver_fdctx(
a82cc2
	struct slbt_driver_ctx *	dctx,
a82cc2
	const struct slbt_fd_ctx *	fdctx)
a82cc2
{
a82cc2
	struct slbt_driver_ctx_impl *	ictx;
a82cc2
a82cc2
	ictx = slbt_get_driver_ictx(dctx);
a82cc2
a82cc2
	ictx->fdctx.fdin  = fdctx->fdin;
a82cc2
	ictx->fdctx.fdout = fdctx->fdout;
a82cc2
	ictx->fdctx.fderr = fdctx->fderr;
a82cc2
	ictx->fdctx.fdlog = fdctx->fdlog;
ca72f5
	ictx->fdctx.fdcwd = fdctx->fdcwd;
ca72f5
	ictx->fdctx.fddst = fdctx->fddst;
a82cc2
a82cc2
	return 0;
a82cc2
}