orbea / cross / slibtool

Forked from cross/slibtool 3 years ago
Clone

Blame src/driver/slbt_driver_ctx.c

9ca8c4
/*******************************************************************/
9ca8c4
/*  slibtool: a skinny libtool implementation, written in C        */
9ca8c4
/*  Copyright (C) 2016  Z. Gilboa                                  */
9ca8c4
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
9ca8c4
/*******************************************************************/
9ca8c4
9ca8c4
#include <stdint.h>
9ca8c4
#include <unistd.h>
9ca8c4
#include <fcntl.h>
9ca8c4
9ca8c4
#define ARGV_DRIVER
9ca8c4
9ca8c4
#include <slibtool/slibtool.h>
9ca8c4
#include "slibtool_driver_impl.h"
9ca8c4
#include "argv/argv.h"
9ca8c4
5a9161
a66d34
/* flavor settings */
bcd5af
#define SLBT_FLAVOR_SETTINGS(flavor,bfmt,arp,ars,dsop,dsos,exep,exes,impp,imps,ldenv) \
a66d34
	static const struct slbt_flavor_settings flavor = {		   \
bcd5af
		bfmt,arp,ars,dsop,dsos,exep,exes,impp,imps,ldenv}
a66d34
bcd5af
SLBT_FLAVOR_SETTINGS(host_flavor_default, "elf",  "lib",".a", "lib",".so",    "","",     "",   "",       "LD_LIBRARY_PATH");
bcd5af
SLBT_FLAVOR_SETTINGS(host_flavor_midipix, "pe",   "lib",".a", "lib",".so",    "","",     "lib",".lib.a", "PATH");
bcd5af
SLBT_FLAVOR_SETTINGS(host_flavor_mingw,   "pe",   "lib",".a", "lib",".dll",   "",".exe", "lib",".dll.a", "PATH");
bcd5af
SLBT_FLAVOR_SETTINGS(host_flavor_cygwin,  "pe",   "lib",".a", "lib",".dll",   "",".exe", "lib",".dll.a", "PATH");
bcd5af
SLBT_FLAVOR_SETTINGS(host_flavor_darwin,  "macho","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>";
46ea99
static const char cfgmachine[]  = "native (derived from -dumpmachine)";
46ea99
static const char cfgnative[]   = "native";
46ea99
56cab3
struct slbt_split_vector {
56cab3
	char **		targv;
56cab3
	char **		cargv;
56cab3
};
56cab3
9ca8c4
struct slbt_driver_ctx_alloc {
9ca8c4
	struct argv_meta *		meta;
9ca8c4
	struct slbt_driver_ctx_impl	ctx;
9ca8c4
	uint64_t			guard;
9ca8c4
	const char *			units[];
9ca8c4
};
9ca8c4
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
9ca8c4
static int slbt_driver_usage(
9ca8c4
	const char *			program,
9ca8c4
	const char *			arg,
9ca8c4
	const struct argv_option *	options,
9ca8c4
	struct argv_meta *		meta)
9ca8c4
{
9ca8c4
	char header[512];
9ca8c4
9ca8c4
	snprintf(header,sizeof(header),
9ca8c4
		"Usage: %s [options] <file>...\n" "Options:\n",
9ca8c4
		program);
9ca8c4
9ca8c4
	argv_usage(stdout,header,options,arg);
9ca8c4
	argv_free(meta);
9ca8c4
9ca8c4
	return SLBT_USAGE;
9ca8c4
}
9ca8c4
9ca8c4
static struct slbt_driver_ctx_impl * slbt_driver_ctx_alloc(
9ca8c4
	struct argv_meta *		meta,
9ca8c4
	const struct slbt_common_ctx *	cctx,
9ca8c4
	size_t				nunits)
9ca8c4
{
9ca8c4
	struct slbt_driver_ctx_alloc *	ictx;
9ca8c4
	size_t				size;
9ca8c4
	struct argv_entry *		entry;
9ca8c4
	const char **			units;
9ca8c4
9ca8c4
	size =  sizeof(struct slbt_driver_ctx_alloc);
9ca8c4
	size += (nunits+1)*sizeof(const char *);
9ca8c4
9ca8c4
	if (!(ictx = calloc(1,size)))
9ca8c4
		return 0;
9ca8c4
9ca8c4
	if (cctx)
9ca8c4
		memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
9ca8c4
9ca8c4
	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
9ca8c4
		if (!entry->fopt)
9ca8c4
			*units++ = entry->arg;
9ca8c4
9ca8c4
	ictx->meta = meta;
9ca8c4
	ictx->ctx.ctx.units = ictx->units;
9ca8c4
	return &ictx->ctx;
9ca8c4
}
9ca8c4
9ca8c4
static int slbt_get_driver_ctx_fail(struct argv_meta * meta)
9ca8c4
{
9ca8c4
	argv_free(meta);
9ca8c4
	return -1;
9ca8c4
}
9ca8c4
56cab3
static int slbt_split_argv(
56cab3
	char **				argv,
56cab3
	uint32_t			flags,
56cab3
	struct slbt_split_vector *	sargv)
56cab3
{
56cab3
	int				i;
56cab3
	int				argc;
56cab3
	const char *			program;
56cab3
	char *				compiler;
56cab3
	char **				targv;
56cab3
	char **				cargv;
56cab3
	struct argv_meta *		meta;
56cab3
	struct argv_entry *		entry;
56cab3
	struct argv_entry *		mode;
37ff4a
	struct argv_entry *		config;
56cab3
	const struct argv_option *	option;
56cab3
	const struct argv_option *	options = slbt_default_options;
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? */
56cab3
	if (!argv[1] && (flags & SLBT_DRIVER_VERBOSITY_USAGE))
56cab3
		return slbt_driver_usage(program,0,options,0);
56cab3
56cab3
	/* initial argv scan: ... --mode=xxx ... <compiler> ... */
56cab3
	argv_scan(argv,options,&ctx,0);
56cab3
56cab3
	/* invalid slibtool arguments? */
56cab3
	if (ctx.erridx && !ctx.unitidx) {
56cab3
		if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
56cab3
			argv_get(
56cab3
				argv,options,
56cab3
				slbt_argv_flags(flags));
56cab3
		return -1;
56cab3
	}
56cab3
56cab3
	/* missing compiler? */
56cab3
	if (!ctx.unitidx) {
56cab3
		if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
56cab3
			fprintf(stderr,
56cab3
				"%s: error: <compiler> is missing.\n",
56cab3
				program);
56cab3
		return -1;
56cab3
	}
56cab3
56cab3
	/* obtain slibtool's own arguments */
56cab3
	compiler = argv[ctx.unitidx];
56cab3
	argv[ctx.unitidx] = 0;
56cab3
56cab3
	meta = argv_get(argv,options,ARGV_VERBOSITY_NONE);
56cab3
	argv[ctx.unitidx] = compiler;
56cab3
37ff4a
	/* missing both --mode and --config? */
94d109
	for (mode=0, config=0, 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;
56cab3
56cab3
	argv_free(meta);
56cab3
37ff4a
	if (!mode && !config) {
56cab3
		fprintf(stderr,
56cab3
			"%s: error: --mode must be specified.\n",
56cab3
			program);
56cab3
		return -1;
56cab3
	}
56cab3
56cab3
	/* allocate split vectors */
56cab3
	for (argc=0, targv=argv; *targv; targv++)
56cab3
		argc++;
56cab3
56cab3
	if ((sargv->targv = calloc(2*(argc+1),sizeof(char *))))
56cab3
		sargv->cargv = sargv->targv + argc + 1;
56cab3
	else
56cab3
		return -1;
56cab3
56cab3
	/* split vectors: slibtool's own options */
56cab3
	for (i=0; i
56cab3
		sargv->targv[i] = argv[i];
56cab3
56cab3
	/* split vectors: legacy mixture */
56cab3
	options = option_from_tag(
56cab3
			slbt_default_options,
56cab3
			TAG_OUTPUT);
56cab3
56cab3
	targv = sargv->targv + i;
56cab3
	cargv = sargv->cargv;
56cab3
56cab3
	for (; i
56cab3
		if (argv[i][0] != '-')
56cab3
			*cargv++ = argv[i];
56cab3
a288c4
		else if (argv[i][1] == 'o') {
56cab3
			*targv++ = argv[i];
56cab3
a87fd1
			if (argv[i][2] == 0)
a288c4
				*targv++ = argv[++i];
a288c4
		}
a288c4
56cab3
		else if ((argv[i][1] == 'W')  && (argv[i][2] == 'c'))
56cab3
			*cargv++ = argv[i];
56cab3
56cab3
		else if (!(strcmp("Xcompiler",&argv[i][1])))
56cab3
			*cargv++ = argv[++i];
56cab3
411564
		else if (!(strncmp("-target=",&argv[i][1],strlen("-target="))))
666296
			*targv++ = argv[i];
411564
411564
		else if (!(strcmp("-target",&argv[i][1]))) {
411564
			*targv++ = argv[i++];
666296
			*targv++ = argv[i];
411564
a87fd1
		} 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
63a1b4
		} else if (!(strcmp("bindir",&argv[i][1]))) {
63a1b4
			*targv++ = argv[i++];
63a1b4
			*targv++ = argv[i];
63a1b4
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
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
411564
		} else {
56cab3
			for (option=options; option->long_name; option++)
56cab3
				if (!(strcmp(option->long_name,&argv[i][1])))
56cab3
					break;
56cab3
56cab3
			if (option->long_name)
56cab3
				*targv++ = argv[i];
56cab3
			else
56cab3
				*cargv++ = argv[i];
56cab3
		}
56cab3
	}
56cab3
56cab3
	return 0;
56cab3
}
56cab3
f0921b
static int slbt_init_host_params(
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;
46ea99
	const char *	machine;
46ea99
	bool		ftarget       = false;
46ea99
	bool		fhost         = false;
46ea99
	bool		fcompiler     = false;
46ea99
	bool		fnative       = false;
46ea99
46ea99
	/* host */
46ea99
	if (host->host) {
46ea99
		cfgmeta->host = cfgexplicit;
46ea99
		fhost         = true;
46ea99
	} else if (cctx->target) {
46ea99
		host->host    = cctx->target;
46ea99
		cfgmeta->host = cfgtarget;
46ea99
		ftarget       = true;
46ea99
	} else if (strrchr(cctx->cargv[0],'-')) {
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;
46ea99
	} else {
46ea99
		host->host    = SLBT_MACHINE;
46ea99
		cfgmeta->host = cfgmachine;
46ea99
		fnative       = true;
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 {
46ea99
			machine         = SLBT_MACHINE;
46ea99
			cfgmeta->flavor = cfgmachine;
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";
a07c9b
		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";
46ea99
		else {
46ea99
			host->flavor   = "default";
46ea99
			cfgmeta->flavor = "fallback, unverified";
46ea99
		}
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
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
46ea99
	return 0;
46ea99
}
46ea99
52556c
static void slbt_free_host_params(struct slbt_host_strs * host)
52556c
{
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
52556c
	if (host->dlltool)
52556c
		free(host->dlltool);
a313a4
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"))
1f442f
			cctx->drvflags |= SLBT_DRIVER_IMAGE_PE;
1f442f
	}
bcd5af
0b68ad
	memcpy(psettings,settings,sizeof(*settings));
a66d34
}
a66d34
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)
5a9161
			fprintf(stderr,
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;
f8e27e
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)
f8e27e
			fprintf(stderr,
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)
f8e27e
				fprintf(stderr,
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)
f8e27e
				fprintf(stderr,
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)
f8e27e
				fprintf(stderr,
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,
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;
9ca8c4
	const struct argv_option *	options;
9ca8c4
	struct argv_meta *		meta;
9ca8c4
	struct argv_entry *		entry;
9ca8c4
	size_t				nunits;
9ca8c4
	const char *			program;
9ca8c4
9ca8c4
	options = slbt_default_options;
9ca8c4
56cab3
	if (slbt_split_argv(argv,flags,&sargv))
56cab3
		return -1;
56cab3
56cab3
	if (!(meta = argv_get(sargv.targv,options,slbt_argv_flags(flags))))
9ca8c4
		return -1;
9ca8c4
9ca8c4
	nunits	= 0;
9ca8c4
	program = argv_program_name(argv[0]);
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
9ca8c4
	/* get options, count units */
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)
9ca8c4
						return slbt_driver_usage(program,entry->arg,options,meta);
9ca8c4
9ca8c4
				case TAG_VERSION:
9ca8c4
					cctx.drvflags |= SLBT_DRIVER_VERSION;
9ca8c4
					break;
667ce2
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
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
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
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
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
db67ad
				case TAG_DLLTOOL:
db67ad
					cctx.host.dlltool = entry->arg;
db67ad
					break;
db67ad
b83b64
				case TAG_OUTPUT:
b83b64
					cctx.output = entry->arg;
b83b64
					break;
4f1b20
9c664d
				case TAG_RPATH:
9c664d
					cctx.rpath = entry->arg;
9c664d
					break;
9c664d
9aa1f4
				case TAG_RELEASE:
9aa1f4
					cctx.release = entry->arg;
9aa1f4
					break;
9aa1f4
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:
341c87
					cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_STATIC;
9c25c7
					break;
9c25c7
9c25c7
				case TAG_STATIC:
341c87
					cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_SHARED;
9c25c7
					break;
9ca8c4
			}
9ca8c4
		} else
9ca8c4
			nunits++;
9ca8c4
	}
9ca8c4
c778cc
	/* driver context */
9ca8c4
	if (!(ctx = slbt_driver_ctx_alloc(meta,&cctx,nunits)))
9ca8c4
		return slbt_get_driver_ctx_fail(meta);
9ca8c4
9ca8c4
	ctx->ctx.program	= program;
9ca8c4
	ctx->ctx.cctx		= &ctx->cctx;
56cab3
	ctx->targv		= sargv.targv;
56cab3
	ctx->cargv		= sargv.cargv;
9ca8c4
a288c4
	ctx->cctx.targv		= sargv.targv;
a288c4
	ctx->cctx.cargv		= sargv.cargv;
a288c4
46ea99
	/* host params */
46ea99
	if ((cctx.drvflags & SLBT_DRIVER_HEURISTICS)
24efc6
			|| (cctx.drvflags & SLBT_DRIVER_CONFIG)
a66d34
			|| (cctx.mode != SLBT_MODE_COMPILE)) {
46ea99
		if (slbt_init_host_params(
46ea99
				&ctx->cctx,
46ea99
				&ctx->host,
46ea99
				&ctx->cctx.host,
46ea99
				&ctx->cctx.cfgmeta)) {
46ea99
			slbt_free_driver_ctx(&ctx->ctx);
46ea99
			return -1;
a66d34
		} else
0b68ad
			slbt_init_flavor_settings(
1f442f
				&ctx->cctx,0,
0b68ad
				&ctx->cctx.settings);
a66d34
	}
46ea99
5a9161
	/* version info */
dcb453
	if (slbt_init_version_info(ctx,&ctx->cctx.verinfo)) {
dcb453
		slbt_free_driver_ctx(&ctx->ctx);
dcb453
		return -1;
dcb453
	}
5a9161
f8e27e
	/* link params */
f8e27e
	if (cctx.mode == SLBT_MODE_LINK)
f8e27e
		if (slbt_init_link_params(ctx)) {
f8e27e
			slbt_free_driver_ctx(&ctx->ctx);
f8e27e
			return -1;
f8e27e
		}
f8e27e
9ca8c4
	*pctx = &ctx->ctx;
9ca8c4
	return SLBT_OK;
9ca8c4
}
9ca8c4
9ca8c4
int slbt_create_driver_ctx(
9ca8c4
	const struct slbt_common_ctx *	cctx,
9ca8c4
	struct slbt_driver_ctx **	pctx)
9ca8c4
{
9ca8c4
	struct argv_meta *		meta;
9ca8c4
	struct slbt_driver_ctx_impl *	ctx;
9ca8c4
	char *				argv[] = {"slibtool_driver",0};
9ca8c4
9ca8c4
	if (!(meta = argv_get(argv,slbt_default_options,0)))
9ca8c4
		return -1;
9ca8c4
9ca8c4
	if (!(ctx = slbt_driver_ctx_alloc(meta,cctx,0)))
9ca8c4
		return slbt_get_driver_ctx_fail(0);
9ca8c4
9ca8c4
	ctx->ctx.cctx = &ctx->cctx;
9ca8c4
	memcpy(&ctx->cctx,cctx,sizeof(*cctx));
9ca8c4
	*pctx = &ctx->ctx;
9ca8c4
	return SLBT_OK;
9ca8c4
}
9ca8c4
9ca8c4
static void slbt_free_driver_ctx_impl(struct slbt_driver_ctx_alloc * ictx)
9ca8c4
{
56cab3
	if (ictx->ctx.targv)
56cab3
		free(ictx->ctx.targv);
56cab3
f8e27e
	if (ictx->ctx.libname)
f8e27e
		free(ictx->ctx.libname);
f8e27e
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) {
9ca8c4
		addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_alloc,ctx);
9ca8c4
		addr = addr - offsetof(struct slbt_driver_ctx_impl,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)))
a313a4
		return -1;
a313a4
a313a4
	if (!(ictx->ctx.ahost.flavor = strdup(flavor))) {
a313a4
		slbt_free_host_params(&ictx->ctx.ahost);
a313a4
		return -1;
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(
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);
a313a4
		return -1;
a313a4
	}
a313a4
a313a4
	slbt_init_flavor_settings(
a313a4
		&ictx->ctx.cctx,
a313a4
		&ictx->ctx.cctx.ahost,
a313a4
		&ictx->ctx.cctx.asettings);
a313a4
a313a4
	return 0;
a313a4
}