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