Blame src/logic/slbt_exec_link.c

2bd749
/*******************************************************************/
2bd749
/*  slibtool: a skinny libtool implementation, written in C        */
bb281c
/*  Copyright (C) 2016--2021  SysDeer Technologies, LLC            */
2bd749
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
2bd749
/*******************************************************************/
2bd749
Lucio Andrés Illanes Albornoz e945f1
#include <stdarg.h>
8b7d50
#include <stdlib.h>
f0d5f3
#include <stdio.h>
2bd749
#include <string.h>
2bd749
#include <stdbool.h>
2bd749
#include <fcntl.h>
2bd749
#include <errno.h>
2bd749
#include <sys/stat.h>
2bd749
2bd749
#include <slibtool/slibtool.h>
2bd749
#include "slibtool_spawn_impl.h"
3895af
#include "slibtool_mkdir_impl.h"
9706fa
#include "slibtool_driver_impl.h"
c178e3
#include "slibtool_dprintf_impl.h"
9c9f28
#include "slibtool_errinfo_impl.h"
b08054
#include "slibtool_linkcmd_impl.h"
05ea52
#include "slibtool_mapfile_impl.h"
a9cfe4
#include "slibtool_metafile_impl.h"
50b6ef
#include "slibtool_readlink_impl.h"
19022e
#include "slibtool_snprintf_impl.h"
6529aa
#include "slibtool_symlink_impl.h"
2bd749
5cc3b3
/*******************************************************************/
5cc3b3
/*                                                                 */
5cc3b3
/* -o <ltlib>  switches              input   result                */
5cc3b3
/* ----------  --------------------- -----   ------                */
b07789
/* libfoo.a    [-shared|-static]     bar.lo  libfoo.a              */
5cc3b3
/*                                                                 */
5728ce
/* ar -crs libfoo.a bar.o                                          */
5cc3b3
/*                                                                 */
5cc3b3
/*******************************************************************/
5cc3b3
a0c318
/*******************************************************************/
a0c318
/*                                                                 */
a0c318
/* -o <ltlib>  switches              input   result                */
a0c318
/* ----------  --------------------- -----   ------                */
a0c318
/* libfoo.la   -shared               bar.lo  libfoo.la             */
a0c318
/*                                           .libs/libfoo.a        */
a0c318
/*                                           .libs/libfoo.la (lnk) */
a0c318
/*                                                                 */
5728ce
/* ar -crs .libs/libfoo.a .libs/bar.o                              */
a0c318
/* (generate libfoo.la)                                            */
a0c318
/* ln -s ../libfoo.la .libs/libfoo.la                              */
f730ac
/*                                                                 */
f730ac
/*******************************************************************/
f730ac
f730ac
/*******************************************************************/
f730ac
/*                                                                 */
f730ac
/* -o <ltlib>  switches              input   result                */
f730ac
/* ----------  --------------------- -----   ------                */
f730ac
/* libfoo.la   -static               bar.lo  libfoo.la             */
f730ac
/*                                           .libs/libfoo.a        */
f730ac
/*                                           .libs/libfoo.la (lnk) */
f730ac
/*                                                                 */
5728ce
/* ar -crs .libs/libfoo.a bar.o                                    */
f730ac
/* (generate libfoo.la)                                            */
f730ac
/* ln -s ../libfoo.la .libs/libfoo.la                              */
a0c318
/*                                                                 */
a0c318
/*******************************************************************/
a0c318
3be47d
static int slbt_exec_link_exit(
3be47d
	struct slbt_deps_meta *	depsmeta,
3be47d
	int			ret)
3be47d
{
3be47d
	if (depsmeta->altv)
3be47d
		free(depsmeta->altv);
3be47d
3be47d
	if (depsmeta->args)
3be47d
		free(depsmeta->args);
3be47d
3be47d
	return ret;
3be47d
}
3be47d
Lucio Andrés Illanes Albornoz e945f1
static void slbt_emit_fdwrap_dl_path_fixup(
Lucio Andrés Illanes Albornoz e945f1
	char *	cwd,
Lucio Andrés Illanes Albornoz e945f1
	char *	dpfixup,
Lucio Andrés Illanes Albornoz e945f1
	size_t	dpfixup_size,
Lucio Andrés Illanes Albornoz e945f1
	char *	wrapper)
Lucio Andrés Illanes Albornoz e945f1
{
Lucio Andrés Illanes Albornoz e945f1
	char *	p;
Lucio Andrés Illanes Albornoz e945f1
	char *	q;
Lucio Andrés Illanes Albornoz e945f1
	char *	wrapper_dname;
Lucio Andrés Illanes Albornoz e945f1
Lucio Andrés Illanes Albornoz e945f1
	/* obtain cwd-relative directory name of wrapper */
Lucio Andrés Illanes Albornoz e945f1
	for (p=cwd,q=wrapper; *p && *q && (*p==*q); p++,q++)
Lucio Andrés Illanes Albornoz e945f1
		(void)0;
Lucio Andrés Illanes Albornoz e945f1
Lucio Andrés Illanes Albornoz e945f1
	wrapper_dname = (*q == '/') ? (q + 1) : q;
Lucio Andrés Illanes Albornoz e945f1
Lucio Andrés Illanes Albornoz e945f1
	dpfixup[0] = 0; strncat(dpfixup,"${0%/*}",dpfixup_size - 1);
Lucio Andrés Illanes Albornoz e945f1
Lucio Andrés Illanes Albornoz e945f1
	/* append parent directory fixup for each level of depth in wrapper_dname */
bd56f8
	for (p=wrapper_dname,q=0; *p; ) {
Lucio Andrés Illanes Albornoz e945f1
		if ((p[0] == '.') && (p[1] == '/')) {
Lucio Andrés Illanes Albornoz e945f1
			p++; p++;
Lucio Andrés Illanes Albornoz e945f1
		} else if ((q = strchr(p, '/'))) {
Lucio Andrés Illanes Albornoz e945f1
			strncat(dpfixup,"/..",dpfixup_size-1); p = (q + 1);
Lucio Andrés Illanes Albornoz e945f1
		} else {
Lucio Andrés Illanes Albornoz e945f1
			break;
Lucio Andrés Illanes Albornoz e945f1
		}
Lucio Andrés Illanes Albornoz e945f1
	}
Lucio Andrés Illanes Albornoz e945f1
Lucio Andrés Illanes Albornoz e945f1
	strncat(dpfixup,"/",dpfixup_size-1);
Lucio Andrés Illanes Albornoz e945f1
}
Lucio Andrés Illanes Albornoz e945f1
f6ccbe
static int slbt_exec_link_create_executable(
f6ccbe
	const struct slbt_driver_ctx *	dctx,
f6ccbe
	struct slbt_exec_ctx *		ectx,
f6ccbe
	const char *			exefilename)
f6ccbe
{
5fac6c
	int	fdcwd;
9706fa
	int	fdwrap;
f6ccbe
	char ** parg;
46aa6f
	char ** xarg;
e9dbdf
	char *	base;
34988f
	char *	ccwrap;
5ee0d1
	char	cwd    [PATH_MAX];
Lucio Andrés Illanes Albornoz e945f1
	char	dpfixup[PATH_MAX];
f6ccbe
	char	output [PATH_MAX];
5ee0d1
	char	wrapper[PATH_MAX];
5e5804
	char	wraplnk[PATH_MAX];
238670
	bool	fabspath;
372423
	bool	fpic;
dac9cd
	const struct slbt_source_version * verinfo;
bd9cc9
	struct slbt_deps_meta depsmeta = {0,0,0,0};
6beda1
	struct stat st;
f6ccbe
f6ccbe
	/* initial state */
f6ccbe
	slbt_reset_arguments(ectx);
f6ccbe
f6ccbe
	/* placeholders */
f6ccbe
	slbt_reset_placeholders(ectx);
f6ccbe
5fac6c
	/* fdcwd */
5fac6c
	fdcwd = slbt_driver_fdcwd(dctx);
5fac6c
372423
	/* fpic */
372423
	fpic = !(dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC);
372423
f6ccbe
	/* input argument adjustment */
f6ccbe
	for (parg=ectx->cargv; *parg; parg++)
2fd6a3
		slbt_adjust_object_argument(*parg,fpic,true,fdcwd);
f6ccbe
f6ccbe
	/* linker argument adjustment */
46aa6f
	for (parg=ectx->cargv, xarg=ectx->xargv; *parg; parg++, xarg++)
afaba2
		if (slbt_adjust_linker_argument(
9c9f28
				dctx,
46aa6f
				*parg,xarg,true,
afaba2
				dctx->cctx->settings.dsosuffix,
8b7d50
				dctx->cctx->settings.arsuffix,
8b7d50
				&depsmeta) < 0)
9c9f28
			return SLBT_NESTED_ERROR(dctx);
f6ccbe
f6ccbe
	/* --no-undefined */
f6ccbe
	if (dctx->cctx->drvflags & SLBT_DRIVER_NO_UNDEFINED)
f6ccbe
		*ectx->noundef = "-Wl,--no-undefined";
f6ccbe
9706fa
	/* executable wrapper: create */
19022e
	if (slbt_snprintf(wrapper,sizeof(wrapper),
9706fa
				"%s.wrapper.tmp",
19022e
				dctx->cctx->output) < 0)
9c9f28
		return SLBT_BUFFER_ERROR(dctx);
5ee0d1
5fac6c
	if ((fdwrap = openat(fdcwd,wrapper,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0)
6beda1
		return SLBT_SYSTEM_ERROR(dctx,wrapper);
5ee0d1
9706fa
	slbt_exec_set_fdwrapper(ectx,fdwrap);
9706fa
9706fa
	/* executable wrapper: header */
dac9cd
	verinfo = slbt_source_version();
dac9cd
Lucio Andrés Illanes Albornoz e945f1
	/* cwd, DL_PATH fixup */
bd56f8
	if (slbt_realpath(fdcwd,".",O_DIRECTORY,cwd,sizeof(cwd)))
Lucio Andrés Illanes Albornoz e945f1
		return SLBT_SYSTEM_ERROR(dctx,0);
bd56f8
bd56f8
	slbt_emit_fdwrap_dl_path_fixup(
bd56f8
		cwd,dpfixup,sizeof(dpfixup),
bd56f8
		wrapper);
Lucio Andrés Illanes Albornoz e945f1
9706fa
	if (slbt_dprintf(fdwrap,
5ee0d1
			"#!/bin/sh\n"
821d55
			"# libtool compatible executable wrapper\n"
dac9cd
			"# Generated by %s (slibtool %d.%d.%d)\n"
dac9cd
			"# [commit reference: %s]\n\n"
1f87fd
5ee0d1
			"if [ -z \"$%s\" ]; then\n"
5ee0d1
			"\tDL_PATH=\n"
5ee0d1
			"\tCOLON=\n"
5ee0d1
			"\tLCOLON=\n"
5ee0d1
			"else\n"
5ee0d1
			"\tDL_PATH=\n"
5ee0d1
			"\tCOLON=\n"
5ee0d1
			"\tLCOLON=':'\n"
Lucio Andrés Illanes Albornoz e945f1
			"fi\n\n"
Lucio Andrés Illanes Albornoz e945f1
			"DL_PATH_FIXUP=\"%s\";\n\n",
1f87fd
1f87fd
			dctx->program,
dac9cd
			verinfo->major,verinfo->minor,verinfo->revision,
dac9cd
			verinfo->commit,
Lucio Andrés Illanes Albornoz e945f1
			dctx->cctx->settings.ldpathenv,
Lucio Andrés Illanes Albornoz e945f1
			dpfixup) < 0)
6beda1
		return SLBT_SYSTEM_ERROR(dctx,0);
5ee0d1
f6ccbe
	/* output */
19022e
	if (slbt_snprintf(output,sizeof(output),
19022e
			"%s",exefilename) < 0)
9c9f28
		return SLBT_BUFFER_ERROR(dctx);
f6ccbe
f6ccbe
	*ectx->lout[0] = "-o";
f6ccbe
	*ectx->lout[1] = output;
f6ccbe
e5d83d
	/* static? */
e5d83d
	if (dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC)
e5d83d
		*ectx->dpic = "-static";
e5d83d
2ef5be
	/* .libs/libfoo.so --> -L.libs -lfoo */
2ef5be
	if (slbt_exec_link_adjust_argument_vector(
3be47d
			dctx,ectx,&depsmeta,cwd,false))
9c9f28
		return SLBT_NESTED_ERROR(dctx);
2ef5be
2ef5be
	/* using alternate argument vector */
34988f
	ccwrap        = (char *)dctx->cctx->ccwrap;
3be47d
	ectx->argv    = depsmeta.altv;
34988f
	ectx->program = ccwrap ? ccwrap : depsmeta.altv[0];
2ef5be
4a0a6c
	/* executable wrapper symlink */
19022e
	if (slbt_snprintf(wraplnk,sizeof(wraplnk),
19022e
			"%s.exe.wrapper",
19022e
			exefilename) < 0)
9c9f28
		return slbt_exec_link_exit(
9c9f28
			&depsmeta,
9c9f28
			SLBT_BUFFER_ERROR(dctx));
4a0a6c
e9dbdf
	/* executable wrapper: base name */
70949a
	base = strrchr(wraplnk,'/');
70949a
	base++;
e9dbdf
5ee0d1
	/* executable wrapper: footer */
238670
	fabspath = (exefilename[0] == '/');
238670
9706fa
	if (slbt_dprintf(fdwrap,
Lucio Andrés Illanes Albornoz acc4e7
			"DL_PATH=\"${DL_PATH}${LCOLON}${%s}\"\n\n"
92ddbc
			"export %s=\"$DL_PATH\"\n\n"
1ce3d5
			"if [ $(basename \"$0\") = \"%s\" ]; then\n"
e9dbdf
			"\tprogram=\"$1\"; shift\n"
e9dbdf
			"\texec \"$program\" \"$@\"\n"
e9dbdf
			"fi\n\n"
5ee0d1
			"exec %s/%s \"$@\"\n",
5ee0d1
			dctx->cctx->settings.ldpathenv,
5ee0d1
			dctx->cctx->settings.ldpathenv,
e9dbdf
			base,
238670
			fabspath ? "" : cwd,
238670
			fabspath ? &exefilename[1] : exefilename) < 0)
9c9f28
		return slbt_exec_link_exit(
9c9f28
			&depsmeta,
6beda1
			SLBT_SYSTEM_ERROR(dctx,0));
5ee0d1
671454
	/* sigh */
671454
	if (slbt_exec_link_finalize_argument_vector(dctx,ectx))
671454
		return SLBT_NESTED_ERROR(dctx);
671454
f6ccbe
	/* step output */
f6ccbe
	if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
f6ccbe
		if (slbt_output_link(dctx,ectx))
9c9f28
			return slbt_exec_link_exit(
9c9f28
				&depsmeta,
9c9f28
				SLBT_NESTED_ERROR(dctx));
f6ccbe
f6ccbe
	/* spawn */
5c4295
	if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
9c9f28
		return slbt_exec_link_exit(
9c9f28
			&depsmeta,
9c9f28
			SLBT_SPAWN_ERROR(dctx));
f6ccbe
5c4295
	} else if (ectx->exitcode) {
5c4295
		return slbt_exec_link_exit(
5c4295
			&depsmeta,
5c4295
			SLBT_CUSTOM_ERROR(
5c4295
				dctx,
5c4295
				SLBT_ERR_LINK_ERROR));
5c4295
	}
5c4295
5ee0d1
	/* executable wrapper: finalize */
9706fa
	slbt_exec_close_fdwrapper(ectx);
5ee0d1
5e5804
	if (slbt_create_symlink(
5e5804
			dctx,ectx,
5e5804
			dctx->cctx->output,wraplnk,
70949a
			SLBT_SYMLINK_WRAPPER))
9c9f28
		return slbt_exec_link_exit(
9c9f28
			&depsmeta,
9c9f28
			SLBT_NESTED_ERROR(dctx));
5e5804
7ae5c1
	if (fstatat(fdcwd,wrapper,&st,0))
6beda1
		return slbt_exec_link_exit(
6beda1
			&depsmeta,
6beda1
			SLBT_SYSTEM_ERROR(dctx,wrapper));
6beda1
d586fc
	if (renameat(fdcwd,wrapper,fdcwd,dctx->cctx->output))
9c9f28
		return slbt_exec_link_exit(
9c9f28
			&depsmeta,
6beda1
			SLBT_SYSTEM_ERROR(dctx,dctx->cctx->output));
5ee0d1
289362
	if (fchmodat(fdcwd,dctx->cctx->output,0755,0))
9c9f28
		return slbt_exec_link_exit(
9c9f28
			&depsmeta,
6beda1
			SLBT_SYSTEM_ERROR(dctx,dctx->cctx->output));
5ee0d1
3be47d
	return slbt_exec_link_exit(&depsmeta,0);
f6ccbe
}
f6ccbe
b3940a
static int slbt_exec_link_create_library_symlink(
b3940a
	const struct slbt_driver_ctx *	dctx,
b3940a
	struct slbt_exec_ctx *		ectx,
b3940a
	bool				fmajor)
b3940a
{
b3940a
	char	target[PATH_MAX];
b3940a
	char	lnkname[PATH_MAX];
b3940a
c86059
	if (ectx->relfilename && dctx->cctx->verinfo.verinfo) {
c86059
		strcpy(target,ectx->relfilename);
c86059
		sprintf(lnkname,"%s.dualver",ectx->dsofilename);
c86059
c86059
		if (slbt_create_symlink(
c86059
				dctx,ectx,
c86059
				target,lnkname,
c86059
				SLBT_SYMLINK_DEFAULT))
c86059
			return SLBT_NESTED_ERROR(dctx);
c86059
	} else if (ectx->relfilename) {
112a2b
		strcpy(target,ectx->relfilename);
112a2b
		sprintf(lnkname,"%s.release",ectx->dsofilename);
112a2b
c86059
		if (slbt_create_symlink(
c86059
				dctx,ectx,
c86059
				target,lnkname,
c86059
				SLBT_SYMLINK_DEFAULT))
c86059
			return SLBT_NESTED_ERROR(dctx);
600957
	} else {
08f5f9
		sprintf(target,"%s%s.%d.%d.%d%s",
08f5f9
			ectx->dsobasename,
08f5f9
			dctx->cctx->settings.osdsuffix,
112a2b
			dctx->cctx->verinfo.major,
112a2b
			dctx->cctx->verinfo.minor,
08f5f9
			dctx->cctx->verinfo.revision,
08f5f9
			dctx->cctx->settings.osdfussix);
600957
	}
600957
b3940a
600957
	if (fmajor && ectx->dsorellnkname) {
600957
		sprintf(lnkname,"%s.%d",
600957
			ectx->dsorellnkname,
600957
			dctx->cctx->verinfo.major);
600957
600957
	} else if (fmajor) {
08f5f9
		sprintf(lnkname,"%s%s.%d%s",
08f5f9
			ectx->dsobasename,
08f5f9
			dctx->cctx->settings.osdsuffix,
08f5f9
			dctx->cctx->verinfo.major,
08f5f9
			dctx->cctx->settings.osdfussix);
b3940a
600957
	} else {
b3940a
		strcpy(lnkname,ectx->dsofilename);
600957
	}
600957
b3940a
dbd229
	if (fmajor && (dctx->cctx->drvflags & SLBT_DRIVER_IMAGE_PE))
dbd229
		return slbt_copy_file(
dbd229
			dctx,ectx,
dbd229
			target,lnkname);
dbd229
	else
dbd229
		return slbt_create_symlink(
dbd229
			dctx,ectx,
dbd229
			target,lnkname,
cc0827
			SLBT_SYMLINK_DEFAULT);
b3940a
}
b3940a
2bd749
int slbt_exec_link(
2bd749
	const struct slbt_driver_ctx *	dctx,
2bd749
	struct slbt_exec_ctx *		ectx)
2bd749
{
2bd749
	int			ret;
a51ace
	const char *		output;
2bd749
	char *			dot;
2bd749
	struct slbt_exec_ctx *	actx;
372423
	bool			fpic;
372423
	bool			fstaticonly;
9112ac
	char			soname[PATH_MAX];
4469ed
	char			soxyz [PATH_MAX];
4469ed
	char			solnk [PATH_MAX];
4469ed
	char			arname[PATH_MAX];
d75902
	char			target[PATH_MAX];
d75902
	char			lnkname[PATH_MAX];
4469ed
c4a389
	/* dry run */
c4a389
	if (dctx->cctx->drvflags & SLBT_DRIVER_DRY_RUN)
c4a389
		return 0;
c4a389
2f9f52
	/* context */
2f9f52
	if (ectx)
2f9f52
		actx = 0;
2f9f52
	else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
2f9f52
		return SLBT_NESTED_ERROR(dctx);
2f9f52
	else
2f9f52
		actx = ectx;
2f9f52
4469ed
	/* libfoo.so.x.y.z */
19022e
	if (slbt_snprintf(soxyz,sizeof(soxyz),
19022e
				"%s%s%s%s%s.%d.%d.%d%s",
2f9f52
				ectx->sonameprefix,
4469ed
				dctx->cctx->libname,
f02083
				dctx->cctx->release ? "-" : "",
f02083
				dctx->cctx->release ? dctx->cctx->release : "",
08f5f9
				dctx->cctx->settings.osdsuffix,
4469ed
				dctx->cctx->verinfo.major,
4469ed
				dctx->cctx->verinfo.minor,
08f5f9
				dctx->cctx->verinfo.revision,
19022e
				dctx->cctx->settings.osdfussix) < 0) {
2f9f52
		slbt_free_exec_ctx(actx);
9c9f28
		return SLBT_BUFFER_ERROR(dctx);
2f9f52
	}
4469ed
4469ed
	/* libfoo.so.x */
f02083
	sprintf(soname,"%s%s%s%s%s.%d%s",
2f9f52
		ectx->sonameprefix,
4469ed
		dctx->cctx->libname,
f02083
		dctx->cctx->release ? "-" : "",
f02083
		dctx->cctx->release ? dctx->cctx->release : "",
08f5f9
		dctx->cctx->settings.osdsuffix,
08f5f9
		dctx->cctx->verinfo.major,
08f5f9
		dctx->cctx->settings.osdfussix);
4469ed
4469ed
	/* libfoo.so */
4469ed
	sprintf(solnk,"%s%s%s",
2f9f52
		ectx->sonameprefix,
4469ed
		dctx->cctx->libname,
4469ed
		dctx->cctx->settings.dsosuffix);
4469ed
4469ed
	/* libfoo.a */
4469ed
	sprintf(arname,"%s%s%s",
4469ed
		dctx->cctx->settings.arprefix,
4469ed
		dctx->cctx->libname,
4469ed
		dctx->cctx->settings.arsuffix);
2bd749
5cc3b3
	/* output suffix */
a51ace
	output = dctx->cctx->output;
a51ace
	dot    = strrchr(output,'.');
5cc3b3
2bd749
	/* .libs directory */
267766
	if (slbt_mkdir(dctx,ectx->ldirname)) {
c141a0
		ret = SLBT_SYSTEM_ERROR(dctx,ectx->ldirname);
723ef0
		slbt_free_exec_ctx(actx);
c141a0
		return ret;
723ef0
	}
2bd749
5cc3b3
	/* non-pic libfoo.a */
5cc3b3
	if (dot && !strcmp(dot,".a"))
4ee438
		if (slbt_exec_link_create_archive(dctx,ectx,output,false)) {
5cc3b3
			slbt_free_exec_ctx(actx);
9c9f28
			return SLBT_NESTED_ERROR(dctx);
5cc3b3
		}
5cc3b3
372423
	/* fpic, fstaticonly */
372423
	if (dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC) {
372423
		fstaticonly = true;
372423
		fpic        = false;
f782a1
	} else if (dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_SHARED) {
f782a1
		fstaticonly = true;
f782a1
		fpic        = false;
2c2879
	} else if (dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_STATIC) {
2c2879
		fstaticonly = false;
2c2879
		fpic        = true;
372423
	} else if (dctx->cctx->drvflags & SLBT_DRIVER_SHARED) {
372423
		fstaticonly = false;
372423
		fpic        = true;
372423
	} else {
372423
		fstaticonly = false;
372423
		fpic        = false;
372423
	}
372423
c7981c
	/* libfoo.so.def.{flavor} */
c7981c
	if (dctx->cctx->libname) {
c7981c
		if (slbt_exec_link_create_host_tag(
c7981c
				dctx,ectx,
c7981c
				ectx->deffilename))
c7981c
			return SLBT_NESTED_ERROR(dctx);
c7981c
	}
c7981c
a0c318
	/* pic libfoo.a */
a0c318
	if (dot && !strcmp(dot,".la"))
a0c318
		if (slbt_exec_link_create_archive(
a0c318
				dctx,ectx,
a0c318
				ectx->arfilename,
4ee438
				fpic)) {
a0c318
			slbt_free_exec_ctx(actx);
9c9f28
			return SLBT_NESTED_ERROR(dctx);
a0c318
		}
a0c318
d55a46
	/* static-only libfoo.la */
d55a46
	if (fstaticonly && dot && !strcmp(dot,".la")) {
d55a46
		const struct slbt_flavor_settings * dflavor;
d55a46
d55a46
		if (slbt_get_flavor_settings("default",&dflavor) < 0)
d55a46
			return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LINK_FLOW);
d55a46
d55a46
		if (strcmp(dctx->cctx->settings.dsosuffix,dflavor->dsosuffix)) {
d55a46
			strcpy(target,ectx->lafilename);
d55a46
			sprintf(lnkname,"%s.shrext%s",
d55a46
				ectx->lafilename,
d55a46
				dctx->cctx->settings.dsosuffix);
d55a46
d55a46
			if (slbt_create_symlink(
d55a46
					dctx,ectx,
d55a46
					target,lnkname,
d55a46
					SLBT_SYMLINK_DEFAULT))
d55a46
				return SLBT_NESTED_ERROR(dctx);
d55a46
d55a46
			strcpy(target,lnkname);
d55a46
			sprintf(lnkname,"%s.shrext",ectx->lafilename);
d55a46
d55a46
			if (slbt_create_symlink(
d55a46
					dctx,ectx,
d55a46
					target,lnkname,
d55a46
					SLBT_SYMLINK_DEFAULT))
d55a46
				return SLBT_NESTED_ERROR(dctx);
d55a46
		}
c7981c
c7981c
		if (slbt_create_symlink(
c7981c
				dctx,ectx,
c7981c
				"/dev/null",
c7981c
				ectx->deffilename,
c7981c
				SLBT_SYMLINK_LITERAL|SLBT_SYMLINK_DEVNULL))
c7981c
			return SLBT_NESTED_ERROR(dctx);
d55a46
	}
d55a46
372423
	/* -all-static library */
372423
	if (fstaticonly && dctx->cctx->libname)
372423
		if (slbt_create_symlink(
372423
				dctx,ectx,
372423
				"/dev/null",
372423
				ectx->dsofilename,
cc0827
				SLBT_SYMLINK_LITERAL))
9c9f28
			return SLBT_NESTED_ERROR(dctx);
372423
d83e2a
	/* dynamic library via -module */
89f5e3
	if (dctx->cctx->rpath && !fstaticonly) {
89f5e3
		if (dctx->cctx->drvflags & SLBT_DRIVER_MODULE) {
89f5e3
			if (!dot || strcmp(dot,".la")) {
89f5e3
				if (slbt_exec_link_create_library(
89f5e3
						dctx,ectx,
89f5e3
						ectx->dsobasename,
89f5e3
						ectx->dsofilename,
89f5e3
						ectx->relfilename)) {
89f5e3
					slbt_free_exec_ctx(actx);
89f5e3
					return SLBT_NESTED_ERROR(dctx);
89f5e3
				}
89f5e3
ff7fb8
				slbt_free_exec_ctx(actx);
89f5e3
				return 0;
ff7fb8
			}
712060
		}
712060
	}
712060
b3940a
	/* dynamic library */
372423
	if (dot && !strcmp(dot,".la") && dctx->cctx->rpath && !fstaticonly) {
26354e
		const struct slbt_flavor_settings * dflavor;
26354e
26354e
		if (slbt_get_flavor_settings("default",&dflavor) < 0)
26354e
			return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LINK_FLOW);
26354e
d75902
		/* -shrext support */
d75902
		if (dctx->cctx->shrext) {
d75902
			strcpy(target,ectx->lafilename);
d75902
			sprintf(lnkname,"%s.shrext%s",ectx->lafilename,dctx->cctx->shrext);
d75902
d75902
			if (slbt_create_symlink(
d75902
					dctx,ectx,
d75902
					target,lnkname,
cc0827
					SLBT_SYMLINK_DEFAULT))
d75902
				return SLBT_NESTED_ERROR(dctx);
d75902
d75902
			strcpy(target,lnkname);
d75902
			sprintf(lnkname,"%s.shrext",ectx->lafilename);
d75902
d75902
			if (slbt_create_symlink(
d75902
					dctx,ectx,
d75902
					target,lnkname,
cc0827
					SLBT_SYMLINK_DEFAULT))
d75902
				return SLBT_NESTED_ERROR(dctx);
d75902
26354e
		/* non-default shared-object suffix support */
26354e
		} else if (strcmp(dctx->cctx->settings.dsosuffix,dflavor->dsosuffix)) {
26354e
			strcpy(target,ectx->lafilename);
26354e
			sprintf(lnkname,"%s.shrext%s",
26354e
				ectx->lafilename,
26354e
				dctx->cctx->settings.dsosuffix);
26354e
26354e
			if (slbt_create_symlink(
26354e
					dctx,ectx,
26354e
					target,lnkname,
26354e
					SLBT_SYMLINK_DEFAULT))
26354e
				return SLBT_NESTED_ERROR(dctx);
26354e
26354e
			strcpy(target,lnkname);
26354e
			sprintf(lnkname,"%s.shrext",ectx->lafilename);
26354e
26354e
			if (slbt_create_symlink(
26354e
					dctx,ectx,
26354e
					target,lnkname,
26354e
					SLBT_SYMLINK_DEFAULT))
26354e
				return SLBT_NESTED_ERROR(dctx);
26354e
		}
d75902
b3940a
		/* linking: libfoo.so.x.y.z */
b3940a
		if (slbt_exec_link_create_library(
b3940a
				dctx,ectx,
08f5f9
				ectx->dsobasename,
112a2b
				ectx->dsofilename,
112a2b
				ectx->relfilename)) {
b3940a
			slbt_free_exec_ctx(actx);
9c9f28
			return SLBT_NESTED_ERROR(dctx);
b3940a
		}
b3940a
867d1e
		if (!(dctx->cctx->drvflags & SLBT_DRIVER_AVOID_VERSION)) {
867d1e
			/* symlink: libfoo.so.x --> libfoo.so.x.y.z */
867d1e
			if (slbt_exec_link_create_library_symlink(
867d1e
					dctx,ectx,
867d1e
					true)) {
867d1e
				slbt_free_exec_ctx(actx);
9c9f28
				return SLBT_NESTED_ERROR(dctx);
867d1e
			}
b3940a
867d1e
			/* symlink: libfoo.so --> libfoo.so.x.y.z */
867d1e
			if (slbt_exec_link_create_library_symlink(
867d1e
					dctx,ectx,
867d1e
					false)) {
867d1e
				slbt_free_exec_ctx(actx);
9c9f28
				return SLBT_NESTED_ERROR(dctx);
867d1e
			}
112a2b
		} else if (ectx->relfilename) {
112a2b
			/* symlink: libfoo.so --> libfoo-x.y.z.so */
112a2b
			if (slbt_exec_link_create_library_symlink(
112a2b
					dctx,ectx,
112a2b
					false)) {
112a2b
				slbt_free_exec_ctx(actx);
9c9f28
				return SLBT_NESTED_ERROR(dctx);
112a2b
			}
b3940a
		}
9112ac
9112ac
		/* PE import libraries */
9112ac
		if (dctx->cctx->drvflags & SLBT_DRIVER_IMAGE_PE) {
ff4b97
			/* libfoo.x.lib.a */
9112ac
			if (slbt_exec_link_create_import_library(
9112ac
					dctx,ectx,
ff4b97
					ectx->pimpfilename,
9112ac
					ectx->deffilename,
c7981c
					soname))
9c9f28
				return SLBT_NESTED_ERROR(dctx);
9112ac
ff4b97
			/* symlink: libfoo.lib.a --> libfoo.x.lib.a */
ff4b97
			if (slbt_create_symlink(
9112ac
					dctx,ectx,
9112ac
					ectx->pimpfilename,
ff4b97
					ectx->dimpfilename,
cc0827
					SLBT_SYMLINK_DEFAULT))
9c9f28
				return SLBT_NESTED_ERROR(dctx);
9112ac
9112ac
			/* libfoo.x.y.z.lib.a */
9112ac
			if (slbt_exec_link_create_import_library(
9112ac
					dctx,ectx,
9112ac
					ectx->vimpfilename,
9112ac
					ectx->deffilename,
c7981c
					soxyz))
c7981c
				return SLBT_NESTED_ERROR(dctx);
c7981c
		} else {
c7981c
			if (slbt_create_symlink(
c7981c
					dctx,ectx,
c7981c
					"/dev/null",
c7981c
					ectx->deffilename,
c7981c
					SLBT_SYMLINK_LITERAL|SLBT_SYMLINK_DEVNULL))
9c9f28
				return SLBT_NESTED_ERROR(dctx);
9112ac
		}
b3940a
	}
b3940a
f6ccbe
	/* executable */
a02c0e
	if (!dctx->cctx->libname) {
f6ccbe
		/* linking: .libs/exefilename */
f6ccbe
		if (slbt_exec_link_create_executable(
f6ccbe
				dctx,ectx,
f6ccbe
				ectx->exefilename)) {
f6ccbe
			slbt_free_exec_ctx(actx);
9c9f28
			return SLBT_NESTED_ERROR(dctx);
f6ccbe
		}
f6ccbe
	}
f6ccbe
2bd749
	/* no wrapper? */
5cc3b3
	if (!dot || strcmp(dot,".la")) {
2bd749
		slbt_free_exec_ctx(actx);
2bd749
		return 0;
2bd749
	}
2bd749
a9cfe4
	/* library wrapper */
a9cfe4
	if (slbt_create_library_wrapper(
a9cfe4
			dctx,ectx,
a9cfe4
			arname,soname,soxyz,solnk)) {
2bd749
		slbt_free_exec_ctx(actx);
9c9f28
		return SLBT_NESTED_ERROR(dctx);
2bd749
	}
2bd749
4c76f7
	/* wrapper symlink */
9c9f28
	if ((ret = slbt_create_symlink(
a9cfe4
			dctx,ectx,
a9cfe4
			output,
a9cfe4
			ectx->lafilename,
cc0827
			SLBT_SYMLINK_WRAPPER)))
9c9f28
		SLBT_NESTED_ERROR(dctx);
4c76f7
26ea30
	/* .lai wrapper symlink */
26ea30
	if (ret == 0)
9c9f28
		if ((ret = slbt_create_symlink(
26ea30
				dctx,ectx,
26ea30
				output,
26ea30
				ectx->laifilename,
cc0827
				SLBT_SYMLINK_WRAPPER)))
9c9f28
			SLBT_NESTED_ERROR(dctx);
26ea30
2bd749
	/* all done */
2bd749
	slbt_free_exec_ctx(actx);
2bd749
4469ed
	return ret;
2bd749
}