Blame src/logic/linkcmd/slbt_linkcmd_argv.c

3d5567
/*******************************************************************/
3d5567
/*  slibtool: a skinny libtool implementation, written in C        */
49181b
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
3d5567
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
3d5567
/*******************************************************************/
3d5567
3d5567
#include <stdarg.h>
3d5567
#include <stdlib.h>
3d5567
#include <stdio.h>
3d5567
#include <string.h>
3d5567
#include <fcntl.h>
3d5567
#include <errno.h>
3d5567
#include <sys/stat.h>
3d5567
3d5567
#include <slibtool/slibtool.h>
3d5567
#include "slibtool_driver_impl.h"
3d5567
#include "slibtool_errinfo_impl.h"
3d5567
#include "slibtool_linkcmd_impl.h"
3d5567
#include "slibtool_mapfile_impl.h"
3d5567
#include "slibtool_metafile_impl.h"
3d5567
#include "slibtool_snprintf_impl.h"
3d5567
#include "slibtool_symlink_impl.h"
3d5567
#include "slibtool_readlink_impl.h"
3d5567
3d5567
3d5567
static int slbt_linkcmd_exit(
3d5567
	struct slbt_deps_meta *	depsmeta,
3d5567
	int			ret)
3d5567
{
3d5567
	if (depsmeta->altv)
3d5567
		free(depsmeta->altv);
3d5567
3d5567
	if (depsmeta->args)
3d5567
		free(depsmeta->args);
3d5567
3d5567
	return ret;
3d5567
}
3d5567
3d5567
3d5567
static int slbt_emit_fdwrap_amend_dl_path(
3d5567
	const struct slbt_driver_ctx *	dctx,
3d5567
	struct slbt_exec_ctx *		ectx,
3d5567
	struct slbt_deps_meta * 	depsmeta,
3d5567
	const char *			fmt,
3d5567
					...)
3d5567
{
3d5567
	va_list		ap;
3d5567
	char *		buf;
3d5567
	int		cnt;
3d5567
	char		dlpathbuf[2048];
3d5567
	int		fdwrap;
3d5567
	const char *	fdwrap_fmt;
3d5567
	int		size;
3d5567
3d5567
	va_start(ap,fmt);
3d5567
3d5567
	size = sizeof(dlpathbuf);
3d5567
3d5567
	buf  = ((cnt = vsnprintf(dlpathbuf,size,fmt,ap)) < size)
3d5567
		? dlpathbuf : malloc((size = cnt + 1));
3d5567
3d5567
	va_end(ap);
3d5567
3d5567
	if (buf == dlpathbuf) {
3d5567
		(void)0;
3d5567
3d5567
	} else if (buf) {
3d5567
		va_start(ap,fmt);
3d5567
		vsprintf(buf,fmt,ap);
3d5567
		va_end(ap);
3d5567
3d5567
	} else {
3d5567
		return slbt_linkcmd_exit(
3d5567
			depsmeta,
3d5567
			SLBT_SYSTEM_ERROR(dctx,0));
3d5567
	}
3d5567
3d5567
	if ((fdwrap = slbt_exec_get_fdwrapper(ectx)) >= 0) {
3d5567
		if (buf[0] == '/') {
3d5567
			fdwrap_fmt =
3d5567
				"DL_PATH=\"${DL_PATH}${COLON}%s\"\n"
3d5567
				"COLON=':'\n\n";
3d5567
		} else {
3d5567
			fdwrap_fmt =
3d5567
				"DL_PATH=\"${DL_PATH}${COLON}${DL_PATH_FIXUP}%s\"\n"
3d5567
				"COLON=':'\n\n";
3d5567
		}
3d5567
3d5567
		if (slbt_dprintf(fdwrap,fdwrap_fmt,buf) < 0) {
3d5567
			return slbt_linkcmd_exit(
3d5567
				depsmeta,
3d5567
				SLBT_SYSTEM_ERROR(dctx,0));
3d5567
		}
3d5567
	}
3d5567
3d5567
	return 0;
3d5567
}
3d5567
3d5567
3d5567
bool slbt_adjust_object_argument(
3d5567
	char *		arg,
3d5567
	bool		fpic,
3d5567
	bool		fany,
3d5567
	int		fdcwd)
3d5567
{
3d5567
	char *	slash;
3d5567
	char *	dot;
3d5567
	char	base[PATH_MAX];
3d5567
3d5567
	if (*arg == '-')
3d5567
		return false;
3d5567
3d5567
	/* object argument: foo.lo or foo.o */
3d5567
	if (!(dot = strrchr(arg,'.')))
3d5567
		return false;
3d5567
3d5567
	if ((dot[1]=='l') && (dot[2]=='o') && !dot[3]) {
3d5567
		dot[1] = 'o';
3d5567
		dot[2] = 0;
3d5567
3d5567
	} else if ((dot[1]=='o') && !dot[2]) {
3d5567
		(void)0;
3d5567
3d5567
	} else {
3d5567
		return false;
3d5567
	}
3d5567
3d5567
	/* foo.o requested and is present? */
3d5567
	if (!fpic && !faccessat(fdcwd,arg,0,0))
3d5567
		return true;
3d5567
3d5567
	/* .libs/foo.o */
3d5567
	if ((slash = strrchr(arg,'/')))
3d5567
		slash++;
3d5567
	else
3d5567
		slash = arg;
3d5567
3d5567
	if (slbt_snprintf(base,sizeof(base),
3d5567
			"%s",slash) < 0)
3d5567
		return false;
3d5567
3d5567
	sprintf(slash,".libs/%s",base);
3d5567
3d5567
	if (!faccessat(fdcwd,arg,0,0))
3d5567
		return true;
3d5567
3d5567
	/* foo.o requested and neither is present? */
3d5567
	if (!fpic) {
3d5567
		strcpy(slash,base);
3d5567
		return true;
3d5567
	}
3d5567
3d5567
	/* .libs/foo.o explicitly requested and is not present? */
3d5567
	if (!fany)
3d5567
		return true;
3d5567
3d5567
	/* use foo.o in place of .libs/foo.o */
3d5567
	strcpy(slash,base);
3d5567
3d5567
	if (faccessat(fdcwd,arg,0,0))
3d5567
		sprintf(slash,".libs/%s",base);
3d5567
3d5567
	return true;
3d5567
}
3d5567
3d5567
3d5567
bool slbt_adjust_wrapper_argument(
3d5567
	char *		arg,
3d5567
	bool		fpic)
3d5567
{
3d5567
	char *	slash;
3d5567
	char *	dot;
3d5567
	char	base[PATH_MAX];
3d5567
3d5567
	if (*arg == '-')
3d5567
		return false;
3d5567
3d5567
	if (!(dot = strrchr(arg,'.')))
3d5567
		return false;
3d5567
3d5567
	if (strcmp(dot,".la"))
3d5567
		return false;
3d5567
3d5567
	if (fpic) {
3d5567
		if ((slash = strrchr(arg,'/')))
3d5567
			slash++;
3d5567
		else
3d5567
			slash = arg;
3d5567
3d5567
		if (slbt_snprintf(base,sizeof(base),
3d5567
				"%s",slash) < 0)
3d5567
			return false;
3d5567
3d5567
		sprintf(slash,".libs/%s",base);
3d5567
		dot = strrchr(arg,'.');
3d5567
	}
3d5567
3d5567
	strcpy(dot,".a");
3d5567
	return true;
3d5567
}
3d5567
3d5567
3d5567
int slbt_adjust_linker_argument(
3d5567
	const struct slbt_driver_ctx *	dctx,
3d5567
	char *				arg,
3d5567
	char **				xarg,
3d5567
	bool				fpic,
3d5567
	const char *			dsosuffix,
3d5567
	const char *			arsuffix,
3d5567
	struct slbt_deps_meta * 	depsmeta)
3d5567
{
3d5567
	int	fdcwd;
3d5567
	int	fdlib;
3d5567
	char *	slash;
3d5567
	char *	dot;
3d5567
	char	base[PATH_MAX];
3d5567
3d5567
	if (*arg == '-')
3d5567
		return 0;
3d5567
3d5567
	if (!(dot = strrchr(arg,'.')))
3d5567
		return 0;
3d5567
3d5567
	if (!(strcmp(dot,arsuffix))) {
3d5567
		*xarg = arg;
3d5567
		return slbt_get_deps_meta(dctx,arg,1,depsmeta);
3d5567
	}
3d5567
3d5567
	if (!(strcmp(dot,dsosuffix)))
3d5567
		return slbt_get_deps_meta(dctx,arg,1,depsmeta);
3d5567
3d5567
	if (strcmp(dot,".la"))
3d5567
		return 0;
3d5567
3d5567
	if (fpic) {
3d5567
		if ((slash = strrchr(arg,'/')))
3d5567
			slash++;
3d5567
		else
3d5567
			slash = arg;
3d5567
3d5567
		if (slbt_snprintf(base,sizeof(base),
3d5567
				"%s",slash) < 0)
3d5567
			return 0;
3d5567
3d5567
		sprintf(slash,".libs/%s",base);
3d5567
		dot = strrchr(arg,'.');
3d5567
	}
3d5567
3d5567
	/* fdcwd */
3d5567
	fdcwd = slbt_driver_fdcwd(dctx);
3d5567
3d5567
	/* shared library dependency? */
3d5567
	if (fpic) {
3d5567
		sprintf(dot,"%s",dsosuffix);
3d5567
3d5567
		if (slbt_symlink_is_a_placeholder(fdcwd,arg))
3d5567
			sprintf(dot,"%s",arsuffix);
3d5567
		else if ((fdlib = openat(fdcwd,arg,O_RDONLY)) >= 0)
3d5567
			close(fdlib);
3d5567
		else
3d5567
			sprintf(dot,"%s",arsuffix);
3d5567
3d5567
		return slbt_get_deps_meta(dctx,arg,0,depsmeta);
3d5567
	}
3d5567
3d5567
	/* input archive */
3d5567
	sprintf(dot,"%s",arsuffix);
3d5567
	return slbt_get_deps_meta(dctx,arg,0,depsmeta);
3d5567
}
3d5567
3d5567
3d5567
int slbt_exec_link_adjust_argument_vector(
3d5567
	const struct slbt_driver_ctx *	dctx,
3d5567
	struct slbt_exec_ctx *		ectx,
3d5567
	struct slbt_deps_meta *		depsmeta,
3d5567
	const char *			cwd,
3d5567
	bool				flibrary)
3d5567
{
3d5567
	int			fd;
3d5567
	int			fdcwd;
3d5567
	char ** 		carg;
3d5567
	char ** 		aarg;
3d5567
	char *			ldir;
3d5567
	char *			slash;
3d5567
	char *			mark;
3d5567
	char *			darg;
3d5567
	char *			dot;
3d5567
	char *			base;
3d5567
	char *			dpath;
3d5567
	int			argc;
3d5567
	char			arg[PATH_MAX];
3d5567
	char			lib[PATH_MAX];
3d5567
	char			depdir  [PATH_MAX];
3d5567
	char			rpathdir[PATH_MAX];
3d5567
	char			rpathlnk[PATH_MAX];
3d5567
	struct stat		st;
3d5567
	size_t			size;
3d5567
	size_t			dlen;
9c528f
	struct slbt_map_info *	mapinfo = 0;
3d5567
	bool			fwholearchive = false;
3d5567
	int			ret;
3d5567
3d5567
	for (argc=0,carg=ectx->cargv; *carg; carg++)
3d5567
		argc++;
3d5567
3d5567
	if (!(depsmeta->args = calloc(1,depsmeta->infolen)))
3d5567
		return SLBT_SYSTEM_ERROR(dctx,0);
3d5567
3d5567
	argc *= 3;
3d5567
	argc += depsmeta->depscnt;
3d5567
3d5567
	if (!(depsmeta->altv = calloc(argc,sizeof(char *))))
3d5567
		return slbt_linkcmd_exit(
3d5567
			depsmeta,
3d5567
			SLBT_SYSTEM_ERROR(dctx,0));
3d5567
3d5567
	fdcwd = slbt_driver_fdcwd(dctx);
3d5567
3d5567
	carg = ectx->cargv;
3d5567
	aarg = depsmeta->altv;
3d5567
	darg = depsmeta->args;
3d5567
	size = depsmeta->infolen;
3d5567
3d5567
	for (; *carg; ) {
3d5567
		dpath = 0;
3d5567
3d5567
		if (!strcmp(*carg,"-Wl,--whole-archive"))
3d5567
			fwholearchive = true;
3d5567
		else if (!strcmp(*carg,"-Wl,--no-whole-archive"))
3d5567
			fwholearchive = false;
3d5567
3d5567
3d5567
3d5567
		/* output annotation */
3d5567
		if (carg == ectx->lout[0]) {
3d5567
			ectx->mout[0] = &aarg[0];
3d5567
			ectx->mout[1] = &aarg[1];
3d5567
		}
3d5567
3d5567
		/* argument translation */
3d5567
		mark = *carg;
3d5567
3d5567
		if ((mark[0] == '-') && (mark[1] == 'L')) {
3d5567
			if (mark[2]) {
3d5567
				ldir = &mark[2];
3d5567
			} else {
3d5567
				*aarg++ = *carg++;
3d5567
				ldir    = *carg;
3d5567
			}
3d5567
3d5567
			mark = ldir + strlen(ldir);
3d5567
3d5567
			if (mark[-1] == '/')
3d5567
				strcpy(mark,".libs");
3d5567
			else
3d5567
				strcpy(mark,"/.libs");
3d5567
3d5567
			if ((fd = openat(fdcwd,ldir,O_DIRECTORY,0)) < 0)
3d5567
				*mark = 0;
3d5567
			else {
3d5567
				close(fd);
3d5567
3d5567
				if ((ret = slbt_emit_fdwrap_amend_dl_path(
3d5567
						dctx,ectx,depsmeta,
3d5567
						"%s",ldir)) < 0)
3d5567
					return ret;
3d5567
			}
3d5567
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (**carg == '-') {
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (!(dot = strrchr(*carg,'.'))) {
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (ectx->xargv[carg - ectx->cargv]) {
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (!(strcmp(dot,".a"))) {
3d5567
			if (flibrary && !fwholearchive)
3d5567
				*aarg++ = "-Wl,--whole-archive";
3d5567
3d5567
			dpath = lib;
3d5567
			sprintf(lib,"%s.slibtool.deps",*carg);
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
			if (flibrary && !fwholearchive)
3d5567
				*aarg++ = "-Wl,--no-whole-archive";
3d5567
3d5567
		} else if (strcmp(dot,dctx->cctx->settings.dsosuffix)) {
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (carg == ectx->lout[1]) {
3d5567
			/* ^^^hoppla^^^ */
3d5567
			*aarg++ = *carg++;
3d5567
		} else {
3d5567
			/* -rpath */
3d5567
			sprintf(rpathlnk,"%s.slibtool.rpath",*carg);
3d5567
3d5567
			if (!fstatat(fdcwd,rpathlnk,&st,AT_SYMLINK_NOFOLLOW)) {
3d5567
				if (slbt_readlinkat(
3d5567
						fdcwd,
3d5567
						rpathlnk,
3d5567
						rpathdir,
3d5567
						sizeof(rpathdir)))
3d5567
					return slbt_linkcmd_exit(
3d5567
						depsmeta,
3d5567
						SLBT_SYSTEM_ERROR(dctx,rpathlnk));
3d5567
3d5567
				sprintf(darg,"-Wl,%s",rpathdir);
3d5567
				*aarg++ = "-Wl,-rpath";
3d5567
				*aarg++ = darg;
3d5567
				darg   += strlen(darg);
3d5567
				darg++;
3d5567
			}
3d5567
3d5567
			dpath = lib;
3d5567
			sprintf(lib,"%s.slibtool.deps",*carg);
3d5567
3d5567
			/* account for {'-','L','-','l'} */
3d5567
			if (slbt_snprintf(arg,
3d5567
					sizeof(arg) - 4,
3d5567
					"%s",*carg) < 0)
3d5567
				return slbt_linkcmd_exit(
3d5567
					depsmeta,
3d5567
					SLBT_BUFFER_ERROR(dctx));
3d5567
3d5567
			if ((slash = strrchr(arg,'/'))) {
3d5567
				sprintf(*carg,"-L%s",arg);
3d5567
3d5567
				mark   = strrchr(*carg,'/');
3d5567
				*mark  = 0;
3d5567
				*slash = 0;
3d5567
3d5567
				if ((ret = slbt_emit_fdwrap_amend_dl_path(
3d5567
						dctx,ectx,depsmeta,
3d5567
						"%s%s%s",
3d5567
						((arg[0] == '/') ? "" : cwd),
3d5567
						((arg[0] == '/') ? "" : "/"),
3d5567
						arg)) < 0) {
3d5567
					return ret;
3d5567
				}
3d5567
3d5567
				dlen = strlen(dctx->cctx->settings.dsoprefix);
3d5567
3d5567
				/* -module? (todo: non-portable usage, display warning) */
3d5567
				if (strncmp(++slash,dctx->cctx->settings.dsoprefix,dlen)) {
3d5567
					*--slash = '/';
3d5567
					strcpy(*carg,arg);
3d5567
					*aarg++ = *carg++;
3d5567
				} else {
3d5567
					*aarg++ = *carg++;
3d5567
					*aarg++ = ++mark;
3d5567
3d5567
					slash += dlen;
3d5567
3d5567
					sprintf(mark,"-l%s",slash);
3d5567
					dot  = strrchr(mark,'.');
3d5567
					*dot = 0;
3d5567
				}
3d5567
			} else {
3d5567
				*aarg++ = *carg++;
3d5567
			}
3d5567
		}
3d5567
3d5567
		if (dpath && !fstatat(fdcwd,dpath,&st,0)) {
3d5567
			if (!(mapinfo = slbt_map_file(
3d5567
					fdcwd,dpath,
3d5567
					SLBT_MAP_INPUT)))
3d5567
				return slbt_linkcmd_exit(
3d5567
					depsmeta,
3d5567
					SLBT_SYSTEM_ERROR(dctx,dpath));
3d5567
3d5567
			if (!(strncmp(lib,".libs/",6))) {
3d5567
				*aarg++ = "-L.libs";
3d5567
				lib[1] = 0;
3d5567
			} else if ((base = strrchr(lib,'/'))) {
3d5567
				if (base - lib == 5) {
3d5567
					if (!(strncmp(&base[-5],".libs/",6)))
3d5567
						base -= 4;
3d5567
3d5567
				} else if (base - lib >= 6) {
3d5567
					if (!(strncmp(&base[-6],"/.libs/",7)))
3d5567
						base -= 6;
3d5567
				}
3d5567
3d5567
				*base = 0;
3d5567
			} else {
3d5567
				lib[0] = '.';
3d5567
				lib[1] = 0;
3d5567
			}
3d5567
3d5567
			while (mapinfo->mark < mapinfo->cap) {
3d5567
				if (slbt_mapped_readline(dctx,mapinfo,darg,size))
3d5567
					return slbt_linkcmd_exit(
3d5567
						depsmeta,
3d5567
						SLBT_NESTED_ERROR(dctx));
3d5567
3d5567
				*aarg++   = darg;
3d5567
				mark      = darg;
3d5567
3d5567
				dlen      = strlen(darg);
3d5567
				size     -= dlen;
3d5567
				darg     += dlen;
3d5567
				darg[-1]  = 0;
3d5567
3d5567
				/* handle -L... as needed */
3d5567
				if ((mark[0] == '-')
3d5567
						&& (mark[1] == 'L')
3d5567
						&& (mark[2] != '/')) {
3d5567
					if (strlen(mark) >= sizeof(depdir) - 1)
3d5567
						return slbt_linkcmd_exit(
3d5567
							depsmeta,
3d5567
							SLBT_BUFFER_ERROR(dctx));
3d5567
3d5567
					darg = mark;
3d5567
					strcpy(depdir,&mark[2]);
3d5567
					sprintf(darg,"-L%s/%s",lib,depdir);
3d5567
3d5567
					darg += strlen(darg);
3d5567
					darg++;
3d5567
3d5567
					if ((ret = slbt_emit_fdwrap_amend_dl_path(
3d5567
							dctx,ectx,depsmeta,
3d5567
							"%s/%s",lib,depdir)) < 0)
3d5567
						return ret;
3d5567
3d5567
				} else if ((mark[0] == '-') && (mark[1] == 'L')) {
3d5567
					if ((ret = slbt_emit_fdwrap_amend_dl_path(
3d5567
							dctx,ectx,depsmeta,
3d5567
							"%s",&mark[2])) < 0)
3d5567
						return ret;
3d5567
				}
3d5567
			}
3d5567
		}
9c528f
9c528f
		if (mapinfo) {
9c528f
			slbt_unmap_file(mapinfo);
9c528f
			mapinfo = 0;
9c528f
		}
3d5567
	}
3d5567
3d5567
	if (dctx->cctx->drvflags & SLBT_DRIVER_EXPORT_DYNAMIC)
3d5567
		*aarg++ = "-Wl,--export-dynamic";
3d5567
3d5567
	return 0;
3d5567
}
3d5567
3d5567
3d5567
int slbt_exec_link_finalize_argument_vector(
3d5567
	const struct slbt_driver_ctx *	dctx,
3d5567
	struct slbt_exec_ctx *		ectx)
3d5567
{
3d5567
	char *		sargv[1024];
3d5567
	char **		sargvbuf;
3d5567
	char **		base;
3d5567
	char **		parg;
3d5567
	char **		aarg;
3d5567
	char **		oarg;
3d5567
	char **		larg;
3d5567
	char **		darg;
3d5567
	char **		earg;
3d5567
	char **		rarg;
3d5567
	char **		aargv;
3d5567
	char **		oargv;
3d5567
	char **		cap;
3d5567
	char **		src;
3d5567
	char **		dst;
3d5567
	char *		arg;
3d5567
	char *		dot;
3d5567
	char *		ccwrap;
3d5567
	const char *	arsuffix;
3d5567
3d5567
	/* vector size */
3d5567
	base     = ectx->argv;
3d5567
	arsuffix = dctx->cctx->settings.arsuffix;
3d5567
3d5567
	for (parg=base; *parg; parg++)
3d5567
		(void)0;
3d5567
3d5567
	/* buffer */
3d5567
	if (parg - base < 512) {
3d5567
		aargv    = &sargv[0];
3d5567
		oargv    = &sargv[512];
3d5567
		aarg     = aargv;
3d5567
		oarg     = oargv;
3d5567
		sargvbuf = 0;
3d5567
3d5567
	} else if (!(sargvbuf = calloc(2*(parg-base+1),sizeof(char *)))) {
3d5567
		return SLBT_SYSTEM_ERROR(dctx,0);
3d5567
3d5567
	} else {
3d5567
		aargv = &sargvbuf[0];
3d5567
		oargv = &sargvbuf[parg-base+1];
3d5567
		aarg  = aargv;
3d5567
		oarg  = oargv;
3d5567
	}
3d5567
3d5567
	/* (program name) */
3d5567
	parg = &base[1];
3d5567
3d5567
	/* split object args from all other args, record output */
3d5567
	/* annotation, and remove redundant -l arguments       */
3d5567
	for (; *parg; ) {
3d5567
		if (ectx->lout[0] == parg) {
3d5567
			ectx->lout[0] = &aarg[0];
3d5567
			ectx->lout[1] = &aarg[1];
3d5567
		}
3d5567
3d5567
		if (ectx->mout[0] == parg) {
3d5567
			ectx->mout[0] = &aarg[0];
3d5567
			ectx->mout[1] = &aarg[1];
3d5567
		}
3d5567
3d5567
		arg = *parg;
3d5567
		dot = strrchr(arg,'.');
3d5567
3d5567
		/* object input argument? */
3d5567
		if (dot && (!strcmp(dot,".o") || !strcmp(dot,".lo"))) {
3d5567
			*oarg++ = *parg++;
3d5567
3d5567
		/* --whole-archive input argument? */
3d5567
		} else if ((arg[0] == '-')
3d5567
				&& (arg[1] == 'W')
3d5567
				&& (arg[2] == 'l')
3d5567
				&& (arg[3] == ',')
3d5567
				&& !strcmp(&arg[4],"--whole-archive")
3d5567
				&& parg[1] && parg[2]
3d5567
				&& !strcmp(parg[2],"-Wl,--no-whole-archive")
3d5567
				&& (dot = strrchr(parg[1],'.'))
3d5567
				&& !strcmp(dot,arsuffix)) {
3d5567
			*oarg++ = *parg++;
3d5567
			*oarg++ = *parg++;
3d5567
			*oarg++ = *parg++;
3d5567
3d5567
		/* local archive input argument? */
3d5567
		} else if (dot && !strcmp(dot,arsuffix)) {
3d5567
			*oarg++ = *parg++;
3d5567
3d5567
		/* -l argument? */
3d5567
		} else if ((parg[0][0] == '-') && (parg[0][1] == 'l')) {
3d5567
			/* find the previous occurence of this -l argument */
3d5567
			for (rarg=0, larg=&aarg[-1]; !rarg && (larg>=aargv); larg--)
3d5567
				if (!strcmp(*larg,*parg))
3d5567
					rarg = larg;
3d5567
3d5567
			/* first occurence of this specific -l argument? */
3d5567
			if (!rarg) {
3d5567
				*aarg++ = *parg++;
3d5567
3d5567
			} else {
3d5567
				larg = rarg;
3d5567
3d5567
				/* if all -l arguments following the previous */
3d5567
				/* occurence had already appeared before the */
3d5567
				/* previous argument, then the current      */
3d5567
				/* occurence is redundant.                 */
3d5567
3d5567
				for (darg=&larg[1]; rarg && darg
3d5567
					/* only test -l arguments */
3d5567
					if ((darg[0][0] == '-') && (darg[0][1] == 'l')) {
3d5567
						for (rarg=0, earg=aargv; !rarg && earg
3d5567
							if (!strcmp(*earg,*darg))
3d5567
								rarg = darg;
3d5567
					}
3d5567
				}
3d5567
3d5567
				/* final verdict: repeated -l argument? */
3d5567
				if (rarg) {
3d5567
					parg++;
3d5567
3d5567
				} else {
3d5567
					*aarg++ = *parg++;
3d5567
				}
3d5567
			}
3d5567
3d5567
		/* -L argument? */
3d5567
		} else if ((parg[0][0] == '-') && (parg[0][1] == 'L')) {
3d5567
			/* find a previous occurence of this -L argument */
3d5567
			for (rarg=0, larg=aargv; !rarg && (larg
3d5567
				if (!strcmp(*larg,*parg))
3d5567
					rarg = larg;
3d5567
3d5567
			/* repeated -L argument? */
3d5567
			if (rarg) {
3d5567
				parg++;
3d5567
			} else {
3d5567
				*aarg++ = *parg++;
3d5567
			}
3d5567
3d5567
		/* placeholder argument? */
3d5567
		} else if (!strncmp(*parg,"-USLIBTOOL_PLACEHOLDER_",23)) {
3d5567
			parg++;
3d5567
3d5567
		/* all other arguments */
3d5567
		} else {
3d5567
			*aarg++ = *parg++;
3d5567
		}
3d5567
	}
3d5567
3d5567
	/* program name, ccwrap */
3d5567
	if ((ccwrap = (char *)dctx->cctx->ccwrap)) {
3d5567
		base[1] = base[0];
3d5567
		base[0] = ccwrap;
3d5567
		base++;
3d5567
	}
3d5567
3d5567
	/* join object args */
3d5567
	src = oargv;
3d5567
	cap = oarg;
3d5567
	dst = &base[1];
3d5567
3d5567
	for (; src
3d5567
		*dst++ = *src++;
3d5567
3d5567
	/* join all other args */
3d5567
	src = aargv;
3d5567
	cap = aarg;
3d5567
3d5567
	for (; src
3d5567
		*dst++ = *src++;
3d5567
3d5567
	/* properly null-terminate argv, accounting for redundant -l arguments */
3d5567
	*dst = 0;
3d5567
3d5567
	/* output annotation */
3d5567
	if (ectx->lout[0]) {
3d5567
		ectx->lout[0] = &base[1] + (oarg - oargv) + (ectx->lout[0] - aargv);
3d5567
		ectx->lout[1] = ectx->lout[0] + 1;
3d5567
	}
3d5567
3d5567
	if (ectx->mout[0]) {
3d5567
		ectx->mout[0] = &base[1] + (oarg - oargv) + (ectx->mout[0] - aargv);
3d5567
		ectx->mout[1] = ectx->mout[0] + 1;
3d5567
	}
3d5567
3d5567
	/* all done */
3d5567
	if (sargvbuf)
3d5567
		free(sargvbuf);
3d5567
3d5567
	return 0;
3d5567
}