Blame src/logic/slbt_exec_link.c

2bd749
/*******************************************************************/
2bd749
/*  slibtool: a skinny libtool implementation, written in C        */
49181b
/*  Copyright (C) 2016--2024  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
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 */
9f995b
	if ((ret == 0) && dctx->cctx->rpath)
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
}