Blame src/driver/slbt_driver_ctx.c

9ca8c4
/*******************************************************************/
9ca8c4
/*  slibtool: a skinny libtool implementation, written in C        */
49181b
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
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>
6ab3f1
#include <sys/mman.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"
a126a7
#include "slibtool_objlist_impl.h"
8069c3
#include "slibtool_errinfo_impl.h"
499a71
#include "slibtool_lconf_impl.h"
11f3c7
#include "slibtool_ar_impl.h"
9ca8c4
#include "argv/argv.h"
9ca8c4
d5e3ae
extern char ** environ;
d5e3ae
8f60d4
/* annotation strings */
8f60d4
static const char cfgexplicit[] = "command-line argument";
8f60d4
static const char cfglconf[]    = "derived from <libtool>";
8f60d4
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
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
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
4b56de
slbt_hidden const char * slbt_program_name(const char * path)
99c275
{
99c275
	return argv_program_name(path);
99c275
}
99c275
c3d88b
4b56de
slbt_hidden int slbt_optv_init(
c3d88b
	const struct argv_option    options[],
c3d88b
	const struct argv_option ** optv)
c3d88b
{
c3d88b
	return argv_optv_init(options,optv);
c3d88b
}
c3d88b
c3d88b
4b56de
slbt_hidden void slbt_argv_scan(
c3d88b
	char **				argv,
c3d88b
	const struct argv_option **	optv,
c3d88b
	struct argv_ctx *		ctx,
c3d88b
	struct argv_meta *		meta)
c3d88b
{
bc3103
	argv_scan(argv,optv,ctx,meta);
c3d88b
}
c3d88b
c3d88b
4b56de
slbt_hidden struct argv_meta * slbt_argv_get(
c3d88b
	char **                         argv,
c3d88b
	const struct argv_option **     optv,
c3d88b
	int                             flags,
c3d88b
	int                             fd)
c3d88b
{
c3d88b
	return argv_get(argv,optv,flags,fd);
c3d88b
}
c3d88b
c3d88b
4b56de
slbt_hidden void slbt_argv_free(struct argv_meta * meta)
c3d88b
{
bc3103
	argv_free(meta);
c3d88b
}
c3d88b
c3d88b
4b56de
slbt_hidden void slbt_argv_usage(
6b2413
	int		                fd,
6b2413
	const char *	                header,
6b2413
	const struct	argv_option **  optv,
6b2413
	const char *	                mode)
6b2413
{
bc3103
	argv_usage(fd,header,optv,mode);
6b2413
}
6b2413
6b2413
4b56de
slbt_hidden void slbt_argv_usage_plain(
6b2413
	int		                fd,
6b2413
	const char *	                header,
6b2413
	const struct	argv_option **  optv,
6b2413
	const char *	                mode)
6b2413
{
bc3103
	argv_usage_plain(fd,header,optv,mode);
6b2413
}
6b2413
6b2413
4b56de
slbt_hidden uint64_t slbt_argv_flags(uint64_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
a126a7
static int slbt_free_argv_buffer(
a126a7
	struct slbt_split_vector * sargv,
a126a7
	struct slbt_obj_list *     objlistv)
0cbb20
{
a126a7
	struct slbt_obj_list * objlistp;
a126a7
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
a126a7
	if (objlistv) {
a126a7
		for (objlistp=objlistv; objlistp->name; objlistp++) {
a126a7
			free(objlistp->objv);
a126a7
			free(objlistp->addr);
a126a7
		}
a126a7
a126a7
		free(objlistv);
a126a7
	}
a126a7
0cbb20
	return -1;
0cbb20
}
0cbb20
4b56de
slbt_hidden 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,
a126a7
	struct slbt_obj_list *		objlistv,
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);
a126a7
	slbt_free_argv_buffer(sargv,objlistv);
9ca8c4
9ca8c4
	return SLBT_USAGE;
9ca8c4
}
9ca8c4
9ca8c4
static struct slbt_driver_ctx_impl * slbt_driver_ctx_alloc(
a82cc2
	const struct slbt_fd_ctx *	fdctx,
0cbb20
	const struct slbt_common_ctx *	cctx,
684b80
	struct slbt_split_vector *	sargv,
a126a7
	struct slbt_obj_list *		objlistv,
9da202
	char **				envp,
9da202
	size_t				ndlopen)
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))) {
a126a7
		slbt_free_argv_buffer(sargv,objlistv);
9ca8c4
		return 0;
0cbb20
	}
0cbb20
9da202
	if (ndlopen) {
9da202
		if (!(ictx->ctx.dlopenv = calloc(ndlopen+1,sizeof(char *)))) {
9da202
			free(ictx);
9da202
			slbt_free_argv_buffer(sargv,objlistv);
9da202
			return 0;
9da202
		}
9da202
9da202
		ictx->ctx.ndlopen = ndlopen;
9da202
	}
9da202
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
a126a7
	ictx->ctx.objlistv = objlistv;
a126a7
53c651
	ictx->ctx.ctx.errv = ictx->ctx.errinfp;
a126a7
9ca8c4
	return &ictx->ctx;
9ca8c4
}
9ca8c4
ea4137
static int slbt_lib_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);
ea4137
		slbt_lib_free_driver_ctx(dctx);
38b351
	} else {
38b351
		argv_free(meta);
38b351
	}
38b351
9ca8c4
	return -1;
9ca8c4
}
9ca8c4
af7db9
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
ea4137
	return slbt_lib_get_driver_ctx_fail(0,meta);
89f5ab
}
89f5ab
261127
261127
static int slbt_driver_parse_tool_argv(const char * tool, char *** tool_argv)
261127
{
261127
	int             argc;
261127
	char **         argv;
261127
	const char *    ch;
261127
	const char *    mark;
261127
261127
	if (!(ch = tool))
261127
		return 0;
261127
261127
	argc = 1;
261127
261127
	for (; *ch == ' '; )
261127
		ch++;
261127
261127
	for (; *ch; ) {
261127
		if (*ch++ == ' ') {
261127
			argc++;
261127
261127
			for (; (*ch == ' '); )
261127
				ch++;
261127
		}
261127
	}
261127
261127
	if (argc == 1)
261127
		return 0;
261127
261127
	if (!(*tool_argv = calloc(++argc,sizeof(char *))))
261127
		return -1;
261127
261127
	for (ch=tool; (*ch == ' '); ch++)
261127
		(void)0;
261127
261127
	argv = *tool_argv;
261127
	mark = ch;
261127
261127
	for (; *ch; ) {
261127
		if (*ch == ' ') {
261127
			if (!(*argv++ = strndup(mark,ch-mark)))
261127
				return -1;
261127
261127
			for (; (*ch == ' '); )
261127
				ch++;
261127
261127
			mark = ch;
261127
		} else {
261127
			ch++;
261127
		}
261127
	}
261127
261127
	if (!(*argv++ = strndup(mark,ch-mark)))
261127
		return -1;
261127
261127
	return 0;
261127
}
261127
261127
ea4137
int slbt_lib_get_driver_ctx(
9ca8c4
	char **				argv,
9ca8c4
	char **				envp,
1c4305
	uint64_t			flags,
a82cc2
	const struct slbt_fd_ctx *	fdctx,
9ca8c4
	struct slbt_driver_ctx **	pctx)
9ca8c4
{
56cab3
	struct slbt_split_vector	sargv;
a126a7
	struct slbt_obj_list *		objlistv;
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;
9da202
	size_t                          ndlopen;
9da202
	const char **			dlopenv;
771899
	const char *                    cfgmeta_host;
d29f9c
	const char *                    cfgmeta_ar;
b4058c
	const char *                    cfgmeta_as;
b5e104
	const char *                    cfgmeta_nm;
d29f9c
	const char *                    cfgmeta_ranlib;
fc8ee9
	const char *                    cfgmeta_dlltool;
9ca8c4
11f3c7
	if (flags & SLBT_DRIVER_MODE_AR)
11f3c7
		argv_optv_init(slbt_ar_options,optv);
11f3c7
	else
11f3c7
		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;
a126a7
	objlistv    = 0;
9da202
	ndlopen     = 0;
0cbb20
626342
	switch (slbt_split_argv(argv,flags,&sargv,&objlistv,fdctx->fderr,fdctx->fdcwd)) {
626342
		case SLBT_OK:
626342
			break;
626342
626342
		case SLBT_USAGE:
626342
			return SLBT_USAGE;
626342
626342
		default:
626342
			return slbt_free_argv_buffer(&sargv,objlistv);
626342
	}
56cab3
93f9e4
	if (!(meta = argv_get(
93f9e4
			sargv.targv,optv,
0cbb20
			slbt_argv_flags(flags),
a82cc2
			fdctx->fderr)))
a126a7
		return slbt_free_argv_buffer(&sargv,objlistv);
9ca8c4
499a71
	lconf   = 0;
9ca8c4
	program = argv_program_name(argv[0]);
499a71
9ca8c4
	memset(&cctx,0,sizeof(cctx));
9ca8c4
11f3c7
	if (flags & SLBT_DRIVER_MODE_AR)
11f3c7
		cctx.mode = SLBT_MODE_AR;
11f3c7
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
771899
	cfgmeta_host   = 0;
d29f9c
	cfgmeta_ar     = 0;
b4058c
	cfgmeta_as     = 0;
b5e104
	cfgmeta_nm     = 0;
d29f9c
	cfgmeta_ranlib = 0;
fc8ee9
	cfgmeta_dlltool = 0;
d29f9c
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:
5b1d0e
					switch (cctx.mode) {
5b1d0e
						case SLBT_MODE_INSTALL:
5b1d0e
						case SLBT_MODE_UNINSTALL:
11f3c7
						case SLBT_MODE_AR:
5b1d0e
							break;
5b1d0e
5b1d0e
					default:
5b1d0e
						return (flags & SLBT_DRIVER_VERBOSITY_USAGE)
5b1d0e
							? slbt_driver_usage(
5b1d0e
								fdctx->fdout,program,
5b1d0e
								entry->arg,optv,
a126a7
								meta,&sargv,objlistv,
5b1d0e
								(cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER))
5b1d0e
							: SLBT_USAGE;
5b1d0e
					}
5b1d0e
5b1d0e
					break;
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;
11f3c7
11f3c7
					else if (!strcmp("ar",entry->arg))
11f3c7
						cctx.mode = SLBT_MODE_AR;
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
fb5e7f
					else if (!strcmp("ASM",entry->arg))
fb5e7f
						cctx.tag = SLBT_TAG_ASM;
fb5e7f
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
c57816
				case TAG_INFO:
c57816
					cctx.drvflags |= SLBT_DRIVER_INFO;
173b54
					break;
173b54
c1f216
				case TAG_CONFIG:
c1f216
					cctx.drvflags |= SLBT_DRIVER_OUTPUT_CONFIG;
c1f216
					break;
c1f216
6f4115
				case TAG_DUMPMACHINE:
6f4115
					cctx.drvflags |= SLBT_DRIVER_OUTPUT_MACHINE;
6f4115
					break;
6f4115
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;
771899
					cfgmeta_host   = cfgexplicit;
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;
d29f9c
					cfgmeta_ar   = cfgexplicit;
db67ad
					break;
db67ad
6bc170
				case TAG_AS:
6bc170
					cctx.host.as = entry->arg;
b4058c
					cfgmeta_as   = cfgexplicit;
6bc170
					break;
6bc170
b5e104
				case TAG_NM:
b5e104
					cctx.host.nm = entry->arg;
b5e104
					cfgmeta_nm   = cfgexplicit;
b5e104
					break;
b5e104
db67ad
				case TAG_RANLIB:
db67ad
					cctx.host.ranlib = entry->arg;
d29f9c
					cfgmeta_ranlib   = cfgexplicit;
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;
fc8ee9
					cfgmeta_dlltool   = cfgexplicit;
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
9da202
				case TAG_DLPREOPEN:
9da202
					ndlopen++;
9da202
					break;
9da202
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
21bb4b
				case TAG_EXPSYMS_FILE:
161c3d
					cctx.expsyms = entry->arg;
873ecb
					break;
873ecb
21bb4b
				case TAG_EXPSYMS_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;
5e0269
5e0269
				case TAG_WEAK:
5e0269
					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
c1f216
	/* config mode */
c1f216
	if (cctx.drvflags & SLBT_DRIVER_OUTPUT_CONFIG)
c1f216
		cctx.mode = SLBT_MODE_CONFIG;
c1f216
3c1679
	/* info mode */
c57816
	if (cctx.drvflags & (SLBT_DRIVER_INFO | 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 */
9da202
	if (!(ctx = slbt_driver_ctx_alloc(fdctx,&cctx,&sargv,objlistv,envp,ndlopen)))
ea4137
		return slbt_lib_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;
53c651
	ctx->meta               = meta;
9ca8c4
499a71
	/* heuristics */
499a71
	if (cctx.drvflags & SLBT_DRIVER_HEURISTICS) {
38b351
		if (slbt_get_lconf_flags(&ctx->ctx,lconf,&lflags) < 0)
ea4137
			return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
499a71
771899
		if (ctx->cctx.host.host && !cfgmeta_host)
771899
			cfgmeta_host = cfglconf;
771899
d29f9c
		if (ctx->cctx.host.ar && !cfgmeta_ar)
d29f9c
			cfgmeta_ar = cfglconf;
d29f9c
b4058c
		if (ctx->cctx.host.as && !cfgmeta_as)
b4058c
			cfgmeta_as = cfglconf;
b4058c
b5e104
		if (ctx->cctx.host.nm && !cfgmeta_nm)
b5e104
			cfgmeta_nm = cfglconf;
b5e104
d29f9c
		if (ctx->cctx.host.ranlib && !cfgmeta_ranlib)
d29f9c
			cfgmeta_ranlib = cfglconf;
d29f9c
fc8ee9
		if (ctx->cctx.host.dlltool && !cfgmeta_dlltool)
fc8ee9
			cfgmeta_dlltool = cfglconf;
fc8ee9
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,
d29f9c
			&ctx->cctx.cfgmeta,
771899
			cfgmeta_host,
d29f9c
			cfgmeta_ar,
b4058c
			cfgmeta_as,
b5e104
			cfgmeta_nm,
fc8ee9
			cfgmeta_ranlib,
fc8ee9
			cfgmeta_dlltool))
ea4137
		return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
46ea99
261127
	/* host tool arguments */
261127
	if (slbt_driver_parse_tool_argv(ctx->cctx.host.ar,&ctx->host.ar_argv) < 0)
ea4137
		return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
261127
b5e104
	if (slbt_driver_parse_tool_argv(ctx->cctx.host.nm,&ctx->host.nm_argv) < 0)
b5e104
		return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
b5e104
261127
	if (slbt_driver_parse_tool_argv(ctx->cctx.host.ranlib,&ctx->host.ranlib_argv) < 0)
ea4137
		return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
261127
ba9228
	if (slbt_driver_parse_tool_argv(ctx->cctx.host.as,&ctx->host.as_argv) < 0)
ea4137
		return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
ba9228
94868f
	if (slbt_driver_parse_tool_argv(ctx->cctx.host.dlltool,&ctx->host.dlltool_argv) < 0)
ea4137
		return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
94868f
94868f
	if (slbt_driver_parse_tool_argv(ctx->cctx.host.mdso,&ctx->host.mdso_argv) < 0)
ea4137
		return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
94868f
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))
ea4137
		return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
af7db9
5a9161
	/* version info */
38b351
	if (slbt_init_version_info(ctx,&ctx->cctx.verinfo))
ea4137
		return slbt_lib_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))
ea4137
			return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
f8e27e
9da202
	/* dlpreopen */
9da202
	if ((dlopenv = ctx->dlopenv)) {
9da202
		for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
9da202
			if (entry->fopt) {
9da202
				switch (entry->tag) {
9da202
					case TAG_DLPREOPEN:
9da202
						*dlopenv++ = entry->arg;
9da202
9da202
					default:
9da202
						break;
9da202
				}
9da202
			}
9da202
		}
9da202
	}
9da202
9da202
	/* all ready */
9ca8c4
	*pctx = &ctx->ctx;
38b351
38b351
	return 0;
9ca8c4
}
9ca8c4
8f60d4
ea4137
static void slbt_lib_free_driver_ctx_impl(struct slbt_driver_ctx_alloc * ictx)
9ca8c4
{
6beda1
	struct slbt_error_info ** perr;
6beda1
	struct slbt_error_info *  erri;
a126a7
	struct slbt_obj_list *    objlistp;
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
f8e27e
	if (ictx->ctx.libname)
f8e27e
		free(ictx->ctx.libname);
f8e27e
9da202
	if (ictx->ctx.dlopenv)
9da202
		free(ictx->ctx.dlopenv);
9da202
6ab3f1
	if (ictx->ctx.lconf.addr)
6ab3f1
		munmap(
6ab3f1
			ictx->ctx.lconf.addr,
6ab3f1
			ictx->ctx.lconf.size);
6ab3f1
a2aa78
	if (ictx->ctx.lconfctx)
a2aa78
		slbt_lib_free_txtfile_ctx(ictx->ctx.lconfctx);
a2aa78
a126a7
	for (objlistp=ictx->ctx.objlistv; objlistp->name; objlistp++) {
a126a7
		free(objlistp->objv);
a126a7
		free(objlistp->addr);
a126a7
	}
a126a7
a126a7
	free(ictx->ctx.objlistv);
a126a7
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);
53c651
	argv_free(ictx->ctx.meta);
a126a7
9ca8c4
	free(ictx);
9ca8c4
}
9ca8c4
8f60d4
ea4137
void slbt_lib_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;
ea4137
		slbt_lib_free_driver_ctx_impl(ictx);
9ca8c4
	}
9ca8c4
}
a313a4
1f2c01
f0270a
const struct slbt_source_version * slbt_api_source_version(void)
9f24d2
{
9f24d2
	return &slbt_src_version;
9f24d2
}
a82cc2
8f60d4
ea4137
int slbt_lib_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
8f60d4
ea4137
int slbt_lib_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
}