|
|
11c887 |
/*******************************************************************/
|
|
|
eac61a |
/* slibtool: a strong libtool implementation, written in C */
|
|
|
49181b |
/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
|
|
|
11c887 |
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
|
|
|
11c887 |
/*******************************************************************/
|
|
|
11c887 |
|
|
|
11c887 |
#include <stdlib.h>
|
|
|
11c887 |
#include <stdio.h>
|
|
|
11c887 |
#include <string.h>
|
|
|
11c887 |
#include <fcntl.h>
|
|
|
11c887 |
#include <errno.h>
|
|
|
11c887 |
#include <sys/stat.h>
|
|
|
11c887 |
|
|
|
11c887 |
#include <slibtool/slibtool.h>
|
|
|
11c887 |
#include "slibtool_driver_impl.h"
|
|
|
11c887 |
#include "slibtool_errinfo_impl.h"
|
|
|
11c887 |
#include "slibtool_linkcmd_impl.h"
|
|
|
11c887 |
#include "slibtool_mapfile_impl.h"
|
|
|
11c887 |
#include "slibtool_metafile_impl.h"
|
|
|
d4b2a5 |
#include "slibtool_realpath_impl.h"
|
|
|
11c887 |
#include "slibtool_snprintf_impl.h"
|
|
|
11c887 |
#include "slibtool_symlink_impl.h"
|
|
|
11c887 |
#include "slibtool_spawn_impl.h"
|
|
|
4b56de |
#include "slibtool_visibility_impl.h"
|
|
|
11c887 |
|
|
|
11c887 |
static int slbt_linkcmd_exit(
|
|
|
11c887 |
struct slbt_deps_meta * depsmeta,
|
|
|
11c887 |
int ret)
|
|
|
11c887 |
{
|
|
|
11c887 |
if (depsmeta->altv)
|
|
|
11c887 |
free(depsmeta->altv);
|
|
|
11c887 |
|
|
|
11c887 |
if (depsmeta->args)
|
|
|
11c887 |
free(depsmeta->args);
|
|
|
11c887 |
|
|
|
11c887 |
return ret;
|
|
|
11c887 |
}
|
|
|
11c887 |
|
|
|
11c887 |
static void slbt_emit_fdwrap_dl_path_fixup(
|
|
|
11c887 |
char * cwd,
|
|
|
11c887 |
char * dpfixup,
|
|
|
11c887 |
size_t dpfixup_size,
|
|
|
11c887 |
char * wrapper)
|
|
|
11c887 |
{
|
|
|
11c887 |
char * p;
|
|
|
11c887 |
char * q;
|
|
|
11c887 |
char * wrapper_dname;
|
|
|
11c887 |
|
|
|
11c887 |
/* obtain cwd-relative directory name of wrapper */
|
|
|
11c887 |
for (p=cwd,q=wrapper; *p && *q && (*p==*q); p++,q++)
|
|
|
11c887 |
(void)0;
|
|
|
11c887 |
|
|
|
11c887 |
wrapper_dname = (*q == '/') ? (q + 1) : q;
|
|
|
11c887 |
|
|
|
11c887 |
dpfixup[0] = 0; strncat(dpfixup,"${0%/*}",dpfixup_size - 1);
|
|
|
11c887 |
|
|
|
11c887 |
/* append parent directory fixup for each level of depth in wrapper_dname */
|
|
|
11c887 |
for (p=wrapper_dname,q=0; *p; ) {
|
|
|
11c887 |
if ((p[0] == '.') && (p[1] == '/')) {
|
|
|
11c887 |
p++; p++;
|
|
|
11c887 |
} else if ((q = strchr(p, '/'))) {
|
|
|
11c887 |
strncat(dpfixup,"/..",dpfixup_size-1); p = (q + 1);
|
|
|
11c887 |
} else {
|
|
|
11c887 |
break;
|
|
|
11c887 |
}
|
|
|
11c887 |
}
|
|
|
11c887 |
|
|
|
11c887 |
strncat(dpfixup,"/",dpfixup_size-1);
|
|
|
11c887 |
}
|
|
|
11c887 |
|
|
|
4b56de |
slbt_hidden int slbt_exec_link_create_executable(
|
|
|
11c887 |
const struct slbt_driver_ctx * dctx,
|
|
|
11c887 |
struct slbt_exec_ctx * ectx,
|
|
|
11c887 |
const char * exefilename)
|
|
|
11c887 |
{
|
|
|
11c887 |
int fdcwd;
|
|
|
11c887 |
int fdwrap;
|
|
|
11c887 |
char ** parg;
|
|
|
11c887 |
char ** xarg;
|
|
|
11c887 |
char * base;
|
|
|
11c887 |
char * ccwrap;
|
|
|
11c887 |
char cwd [PATH_MAX];
|
|
|
11c887 |
char dpfixup[PATH_MAX];
|
|
|
11c887 |
char output [PATH_MAX];
|
|
|
11c887 |
char wrapper[PATH_MAX];
|
|
|
11c887 |
char wraplnk[PATH_MAX];
|
|
|
11c887 |
bool fabspath;
|
|
|
11c887 |
bool fpic;
|
|
|
11c887 |
const struct slbt_source_version * verinfo;
|
|
|
11c887 |
struct slbt_deps_meta depsmeta = {0,0,0,0};
|
|
|
11c887 |
struct stat st;
|
|
|
11c887 |
|
|
|
11c887 |
/* initial state */
|
|
|
f3d47a |
slbt_ectx_reset_arguments(ectx);
|
|
|
11c887 |
|
|
|
11c887 |
/* placeholders */
|
|
|
11c887 |
slbt_reset_placeholders(ectx);
|
|
|
11c887 |
|
|
|
11c887 |
/* fdcwd */
|
|
|
11c887 |
fdcwd = slbt_driver_fdcwd(dctx);
|
|
|
11c887 |
|
|
|
11c887 |
/* fpic */
|
|
|
b48cb7 |
fpic = (dctx->cctx->drvflags & SLBT_DRIVER_SHARED);
|
|
|
b48cb7 |
fpic &= !(dctx->cctx->drvflags & SLBT_DRIVER_PREFER_STATIC);
|
|
|
11c887 |
|
|
|
11c887 |
/* input argument adjustment */
|
|
|
11c887 |
for (parg=ectx->cargv; *parg; parg++)
|
|
|
11c887 |
slbt_adjust_object_argument(*parg,fpic,true,fdcwd);
|
|
|
11c887 |
|
|
|
11c887 |
/* linker argument adjustment */
|
|
|
11c887 |
for (parg=ectx->cargv, xarg=ectx->xargv; *parg; parg++, xarg++)
|
|
|
11c887 |
if (slbt_adjust_linker_argument(
|
|
|
11c887 |
dctx,
|
|
|
a3e2d3 |
*parg,xarg,fpic,
|
|
|
11c887 |
dctx->cctx->settings.dsosuffix,
|
|
|
11c887 |
dctx->cctx->settings.arsuffix,
|
|
|
11c887 |
&depsmeta) < 0)
|
|
|
11c887 |
return SLBT_NESTED_ERROR(dctx);
|
|
|
11c887 |
|
|
|
11c887 |
/* --no-undefined */
|
|
|
11c887 |
if (dctx->cctx->drvflags & SLBT_DRIVER_NO_UNDEFINED)
|
|
|
4560b9 |
*ectx->noundef = slbt_host_group_is_darwin(dctx)
|
|
|
d2d5af |
? "-Wl,-undefined,error"
|
|
|
d2d5af |
: "-Wl,--no-undefined";
|
|
|
11c887 |
|
|
|
11c887 |
/* executable wrapper: create */
|
|
|
11c887 |
if (slbt_snprintf(wrapper,sizeof(wrapper),
|
|
|
11c887 |
"%s.wrapper.tmp",
|
|
|
11c887 |
dctx->cctx->output) < 0)
|
|
|
11c887 |
return SLBT_BUFFER_ERROR(dctx);
|
|
|
11c887 |
|
|
|
11c887 |
if ((fdwrap = openat(fdcwd,wrapper,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0)
|
|
|
11c887 |
return SLBT_SYSTEM_ERROR(dctx,wrapper);
|
|
|
11c887 |
|
|
|
11c887 |
slbt_exec_set_fdwrapper(ectx,fdwrap);
|
|
|
11c887 |
|
|
|
11c887 |
/* executable wrapper: header */
|
|
|
f0270a |
verinfo = slbt_api_source_version();
|
|
|
11c887 |
|
|
|
11c887 |
/* cwd, DL_PATH fixup */
|
|
|
d4b2a5 |
if (slbt_realpath(fdcwd,".",O_DIRECTORY,cwd,sizeof(cwd)))
|
|
|
11c887 |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
11c887 |
|
|
|
11c887 |
slbt_emit_fdwrap_dl_path_fixup(
|
|
|
11c887 |
cwd,dpfixup,sizeof(dpfixup),
|
|
|
11c887 |
wrapper);
|
|
|
11c887 |
|
|
|
11c887 |
if (slbt_dprintf(fdwrap,
|
|
|
11c887 |
"#!/bin/sh\n"
|
|
|
11c887 |
"# libtool compatible executable wrapper\n"
|
|
|
11c887 |
"# Generated by %s (slibtool %d.%d.%d)\n"
|
|
|
11c887 |
"# [commit reference: %s]\n\n"
|
|
|
11c887 |
|
|
|
11c887 |
"if [ -z \"$%s\" ]; then\n"
|
|
|
11c887 |
"\tDL_PATH=\n"
|
|
|
11c887 |
"\tCOLON=\n"
|
|
|
11c887 |
"\tLCOLON=\n"
|
|
|
11c887 |
"else\n"
|
|
|
11c887 |
"\tDL_PATH=\n"
|
|
|
11c887 |
"\tCOLON=\n"
|
|
|
11c887 |
"\tLCOLON=':'\n"
|
|
|
11c887 |
"fi\n\n"
|
|
|
11c887 |
"DL_PATH_FIXUP=\"%s\";\n\n",
|
|
|
11c887 |
|
|
|
11c887 |
dctx->program,
|
|
|
11c887 |
verinfo->major,verinfo->minor,verinfo->revision,
|
|
|
11c887 |
verinfo->commit,
|
|
|
11c887 |
dctx->cctx->settings.ldpathenv,
|
|
|
11c887 |
dpfixup) < 0)
|
|
|
11c887 |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
11c887 |
|
|
|
11c887 |
/* output */
|
|
|
11c887 |
if (slbt_snprintf(output,sizeof(output),
|
|
|
11c887 |
"%s",exefilename) < 0)
|
|
|
11c887 |
return SLBT_BUFFER_ERROR(dctx);
|
|
|
11c887 |
|
|
|
11c887 |
*ectx->lout[0] = "-o";
|
|
|
11c887 |
*ectx->lout[1] = output;
|
|
|
11c887 |
|
|
|
11c887 |
/* static? */
|
|
|
11c887 |
if (dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC)
|
|
|
11c887 |
*ectx->dpic = "-static";
|
|
|
11c887 |
|
|
|
11c887 |
/* .libs/libfoo.so --> -L.libs -lfoo */
|
|
|
11c887 |
if (slbt_exec_link_adjust_argument_vector(
|
|
|
11c887 |
dctx,ectx,&depsmeta,cwd,false))
|
|
|
11c887 |
return SLBT_NESTED_ERROR(dctx);
|
|
|
11c887 |
|
|
|
11c887 |
/* using alternate argument vector */
|
|
|
11c887 |
ccwrap = (char *)dctx->cctx->ccwrap;
|
|
|
11c887 |
ectx->argv = depsmeta.altv;
|
|
|
11c887 |
ectx->program = ccwrap ? ccwrap : depsmeta.altv[0];
|
|
|
11c887 |
|
|
|
11c887 |
/* executable wrapper symlink */
|
|
|
11c887 |
if (slbt_snprintf(wraplnk,sizeof(wraplnk),
|
|
|
11c887 |
"%s.exe.wrapper",
|
|
|
11c887 |
exefilename) < 0)
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_BUFFER_ERROR(dctx));
|
|
|
11c887 |
|
|
|
11c887 |
/* executable wrapper: base name */
|
|
|
11c887 |
base = strrchr(wraplnk,'/');
|
|
|
11c887 |
base++;
|
|
|
11c887 |
|
|
|
11c887 |
/* executable wrapper: footer */
|
|
|
11c887 |
fabspath = (exefilename[0] == '/');
|
|
|
11c887 |
|
|
|
11c887 |
if (slbt_dprintf(fdwrap,
|
|
|
11c887 |
"DL_PATH=\"${DL_PATH}${LCOLON}${%s}\"\n\n"
|
|
|
11c887 |
"export %s=\"$DL_PATH\"\n\n"
|
|
|
11c887 |
"if [ $(basename \"$0\") = \"%s\" ]; then\n"
|
|
|
11c887 |
"\tprogram=\"$1\"; shift\n"
|
|
|
dbd501 |
"\texec \"$program\" \"$@\"\n"
|
|
|
11c887 |
"fi\n\n"
|
|
|
dbd501 |
"exec %s/%s \"$@\"\n",
|
|
|
11c887 |
dctx->cctx->settings.ldpathenv,
|
|
|
11c887 |
dctx->cctx->settings.ldpathenv,
|
|
|
11c887 |
base,
|
|
|
11c887 |
fabspath ? "" : cwd,
|
|
|
11c887 |
fabspath ? &exefilename[1] : exefilename) < 0)
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_SYSTEM_ERROR(dctx,0));
|
|
|
11c887 |
|
|
|
11c887 |
/* sigh */
|
|
|
11c887 |
if (slbt_exec_link_finalize_argument_vector(dctx,ectx))
|
|
|
11c887 |
return SLBT_NESTED_ERROR(dctx);
|
|
|
11c887 |
|
|
|
11c887 |
/* step output */
|
|
|
11c887 |
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
|
|
|
33a569 |
if (slbt_output_link(ectx))
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_NESTED_ERROR(dctx));
|
|
|
11c887 |
|
|
|
11c887 |
/* spawn */
|
|
|
11c887 |
if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_SPAWN_ERROR(dctx));
|
|
|
11c887 |
|
|
|
11c887 |
} else if (ectx->exitcode) {
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_CUSTOM_ERROR(
|
|
|
11c887 |
dctx,
|
|
|
11c887 |
SLBT_ERR_LINK_ERROR));
|
|
|
11c887 |
}
|
|
|
11c887 |
|
|
|
11c887 |
/* executable wrapper: finalize */
|
|
|
11c887 |
slbt_exec_close_fdwrapper(ectx);
|
|
|
11c887 |
|
|
|
11c887 |
if (slbt_create_symlink(
|
|
|
11c887 |
dctx,ectx,
|
|
|
11c887 |
dctx->cctx->output,wraplnk,
|
|
|
11c887 |
SLBT_SYMLINK_WRAPPER))
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_NESTED_ERROR(dctx));
|
|
|
11c887 |
|
|
|
11c887 |
if (fstatat(fdcwd,wrapper,&st,0))
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_SYSTEM_ERROR(dctx,wrapper));
|
|
|
11c887 |
|
|
|
11c887 |
if (renameat(fdcwd,wrapper,fdcwd,dctx->cctx->output))
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_SYSTEM_ERROR(dctx,dctx->cctx->output));
|
|
|
11c887 |
|
|
|
11c887 |
if (fchmodat(fdcwd,dctx->cctx->output,0755,0))
|
|
|
11c887 |
return slbt_linkcmd_exit(
|
|
|
11c887 |
&depsmeta,
|
|
|
11c887 |
SLBT_SYSTEM_ERROR(dctx,dctx->cctx->output));
|
|
|
11c887 |
|
|
|
11c887 |
return slbt_linkcmd_exit(&depsmeta,0);
|
|
|
11c887 |
}
|