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>
9ca8c4
#include <fcntl.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
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
a66d34
/* flavor settings */
11e277
#define SLBT_FLAVOR_SETTINGS(flavor,bfmt,pic,arp,ars,dsop,dsos,exep,exes,impp,imps,ldenv) \
a66d34
	static const struct slbt_flavor_settings flavor = {		   \
11e277
		bfmt,arp,ars,dsop,dsos,exep,exes,impp,imps,ldenv,pic}
a66d34
11e277
SLBT_FLAVOR_SETTINGS(host_flavor_default, "elf",  "-fPIC","lib",".a", "lib",".so",    "","",     "",   "",       "LD_LIBRARY_PATH");
11e277
SLBT_FLAVOR_SETTINGS(host_flavor_midipix, "pe",   "-fPIC","lib",".a", "lib",".so",    "","",     "lib",".lib.a", "PATH");
11e277
SLBT_FLAVOR_SETTINGS(host_flavor_mingw,   "pe",   0,      "lib",".a", "lib",".dll",   "",".exe", "lib",".dll.a", "PATH");
11e277
SLBT_FLAVOR_SETTINGS(host_flavor_cygwin,  "pe",   0,      "lib",".a", "lib",".dll",   "",".exe", "lib",".dll.a", "PATH");
11e277
SLBT_FLAVOR_SETTINGS(host_flavor_darwin,  "macho","-fPIC","lib",".a", "lib",".dylib", "","",     "",   "",       "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
a82cc2
static void slbt_output_raw_vector(int fderr, char ** argv, char ** envp)
caf7d0
{
caf7d0
	char **		parg;
caf7d0
	char *		dot;
caf7d0
	const char *	color;
caf7d0
	bool		fcolor;
caf7d0
d3ca02
	(void)envp;
d3ca02
a82cc2
	if ((fcolor = isatty(fderr)))
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,
0cbb20
	struct slbt_split_vector *	sargv)
9ca8c4
{
9ca8c4
	char header[512];
9ca8c4
9ca8c4
	snprintf(header,sizeof(header),
9ca8c4
		"Usage: %s [options] <file>...\n" "Options:\n",
9ca8c4
		program);
9ca8c4
a82cc2
	argv_usage(fdout,header,optv,arg);
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,
0cbb20
	struct slbt_split_vector *	sargv)
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;
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;
0cbb20
	char **				dargv;
56cab3
	char **				targv;
56cab3
	char **				cargv;
0cbb20
	char *				dst;
0cbb20
	bool				flast;
0cbb20
	bool				fcopy;
0cbb20
	size_t				size;
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;
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,
0cbb20
			0,optv,0,sargv);
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? */
23b101
	mode = config = finish = features = 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;
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
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
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;
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
0cbb20
	/* allocate split vectors */
56cab3
	if ((sargv->targv = calloc(2*(argc+1),sizeof(char *))))
56cab3
		sargv->cargv = sargv->targv + argc + 1;
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
56cab3
	/* split vectors: legacy mixture */
d58d2f
	for (optout=optv; optout[0]->tag != TAG_OUTPUT; optout++)
d58d2f
		(void)0;
56cab3
56cab3
	targv = sargv->targv + i;
56cab3
	cargv = sargv->cargv;
56cab3
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
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
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
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
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
{
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];
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;
46ea99
		} else {
46ea99
			sprintf(drvhost->ar,"%s-ar",host->host);
46ea99
			cfgmeta->ar = cfghost;
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;
c61b5b
	const char *                        dot;
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)
c61b5b
		psettings->dsosuffix = (dot = strrchr(cctx->shrext,'.'))
c61b5b
			? dot : 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,'.')))
f8e27e
		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? */
f8e27e
	if (!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? */
f8e27e
	else if (!strcmp(dot,ctx->cctx.settings.dsosuffix)) {
f8e27e
		prefix = ctx->cctx.settings.dsoprefix;
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 (shared library) suffix; "
f8e27e
					"the expected prefix was '%s'\n",
f8e27e
					program,prefix);
f8e27e
			return -1;
f8e27e
		}
f8e27e
	}
f8e27e
f8e27e
	/* wrapper? */
f8e27e
	else if (!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
f8e27e
	dot  = strrchr(ctx->libname,'.');
a87fd1
	*dot = 0;
f8e27e
f8e27e
	ctx->cctx.libname = ctx->libname;
f8e27e
f8e27e
	return 0;
f8e27e
}
f8e27e
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;
9ca8c4
	const char *			program;
499a71
	const char *			lconf;
499a71
	uint64_t			lflags;
9ca8c4
d58d2f
	argv_optv_init(slbt_default_options,optv);
9ca8c4
a82cc2
	if (!fdctx) {
a82cc2
		fdctx = &(const struct slbt_fd_ctx) {
a82cc2
			.fdin  = STDIN_FILENO,
a82cc2
			.fdout = STDOUT_FILENO,
a82cc2
			.fderr = STDERR_FILENO,
ca72f5
			.fdlog = (-1),
ca72f5
			.fdcwd = AT_FDCWD,
ca72f5
			.fddst = AT_FDCWD,
a82cc2
		};
a82cc2
	}
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; */
2bc175
	cctx.drvflags |= SLBT_DRIVER_ANNOTATE_FULL;
2bc175
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:
9ca8c4
					if (flags & SLBT_DRIVER_VERBOSITY_USAGE)
a82cc2
						return slbt_driver_usage(
a82cc2
							fdctx->fdout,program,
0cbb20
							entry->arg,optv,
0cbb20
							meta,&sargv);
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
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))
0e609b
						cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC;
f5fa4c
f5fa4c
					else if (!strcmp("disable-shared",entry->arg))
f5fa4c
						cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED;
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
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
9aa1f4
				case TAG_RELEASE:
9aa1f4
					cctx.release = entry->arg;
9aa1f4
					break;
9aa1f4
05ca7e
				case TAG_DLOPEN:
05ca7e
					break;
05ca7e
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:
0e609b
					cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC;
0e609b
					break;
0e609b
f5fa4c
				case TAG_DISABLE_SHARED:
f5fa4c
					cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED;
f5fa4c
					break;
f5fa4c
68f313
				case TAG_AVOID_VERSION:
68f313
					cctx.drvflags |= SLBT_DRIVER_AVOID_VERSION;
68f313
					break;
68f313
9c25c7
				case TAG_SHARED:
88e561
					cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC;
9c25c7
					break;
9c25c7
9c25c7
				case TAG_STATIC:
88e561
					cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED;
9c25c7
					break;
9ca8c4
			}
1379f7
		}
9ca8c4
	}
9ca8c4
005b65
	/* -disable-static? */
005b65
	if (cctx.drvflags & SLBT_DRIVER_DISABLE_STATIC)
005b65
		cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_STATIC;
005b65
005b65
	/* -disable-shared? */
005b65
	if (cctx.drvflags & SLBT_DRIVER_DISABLE_SHARED)
005b65
		cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_SHARED;
005b65
caf7d0
	/* debug: raw argument vector */
caf7d0
	if (cctx.drvflags & SLBT_DRIVER_DEBUG)
a82cc2
		slbt_output_raw_vector(fdctx->fderr,argv,envp);
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 */
0cbb20
	if (!(ctx = slbt_driver_ctx_alloc(meta,fdctx,&cctx,&sargv)))
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
499a71
		cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC;
499a71
		cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_SHARED;
499a71
499a71
		cctx.drvflags |= lflags;
499a71
		cctx.drvflags |= SLBT_DRIVER_SHARED;
499a71
		cctx.drvflags |= SLBT_DRIVER_STATIC;
499a71
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
{
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)))
8069c3
		return SLBT_SYSTEM_ERROR(ctx);
a313a4
a313a4
	if (!(ictx->ctx.ahost.flavor = strdup(flavor))) {
a313a4
		slbt_free_host_params(&ictx->ctx.ahost);
8069c3
		return SLBT_SYSTEM_ERROR(ctx);
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
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
}