summaryrefslogtreecommitdiff
path: root/src/logic
diff options
context:
space:
mode:
Diffstat (limited to 'src/logic')
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_archive.c188
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_argv.c1127
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_deps.c788
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_dsolib.c373
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_executable.c278
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_host.c70
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_implib.c157
-rw-r--r--src/logic/slbt_exec_ar.c431
-rw-r--r--src/logic/slbt_exec_compile.c108
-rw-r--r--src/logic/slbt_exec_ctx.c405
-rw-r--r--src/logic/slbt_exec_execute.c223
-rw-r--r--src/logic/slbt_exec_install.c231
-rw-r--r--src/logic/slbt_exec_link.c1879
-rw-r--r--src/logic/slbt_exec_stoolie.c371
-rw-r--r--src/logic/slbt_exec_uninstall.c55
15 files changed, 4606 insertions, 2078 deletions
diff --git a/src/logic/linkcmd/slbt_linkcmd_archive.c b/src/logic/linkcmd/slbt_linkcmd_archive.c
new file mode 100644
index 0000000..b7c090b
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_archive.c
@@ -0,0 +1,188 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#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_spawn_impl.h"
+#include "slibtool_visibility_impl.h"
+
+static int slbt_exec_link_remove_file(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * target)
+{
+ int fdcwd;
+ char * mark;
+ char * sbuf;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* remove target (if any) */
+ if (unlinkat(fdcwd,target,0) && (errno != ENOENT))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* remove a previous .disabled placeholder */
+ sbuf = (slbt_get_exec_ictx(ectx))->sbuf;
+ mark = sbuf;
+ mark += sprintf(mark,"%s",target);
+ strcpy(mark,".disabled");
+
+ if (unlinkat(fdcwd,sbuf,0) && (errno != ENOENT))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ return 0;
+}
+
+
+static bool slbt_archive_is_convenience_library(int fdcwd, const char * arpath)
+{
+ int fd;
+ char laipath[PATH_MAX];
+ char * dot;
+
+ strcpy(laipath,arpath);
+ dot = strrchr(laipath,'.');
+ strcpy(dot,".lai");
+
+ if ((fd = openat(fdcwd,laipath,O_RDONLY,0)) >= 0) {
+ close(fd);
+ return false;
+ }
+
+ return true;
+}
+
+
+slbt_hidden int slbt_exec_link_create_archive(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * arfilename,
+ bool fpic,
+ bool fdep)
+{
+ int fdcwd;
+ char ** argv;
+ char ** aarg;
+ char ** parg;
+ char program[PATH_MAX];
+ char output [PATH_MAX];
+ char namebuf[PATH_MAX];
+
+ /* dlopen, dlpreopen: object compilation (derived from dynamic linking) */
+ if (ectx->dlopenobj) {
+ slbt_ectx_reset_arguments(ectx);
+ slbt_reset_placeholders(ectx);
+
+ sprintf(namebuf,"%s%s",ectx->ldirname,"@ARDLOPEN@");
+
+ if (slbt_exec_link_create_library(
+ dctx,ectx,
+ namebuf,namebuf,namebuf,
+ true,fpic) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ /* restore initial state */
+ slbt_ectx_reset_arguments(ectx);
+
+ /* placeholders */
+ slbt_reset_placeholders(ectx);
+
+ /* output */
+ if (slbt_snprintf(output,sizeof(output),
+ "%s",arfilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* tool-specific argument vector */
+ argv = (slbt_get_driver_ictx(dctx))->host.ar_argv;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* input argument adjustment */
+ aarg = ectx->altv;
+
+ if ((parg = argv)) {
+ for (; *parg; )
+ *aarg++ = *parg++;
+ } else {
+ *aarg++ = program;
+ }
+
+ *aarg++ = "-crs";
+ *aarg++ = output;
+
+ for (parg=ectx->cargv; *parg; parg++)
+ if (slbt_adjust_object_argument(*parg,fpic,!fpic,fdcwd))
+ *aarg++ = *parg;
+
+ if (ectx->dlopenobj)
+ *aarg++ = ectx->dlopenobj;
+
+ *aarg = 0;
+ ectx->argv = ectx->altv;
+
+ /* ar program */
+ if (argv) {
+ ectx->program = argv[0];
+ } else {
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",dctx->cctx->host.ar) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ ectx->program = program;
+ }
+
+ /* step output */
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
+ if (slbt_output_link(ectx))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* remove old archive as needed */
+ if (slbt_exec_link_remove_file(dctx,ectx,output))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* .deps */
+ if (fdep)
+ if (slbt_exec_link_create_dep_file(
+ dctx,ectx,ectx->cargv,
+ arfilename,true))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* ar spawn */
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ return SLBT_SPAWN_ERROR(dctx);
+
+ } else if (ectx->exitcode) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_ERROR);
+ }
+
+ /* input objects associated with .la archives */
+ for (parg=ectx->cargv; *parg; parg++)
+ if (slbt_adjust_wrapper_argument(
+ *parg,true,
+ dctx->cctx->settings.arsuffix))
+ if (slbt_archive_is_convenience_library(fdcwd,*parg))
+ if (slbt_util_import_archive(ectx,output,*parg))
+ return SLBT_NESTED_ERROR(dctx);
+ return 0;
+}
diff --git a/src/logic/linkcmd/slbt_linkcmd_argv.c b/src/logic/linkcmd/slbt_linkcmd_argv.c
new file mode 100644
index 0000000..013317f
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_argv.c
@@ -0,0 +1,1127 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 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_spawn_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"
+#include "slibtool_visibility_impl.h"
+#include "slibtool_ar_impl.h"
+
+
+static const char * slbt_ar_self_dlunit = "@PROGRAM@";
+
+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;
+}
+
+
+slbt_hidden 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;
+}
+
+
+slbt_hidden bool slbt_adjust_wrapper_argument(
+ char * arg,
+ bool fpic,
+ const char * suffix)
+{
+ 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,suffix);
+ return true;
+}
+
+
+slbt_hidden 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];
+
+ /* argv switch or non-library input argument? */
+ if (*arg == '-')
+ return 0;
+
+ if (!(dot = strrchr(arg,'.')))
+ return 0;
+
+ /* explicit .a input argument? */
+ if (!(strcmp(dot,arsuffix))) {
+ *xarg = arg;
+ return slbt_get_deps_meta(dctx,arg,1,depsmeta);
+ }
+
+ /* explicit .so input argument? */
+ if (!(strcmp(dot,dsosuffix)))
+ return slbt_get_deps_meta(dctx,arg,1,depsmeta);
+
+ /* not an .la library? */
+ if (strcmp(dot,".la"))
+ return 0;
+
+ /* .la file, associated .deps located under .libs */
+ 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);
+
+ /* .a preferred but a.disabled present? */
+ sprintf(dot,"%s",arsuffix);
+
+ if (slbt_symlink_is_a_placeholder(fdcwd,arg))
+ fpic = true;
+
+ /* 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);
+}
+
+
+slbt_hidden 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 * 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 = 0;
+ 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 ((ret = slbt_emit_fdwrap_amend_dl_path(
+ dctx,ectx,depsmeta,
+ "%s",&mark[2])) < 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) {
+ strcpy(lib,*carg);
+ dot = strrchr(lib,'.');
+ strcpy(dot,".lai");
+
+ if ((fd = openat(fdcwd,lib,O_RDONLY,0)) < 0)
+ *aarg++ = "-Wl,--whole-archive";
+ }
+
+ dpath = lib;
+ sprintf(lib,"%s.slibtool.deps",*carg);
+ *aarg++ = *carg++;
+
+ if (flibrary && !fwholearchive) {
+ if (fd < 0) {
+ *aarg++ = "-Wl,--no-whole-archive";
+ } else {
+ close(fd);
+ }
+ }
+
+ } 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));
+
+ if (darg[0] != '#') {
+ *aarg++ = darg;
+ }
+
+ mark = darg;
+ dlen = strlen(darg);
+ size -= dlen;
+ darg += dlen;
+ darg[-1] = 0;
+
+ /* handle -L... and ::... 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] == ':')) {
+ if (strlen(mark) >= sizeof(depdir) - 1)
+ return slbt_linkcmd_exit(
+ depsmeta,
+ SLBT_BUFFER_ERROR(dctx));
+
+ darg = mark;
+ strcpy(depdir,&mark[2]);
+
+ sprintf(darg,"%s/%s",
+ mark[2] == '/' ? "" : lib,
+ depdir);
+
+ darg += strlen(darg);
+ darg++;
+
+ } 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 (mapinfo) {
+ slbt_unmap_file(mapinfo);
+ mapinfo = 0;
+ }
+ }
+
+ if (dctx->cctx->drvflags & SLBT_DRIVER_EXPORT_DYNAMIC)
+ if (!slbt_host_objfmt_is_coff(dctx))
+ *aarg++ = "-Wl,--export-dynamic";
+
+ return 0;
+}
+
+
+static int slbt_exec_link_remove_file(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * target)
+{
+ int fdcwd;
+
+ (void)ectx;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* remove target (if any) */
+ if (!unlinkat(fdcwd,target,0) || (errno == ENOENT))
+ return 0;
+
+ return SLBT_SYSTEM_ERROR(dctx,0);
+}
+
+
+static int slbt_exec_link_create_expsyms_archive(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ char ** lobjv,
+ char ** cnvlv,
+ char (*arname)[PATH_MAX])
+{
+ int ret;
+ char * dot;
+ char ** argv;
+ char ** aarg;
+ char ** parg;
+ struct slbt_archive_ctx * arctx;
+ char ** ectx_argv;
+ char * ectx_program;
+ char output [PATH_MAX];
+ char program[PATH_MAX];
+
+ /* output */
+ if (slbt_snprintf(output,sizeof(output),
+ "%s",ectx->mapfilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ if (!(dot = strrchr(output,'.')))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ /* .expsyms.xxx --> .expsyms.a */
+ dot[1] = 'a';
+ dot[2] = '\0';
+
+ if (arname)
+ strcpy(*arname,output);
+
+ /* tool-specific argument vector */
+ argv = (slbt_get_driver_ictx(dctx))->host.ar_argv;
+
+ /* ar alternate argument vector */
+ if (!argv)
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",dctx->cctx->host.ar) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* ar command argument vector */
+ aarg = lobjv;
+
+ if ((parg = argv)) {
+ for (; *parg; )
+ *aarg++ = *parg++;
+ } else {
+ *aarg++ = program;
+ }
+
+ *aarg++ = "-crs";
+ *aarg++ = output;
+
+ ectx_argv = ectx->argv;
+ ectx_program = ectx->program;
+
+ ectx->argv = lobjv;
+ ectx->program = ectx->argv[0];
+
+ /* step output */
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
+ if (slbt_output_link(ectx))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* remove old archive as needed */
+ if (slbt_exec_link_remove_file(dctx,ectx,output))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* ar spawn */
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ return SLBT_SPAWN_ERROR(dctx);
+
+ } else if (ectx->exitcode) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_ERROR);
+ }
+
+ /* restore link command ectx */
+ ectx->argv = ectx_argv;
+ ectx->program = ectx_program;
+
+ /* input objects associated with .la archives */
+ for (parg=cnvlv; *parg; parg++)
+ if (slbt_util_import_archive(ectx,output,*parg))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* do the thing */
+ if (slbt_ar_get_archive_ctx(dctx,output,&arctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* .expsyms.a --> .exp */
+ if ((*dot = '\0'), !(dot = strrchr(output,'.'))) {
+ slbt_ar_free_archive_ctx(arctx);
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+ }
+
+ dot[1] = 'e';
+ dot[2] = 'x';
+ dot[3] = 'p';
+ dot[4] = '\0';
+
+ /* symfile */
+ if (dctx->cctx->expsyms) {
+ struct slbt_symlist_ctx * sctx;
+ sctx = (slbt_get_exec_ictx(ectx))->sctx;
+
+ ret = slbt_util_create_symfile(
+ sctx,output,0644);
+ } else {
+ ret = slbt_ar_create_symfile(
+ arctx->meta,
+ output,
+ 0644);
+ }
+
+ /* mapfile */
+ if ((ret == 0) && (dctx->cctx->regex)) {
+ ret = slbt_ar_create_mapfile(
+ arctx->meta,
+ ectx->mapfilename,
+ 0644);
+ }
+
+ slbt_ar_free_archive_ctx(arctx);
+
+ return (ret < 0) ? SLBT_NESTED_ERROR(dctx) : 0;
+}
+
+
+slbt_hidden int slbt_exec_link_finalize_argument_vector(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx)
+{
+ size_t nargs;
+ char * sargv[1024];
+ char ** sargvbuf;
+ char ** base;
+ char ** parg;
+ char ** pcap;
+ char ** argv;
+ char ** mark;
+ char ** aarg;
+ char ** oarg;
+ char ** lobj;
+ char ** cnvl;
+ char ** larg;
+ char ** darg;
+ char ** earg;
+ char ** rarg;
+ char ** aargv;
+ char ** oargv;
+ char ** lobjv;
+ char ** cnvlv;
+ char ** dlargv;
+ char ** cap;
+ char ** src;
+ char ** dst;
+ char * arg;
+ char * dot;
+ char * ccwrap;
+ char * program;
+ const char * arsuffix;
+
+ /* vector size */
+ base = ectx->argv;
+ arsuffix = dctx->cctx->settings.arsuffix;
+
+ for (parg=base; *parg; parg++)
+ (void)0;
+
+ if (dctx->cctx->regex) {
+ argv = (slbt_get_driver_ictx(dctx))->host.ar_argv;
+
+ for (mark=argv; mark && *mark; mark++)
+ (void)0;
+ } else {
+ argv = 0;
+ mark = 0;
+ }
+
+ /* buffer */
+ if ((nargs = ((parg - base) + (mark - argv))) < 256) {
+ aargv = &sargv[0];
+ oargv = &sargv[1*256];
+ lobjv = &sargv[2*256];
+ cnvlv = &sargv[3*256];
+ sargvbuf = 0;
+
+ parg = &sargv[0];
+ pcap = &sargv[1024];
+
+ for (; parg<pcap; )
+ *parg++ = 0;
+
+ } else if (!(sargvbuf = calloc(4*(nargs+1),sizeof(char *)))) {
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ } else {
+ aargv = &sargvbuf[0];
+ oargv = &sargvbuf[1*(nargs+1)];
+ lobjv = &sargvbuf[2*(nargs+1)];
+ cnvlv = &sargvbuf[3*(nargs+1)];
+ }
+
+ aarg = aargv;
+ oarg = oargv;
+ cnvl = cnvlv;
+ lobj = lobjv;
+
+ /* -export-symbols-regex: lobjv in place: ar [arg] [arg] -crs <output> */
+ if (dctx->cctx->regex && argv)
+ lobj += mark - argv + 2;
+ else
+ lobj += 3;
+
+ /* (program name) */
+ parg = &base[1];
+
+ /* split object args from all other args, record output */
+ /* annotation, and remove redundant -l arguments; and */
+ /* create additional vectors of all input objects as */
+ /* convenience libraries for -export-symbols-regex. */
+ 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"))) {
+ *lobj++ = *parg;
+ *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)) {
+ *cnvl++ = parg[1];
+ *oarg++ = *parg++;
+ *oarg++ = *parg++;
+ *oarg++ = *parg++;
+
+ /* local archive input argument? */
+ } else if (dot && !strcmp(dot,arsuffix)) {
+ *aarg++ = *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 (possibly) 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;
+ }
+ }
+
+ /* any archive (.a) input arguments between the */
+ /* current occurrence and the previous one? */
+ for (darg=&larg[1]; rarg && darg<aarg; darg++)
+ if ((dot = strrchr(*darg,'.')))
+ if (!(strcmp(dot,arsuffix)))
+ rarg = 0;
+
+ /* 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++;
+ }
+
+ /* dlsyms vtable object must only be added once (see below) */
+ } else if (!strcmp(*parg,"-dlpreopen")) {
+ parg++;
+
+ /* placeholder argument? */
+ } else if (!strncmp(*parg,"-USLIBTOOL_PLACEHOLDER_",23)) {
+ parg++;
+
+ /* all other arguments */
+ } else {
+ *aarg++ = *parg++;
+ }
+ }
+
+ /* dlsyms vtable object inclusion */
+ if (ectx->dlopenobj)
+ *oarg++ = ectx->dlopenobj;
+
+ /* export-symbols-regex, proper dlpreopen support */
+ if (dctx->cctx->libname)
+ if (slbt_exec_link_create_expsyms_archive(
+ dctx,ectx,lobjv,cnvlv,0) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* -dlpreopen self */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_DLPREOPEN_SELF) {
+ struct slbt_archive_ctx * arctx;
+ struct slbt_archive_ctx ** arctxv;
+ struct slbt_exec_ctx_impl * ictx;
+ char arname[PATH_MAX];
+
+ ictx = slbt_get_exec_ictx(ectx);
+ arctxv = ictx->dlactxv;
+ arctx = 0;
+
+ /* add or repalce the archive context */
+ for (; !arctx && *arctxv; )
+ if (!strcmp(*arctxv[0]->path,slbt_ar_self_dlunit))
+ arctx = *arctxv;
+ else
+ arctxv++;
+
+ if (arctx)
+ slbt_ar_free_archive_ctx(arctx);
+
+ if (slbt_exec_link_create_expsyms_archive(
+ dctx,ectx,lobjv,cnvlv,&arname) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (slbt_ar_get_archive_ctx(dctx,arname,arctxv) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ arctx = *arctxv;
+ arctx->path = &slbt_ar_self_dlunit;
+
+ if (slbt_ar_update_syminfo(arctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* regenerate the dlsyms vtable source */
+ if (slbt_ar_create_dlsyms(
+ ictx->dlactxv,
+ ectx->dlunit,
+ ectx->dlopensrc,
+ 0644) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ /* 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++;
+
+ /* dlpreopen */
+ if (ectx->dlpreopen)
+ *dst++ = ectx->dlpreopen;
+
+ /* join all other args, eliminate no-op linker path args */
+ src = aargv;
+ cap = aarg;
+
+ for (; src<cap; ) {
+ if ((src[0][0] == '-') && (src[0][1] == 'L')) {
+ for (larg=0,rarg=src; *rarg && !larg; rarg++)
+ if ((rarg[0][0] == '-') && (rarg[0][1] == 'l'))
+ larg = rarg;
+
+ if (larg) {
+ *dst++ = *src++;
+ } else {
+ src++;
+ }
+ } else {
+ *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;
+ }
+
+ /* dlsyms vtable object compilation */
+ if (ectx->dlopenobj) {
+ dlargv = (slbt_get_exec_ictx(ectx))->dlargv;
+ *dlargv = base[0];
+
+ src = aargv;
+ cap = aarg;
+ dst = &dlargv[1];
+
+ /* compile argv, based on the linkcmd argv */
+ for (; src<cap; ) {
+ if ((src[0][0] == '-') && (src[0][1] == '-')) {
+ *dst++ = *src;
+
+ } else if ((src[0][0] == '-') && (src[0][1] == 'L')) {
+ (void)0;
+
+ } else if ((src[0][0] == '-') && (src[0][1] == 'l')) {
+ (void)0;
+
+ } else if ((dot = strrchr(*src,'.')) && (dot[1] == 'a') && !dot[2]) {
+ (void)0;
+
+ } else if ((src[0][0] == '-') && (src[0][1] == 'o')) {
+ src++;
+
+ } else if ((src[0][0] == '-') && (src[0][1] == 'D')) {
+ if (!src[0][2])
+ src++;
+
+ } else if ((src[0][0] == '-') && (src[0][1] == 'U')) {
+ if (!src[0][2])
+ src++;
+
+ } else if ((src[0][0] == '-') && (src[0][1] == 'W')) {
+ if ((src[0][2] == 'a') && (src[0][3] == ','))
+ *dst++ = *src;
+
+ } else {
+ *dst++ = *src;
+ }
+
+ src++;
+ }
+
+ *dst++ = dctx->cctx->settings.picswitch
+ ? dctx->cctx->settings.picswitch
+ : *ectx->fpic;
+
+ *dst++ = "-c";
+ *dst++ = ectx->dlopensrc;
+
+ *dst++ = "-o";
+ *dst++ = ectx->dlopenobj;
+
+ *dst++ = 0;
+
+ /* nested compile step */
+ program = ectx->program;
+ ectx->argv = dlargv;
+ ectx->program = dlargv[0];
+
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
+ if (slbt_output_compile(ectx))
+ return SLBT_NESTED_ERROR(dctx);
+
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (ectx->exitcode)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_COMPILE_ERROR);
+
+ ectx->argv = base;
+ ectx->program = program;
+ }
+
+ /* all done */
+ if (sargvbuf)
+ free(sargvbuf);
+
+ return 0;
+}
diff --git a/src/logic/linkcmd/slbt_linkcmd_deps.c b/src/logic/linkcmd/slbt_linkcmd_deps.c
new file mode 100644
index 0000000..19ed716
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_deps.c
@@ -0,0 +1,788 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#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_realpath_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_visibility_impl.h"
+
+slbt_hidden int slbt_get_deps_meta(
+ const struct slbt_driver_ctx * dctx,
+ char * libfilename,
+ int fexternal,
+ struct slbt_deps_meta * depsmeta)
+{
+ int fdcwd;
+ char * ch;
+ char * cap;
+ char * base;
+ size_t libexlen;
+ struct stat st;
+ struct slbt_map_info * mapinfo;
+ char depfile[PATH_MAX];
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* -rpath */
+ if (slbt_snprintf(depfile,sizeof(depfile),
+ "%s.slibtool.rpath",
+ libfilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* -Wl,%s */
+ if (!fstatat(fdcwd,depfile,&st,AT_SYMLINK_NOFOLLOW)) {
+ depsmeta->infolen += st.st_size + 4;
+ depsmeta->infolen++;
+ }
+
+ /* .deps */
+ if (slbt_snprintf(depfile,sizeof(depfile),
+ "%s.slibtool.deps",
+ libfilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* mapinfo */
+ if (!(mapinfo = slbt_map_file(fdcwd,depfile,SLBT_MAP_INPUT)))
+ return (fexternal && (errno == ENOENT))
+ ? 0 : SLBT_SYSTEM_ERROR(dctx,depfile);
+
+ /* copied length */
+ depsmeta->infolen += mapinfo->size;
+ depsmeta->infolen++;
+
+ /* libexlen */
+ libexlen = (base = strrchr(libfilename,'/'))
+ ? strlen(depfile) + 2 + (base - libfilename)
+ : strlen(depfile) + 2;
+
+ /* iterate */
+ ch = mapinfo->addr;
+ cap = mapinfo->cap;
+
+ for (; ch<cap; ) {
+ if (*ch++ == '\n') {
+ depsmeta->infolen += libexlen;
+ depsmeta->depscnt++;
+ }
+ }
+
+ slbt_unmap_file(mapinfo);
+
+ return 0;
+}
+
+
+static int slbt_exec_link_normalize_dep_file(
+ const struct slbt_driver_ctx * dctx,
+ int deps,
+ char (*depfile)[PATH_MAX])
+{
+ int ret;
+ int fdcwd;
+ int fdtgt;
+ char * dot;
+ char * slash;
+ const char * base;
+ const char * mark;
+ struct slbt_txtfile_ctx * tctx;
+ const char ** pline;
+ char * tgtmark;
+ char * depmark;
+ char * relmark;
+ char * tgtnext;
+ char * depnext;
+ char tgtdir [PATH_MAX];
+ char tgtpath [PATH_MAX];
+ char deppath [PATH_MAX];
+ char pathbuf [PATH_MAX];
+ char depsbuf [PATH_MAX];
+ char basebuf [PATH_MAX];
+ char relapath[PATH_MAX];
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* first-pass dependency file */
+ if (slbt_impl_get_txtfile_ctx(dctx,*depfile,deps,&tctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* second-pass dependency file */
+ dot = strrchr(*depfile,'.');
+ strcpy(dot,".tmp2");
+
+ if ((deps = openat(fdcwd,*depfile,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0) {
+ slbt_lib_free_txtfile_ctx(tctx);
+ return SLBT_SYSTEM_ERROR(dctx,depfile);
+ }
+
+ /* fdtgt */
+ strcpy(tgtdir,*depfile);
+
+ if (!(slash = strrchr(tgtdir,'/')))
+ slash = tgtdir;
+
+ slash[0] = '\0';
+
+ if ((slash = strrchr(tgtdir,'/'))) {
+ slash[0] = '\0';
+ slash++;
+ } else {
+ slash = tgtdir;
+ slash[0] = '.';
+ slash[1] = '/';
+ slash[2] = '\0';
+ }
+
+ if ((slash > tgtdir) && strcmp(slash,".libs")) {
+ close(deps);
+ slbt_lib_free_txtfile_ctx(tctx);
+
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+ }
+
+ if ((fdtgt = openat(fdcwd,tgtdir,O_DIRECTORY|O_CLOEXEC,0)) < 0) {
+ close(deps);
+ slbt_lib_free_txtfile_ctx(tctx);
+
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+ }
+
+ if (slbt_realpath(fdcwd,tgtdir,0,tgtpath,sizeof(tgtpath)) < 0) {
+ close(fdtgt);
+ close(deps);
+ slbt_lib_free_txtfile_ctx(tctx);
+
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+ }
+
+ strcpy(pathbuf,tgtpath);
+
+ /* normalize dependency lines as needed */
+ for (pline=tctx->txtlinev; *pline; pline++) {
+ if ((mark = *pline)) {
+ if ((mark[0] == '-') && (mark[1] == 'L')) {
+ mark = &mark[2];
+ base = 0;
+
+ } else if ((mark[0] == ':') && (mark[1] == ':')) {
+ mark = &mark[2];
+ base = mark;
+ }
+
+ if ((mark > *pline) && (mark[0] == '/'))
+ mark = *pline;
+ }
+
+ if (mark > *pline) {
+ if (slbt_realpath(
+ fdtgt,mark,0,deppath,
+ sizeof(deppath)) < 0)
+ mark = *pline;
+
+ else if ((tgtpath[0] != '/') || (deppath[0] != '/'))
+ mark = 0;
+
+ else
+ strcpy(depsbuf,deppath);
+
+ if ((mark > *pline) && base) {
+ slash = strrchr(deppath,'/');
+ *slash = '\0';
+
+ slash = strrchr(deppath,'/');
+ *slash = '\0';
+
+ base = basebuf;
+ slash = &depsbuf[slash - deppath];
+
+ strcpy(basebuf,++slash);
+ strcpy(depsbuf,deppath);
+ }
+ }
+
+ if (mark > *pline) {
+ tgtmark = tgtpath;
+ depmark = deppath;
+
+ tgtnext = strchr(tgtmark,'/');
+ depnext = strchr(depmark,'/');
+
+ while (tgtnext && depnext) {
+ *tgtnext = '\0';
+ *depnext = '\0';
+
+ if (strcmp(tgtmark,depmark)) {
+ tgtnext = 0;
+ depnext = 0;
+ } else {
+ tgtmark = &tgtnext[1];
+ depmark = &depnext[1];
+
+ if (*tgtmark && *depmark) {
+ tgtnext = strchr(tgtmark,'/');
+ depnext = strchr(depmark,'/');
+ } else {
+ tgtnext = 0;
+ depnext = 0;
+ }
+ }
+ }
+
+ strcpy(tgtmark,&pathbuf[tgtmark-tgtpath]);
+ strcpy(depmark,&depsbuf[depmark-deppath]);
+
+ if ((tgtmark - tgtpath) == (depmark - deppath)) {
+ mark = &depmark[strlen(tgtmark)];
+
+ if ((mark[0] == '/') && !strncmp(tgtmark,depmark,mark-depmark))
+ sprintf(relapath,"-L.%s",mark);
+ else
+ mark = relapath;
+ } else {
+ mark = relapath;
+ }
+
+ if (mark == relapath) {
+ relmark = relapath;
+ relmark += sprintf(relapath,"-L../");
+
+ while ((tgtnext = strchr(tgtmark,'/'))) {
+ tgtmark = &tgtnext[1];
+ relmark += sprintf(relmark,"../");
+ }
+
+ strcpy(relmark,depmark);
+ }
+
+ if (base) {
+ relapath[0] = ':';
+ relapath[1] = ':';
+ }
+
+ mark = relapath;
+ }
+
+ if ((mark == relapath) && base) {
+ ret = slbt_dprintf(deps,"%s/%s\n",mark,base);
+
+ } else if (mark) {
+ ret = slbt_dprintf(deps,"%s\n",mark);
+
+ } else {
+ ret = (-1);
+ }
+
+ if (ret < 0) {
+ close(deps);
+ close(fdtgt);
+ slbt_lib_free_txtfile_ctx(tctx);
+
+ return mark
+ ? SLBT_SYSTEM_ERROR(dctx,0)
+ : SLBT_NESTED_ERROR(dctx);
+ }
+
+ if (mark == relapath)
+ strcpy(tgtpath,pathbuf);
+ }
+
+ close(fdtgt);
+ slbt_lib_free_txtfile_ctx(tctx);
+
+ return deps;
+}
+
+
+static int slbt_exec_link_compact_dep_file(
+ const struct slbt_driver_ctx * dctx,
+ int deps,
+ char (*depfile)[PATH_MAX])
+{
+ int fdcwd;
+ struct slbt_txtfile_ctx * tctx;
+ const char ** pline;
+ const char ** pcomp;
+ const char * depline;
+ char * dot;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* second-pass dependency file */
+ if (slbt_impl_get_txtfile_ctx(dctx,*depfile,deps,&tctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* second-pass dependency file */
+ dot = strrchr(*depfile,'.');
+ dot[0] = '\0';
+
+ if ((deps = openat(fdcwd,*depfile,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0) {
+ slbt_lib_free_txtfile_ctx(tctx);
+ return SLBT_SYSTEM_ERROR(dctx,depfile);
+ }
+
+ /* iterate, only write unique entries */
+ for (pline=tctx->txtlinev; *pline; pline++) {
+ depline = *pline;
+
+ if ((depline[0] == '-') && (depline[1] == 'L'))
+ for (pcomp=tctx->txtlinev; depline && pcomp<pline; pcomp++)
+ if (!strcmp(*pcomp,depline))
+ depline = 0;
+
+ if (depline && (slbt_dprintf(deps,"%s\n",depline) < 0)) {
+ close(deps);
+ slbt_lib_free_txtfile_ctx(tctx);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ slbt_lib_free_txtfile_ctx(tctx);
+
+ return deps;
+}
+
+
+static bool slbt_archive_is_convenience_library(int fdcwd, const char * arpath)
+{
+ int fd;
+ char laipath[PATH_MAX];
+ char * dot;
+
+ strcpy(laipath,arpath);
+ dot = strrchr(laipath,'.');
+ strcpy(dot,".lai");
+
+ if ((fd = openat(fdcwd,laipath,O_RDONLY,0)) >= 0) {
+ close(fd);
+ return false;
+ }
+
+ return true;
+}
+
+
+slbt_hidden int slbt_exec_link_create_dep_file(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ char ** altv,
+ const char * libfilename,
+ bool farchive)
+{
+ int ret;
+ int deps;
+ int fdtmp;
+ int slen;
+ int fdcwd;
+ char ** parg;
+ char * popt;
+ char * plib;
+ char * path;
+ char * mark;
+ char * base;
+ size_t size;
+ bool fdep;
+ char deplib [PATH_MAX];
+ char deppref[PATH_MAX];
+ char reladir[PATH_MAX];
+ char depfile[PATH_MAX];
+ char pathbuf[PATH_MAX];
+ struct stat st;
+ int ldepth;
+ int fardep;
+ int fdyndep;
+ struct slbt_map_info * mapinfo;
+ bool is_reladir;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* depfile */
+ if (slbt_snprintf(depfile,sizeof(depfile),
+ "%s.slibtool.deps.tmp1",
+ libfilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ strcpy(pathbuf,depfile);
+
+ /* dependency prefix */
+ if (depfile[0] == '/') {
+ deppref[0] = '\0';
+ } else {
+ if ((mark = strrchr(depfile,'/')))
+ *mark = 0;
+
+ if (!mark)
+ mark = depfile;
+
+ if (slbt_realpath(fdcwd,depfile,0,reladir,sizeof(reladir)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (slbt_realpath(fdcwd,"./",0,deppref,sizeof(deppref)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (mark > depfile)
+ *mark = '/';
+
+ mark = &reladir[strlen(deppref)];
+ *mark++ = '\0';
+
+ if (strcmp(reladir,deppref))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ if ((base = strrchr(mark,'/')))
+ base++;
+
+ if (!base)
+ base = mark;
+
+ if (strcmp(base,".libs"))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ base = mark;
+ mark = deppref;
+
+ for (; base; ) {
+ if ((base = strchr(base,'/'))) {
+ mark += sprintf(mark,"../");
+ base++;
+ }
+ }
+
+ *mark = '\0';
+ }
+
+ /* deps */
+ if ((deps = openat(fdcwd,depfile,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,depfile);
+
+ /* informational header */
+ if (slbt_realpath(fdcwd,"./",0,reladir,sizeof(reladir)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (slbt_dprintf(deps,
+ "# makefile target: %s\n"
+ "# slibtool target: %s\n"
+ "# cprocess fdcwd: %s\n",
+ dctx->cctx->output,
+ libfilename,
+ reladir) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ fdep = 0;
+
+ /* iterate */
+ for (parg=altv; *parg; parg++) {
+ popt = 0;
+ plib = 0;
+ path = 0;
+ mapinfo = 0;
+
+ if (!strncmp(*parg,"-l",2)) {
+ if (fdep) {
+ if (slbt_dprintf(
+ deps,
+ "#\n# makefile target: %s\n",
+ dctx->cctx->output) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ fdep = false;
+ }
+
+ popt = *parg;
+ plib = popt + 2;
+
+ } else if (!strncmp(*parg,"-L",2)) {
+ if (fdep) {
+ if (slbt_dprintf(
+ deps,
+ "#\n# makefile target: %s\n",
+ dctx->cctx->output) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ fdep = false;
+ }
+
+ popt = *parg;
+ path = popt + 2;
+
+ } else if (!strncmp(*parg,"-f",2)) {
+ (void)0;
+
+ } else if ((popt = strrchr(*parg,'.')) && !strcmp(popt,".la")) {
+ /* import dependency list */
+ fdep = true;
+
+ if ((base = strrchr(*parg,'/')))
+ base++;
+ else
+ base = *parg;
+
+ /* [relative .la directory] */
+ if (base > *parg) {
+ slen = slbt_snprintf(
+ reladir,
+ sizeof(reladir),
+ "%s",*parg);
+
+ if (slen < 0) {
+ close(deps);
+ return SLBT_BUFFER_ERROR(dctx);
+ }
+
+ is_reladir = true;
+ reladir[base - *parg - 1] = 0;
+ } else {
+ is_reladir = false;
+ reladir[0] = '.';
+ reladir[1] = 0;
+ }
+
+
+ /* dynamic library dependency? */
+ strcpy(depfile,*parg);
+ mark = depfile + (base - *parg);
+ size = sizeof(depfile) - (base - *parg);
+ slen = slbt_snprintf(mark,size,".libs/%s",base);
+
+ if (slen < 0) {
+ close(deps);
+ return SLBT_BUFFER_ERROR(dctx);
+ }
+
+ mark = strrchr(mark,'.');
+ strcpy(mark,dctx->cctx->settings.dsosuffix);
+
+ fardep = 0;
+ fdyndep = !fstatat(fdcwd,depfile,&st,0);
+
+ if (fdyndep && farchive) {
+ mark = strrchr(mark,'.');
+ strcpy(mark,dctx->cctx->settings.arsuffix);
+
+ if (fstatat(fdcwd,depfile,&st,0) < 0) {
+ strcpy(mark,dctx->cctx->settings.dsosuffix);
+ } else {
+ fdyndep = 0;
+ }
+ }
+
+ /* [-L... as needed] */
+ if (fdyndep && (ectx->ldirdepth >= 0)) {
+ if (slbt_dprintf(deps,"-L") < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ for (ldepth=ectx->ldirdepth; ldepth; ldepth--) {
+ if (slbt_dprintf(deps,"../") < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (slbt_dprintf(deps,"%s%s.libs\n",
+ (is_reladir ? reladir : ""),
+ (is_reladir ? "/" : "")) < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ /* -ldeplib */
+ if (fdyndep) {
+ *popt = 0;
+ mark = base;
+ mark += strlen(dctx->cctx->settings.dsoprefix);
+
+ if (slbt_dprintf(deps,"-l%s\n",mark) < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ *popt = '.';
+ } else {
+ strcpy(depfile,*parg);
+
+ slbt_adjust_wrapper_argument(
+ depfile,true,
+ dctx->cctx->settings.arsuffix);
+
+
+ fardep = farchive;
+ fardep |= !slbt_archive_is_convenience_library(fdcwd,depfile);
+ }
+
+ if (fardep) {
+ if (slbt_dprintf(deps,"::") < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ for (ldepth=ectx->ldirdepth; ldepth; ldepth--) {
+ if (slbt_dprintf(deps,"../") < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+
+ if (ectx->ldirdepth >= 0) {
+ if (slbt_dprintf(deps,"%s\n",depfile) < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ } else {
+ if (slbt_dprintf(deps,"::./%s\n",depfile) < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+ }
+
+ /* [open dependency list] */
+ strcpy(depfile,*parg);
+ mark = depfile + (base - *parg);
+ size = sizeof(depfile) - (base - *parg);
+ slen = slbt_snprintf(mark,size,".libs/%s",base);
+
+ if (slen < 0) {
+ close(deps);
+ return SLBT_BUFFER_ERROR(dctx);
+ }
+
+ mapinfo = 0;
+
+ mark = strrchr(mark,'.');
+ size = sizeof(depfile) - (mark - depfile);
+
+ if (!fardep) {
+ slen = slbt_snprintf(mark,size,
+ "%s.slibtool.deps",
+ dctx->cctx->settings.dsosuffix);
+
+ if (slen < 0) {
+ close(deps);
+ return SLBT_BUFFER_ERROR(dctx);
+ }
+
+ mapinfo = slbt_map_file(
+ fdcwd,depfile,
+ SLBT_MAP_INPUT);
+
+ if (!mapinfo && (errno != ENOENT)) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (!mapinfo) {
+ slen = slbt_snprintf(mark,size,
+ ".a.slibtool.deps");
+
+ if (slen < 0) {
+ close(deps);
+ return SLBT_BUFFER_ERROR(dctx);
+ }
+
+ mapinfo = slbt_map_file(
+ fdcwd,depfile,
+ SLBT_MAP_INPUT);
+
+ if (!mapinfo) {
+ strcpy(mark,".a.disabled");
+
+ if (fstatat(fdcwd,depfile,&st,AT_SYMLINK_NOFOLLOW)) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,depfile);
+ }
+ }
+ }
+
+ /* [-l... as needed] */
+ while (mapinfo && (mapinfo->mark < mapinfo->cap)) {
+ ret = slbt_mapped_readline(
+ dctx,mapinfo,
+ deplib,sizeof(deplib));
+
+ if (ret) {
+ close(deps);
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ if ((deplib[0] == '-') && (deplib[1] == 'L') && (deplib[2] != '/')) {
+ ret = slbt_dprintf(
+ deps,"-L%s%s/%s",
+ deppref,reladir,&deplib[2]);
+
+ } else if ((deplib[0] == ':') && (deplib[1] == ':') && (deplib[2] != '/')) {
+ ret = slbt_dprintf(
+ deps,"::%s%s/%s",
+ deppref,reladir,&deplib[2]);
+
+ } else {
+ ret = slbt_dprintf(
+ deps,"%s",
+ deplib);
+ }
+
+ if (ret < 0) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (mapinfo)
+ slbt_unmap_file(mapinfo);
+ }
+
+ if (plib && (slbt_dprintf(deps,"-l%s\n",plib) < 0)) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ if (path && (slbt_dprintf(deps,"-L%s\n",path) < 0)) {
+ close(deps);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if ((fdtmp = slbt_exec_link_normalize_dep_file(dctx,deps,&pathbuf)) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ close(deps);
+
+ if ((deps = slbt_exec_link_compact_dep_file(dctx,fdtmp,&pathbuf)) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ close(deps);
+ close(fdtmp);
+
+ return 0;
+}
diff --git a/src/logic/linkcmd/slbt_linkcmd_dsolib.c b/src/logic/linkcmd/slbt_linkcmd_dsolib.c
new file mode 100644
index 0000000..cca6aac
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_dsolib.c
@@ -0,0 +1,373 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#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_realpath_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_symlink_impl.h"
+#include "slibtool_spawn_impl.h"
+#include "slibtool_visibility_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_exec_link_remove_file(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * target)
+{
+ int fdcwd;
+
+ (void)ectx;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* remove target (if any) */
+ if (!unlinkat(fdcwd,target,0) || (errno == ENOENT))
+ return 0;
+
+ return SLBT_SYSTEM_ERROR(dctx,0);
+}
+
+static int slbt_exec_link_remove_dso_files(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * target)
+{
+ int fdcwd;
+ char * mark;
+ char * sbuf;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* remove target (if any) */
+ if (unlinkat(fdcwd,target,0) && (errno != ENOENT))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* remove a previous .disabled placeholder */
+ sbuf = (slbt_get_exec_ictx(ectx))->sbuf;
+ mark = sbuf;
+ mark += sprintf(mark,"%s",target);
+ strcpy(mark,".disabled");
+
+ if (unlinkat(fdcwd,sbuf,0) && (errno != ENOENT))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ return 0;
+}
+
+slbt_hidden int slbt_exec_link_create_library(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * dsobasename,
+ const char * dsofilename,
+ const char * relfilename,
+ bool fardlopen,
+ bool fpic)
+{
+ int fdcwd;
+ char ** parg;
+ char ** xarg;
+ char * ccwrap;
+ const char * laout;
+ const char * dot;
+ char cwd [PATH_MAX];
+ char output [PATH_MAX];
+ char soname [PATH_MAX];
+ char symfile[PATH_MAX];
+ char mapfile[PATH_MAX];
+ struct slbt_deps_meta depsmeta = {0,0,0,0};
+
+ /* initial state */
+ slbt_ectx_reset_arguments(ectx);
+
+ /* placeholders */
+ slbt_reset_placeholders(ectx);
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* remove previous libfoo.so, libfoo.so.disabled */
+ if (slbt_exec_link_remove_dso_files(dctx,ectx,ectx->dsofilename) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* input argument adjustment */
+ for (parg=ectx->cargv; *parg; parg++)
+ slbt_adjust_object_argument(*parg,fpic,false,fdcwd);
+
+ /* .deps */
+ if (slbt_exec_link_create_dep_file(
+ dctx,ectx,ectx->cargv,
+ dsofilename,false))
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_NESTED_ERROR(dctx));
+
+ /* linker argument adjustment */
+ for (parg=ectx->cargv, xarg=ectx->xargv; *parg; parg++, xarg++)
+ if (slbt_adjust_linker_argument(
+ dctx,
+ *parg,xarg,true,
+ dctx->cctx->settings.dsosuffix,
+ dctx->cctx->settings.arsuffix,
+ &depsmeta) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* --no-undefined */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_NO_UNDEFINED)
+ *ectx->noundef = slbt_host_group_is_darwin(dctx)
+ ? "-Wl,-undefined,error"
+ : "-Wl,--no-undefined";
+
+ /* -soname */
+ dot = strrchr(dctx->cctx->output,'.');
+ laout = (dot && !strcmp(dot,".la"))
+ ? dctx->cctx->output
+ : 0;
+
+ char wl_soname[24];
+
+ if (slbt_host_group_is_darwin(dctx)) {
+ strcpy(wl_soname,"-Wl,-install_name");
+ } else {
+ strcpy(wl_soname,"-Wl,-soname");
+ }
+
+ if ((dctx->cctx->drvflags & SLBT_DRIVER_IMAGE_MACHO)) {
+ (void)0;
+
+ } else if (!laout && (dctx->cctx->drvflags & SLBT_DRIVER_MODULE)) {
+ if (slbt_snprintf(soname,sizeof(soname),
+ "-Wl,%s",dctx->cctx->output) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *ectx->soname = wl_soname;
+ *ectx->lsoname = soname;
+
+ } else if (relfilename && dctx->cctx->verinfo.verinfo) {
+ if (slbt_snprintf(soname,sizeof(soname),
+ "-Wl,%s%s%s%s%s.%d%s",
+ ectx->sonameprefix,
+ dctx->cctx->libname,
+ dctx->cctx->release ? "-" : "",
+ dctx->cctx->release ? dctx->cctx->release : "",
+ dctx->cctx->settings.osdsuffix,
+ dctx->cctx->verinfo.major,
+ dctx->cctx->settings.osdfussix) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *ectx->soname = wl_soname;
+ *ectx->lsoname = soname;
+
+ } else if (relfilename) {
+ if (slbt_snprintf(soname,sizeof(soname),
+ "-Wl,%s%s%s%s%s",
+ ectx->sonameprefix,
+ dctx->cctx->libname,
+ dctx->cctx->release ? "-" : "",
+ dctx->cctx->release ? dctx->cctx->release : "",
+ dctx->cctx->settings.dsosuffix) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *ectx->soname = wl_soname;
+ *ectx->lsoname = soname;
+
+ } else if (dctx->cctx->drvflags & SLBT_DRIVER_AVOID_VERSION) {
+ if (slbt_snprintf(soname,sizeof(soname),
+ "-Wl,%s%s%s",
+ ectx->sonameprefix,
+ dctx->cctx->libname,
+ dctx->cctx->settings.dsosuffix) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *ectx->soname = wl_soname;
+ *ectx->lsoname = soname;
+
+ } else {
+ if (slbt_snprintf(soname,sizeof(soname),
+ "-Wl,%s%s%s.%d%s",
+ ectx->sonameprefix,
+ dctx->cctx->libname,
+ dctx->cctx->settings.osdsuffix,
+ dctx->cctx->verinfo.major,
+ dctx->cctx->settings.osdfussix) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *ectx->soname = wl_soname;
+ *ectx->lsoname = soname;
+ }
+
+ /* PE: --output-def */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_IMAGE_PE) {
+ if (slbt_snprintf(symfile,sizeof(symfile),
+ "-Wl,%s",
+ ectx->deffilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *ectx->symdefs = "-Wl,--output-def";
+ *ectx->symfile = symfile;
+ }
+
+ /* -export-symbols */
+ if (dctx->cctx->expsyms) {
+ struct slbt_symlist_ctx * sctx;
+ sctx = (slbt_get_exec_ictx(ectx))->sctx;
+
+ if (slbt_util_create_mapfile(sctx,ectx->mapfilename,0644) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (slbt_snprintf(mapfile,sizeof(mapfile),
+ "-Wl,%s",
+ ectx->mapfilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ if (slbt_host_group_is_darwin(dctx)) {
+ *ectx->explarg = "-Wl,-exported_symbols_list";
+ *ectx->expsyms = mapfile;
+
+ } else if (slbt_host_group_is_winnt(dctx)) {
+ *ectx->expsyms = mapfile;
+ } else {
+ *ectx->explarg = "-Wl,--version-script";
+ *ectx->expsyms = mapfile;
+ }
+ }
+
+ /* -export-symbols-regex; and see also: */
+ /* slbt_exec_link_create_expsyms_archive() */
+ if (dctx->cctx->regex) {
+ if (slbt_snprintf(mapfile,sizeof(mapfile),
+ "-Wl,%s",
+ ectx->mapfilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ if (slbt_host_group_is_darwin(dctx)) {
+ *ectx->explarg = "-Wl,-exported_symbols_list";
+ *ectx->expsyms = mapfile;
+
+ } else if (slbt_host_group_is_winnt(dctx)) {
+ *ectx->expsyms = mapfile;
+ } else {
+ *ectx->explarg = "-Wl,--version-script";
+ *ectx->expsyms = mapfile;
+ }
+ }
+
+ /* shared/static */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC) {
+ *ectx->dpic = "-static";
+ } else if (dctx->cctx->settings.picswitch) {
+ *ectx->dpic = "-shared";
+ *ectx->fpic = dctx->cctx->settings.picswitch;
+ } else {
+ *ectx->dpic = "-shared";
+ }
+
+ /* output */
+ if (!laout && dctx->cctx->drvflags & SLBT_DRIVER_MODULE) {
+ strcpy(output,dctx->cctx->output);
+ } else if (relfilename) {
+ strcpy(output,relfilename);
+ } else if (dctx->cctx->drvflags & SLBT_DRIVER_AVOID_VERSION) {
+ strcpy(output,dsofilename);
+ } else {
+ if (slbt_snprintf(output,sizeof(output),
+ "%s%s.%d.%d.%d%s",
+ dsobasename,
+ dctx->cctx->settings.osdsuffix,
+ dctx->cctx->verinfo.major,
+ dctx->cctx->verinfo.minor,
+ dctx->cctx->verinfo.revision,
+ dctx->cctx->settings.osdfussix) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+ }
+
+ /* output marks */
+ *ectx->lout[0] = "-o";
+ *ectx->lout[1] = output;
+
+ /* ldrpath */
+ if (dctx->cctx->host.ldrpath) {
+ if (slbt_exec_link_remove_file(dctx,ectx,ectx->rpathfilename))
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (slbt_create_symlink(
+ dctx,ectx,
+ dctx->cctx->host.ldrpath,
+ ectx->rpathfilename,
+ SLBT_SYMLINK_LITERAL))
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ /* cwd */
+ if (slbt_realpath(fdcwd,".",O_DIRECTORY,cwd,sizeof(cwd)))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* .libs/libfoo.so --> -L.libs -lfoo */
+ if (slbt_exec_link_adjust_argument_vector(
+ dctx,ectx,&depsmeta,cwd,true))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* using alternate argument vector */
+ ccwrap = (char *)dctx->cctx->ccwrap;
+ ectx->argv = depsmeta.altv;
+ ectx->program = ccwrap ? ccwrap : depsmeta.altv[0];
+
+ /* sigh */
+ if (slbt_exec_link_finalize_argument_vector(dctx,ectx))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* all done? */
+ if (fardlopen)
+ return 0;
+
+ /* step output */
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
+ if (slbt_output_link(ectx))
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_NESTED_ERROR(dctx));
+
+ /* spawn */
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_SPAWN_ERROR(dctx));
+
+ } else if (ectx->exitcode) {
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_LINK_ERROR));
+ }
+
+ return slbt_linkcmd_exit(&depsmeta,0);
+}
diff --git a/src/logic/linkcmd/slbt_linkcmd_executable.c b/src/logic/linkcmd/slbt_linkcmd_executable.c
new file mode 100644
index 0000000..936bc02
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_executable.c
@@ -0,0 +1,278 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#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_realpath_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_symlink_impl.h"
+#include "slibtool_spawn_impl.h"
+#include "slibtool_visibility_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 void slbt_emit_fdwrap_dl_path_fixup(
+ char * cwd,
+ char * dpfixup,
+ size_t dpfixup_size,
+ char * wrapper)
+{
+ char * p;
+ char * q;
+ char * wrapper_dname;
+
+ /* obtain cwd-relative directory name of wrapper */
+ for (p=cwd,q=wrapper; *p && *q && (*p==*q); p++,q++)
+ (void)0;
+
+ wrapper_dname = (*q == '/') ? (q + 1) : q;
+
+ dpfixup[0] = 0; strncat(dpfixup,"${0%/*}",dpfixup_size - 1);
+
+ /* append parent directory fixup for each level of depth in wrapper_dname */
+ for (p=wrapper_dname,q=0; *p; ) {
+ if ((p[0] == '.') && (p[1] == '/')) {
+ p++; p++;
+ } else if ((q = strchr(p, '/'))) {
+ strncat(dpfixup,"/..",dpfixup_size-1); p = (q + 1);
+ } else {
+ break;
+ }
+ }
+
+ strncat(dpfixup,"/",dpfixup_size-1);
+}
+
+slbt_hidden int slbt_exec_link_create_executable(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * exefilename)
+{
+ int fdcwd;
+ int fdwrap;
+ char ** parg;
+ char ** xarg;
+ char * base;
+ char * ccwrap;
+ char cwd [PATH_MAX];
+ char dpfixup[PATH_MAX];
+ char output [PATH_MAX];
+ char wrapper[PATH_MAX];
+ char wraplnk[PATH_MAX];
+ bool fabspath;
+ bool fpic;
+ const struct slbt_source_version * verinfo;
+ struct slbt_deps_meta depsmeta = {0,0,0,0};
+ struct stat st;
+
+ /* initial state */
+ slbt_ectx_reset_arguments(ectx);
+
+ /* placeholders */
+ slbt_reset_placeholders(ectx);
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* fpic */
+ fpic = (dctx->cctx->drvflags & SLBT_DRIVER_SHARED);
+ fpic &= !(dctx->cctx->drvflags & SLBT_DRIVER_PREFER_STATIC);
+
+ /* input argument adjustment */
+ for (parg=ectx->cargv; *parg; parg++)
+ slbt_adjust_object_argument(*parg,fpic,true,fdcwd);
+
+ /* linker argument adjustment */
+ for (parg=ectx->cargv, xarg=ectx->xargv; *parg; parg++, xarg++)
+ if (slbt_adjust_linker_argument(
+ dctx,
+ *parg,xarg,fpic,
+ dctx->cctx->settings.dsosuffix,
+ dctx->cctx->settings.arsuffix,
+ &depsmeta) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* --no-undefined */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_NO_UNDEFINED)
+ *ectx->noundef = slbt_host_group_is_darwin(dctx)
+ ? "-Wl,-undefined,error"
+ : "-Wl,--no-undefined";
+
+ /* executable wrapper: create */
+ if (slbt_snprintf(wrapper,sizeof(wrapper),
+ "%s.wrapper.tmp",
+ dctx->cctx->output) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ if ((fdwrap = openat(fdcwd,wrapper,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,wrapper);
+
+ slbt_exec_set_fdwrapper(ectx,fdwrap);
+
+ /* executable wrapper: header */
+ verinfo = slbt_api_source_version();
+
+ /* cwd, DL_PATH fixup */
+ if (slbt_realpath(fdcwd,".",O_DIRECTORY,cwd,sizeof(cwd)))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ slbt_emit_fdwrap_dl_path_fixup(
+ cwd,dpfixup,sizeof(dpfixup),
+ wrapper);
+
+ if (slbt_dprintf(fdwrap,
+ "#!/bin/sh\n"
+ "# libtool compatible executable wrapper\n"
+ "# Generated by %s (slibtool %d.%d.%d)\n"
+ "# [commit reference: %s]\n\n"
+
+ "if [ -z \"$%s\" ]; then\n"
+ "\tDL_PATH=\n"
+ "\tCOLON=\n"
+ "\tLCOLON=\n"
+ "else\n"
+ "\tDL_PATH=\n"
+ "\tCOLON=\n"
+ "\tLCOLON=':'\n"
+ "fi\n\n"
+ "DL_PATH_FIXUP=\"%s\";\n\n",
+
+ dctx->program,
+ verinfo->major,verinfo->minor,verinfo->revision,
+ verinfo->commit,
+ dctx->cctx->settings.ldpathenv,
+ dpfixup) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* output */
+ if (slbt_snprintf(output,sizeof(output),
+ "%s",exefilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *ectx->lout[0] = "-o";
+ *ectx->lout[1] = output;
+
+ /* static? */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC)
+ *ectx->dpic = "-static";
+
+ /* .libs/libfoo.so --> -L.libs -lfoo */
+ if (slbt_exec_link_adjust_argument_vector(
+ dctx,ectx,&depsmeta,cwd,false))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* using alternate argument vector */
+ ccwrap = (char *)dctx->cctx->ccwrap;
+ ectx->argv = depsmeta.altv;
+ ectx->program = ccwrap ? ccwrap : depsmeta.altv[0];
+
+ /* executable wrapper symlink */
+ if (slbt_snprintf(wraplnk,sizeof(wraplnk),
+ "%s.exe.wrapper",
+ exefilename) < 0)
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_BUFFER_ERROR(dctx));
+
+ /* executable wrapper: base name */
+ base = strrchr(wraplnk,'/');
+ base++;
+
+ /* executable wrapper: footer */
+ fabspath = (exefilename[0] == '/');
+
+ if (slbt_dprintf(fdwrap,
+ "DL_PATH=\"${DL_PATH}${LCOLON}${%s}\"\n\n"
+ "export %s=\"$DL_PATH\"\n\n"
+ "if [ $(basename \"$0\") = \"%s\" ]; then\n"
+ "\tprogram=\"$1\"; shift\n"
+ "\texec \"$program\" \"$@\"\n"
+ "fi\n\n"
+ "exec %s/%s \"$@\"\n",
+ dctx->cctx->settings.ldpathenv,
+ dctx->cctx->settings.ldpathenv,
+ base,
+ fabspath ? "" : cwd,
+ fabspath ? &exefilename[1] : exefilename) < 0)
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ /* sigh */
+ if (slbt_exec_link_finalize_argument_vector(dctx,ectx))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* step output */
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
+ if (slbt_output_link(ectx))
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_NESTED_ERROR(dctx));
+
+ /* spawn */
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_SPAWN_ERROR(dctx));
+
+ } else if (ectx->exitcode) {
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_LINK_ERROR));
+ }
+
+ /* executable wrapper: finalize */
+ slbt_exec_close_fdwrapper(ectx);
+
+ if (slbt_create_symlink(
+ dctx,ectx,
+ dctx->cctx->output,wraplnk,
+ SLBT_SYMLINK_WRAPPER))
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_NESTED_ERROR(dctx));
+
+ if (fstatat(fdcwd,wrapper,&st,0))
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_SYSTEM_ERROR(dctx,wrapper));
+
+ if (renameat(fdcwd,wrapper,fdcwd,dctx->cctx->output))
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_SYSTEM_ERROR(dctx,dctx->cctx->output));
+
+ if (fchmodat(fdcwd,dctx->cctx->output,0755,0))
+ return slbt_linkcmd_exit(
+ &depsmeta,
+ SLBT_SYSTEM_ERROR(dctx,dctx->cctx->output));
+
+ return slbt_linkcmd_exit(&depsmeta,0);
+}
diff --git a/src/logic/linkcmd/slbt_linkcmd_host.c b/src/logic/linkcmd/slbt_linkcmd_host.c
new file mode 100644
index 0000000..c3d51f8
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_host.c
@@ -0,0 +1,70 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#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_visibility_impl.h"
+
+slbt_hidden int slbt_exec_link_create_host_tag(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ char * deffilename)
+{
+ char * slash;
+ char hosttag[PATH_MAX];
+ char hostlnk[PATH_MAX];
+
+ /* libfoo.so.def.{flavor} */
+ if (slbt_snprintf(hosttag,
+ sizeof(hosttag),
+ "%s.%s",
+ deffilename,
+ dctx->cctx->host.flavor) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ if (slbt_snprintf(hostlnk,
+ sizeof(hostlnk),
+ "%s.host",
+ deffilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* libfoo.so.def is under .libs/ */
+ if (!(slash = strrchr(deffilename,'/')))
+ return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LINK_FLOW);
+
+ if (slbt_create_symlink(
+ dctx,ectx,
+ deffilename,
+ hosttag,
+ SLBT_SYMLINK_DEFAULT))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* libfoo.so.def.{flavor} is under .libs/ */
+ if (!(slash = strrchr(hosttag,'/')))
+ return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LINK_FLOW);
+
+ if (slbt_create_symlink(
+ dctx,ectx,
+ ++slash,
+ hostlnk,
+ SLBT_SYMLINK_DEFAULT))
+ return SLBT_NESTED_ERROR(dctx);
+
+ return 0;
+}
diff --git a/src/logic/linkcmd/slbt_linkcmd_implib.c b/src/logic/linkcmd/slbt_linkcmd_implib.c
new file mode 100644
index 0000000..b2c0375
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_implib.c
@@ -0,0 +1,157 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#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_spawn_impl.h"
+#include "slibtool_visibility_impl.h"
+
+slbt_hidden int slbt_exec_link_create_import_library(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ char * impfilename,
+ char * deffilename,
+ char * soname)
+{
+ int fmdso;
+ char ** argv;
+ char ** parg;
+ char ** aarg;
+ char program[PATH_MAX];
+ char as[PATH_MAX];
+
+ /* dlltool or mdso? */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_IMPLIB_DSOMETA)
+ fmdso = 1;
+
+ else if (dctx->cctx->drvflags & SLBT_DRIVER_IMPLIB_IDATA)
+ fmdso = 0;
+
+ else if (!(strcmp(dctx->cctx->host.flavor,"midipix")))
+ fmdso = 1;
+
+ else
+ fmdso = 0;
+
+ /* alternate argument vector */
+ ectx->argv = ectx->altv;
+ ectx->program = program;
+
+ /* tool-specific argument vector */
+ argv = (fmdso)
+ ? (slbt_get_driver_ictx(dctx))->host.mdso_argv
+ : (slbt_get_driver_ictx(dctx))->host.dlltool_argv;
+
+ /* tool-specific argv */
+ aarg = ectx->altv;
+
+ if ((parg = argv)) {
+ ectx->program = argv[0];
+
+ for (; *parg; )
+ *aarg++ = *parg++;
+ } else {
+ *aarg++ = program;
+ }
+
+ /* altv */
+ if (fmdso) {
+ if (!argv)
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",dctx->cctx->host.mdso) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *aarg++ = "-i";
+ *aarg++ = impfilename;
+ *aarg++ = "-n";
+ *aarg++ = soname;
+ *aarg++ = deffilename;
+ *aarg = 0;
+ } else {
+ if (!argv)
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",dctx->cctx->host.dlltool) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *aarg++ = "-l";
+ *aarg++ = impfilename;
+ *aarg++ = "-d";
+ *aarg++ = deffilename;
+ *aarg++ = "-D";
+ *aarg++ = soname;
+ *aarg = 0;
+
+ if (dctx->cctx->host.as) {
+ if ((argv = (slbt_get_driver_ictx(dctx))->host.as_argv)) {
+ *aarg++ = "-S";
+ *aarg++ = argv[0];
+
+ for (parg=&argv[1]; *parg; parg++) {
+ *aarg++ = "-f";
+ *aarg++ = *parg;
+ }
+ } else {
+ if (slbt_snprintf(as,sizeof(as),
+ "%s",dctx->cctx->host.as) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *aarg++ = "-S";
+ *aarg++ = as;
+ }
+
+ const char * host = dctx->cctx->host.host;
+
+ if (host && (host[0] == 'i')
+ && (host[1] >= '3')
+ && (host[1] <= '6')
+ && (host[2] == '8')
+ && (host[3] == '6')
+ && (host[4] == '-')) {
+ *aarg++ = "-f";
+ *aarg++ = "--32";
+ *aarg++ = "-m";
+ *aarg++ = "i386";
+ *aarg++ = 0;
+ } else {
+ *aarg++ = "-f";
+ *aarg++ = "--64";
+ *aarg++ = "-m";
+ *aarg++ = "i386:x86-64";
+ *aarg = 0;
+ }
+ }
+ }
+
+ /* step output */
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
+ if (slbt_output_link(ectx))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* dlltool/mdso spawn */
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ return SLBT_SPAWN_ERROR(dctx);
+
+ } else if (ectx->exitcode) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ fmdso ? SLBT_ERR_MDSO_ERROR : SLBT_ERR_DLLTOOL_ERROR);
+ }
+
+ return 0;
+}
diff --git a/src/logic/slbt_exec_ar.c b/src/logic/slbt_exec_ar.c
new file mode 100644
index 0000000..ba56f5b
--- /dev/null
+++ b/src/logic/slbt_exec_ar.c
@@ -0,0 +1,431 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_output.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_ar_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "argv/argv.h"
+
+#define SLBT_DRIVER_MODE_AR_ACTIONS (SLBT_DRIVER_MODE_AR_CHECK \
+ | SLBT_DRIVER_MODE_AR_MERGE)
+
+#define SLBT_DRIVER_MODE_AR_OUTPUTS (SLBT_OUTPUT_ARCHIVE_MEMBERS \
+ | SLBT_OUTPUT_ARCHIVE_HEADERS \
+ | SLBT_OUTPUT_ARCHIVE_SYMBOLS \
+ | SLBT_OUTPUT_ARCHIVE_ARMAPS)
+
+#define SLBT_PRETTY_FLAGS (SLBT_PRETTY_YAML \
+ | SLBT_PRETTY_POSIX \
+ | SLBT_PRETTY_HEXDATA)
+
+static int slbt_ar_usage(
+ int fdout,
+ const char * program,
+ const char * arg,
+ const struct argv_option ** optv,
+ struct argv_meta * meta,
+ struct slbt_exec_ctx * ectx,
+ int noclr)
+{
+ char header[512];
+ bool armode;
+ const char * dash;
+
+ armode = (dash = strrchr(program,'-'))
+ && !strcmp(++dash,"ar");
+
+ snprintf(header,sizeof(header),
+ "Usage: %s%s [options] [ARCHIVE-FILE] [ARCHIVE_FILE] ...\n"
+ "Options:\n",
+ program,
+ armode ? "" : " --mode=ar");
+
+ switch (noclr) {
+ case 0:
+ slbt_argv_usage(fdout,header,optv,arg);
+ break;
+
+ default:
+ slbt_argv_usage_plain(fdout,header,optv,arg);
+ break;
+ }
+
+ if (ectx)
+ slbt_ectx_free_exec_ctx(ectx);
+
+ slbt_argv_free(meta);
+
+ return SLBT_USAGE;
+}
+
+static int slbt_exec_ar_fail(
+ struct slbt_exec_ctx * ectx,
+ struct argv_meta * meta,
+ int ret)
+{
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
+ return ret;
+}
+
+static int slbt_exec_ar_perform_archive_actions(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_ctx ** arctxv)
+{
+ struct slbt_archive_ctx ** arctxp;
+ struct slbt_archive_ctx * arctx;
+ bool farname;
+
+ switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) {
+ case SLBT_PRETTY_POSIX:
+ farname = (arctxv[0] && arctxv[1]);
+ break;
+
+ default:
+ farname = true;
+ break;
+ }
+
+ for (arctxp=arctxv; *arctxp; arctxp++) {
+ if (dctx->cctx->fmtflags & SLBT_DRIVER_MODE_AR_OUTPUTS)
+ if (farname && (slbt_au_output_arname(*arctxp) < 0))
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MEMBERS)
+ if (slbt_au_output_members((*arctxp)->meta) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_SYMBOLS)
+ if (slbt_au_output_symbols((*arctxp)->meta) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MAPFILE)
+ if (slbt_au_output_mapfile((*arctxp)->meta) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_DLSYMS)
+ if (slbt_au_output_dlsyms(arctxv,dctx->cctx->dlunit) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (dctx->cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE) {
+ if (slbt_ar_merge_archives(arctxv,&arctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* (defer mode to umask) */
+ if (slbt_ar_store_archive(arctx,dctx->cctx->output,0666) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ return 0;
+}
+
+int slbt_exec_ar(const struct slbt_driver_ctx * dctx)
+{
+ int ret;
+ int fdout;
+ int fderr;
+ char ** argv;
+ char ** iargv;
+ struct slbt_exec_ctx * ectx;
+ struct slbt_driver_ctx_impl * ictx;
+ const struct slbt_common_ctx * cctx;
+ struct slbt_archive_ctx ** arctxv;
+ struct slbt_archive_ctx ** arctxp;
+ const char ** unitv;
+ const char ** unitp;
+ size_t nunits;
+ struct argv_meta * meta;
+ struct argv_entry * entry;
+ const struct argv_option * optv[SLBT_OPTV_ELEMENTS];
+
+ /* context */
+ if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* initial state, ar mode skin */
+ slbt_ectx_reset_arguments(ectx);
+ slbt_disable_placeholders(ectx);
+
+ ictx = slbt_get_driver_ictx(dctx);
+ cctx = dctx->cctx;
+ iargv = ectx->cargv;
+
+ fdout = slbt_driver_fdout(dctx);
+ fderr = slbt_driver_fderr(dctx);
+
+ /* missing arguments? */
+ slbt_optv_init(slbt_ar_options,optv);
+
+ if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
+ return slbt_ar_usage(
+ fdout,
+ dctx->program,
+ 0,optv,0,ectx,
+ dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
+
+ /* <ar> argv meta */
+ if (!(meta = slbt_argv_get(
+ iargv,optv,
+ dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
+ ? ARGV_VERBOSITY_ERRORS
+ : ARGV_VERBOSITY_NONE,
+ fdout)))
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_AR_FAIL));
+
+ /* dest, alternate argument vector options */
+ argv = ectx->altv;
+ *argv++ = iargv[0];
+ nunits = 0;
+
+ for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
+ if (entry->fopt) {
+ switch (entry->tag) {
+ case TAG_AR_HELP:
+ slbt_ar_usage(
+ fdout,
+ dctx->program,
+ 0,optv,0,ectx,
+ dctx->cctx->drvflags
+ & SLBT_DRIVER_ANNOTATE_NEVER);
+
+ ictx->cctx.drvflags |= SLBT_DRIVER_VERSION;
+ ictx->cctx.drvflags ^= SLBT_DRIVER_VERSION;
+
+ slbt_argv_free(meta);
+
+ return SLBT_OK;
+
+ case TAG_AR_VERSION:
+ ictx->cctx.drvflags |= SLBT_DRIVER_VERSION;
+ break;
+
+ case TAG_AR_CHECK:
+ ictx->cctx.drvflags |= SLBT_DRIVER_MODE_AR_CHECK;
+ break;
+
+ case TAG_AR_MERGE:
+ ictx->cctx.drvflags |= SLBT_DRIVER_MODE_AR_MERGE;
+ break;
+
+ case TAG_AR_OUTPUT:
+ ictx->cctx.output = entry->arg;
+ break;
+
+ case TAG_AR_PRINT:
+ if (!entry->arg)
+ ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MEMBERS;
+
+ else if (!strcmp(entry->arg,"members"))
+ ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MEMBERS;
+
+ else if (!strcmp(entry->arg,"headers"))
+ ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_HEADERS;
+
+ else if (!strcmp(entry->arg,"symbols"))
+ ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_SYMBOLS;
+
+ else if (!strcmp(entry->arg,"armaps"))
+ ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_ARMAPS;
+
+ break;
+
+ case TAG_AR_MAPFILE:
+ ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MAPFILE;
+ break;
+
+ case TAG_AR_DLSYMS:
+ ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_DLSYMS;
+ break;
+
+ case TAG_AR_DLUNIT:
+ ictx->cctx.dlunit = entry->arg;
+ break;
+
+ case TAG_AR_NOSORT:
+ ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_NOSORT;
+ break;
+
+ case TAG_AR_REGEX:
+ ictx->cctx.regex = entry->arg;
+ break;
+
+ case TAG_AR_PRETTY:
+ if (!strcmp(entry->arg,"yaml")) {
+ ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS;
+ ictx->cctx.fmtflags |= SLBT_PRETTY_YAML;
+
+ } else if (!strcmp(entry->arg,"posix")) {
+ ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS;
+ ictx->cctx.fmtflags |= SLBT_PRETTY_POSIX;
+ }
+
+ break;
+
+ case TAG_AR_POSIX:
+ ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS;
+ ictx->cctx.fmtflags |= SLBT_PRETTY_POSIX;
+ break;
+
+ case TAG_AR_YAML:
+ ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS;
+ ictx->cctx.fmtflags |= SLBT_PRETTY_YAML;
+ break;
+
+ case TAG_AR_VERBOSE:
+ ictx->cctx.fmtflags |= SLBT_PRETTY_VERBOSE;
+ break;
+ }
+
+ if (entry->fval) {
+ *argv++ = (char *)entry->arg;
+ }
+ } else {
+ nunits++;
+ };
+ }
+
+ /* defer --version printing to slbt_main() as needed */
+ if (cctx->drvflags & SLBT_DRIVER_VERSION) {
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
+ return SLBT_OK;
+ }
+
+ /* at least one action must be specified */
+ if (cctx->fmtflags & SLBT_DRIVER_MODE_AR_OUTPUTS) {
+ (void)0;
+
+ } else if (cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MAPFILE) {
+ (void)0;
+
+ } else if (cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_DLSYMS) {
+ if (!cctx->dlunit) {
+ slbt_dprintf(fderr,
+ "%s: missing -Wdlunit: generation of a dlsyms vtable "
+ "requires the name of the dynamic library, executable "
+ "program, or dynamic module for which the vtable would "
+ "be generated.\n",
+ dctx->program);
+
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_DLUNIT_NOT_SPECIFIED));
+ }
+ } else if (!(cctx->drvflags & SLBT_DRIVER_MODE_AR_ACTIONS)) {
+ if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
+ slbt_dprintf(fderr,
+ "%s: at least one action must be specified\n",
+ dctx->program);
+
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_NO_ACTION_SPECIFIED));
+ }
+
+ /* -Wmerge without -Woutput? */
+ if ((cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE) && !cctx->output) {
+ if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
+ slbt_dprintf(fderr,
+ "%s: archive merging: output must be specified.\n",
+ dctx->program);
+
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_OUTPUT_NOT_SPECIFIED));
+ }
+
+
+ /* -Woutput without -Wmerge? */
+ if (cctx->output && !(cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE)) {
+ if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
+ slbt_dprintf(fderr,
+ "%s: output may only be specified "
+ "when merging one or more archives.\n",
+ dctx->program);
+
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_OUTPUT_NOT_APPLICABLE));
+ }
+
+
+ /* at least one unit must be specified */
+ if (!nunits) {
+ if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS)
+ slbt_dprintf(fderr,
+ "%s: all actions require at least one input unit\n",
+ dctx->program);
+
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_NO_INPUT_SPECIFIED));
+ }
+
+ /* archive vector allocation */
+ if (!(arctxv = calloc(nunits+1,sizeof(struct slbt_archive_ctx *))))
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ /* unit vector allocation */
+ if (!(unitv = calloc(nunits+1,sizeof(const char *)))) {
+ free (arctxv);
+
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_SYSTEM_ERROR(dctx,0));
+ }
+
+ /* unit vector initialization */
+ for (entry=meta->entries,unitp=unitv; entry->fopt || entry->arg; entry++)
+ if (!entry->fopt)
+ *unitp++ = entry->arg;
+
+ /* archive context vector initialization */
+ for (unitp=unitv,arctxp=arctxv; *unitp; unitp++,arctxp++) {
+ if (slbt_ar_get_archive_ctx(dctx,*unitp,arctxp) < 0) {
+ for (arctxp=arctxv; *arctxp; arctxp++)
+ slbt_ar_free_archive_ctx(*arctxp);
+
+ free(unitv);
+ free(arctxv);
+
+ return slbt_exec_ar_fail(
+ ectx,meta,
+ SLBT_NESTED_ERROR(dctx));
+ }
+ }
+
+ /* archive operations */
+ ret = slbt_exec_ar_perform_archive_actions(dctx,arctxv);
+
+ /* all done */
+ for (arctxp=arctxv; *arctxp; arctxp++)
+ slbt_ar_free_archive_ctx(*arctxp);
+
+ free(unitv);
+ free(arctxv);
+
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
+
+ return ret;
+}
diff --git a/src/logic/slbt_exec_compile.c b/src/logic/slbt_exec_compile.c
index cbd0691..47d8e72 100644
--- a/src/logic/slbt_exec_compile.c
+++ b/src/logic/slbt_exec_compile.c
@@ -1,6 +1,6 @@
/*******************************************************************/
-/* slibtool: a skinny libtool implementation, written in C */
-/* Copyright (C) 2016--2021 Z. Gilboa */
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/
@@ -48,7 +48,9 @@ static int slbt_exec_compile_finalize_argument_vector(
char ** cap;
char ** src;
char ** dst;
+ char ** cmp;
char * ccwrap;
+ char * custom;
/* vector size */
base = ectx->argv;
@@ -74,6 +76,9 @@ static int slbt_exec_compile_finalize_argument_vector(
/* (program name) */
parg = &base[1];
+ /* avoid -I deduplication with project specific drivers */
+ custom = strchr(ectx->program,'/');
+
/* split object args from all other args, record output */
/* annotation, and remove redundant -l arguments */
for (; *parg; ) {
@@ -102,13 +107,47 @@ static int slbt_exec_compile_finalize_argument_vector(
base++;
}
- /* join all other args */
+ /* join all other args, starting with de-duplicated -I arguments, */
+ /* and filter out all -f switches when compiling in --tag=RC mode */
src = aargv;
cap = aarg;
dst = &base[1];
- for (; src<cap; )
- *dst++ = *src++;
+ for (; !custom && src<cap; ) {
+ if (((*src)[0] == '-') && ((*src)[1] == 'I')) {
+ cmp = &base[1];
+
+ for (; cmp && cmp<dst; ) {
+ if (!strcmp(*src,*cmp)) {
+ cmp = 0;
+ } else {
+ cmp++;
+ }
+ }
+
+ if (cmp)
+ *dst++ = *src;
+ }
+
+ src++;
+ }
+
+ src = aargv;
+
+ for (; src<cap; ) {
+ if ((dctx->cctx->tag == SLBT_TAG_RC)
+ && ((*src)[0] == '-')
+ && ((*src)[1] == 'f'))
+ (void)0;
+
+ else if (((*src)[0] != '-') || ((*src)[1] != 'I'))
+ *dst++ = *src;
+
+ else if (custom)
+ *dst++ = *src;
+
+ src++;
+ }
/* properly null-terminate argv, accounting for redundant arguments */
*dst = 0;
@@ -131,14 +170,14 @@ static int slbt_exec_compile_finalize_argument_vector(
return 0;
}
-int slbt_exec_compile(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx)
+int slbt_exec_compile(const struct slbt_driver_ctx * dctx)
{
int ret;
char * fpic;
char * ccwrap;
- struct slbt_exec_ctx * actx = 0;
+ bool fshared;
+ bool fstatic;
+ struct slbt_exec_ctx * ectx;
const struct slbt_common_ctx * cctx = dctx->cctx;
/* dry run */
@@ -146,22 +185,22 @@ int slbt_exec_compile(
return 0;
/* context */
- if (ectx)
- slbt_reset_placeholders(ectx);
- else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
- return ret;
- else
- actx = ectx;
+ if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
/* remove old .lo wrapper */
if (slbt_exec_compile_remove_file(dctx,ectx,ectx->ltobjname))
return SLBT_NESTED_ERROR(dctx);
+ /* fshared, fstatic */
+ fshared = (cctx->drvflags & (SLBT_DRIVER_SHARED | SLBT_DRIVER_PREFER_SHARED));
+ fstatic = (cctx->drvflags & (SLBT_DRIVER_STATIC | SLBT_DRIVER_PREFER_STATIC));
+
/* .libs directory */
- if (cctx->drvflags & SLBT_DRIVER_SHARED)
+ if (fshared)
if (slbt_mkdir(dctx,ectx->ldirname)) {
ret = SLBT_SYSTEM_ERROR(dctx,ectx->ldirname);
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return ret;
}
@@ -175,6 +214,7 @@ int slbt_exec_compile(
case SLBT_TAG_CC:
case SLBT_TAG_CXX:
case SLBT_TAG_F77:
+ case SLBT_TAG_FC:
fpic = cctx->settings.picswitch
? cctx->settings.picswitch
: *ectx->fpic;
@@ -185,7 +225,7 @@ int slbt_exec_compile(
}
/* shared library object */
- if (cctx->drvflags & SLBT_DRIVER_SHARED) {
+ if (fshared) {
if (!(cctx->drvflags & SLBT_DRIVER_ANTI_PIC)) {
*ectx->dpic = "-DPIC";
*ectx->fpic = fpic;
@@ -198,23 +238,27 @@ int slbt_exec_compile(
return SLBT_NESTED_ERROR(dctx);
if (!(cctx->drvflags & SLBT_DRIVER_SILENT)) {
- if (slbt_output_compile(dctx,ectx)) {
- slbt_free_exec_ctx(actx);
+ if (slbt_output_compile(ectx)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
}
- if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode) {
- slbt_free_exec_ctx(actx);
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_SYSTEM_ERROR(dctx,0);
+
+ } else if (ectx->exitcode) {
+ slbt_ectx_free_exec_ctx(ectx);
+ return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_COMPILE_ERROR);
}
- if (cctx->drvflags & SLBT_DRIVER_STATIC)
- slbt_reset_argvector(ectx);
+ if (fstatic)
+ slbt_ectx_reset_argvector(ectx);
}
/* static archive object */
- if (cctx->drvflags & SLBT_DRIVER_STATIC) {
+ if (fstatic) {
slbt_reset_placeholders(ectx);
if (cctx->drvflags & SLBT_DRIVER_PRO_PIC) {
@@ -229,20 +273,24 @@ int slbt_exec_compile(
return SLBT_NESTED_ERROR(dctx);
if (!(cctx->drvflags & SLBT_DRIVER_SILENT)) {
- if (slbt_output_compile(dctx,ectx)) {
- slbt_free_exec_ctx(actx);
+ if (slbt_output_compile(ectx)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
}
- if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode) {
- slbt_free_exec_ctx(actx);
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_SYSTEM_ERROR(dctx,0);
+
+ } else if (ectx->exitcode) {
+ slbt_ectx_free_exec_ctx(ectx);
+ return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_COMPILE_ERROR);
}
}
ret = slbt_create_object_wrapper(dctx,ectx);
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return ret ? SLBT_NESTED_ERROR(dctx) : 0;
}
diff --git a/src/logic/slbt_exec_ctx.c b/src/logic/slbt_exec_ctx.c
index a170b45..223be17 100644
--- a/src/logic/slbt_exec_ctx.c
+++ b/src/logic/slbt_exec_ctx.c
@@ -1,6 +1,6 @@
/*******************************************************************/
-/* slibtool: a skinny libtool implementation, written in C */
-/* Copyright (C) 2016--2021 Z. Gilboa */
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/
@@ -11,9 +11,17 @@
#include <slibtool/slibtool.h>
#include "slibtool_driver_impl.h"
+#include "slibtool_mkdir_impl.h"
+#include "slibtool_linkcmd_impl.h"
#include "slibtool_errinfo_impl.h"
+#include "slibtool_ar_impl.h"
-#define SLBT_ARGV_SPARE_PTRS 16
+#define SLBT_ECTX_LIB_EXTRAS 26
+#define SLBT_ECTX_SPARE_PTRS 16
+
+static int slbt_ectx_free_exec_ctx_impl(
+ struct slbt_exec_ctx_impl * ictx,
+ int status);
static size_t slbt_parse_comma_separated_flags(
const char * str,
@@ -48,63 +56,82 @@ static char * slbt_source_file(char ** argv)
}
+static int slbt_exec_ctx_tool_argc(char ** argv)
+{
+ char ** parg;
+
+ if (!(parg = argv))
+ return 0;
+
+ for (; *parg; )
+ parg++;
+
+ return parg - argv + 1;
+}
+
+
static struct slbt_exec_ctx_impl * slbt_exec_ctx_alloc(
const struct slbt_driver_ctx * dctx)
{
+ struct slbt_driver_ctx_impl * ctx;
struct slbt_exec_ctx_impl * ictx;
size_t size;
- size_t vsize;
+ size_t slen;
+ size_t exts;
int argc;
char * args;
char * shadow;
char * csrc;
char ** parg;
+ struct slbt_archive_ctx ** dlactxv;
+ size_t ndlopen;
+ /* internal driver context for host-specific tool arguments */
+ ctx = slbt_get_driver_ictx(dctx);
+
+ /* initial buffer size (cargv, -Wc), .libs/.exe.wrapper */
argc = 0;
csrc = 0;
+ size = 0;
+ exts = 20;
- /* clerical [worst-case] buffer size (guard, .libs, version) */
- size = strlen(".lo") + 1;
- size += 12 * (strlen(".libs/") + 1);
- size += 36 * (strlen(".0000") + 1);
-
- /* buffer size (cargv, -Wc) */
- for (parg=dctx->cctx->cargv; *parg; parg++, argc++)
- if (!(strncmp("-Wc,",*parg,4)))
+ for (parg=dctx->cctx->cargv; *parg; parg++, argc++) {
+ if (!(strncmp("-Wc,",*parg,4))) {
size += slbt_parse_comma_separated_flags(
&(*parg)[4],&argc) + 1;
- else
+ } else {
size += strlen(*parg) + 1;
+ }
+ }
- /* buffer size (ldirname, lbasename, lobjname, aobjname, etc.) */
- if (dctx->cctx->output)
- size += 9*strlen(dctx->cctx->output);
- else if ((csrc = slbt_source_file(dctx->cctx->cargv)))
- size += 9*strlen(csrc);
+ /* argument transformation: assume for each argv member */
+ if (dctx->cctx->shrext) {
+ exts += argc * (strlen(dctx->cctx->shrext));
+ }
- /* pessimistic: long dso suffix, long x.y.z version */
- size += 9 * (16 + 16 + 16 + 16);
+ if (dctx->cctx->settings.dsosuffix) {
+ exts += argc * (strlen(dctx->cctx->settings.dsosuffix));
+ }
- /* pessimistic argc: .libs/libfoo.so --> -L.libs -lfoo */
- argc *= 2;
- argc += SLBT_ARGV_SPARE_PTRS;
-
- /* buffer size (.libs/%.o, pessimistic) */
- size += argc * strlen(".libs/-L-l");
-
- /* buffer size (linking) */
- if (dctx->cctx->mode == SLBT_MODE_LINK)
- size += strlen(dctx->cctx->settings.arprefix) + 1
- + strlen(dctx->cctx->settings.arsuffix) + 1
- + strlen(dctx->cctx->settings.dsoprefix) + 1
- + strlen(dctx->cctx->settings.dsoprefix) + 1
- + strlen(dctx->cctx->settings.dsoprefix) + 1
- + strlen(dctx->cctx->settings.exeprefix) + 1
- + strlen(dctx->cctx->settings.exeprefix) + 1
- + strlen(dctx->cctx->settings.impprefix) + 1
- + strlen(dctx->cctx->settings.impprefix) + 1;
+ size += argc * exts;
- /* alloc */
+ /* buffer size (csrc, ldirname, lbasename, lobjname, aobjname, etc.) */
+ if (dctx->cctx->libname) {
+ slen = strlen(dctx->cctx->libname);
+ size += (strlen(".slibtool.expsyms.extension") + slen + exts + 1) * SLBT_ECTX_LIB_EXTRAS;
+
+ } else if (dctx->cctx->output) {
+ slen = strlen(dctx->cctx->output);
+ size += (strlen(".slibtool.expsyms.extension") + slen + exts + 1) * SLBT_ECTX_LIB_EXTRAS;
+
+ } else if ((csrc = slbt_source_file(dctx->cctx->cargv))) {
+ slen = strlen(csrc);
+ size += (strlen(".slibtool.expsyms.extension") + slen + exts + 1) * SLBT_ECTX_LIB_EXTRAS;
+ } else {
+ size += exts * SLBT_ECTX_LIB_EXTRAS;
+ }
+
+ /* string buffers: args, shadow */
if (!(args = malloc(size)))
return 0;
@@ -113,24 +140,54 @@ static struct slbt_exec_ctx_impl * slbt_exec_ctx_alloc(
return 0;
}
- /* ictx, argv, xargv */
- vsize = sizeof(*ictx);
- vsize += sizeof(char *) * (argc + 1);
- vsize += sizeof(char *) * (argc + 1);
+ /* tool-specific argv: to simplify matters, be additive */
+ argc += slbt_exec_ctx_tool_argc(ctx->host.ar_argv);
+ argc += slbt_exec_ctx_tool_argc(ctx->host.as_argv);
+ argc += slbt_exec_ctx_tool_argc(ctx->host.nm_argv);
+ argc += slbt_exec_ctx_tool_argc(ctx->host.ranlib_argv);
+ argc += slbt_exec_ctx_tool_argc(ctx->host.windres_argv);
+ argc += slbt_exec_ctx_tool_argc(ctx->host.dlltool_argv);
+ argc += slbt_exec_ctx_tool_argc(ctx->host.mdso_argv);
- /* altv: duplicate set, -Wl,--whole-archive, -Wl,--no-whole-archive */
- vsize += sizeof(char *) * (argc + 1) * 3;
+ /* argv transformation: .libs/libfoo.so --> -L.libs -lfoo */
+ argc *= 2;
- if (!(ictx = calloc(1,vsize))) {
+ /* argv ad-hoc extensions */
+ argc += SLBT_ECTX_SPARE_PTRS;
+
+ /* ctx alloc and vector alloc: argv, xargv, and altv, where we */
+ /* assume -Wl,--whole-archive arg -Wl,--no-whole-archive; */
+ /* and also dlargv for compiling dlunit.dlopen.c */
+ if (!(ictx = calloc(1,sizeof(*ictx)))) {
free(args);
free(shadow);
return 0;
}
+ if (!(ictx->vbuffer = calloc(6*(argc+1),sizeof(char *)))) {
+ free(args);
+ free(shadow);
+ free(ictx);
+ }
+
+ if ((ndlopen = (slbt_get_driver_ictx(dctx))->ndlopen)) {
+ if (!(dlactxv = calloc(ndlopen+1,sizeof(*dlactxv)))) {
+ free(ictx->vbuffer);
+ free(ictx);
+ free(args);
+ free(shadow);
+ }
+
+ ictx->dlactxv = dlactxv;
+ }
+
+ /* all ready */
+ ictx->dctx = dctx;
ictx->args = args;
ictx->argc = argc;
ictx->size = size;
+ ictx->exts = exts;
ictx->shadow = shadow;
ictx->ctx.csrc = csrc;
@@ -142,24 +199,35 @@ static struct slbt_exec_ctx_impl * slbt_exec_ctx_alloc(
}
-int slbt_get_exec_ctx(
+int slbt_ectx_get_exec_ctx(
const struct slbt_driver_ctx * dctx,
struct slbt_exec_ctx ** ectx)
{
struct slbt_exec_ctx_impl * ictx;
+ struct slbt_driver_ctx_impl * idctx;
+ struct slbt_error_info** errinfp;
char ** parg;
char ** src;
char ** dst;
char * ch;
char * mark;
const char * dmark;
+ const char * dsoext;
char * slash;
+ char * arname;
+ struct slbt_archive_ctx ** dlactxv;
+ struct argv_entry * dlentry;
+ struct argv_entry ** dlopenv;
+ bool fpreopen;
const char * arprefix;
const char * dsoprefix;
const char * impprefix;
const char * ref;
int i;
+ /* internal driver context */
+ idctx = slbt_get_driver_ictx(dctx);
+
/* alloc */
if (!(ictx = slbt_exec_ctx_alloc(dctx)))
return SLBT_NESTED_ERROR(dctx);
@@ -169,6 +237,7 @@ int slbt_get_exec_ctx(
ictx->ctx.argv = ictx->vbuffer;
ictx->ctx.xargv = &ictx->ctx.argv [ictx->argc + 1];
ictx->ctx.altv = &ictx->ctx.xargv[ictx->argc + 1];
+ ictx->dlargv = &ictx->ctx.altv [ictx->argc + 1];
/* <compiler> */
ictx->ctx.compiler = dctx->cctx->cargv[0];
@@ -252,7 +321,7 @@ int slbt_get_exec_ctx(
} else {
ictx->ctx.argv[i++] = ch;
ch += sprintf(ch,"%s",*parg);
- ch += strlen(".libs/-L-l");
+ ch += ictx->exts;
}
}
@@ -266,6 +335,8 @@ int slbt_get_exec_ctx(
ictx->ctx.lsoname = &ictx->ctx.argv[i++];
ictx->ctx.symdefs = &ictx->ctx.argv[i++];
ictx->ctx.symfile = &ictx->ctx.argv[i++];
+ ictx->ctx.explarg = &ictx->ctx.argv[i++];
+ ictx->ctx.expsyms = &ictx->ctx.argv[i++];
ictx->ctx.lout[0] = &ictx->ctx.argv[i++];
ictx->ctx.lout[1] = &ictx->ctx.argv[i++];
@@ -311,8 +382,11 @@ int slbt_get_exec_ctx(
+ 1;
}
- /* linking: arfilename, lafilename, laifilename, dsobasename, dsofilename */
+ /* linking: arfilename, lafilename, laifilename, dsobasename, dsofilename, mapfilename */
if (dctx->cctx->mode == SLBT_MODE_LINK && dctx->cctx->libname) {
+ if (!(dsoext = dctx->cctx->shrext))
+ dsoext = dctx->cctx->settings.dsosuffix;
+
/* arprefix, dsoprefix */
if (dctx->cctx->drvflags & SLBT_DRIVER_MODULE) {
ictx->ctx.sonameprefix = "";
@@ -369,7 +443,18 @@ int slbt_get_exec_ctx(
ictx->ctx.ldirname,
dsoprefix,
dctx->cctx->libname,
- dctx->cctx->settings.dsosuffix);
+ dsoext);
+ ch++;
+
+ /* mapfilename */
+ ictx->ctx.mapfilename = ch;
+ ch += sprintf(ch,"%s%s%s%s%s%s",
+ ictx->ctx.ldirname,
+ dsoprefix,
+ dctx->cctx->libname,
+ dctx->cctx->release ? "-" : "",
+ dctx->cctx->release ? dctx->cctx->release : "",
+ dctx->cctx->settings.mapsuffix);
ch++;
/* deffilename */
@@ -380,7 +465,7 @@ int slbt_get_exec_ctx(
dctx->cctx->libname,
dctx->cctx->release ? "-" : "",
dctx->cctx->release ? dctx->cctx->release : "",
- dctx->cctx->settings.dsosuffix);
+ dsoext);
ch++;
/* rpathfilename */
@@ -389,7 +474,7 @@ int slbt_get_exec_ctx(
ictx->ctx.ldirname,
dsoprefix,
dctx->cctx->libname,
- dctx->cctx->settings.dsosuffix);
+ dsoext);
ch++;
/* default implib file name */
@@ -447,7 +532,7 @@ int slbt_get_exec_ctx(
dsoprefix,
dctx->cctx->libname,
dctx->cctx->release,
- dctx->cctx->settings.dsosuffix);
+ dsoext);
ch++;
}
@@ -459,13 +544,46 @@ int slbt_get_exec_ctx(
dsoprefix,
dctx->cctx->libname,
dctx->cctx->release,
- dctx->cctx->settings.dsosuffix);
+ dsoext);
+ ch++;
+ }
+
+ /* dlopensrc, dlopenobj */
+ if (idctx->dlopenv) {
+ ictx->ctx.dlopensrc = ch;
+ ch += sprintf(ch,"%s%s%s.dlopen.c",
+ ictx->ctx.ldirname,
+ dsoprefix,
+ dctx->cctx->libname);
+
+ ch++;
+
+ ictx->ctx.dlopenobj = ch;
+ ch += sprintf(ch,"%s%s%s.dlopen.o",
+ ictx->ctx.ldirname,
+ dsoprefix,
+ dctx->cctx->libname);
+
+ ch++;
+
+ ictx->ctx.dlpreopen = ch;
+ ch += sprintf(ch,"%s%s%s.dlpreopen.a",
+ ictx->ctx.ldirname,
+ dsoprefix,
+ dctx->cctx->libname);
+
+ ch++;
+
+ ictx->ctx.dlunit = ch;
+ ch += sprintf(ch,"%s%s",
+ dsoprefix,
+ dctx->cctx->libname);
+
ch++;
}
- }
/* linking: exefilename */
- if (dctx->cctx->mode == SLBT_MODE_LINK && !dctx->cctx->libname) {
+ } else if (dctx->cctx->mode == SLBT_MODE_LINK) {
ictx->ctx.exefilename = ch;
if ((slash = strrchr(dctx->cctx->output,'/'))) {
@@ -477,6 +595,141 @@ int slbt_get_exec_ctx(
ch += sprintf(ch,".libs/%s",dctx->cctx->output) + 1;
}
+ /* dlopensrc, dlopenobj: executable program */
+ if (idctx->dlopenv && !dctx->cctx->libname) {
+ ictx->ctx.dlopensrc = ch;
+ ch += sprintf(ch,"%s.dlopen.c",
+ ictx->ctx.exefilename);
+
+ ch++;
+
+ ictx->ctx.dlopenobj = ch;
+ ch += sprintf(ch,"%s.dlopen.o",
+ ictx->ctx.exefilename);
+
+ ch++;
+
+ ictx->ctx.dlpreopen = ch;
+ ch += sprintf(ch,"%s.dlpreopen.a",
+ ictx->ctx.exefilename);
+
+ ch++;
+
+ ictx->ctx.dlunit = ch;
+ ch += sprintf(ch,"%s",
+ "@PROGRAM@");
+
+ ch++;
+
+ ictx->ctx.mapfilename = ch;
+ ch += sprintf(ch,"%s%s",
+ ictx->ctx.exefilename,
+ dctx->cctx->settings.mapsuffix);
+ ch++;
+
+ }
+
+ /* dlopen, dlpreopen */
+ if ((dlopenv = idctx->dlopenv), (dlactxv = ictx->dlactxv)) {
+ if (slbt_ar_get_varchive_ctx(dctx,dlactxv) < 0)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_NESTED_ERROR(dctx));
+
+ if (slbt_ar_update_syminfo(*dlactxv) < 0)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_NESTED_ERROR(dctx));
+
+ dlactxv++;
+
+ for (; *dlopenv; ) {
+ dlentry = *dlopenv;
+ fpreopen = (dlentry->tag == TAG_DLPREOPEN);
+
+ arname = ictx->sbuf;
+ strcpy(arname,dlentry->arg);
+
+ slbt_adjust_wrapper_argument(
+ arname,true,
+ ".expsyms.a");
+
+ errinfp = idctx->errinfp;
+
+ if (slbt_ar_get_archive_ctx(dctx,arname,dlactxv) < 0) {
+ if ((*errinfp)->esyscode != ENOENT)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_NESTED_ERROR(dctx));
+
+ strcpy(arname,dlentry->arg);
+
+ slbt_adjust_wrapper_argument(
+ arname,true,
+ dctx->cctx->settings.arsuffix);
+
+ if (slbt_ar_get_archive_ctx(dctx,arname,dlactxv) < 0)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_NESTED_ERROR(dctx));
+
+ idctx->errinfp = errinfp;
+
+ for (; *errinfp; )
+ *errinfp++ = 0;
+
+ fpreopen = true;
+ }
+
+ if (fpreopen) {
+ if (slbt_ar_update_syminfo(*dlactxv) < 0)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_NESTED_ERROR(dctx));
+
+ dlactxv++;
+ } else {
+ slbt_ar_free_archive_ctx(*dlactxv);
+ *dlactxv = 0;
+ }
+
+ dlopenv++;
+ }
+
+ if (slbt_mkdir(dctx,ictx->ctx.ldirname) < 0)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_SYSTEM_ERROR(
+ dctx,
+ ictx->ctx.ldirname));
+
+ if (slbt_ar_create_dlsyms(
+ ictx->dlactxv,
+ ictx->ctx.dlunit,
+ ictx->ctx.dlopensrc,
+ 0644) < 0)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_NESTED_ERROR(dctx));
+
+ if (slbt_ar_merge_archives(ictx->dlactxv,&ictx->dlpreopen) < 0)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_NESTED_ERROR(dctx));
+
+ if (slbt_ar_store_archive(ictx->dlpreopen,ictx->ctx.dlpreopen,0644) < 0)
+ return slbt_ectx_free_exec_ctx_impl(
+ ictx,
+ SLBT_NESTED_ERROR(dctx));
+ }
+
+ /* vector of exported symbols (raw input via -export-symbols) */
+ if (dctx->cctx->expsyms)
+ if (slbt_lib_get_symlist_ctx(
+ dctx,dctx->cctx->expsyms,
+ &ictx->sctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
/* argument strings shadow copy */
memcpy(ictx->shadow,ictx->args,ictx->size);
@@ -498,22 +751,35 @@ int slbt_get_exec_ctx(
}
-static int slbt_free_exec_ctx_impl(
+static int slbt_ectx_free_exec_ctx_impl(
struct slbt_exec_ctx_impl * ictx,
int status)
{
+ struct slbt_archive_ctx ** dlactxv;
+
+ if (ictx->sctx)
+ slbt_lib_free_symlist_ctx(ictx->sctx);
+
if (ictx->fdwrapper >= 0)
close(ictx->fdwrapper);
+ if (ictx->dlactxv) {
+ for (dlactxv=ictx->dlactxv; *dlactxv; dlactxv++)
+ slbt_ar_free_archive_ctx(*dlactxv);
+
+ free(ictx->dlactxv);
+ }
+
free(ictx->args);
free(ictx->shadow);
+ free(ictx->vbuffer);
free (ictx);
return status;
}
-void slbt_free_exec_ctx(struct slbt_exec_ctx * ctx)
+void slbt_ectx_free_exec_ctx(struct slbt_exec_ctx * ctx)
{
struct slbt_exec_ctx_impl * ictx;
uintptr_t addr;
@@ -521,12 +787,12 @@ void slbt_free_exec_ctx(struct slbt_exec_ctx * ctx)
if (ctx) {
addr = (uintptr_t)ctx - offsetof(struct slbt_exec_ctx_impl,ctx);
ictx = (struct slbt_exec_ctx_impl *)addr;
- slbt_free_exec_ctx_impl(ictx,0);
+ slbt_ectx_free_exec_ctx_impl(ictx,0);
}
}
-void slbt_reset_arguments(struct slbt_exec_ctx * ectx)
+void slbt_ectx_reset_arguments(struct slbt_exec_ctx * ectx)
{
struct slbt_exec_ctx_impl * ictx;
uintptr_t addr;
@@ -537,7 +803,7 @@ void slbt_reset_arguments(struct slbt_exec_ctx * ectx)
}
-void slbt_reset_argvector(struct slbt_exec_ctx * ectx)
+void slbt_ectx_reset_argvector(struct slbt_exec_ctx * ectx)
{
struct slbt_exec_ctx_impl * ictx;
uintptr_t addr;
@@ -560,8 +826,17 @@ void slbt_reset_argvector(struct slbt_exec_ctx * ectx)
}
-void slbt_reset_placeholders(struct slbt_exec_ctx * ectx)
+slbt_hidden void slbt_reset_placeholders(struct slbt_exec_ctx * ectx)
{
+ struct slbt_exec_ctx_impl * ictx;
+
+ ictx = slbt_get_exec_ictx(ectx);
+
+ if (ictx->lout[0]) {
+ ectx->lout[0] = ictx->lout[0];
+ ectx->lout[1] = ictx->lout[1];
+ }
+
*ectx->dpic = "-USLIBTOOL_PLACEHOLDER_DPIC";
*ectx->fpic = "-USLIBTOOL_PLACEHOLDER_FPIC";
*ectx->cass = "-USLIBTOOL_PLACEHOLDER_COMPILE_ASSEMBLE";
@@ -571,6 +846,8 @@ void slbt_reset_placeholders(struct slbt_exec_ctx * ectx)
*ectx->lsoname = "-USLIBTOOL_PLACEHOLDER_LSONAME";
*ectx->symdefs = "-USLIBTOOL_PLACEHOLDER_SYMDEF_SWITCH";
*ectx->symfile = "-USLIBTOOL_PLACEHOLDER_SYMDEF_FILE";
+ *ectx->explarg = "-USLIBTOOL_PLACEHOLDER_EXPSYMS_SWITCH";
+ *ectx->expsyms = "-USLIBTOOL_PLACEHOLDER_EXPSYMS_FILE";
*ectx->lout[0] = "-USLIBTOOL_PLACEHOLDER_OUTPUT_SWITCH";
*ectx->lout[1] = "-USLIBTOOL_PLACEHOLDER_OUTPUT_FILE";
@@ -584,7 +861,7 @@ void slbt_reset_placeholders(struct slbt_exec_ctx * ectx)
*ectx->sentinel= 0;
}
-void slbt_disable_placeholders(struct slbt_exec_ctx * ectx)
+slbt_hidden void slbt_disable_placeholders(struct slbt_exec_ctx * ectx)
{
*ectx->dpic = 0;
*ectx->fpic = 0;
@@ -595,6 +872,8 @@ void slbt_disable_placeholders(struct slbt_exec_ctx * ectx)
*ectx->lsoname = 0;
*ectx->symdefs = 0;
*ectx->symfile = 0;
+ *ectx->explarg = 0;
+ *ectx->expsyms = 0;
*ectx->lout[0] = 0;
*ectx->lout[1] = 0;
diff --git a/src/logic/slbt_exec_execute.c b/src/logic/slbt_exec_execute.c
index 58bb65f..7f9389b 100644
--- a/src/logic/slbt_exec_execute.c
+++ b/src/logic/slbt_exec_execute.c
@@ -1,6 +1,6 @@
/*******************************************************************/
-/* slibtool: a skinny libtool implementation, written in C */
-/* Copyright (C) 2016--2021 Z. Gilboa */
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/
@@ -13,90 +13,189 @@
#include <slibtool/slibtool.h>
#include "slibtool_spawn_impl.h"
#include "slibtool_driver_impl.h"
+#include "slibtool_snprintf_impl.h"
#include "slibtool_errinfo_impl.h"
-int slbt_exec_execute(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx)
+
+/*******************************************************************/
+/* --mode=execute: wrapper script and execution argument vector */
+/* */
+/* The purpose of executable wrapper scripts is to properly handle */
+/* one common scenario where: */
+/* */
+/* (1) a build project would entail both executable programs and */
+/* dynamically linked libraries; and */
+/* */
+/* (2) one or more of the project's executable programs would have */
+/* one or more of the project's libraries as a dynamic runtime */
+/* dependency. */
+/* */
+/* Since the project's dependency libraries are not yet installed, */
+/* correct resolution of a program's dynamic library dependencies */
+/* must depend on an appropriate setting of the LD_LIBRARY_PATH */
+/* encironment variable (on Linxu or Midipix) or an equivalent */
+/* environment variable on any of the other supported platforms. */
+/* */
+/* Here, too, there are two distinct cases: */
+/* */
+/* (a) the executable wrapper script is directly invoked from the */
+/* shell command line or otherwise; or */
+/* */
+/* (b) the build target associated with the executable program is */
+/* an argument passed to `slibtool --mode=execute` either as */
+/* the name of the program to be executed (and thus as the */
+/* first non-slibtool argument) or for processing by another */
+/* program. */
+/* */
+/* The first case is handled entirely from within the executable */
+/* wrapper script. The load environment variable is set based on */
+/* the path that was stored in it by slibtool at link time, and */
+/* the real executable is then exec'ed. */
+/* */
+/* In the second case, slibtool would start by testing whether the */
+/* first non-slibtool argument is the wrapper script of a newly */
+/* built executable program. If it is, then slibtool would invoke */
+/* the wrapper script rather than the executable program, and add */
+/* the path to the executable to the argument vector before all */
+/* other arguments, makign it ${1} from the wrapper script's point */
+/* of view. Then again, and irrespective of the previous step, */
+/* slibtool will replace any remaining command-line argument which */
+/* points to a build target associated with a newly built program */
+/* with the path to the program itself (that is, the one located */
+/* under the internal .libs/ directory). */
+/* */
+/* For the sake of consistency and robustness, wrapper scripts are */
+/* created at link time for _all_ executable programs, including */
+/* those programs which appear to have system libraries as their */
+/* sole dynamic library dependencies. */
+/*******************************************************************/
+
+
+static int slbt_argument_is_an_executable_wrapper_script(
+ const struct slbt_driver_ctx * dctx,
+ const char * arg,
+ char (*altarg)[PATH_MAX])
+{
+ int fdcwd;
+ const char * base;
+ char * mark;
+ struct stat st;
+
+ /* the extra characters: .libs/.exe.wrapper */
+ if (strlen(arg) > (PATH_MAX - 20))
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* path/to/progname --> path/to/.libs/progname.exe.wapper */
+ if ((base = strrchr(arg,'/')))
+ base++;
+
+ if (!base)
+ base = arg;
+
+ mark = *altarg;
+ mark += base - arg;
+
+ strcpy(*altarg,arg);
+ mark += sprintf(mark,".libs/%s",base);
+ strcpy(mark,".exe.wrapper");
+
+ /* not an executable wrapper script? */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ if (fstatat(fdcwd,*altarg,&st,0) < 0)
+ return (errno == ENOENT)
+ ? 0 : SLBT_SYSTEM_ERROR(dctx,*altarg);
+
+ /* path/to/.libs/progname.exe.wapper --> path/to/.libs/progname */
+ *mark = '\0';
+
+ return 1;
+}
+
+
+int slbt_exec_execute(const struct slbt_driver_ctx * dctx)
{
int ret;
- int fdcwd;
+ char ** parg;
+ char ** aarg;
char * program;
- char * script;
- char * base;
- char * mark;
- char exeref [PATH_MAX];
+ char * exeref;
char wrapper[PATH_MAX];
- struct stat st;
- struct slbt_exec_ctx * actx = 0;
+ char exeprog[PATH_MAX];
+ char argbuf [PATH_MAX];
+ struct slbt_exec_ctx * ectx;
/* dry run */
if (dctx->cctx->drvflags & SLBT_DRIVER_DRY_RUN)
return 0;
/* context */
- if (ectx)
- slbt_disable_placeholders(ectx);
- else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
- return ret;
- else {
- actx = ectx;
- slbt_disable_placeholders(ectx);
- }
+ if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
- /* script, program */
- program = ectx->cargv[0];
- script = ectx->cargv[1];
-
- if (script) {
- /* exeref */
- if ((base = strrchr(script,'/')))
- base++;
- else
- base = script;
-
- strcpy(exeref,script);
- mark = exeref + (base - script);
- sprintf(mark,".libs/%s",base);
-
- /* wrapper */
- if ((size_t)snprintf(wrapper,sizeof(wrapper),
- "%s.exe.wrapper",
- exeref)
- >= sizeof(wrapper)) {
- slbt_free_exec_ctx(actx);
- return SLBT_BUFFER_ERROR(dctx);
- }
+ slbt_disable_placeholders(ectx);
+
+ /* original and alternate argument vectors */
+ parg = ectx->cargv;
+ aarg = ectx->altv;
+
+ /* program (first non-slibtool argument) */
+ if (!(program = ectx->cargv[0]))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ /* init the wrapper argument based on the first qualifying argument */
+ for (exeref=0; !exeref && *parg; parg++) {
+ strcpy(argbuf,*parg);
+
+ if ((ret = slbt_argument_is_an_executable_wrapper_script(
+ dctx,argbuf,&exeprog)) < 0) {
+ return SLBT_NESTED_ERROR(dctx);
- /* fdcwd */
- fdcwd = slbt_driver_fdcwd(dctx);
+ } else if (ret == 1) {
+ if (slbt_snprintf(
+ wrapper,sizeof(wrapper),
+ "%s.exe.wrapper",exeprog) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
- /* swap vector */
- if (!fstatat(fdcwd,script,&st,0) && !fstatat(fdcwd,wrapper,&st,0)) {
- ectx->cargv[0] = wrapper;
- ectx->cargv[1] = program;
- ectx->cargv[2] = exeref;
+ exeref = *parg;
+ *aarg++ = wrapper;
} else {
- script = program;
+ strcpy(*parg,argbuf);
}
+ }
+
+ /* transform in place as needed all arguments */
+ for (parg=ectx->cargv; *parg; parg++) {
+ if ((ret = slbt_argument_is_an_executable_wrapper_script(
+ dctx,*parg,&argbuf)) < 0) {
+ return SLBT_NESTED_ERROR(dctx);
- /* execute mode */
- ectx->program = script;
- ectx->argv = ectx->cargv;
- } else {
- ectx->program = program;
- ectx->argv = ectx->cargv;
+ } else if (ret == 1) {
+ strcpy(*parg,argbuf);
+ *aarg++ = *parg;
+ } else {
+ *aarg++ = *parg;
+ }
}
+ *aarg = 0;
+
+ /* execute mode */
+ ectx->program = ectx->altv[0];
+ ectx->argv = ectx->altv;
+
/* step output */
- if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_execute(dctx,ectx)) {
- slbt_free_exec_ctx(actx);
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) {
+ if (slbt_output_execute(ectx)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
+ }
- execvp(ectx->cargv[0],ectx->argv);
+ execvp(ectx->altv[0],ectx->altv);
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_SYSTEM_ERROR(dctx,0);
}
diff --git a/src/logic/slbt_exec_install.c b/src/logic/slbt_exec_install.c
index 4461d0b..228d2ff 100644
--- a/src/logic/slbt_exec_install.c
+++ b/src/logic/slbt_exec_install.c
@@ -1,6 +1,6 @@
/*******************************************************************/
-/* slibtool: a skinny libtool implementation, written in C */
-/* Copyright (C) 2016--2021 Z. Gilboa */
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/
@@ -12,8 +12,6 @@
#include <errno.h>
#include <sys/stat.h>
-#define ARGV_DRIVER
-
#include <slibtool/slibtool.h>
#include "slibtool_driver_impl.h"
#include "slibtool_install_impl.h"
@@ -22,6 +20,7 @@
#include "slibtool_spawn_impl.h"
#include "slibtool_symlink_impl.h"
#include "slibtool_errinfo_impl.h"
+#include "slibtool_snprintf_impl.h"
#include "argv/argv.h"
static int slbt_install_usage(
@@ -41,26 +40,26 @@ static int slbt_install_usage(
switch (noclr) {
case 0:
- argv_usage(fdout,header,optv,arg);
+ slbt_argv_usage(fdout,header,optv,arg);
break;
default:
- argv_usage_plain(fdout,header,optv,arg);
+ slbt_argv_usage_plain(fdout,header,optv,arg);
break;
}
- argv_free(meta);
+ slbt_argv_free(meta);
return SLBT_USAGE;
}
static int slbt_exec_install_fail(
- struct slbt_exec_ctx * actx,
+ struct slbt_exec_ctx * ectx,
struct argv_meta * meta,
int ret)
{
- argv_free(meta);
- slbt_free_exec_ctx(actx);
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
return ret;
}
@@ -83,8 +82,8 @@ static int slbt_exec_install_init_dstdir(
last = dest;
/* dstdir: initial string */
- if ((size_t)snprintf(dstdir,PATH_MAX,"%s",
- last->arg) >= PATH_MAX)
+ if (slbt_snprintf(dstdir,PATH_MAX,
+ "%s",last->arg) < 0)
return SLBT_BUFFER_ERROR(dctx);
/* dstdir might end with a slash */
@@ -126,8 +125,8 @@ static int slbt_exec_install_import_libraries(
char rev [128];
/* .libs/libfoo.so.x.y.z */
- if ((size_t)snprintf(srcbuf,sizeof(srcbuf),"%s",
- srcdso) >= sizeof(srcbuf))
+ if (slbt_snprintf(srcbuf,sizeof(srcbuf),
+ "%s",srcdso) <0)
return SLBT_BUFFER_ERROR(dctx);
/* (dso is under .libs) */
@@ -135,9 +134,11 @@ static int slbt_exec_install_import_libraries(
return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
/* libfoo.so.x.y.z */
- if ((size_t)snprintf(implib,sizeof(implib),"%s",
- ++slash) >= sizeof(implib)
- - strlen(dctx->cctx->settings.impsuffix))
+ const char * impsuffix = dctx->cctx->settings.impsuffix;
+
+ if (slbt_snprintf(implib,
+ sizeof(implib) - strlen(impsuffix),
+ "%s",++slash) < 0)
return SLBT_BUFFER_ERROR(dctx);
/* guard against an infinitely long version */
@@ -190,7 +191,7 @@ static int slbt_exec_install_import_libraries(
dctx->cctx->asettings.impsuffix);
/* copy: .libs/libfoo.x.y.z.lib.a --> dstdir */
- if (slbt_copy_file(dctx,ectx,srcbuf,dstdir))
+ if (slbt_util_copy_file(ectx,srcbuf,dstdir))
return SLBT_NESTED_ERROR(dctx);
/* .libs/libfoo.x.lib.a */
@@ -199,15 +200,15 @@ static int slbt_exec_install_import_libraries(
dctx->cctx->asettings.impsuffix);
/* copy: .libs/libfoo.x.lib.a --> dstdir */
- if (slbt_copy_file(dctx,ectx,srcbuf,dstdir))
+ if (slbt_util_copy_file(ectx,srcbuf,dstdir))
return SLBT_NESTED_ERROR(dctx);
/* /dstdir/libfoo.lib.a */
strcpy(implib,slash);
strcpy(dot,dctx->cctx->asettings.impsuffix);
- if ((size_t)snprintf(hostlnk,sizeof(hostlnk),"%s/%s",
- dstdir,slash) >= sizeof(hostlnk))
+ if (slbt_snprintf(hostlnk,sizeof(hostlnk),
+ "%s/%s",dstdir,slash) <0)
return SLBT_BUFFER_ERROR(dctx);
if (slbt_create_symlink(
@@ -244,13 +245,14 @@ static int slbt_exec_install_library_wrapper(
base = entry->arg;
/* /dstdir/libfoo.la */
- if ((size_t)snprintf(instname,sizeof(instname),"%s/%s",
- dstdir,base) >= sizeof(instname))
+ if (slbt_snprintf(instname,sizeof(instname),
+ "%s/%s",dstdir,base) < 0)
return SLBT_BUFFER_ERROR(dctx);
/* libfoo.la.slibtool.install */
- if ((size_t)snprintf(clainame,sizeof(clainame),"%s.slibtool.install",
- entry->arg) >= sizeof(clainame))
+ if (slbt_snprintf(clainame,sizeof(clainame),
+ "%s.slibtool.install",
+ entry->arg) < 0)
return SLBT_BUFFER_ERROR(dctx);
/* fdcwd */
@@ -307,8 +309,8 @@ static int slbt_exec_install_library_wrapper(
close(fddst);
slbt_unmap_file(mapinfo);
- /* cp libfoo.la.slibtool.instal /dstdir/libfoo.la */
- if (slbt_copy_file(dctx,ectx,clainame,instname))
+ /* cp libfoo.la.slibtool.install /dstdir/libfoo.la */
+ if (slbt_util_copy_file(ectx,clainame,instname))
return SLBT_NESTED_ERROR(dctx);
return 0;
@@ -324,7 +326,6 @@ static int slbt_exec_install_entry(
char ** src,
char ** dst)
{
- int ret;
int fdcwd;
const char * base;
char * dot;
@@ -345,8 +346,6 @@ static int slbt_exec_install_entry(
bool fpe;
bool frelease;
bool fdualver;
- bool fstatic;
- bool farchive;
size_t slen;
size_t dlen;
struct stat st;
@@ -359,9 +358,9 @@ static int slbt_exec_install_entry(
mark = &slnkname[base - entry->arg];
slen = sizeof(slnkname) - (mark - slnkname);
- if ((size_t)snprintf(mark,slen,
+ if (slbt_snprintf(mark,slen,
".libs/%s.exe.wrapper",
- base) >= slen)
+ base) < 0)
return SLBT_BUFFER_ERROR(dctx);
/* fdcwd */
@@ -396,19 +395,27 @@ static int slbt_exec_install_entry(
*dst = dest ? 0 : (char *)last->arg;
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_install(dctx,ectx))
+ if (slbt_output_install(ectx))
return SLBT_NESTED_ERROR(dctx);
- return (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
- ? SLBT_SPAWN_ERROR(dctx) : 0;
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ return SLBT_SPAWN_ERROR(dctx);
+
+ } else if (ectx->exitcode) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_INSTALL_ERROR);
+ }
+
+ return 0;
}
/* -shrext, dsosuffix */
strcpy(sobuf,dctx->cctx->settings.dsosuffix);
dsosuffix = sobuf;
- if ((size_t)snprintf(slnkname,sizeof(slnkname),"%s.shrext",
- srcfile) >= sizeof(slnkname))
+ if (slbt_snprintf(slnkname,sizeof(slnkname),
+ "%s.shrext",srcfile) < 0)
return SLBT_BUFFER_ERROR(dctx);
if (!fstatat(fdcwd,slnkname,&st,0)) {
@@ -439,6 +446,14 @@ static int slbt_exec_install_entry(
dot = strrchr(srcfile,'.');
strcpy(dot,dctx->cctx->settings.arsuffix);
+ /* libfoo.a installation */
+ if (!slbt_symlink_is_a_placeholder(fdcwd,srcfile))
+ if (slbt_util_copy_file(
+ ectx,
+ srcfile,
+ dest ? (char *)dest->arg : *dst))
+ return SLBT_NESTED_ERROR(dctx);
+
/* dot/suffix */
strcpy(slnkname,srcfile);
dot = strrchr(slnkname,'.');
@@ -447,33 +462,29 @@ static int slbt_exec_install_entry(
slen = sizeof(slnkname);
slen -= (dot - slnkname);
+ /* static library only? */
+ sprintf(dot,"%s",dsosuffix);
+
+ if (slbt_symlink_is_a_placeholder(fdcwd,slnkname))
+ return 0;
+
/* detect -release, exclusively or alongside -version-info */
frelease = false;
fdualver = false;
- fstatic = false;
fpe = false;
- /* static library only? */
- sprintf(dot,"%s",dsosuffix);
- fstatic = slbt_symlink_is_a_placeholder(fdcwd,slnkname);
-
/* libfoo.a --> libfoo.so.release */
- if (!fstatic) {
- sprintf(dot,"%s.release",dsosuffix);
- frelease = !fstatat(fdcwd,slnkname,&st,0);
- }
+ sprintf(dot,"%s.release",dsosuffix);
+ frelease = !fstatat(fdcwd,slnkname,&st,0);
/* libfoo.a --> libfoo.so.dualver */
- if (!fstatic && !frelease) {
+ if (!frelease) {
sprintf(dot,"%s.dualver",dsosuffix);
fdualver = !fstatat(fdcwd,slnkname,&st,0);
}
/* libfoo.so.def.{flavor} */
- if (fstatic) {
- (void)0;
-
- } else if (frelease || fdualver) {
+ if (frelease || fdualver) {
strcpy(dlnkname,slnkname);
slash = strrchr(dlnkname,'/');
@@ -509,7 +520,7 @@ static int slbt_exec_install_entry(
if (slbt_readlinkat(fdcwd,dlnkname,hosttag,sizeof(hosttag)))
return SLBT_SYSTEM_ERROR(dctx,slnkname);
} else {
- if ((size_t)snprintf(dot,slen,"%s.def.host",dsosuffix) >= slen)
+ if (slbt_snprintf(dot,slen,"%s.def.host",dsosuffix) < 0)
return SLBT_BUFFER_ERROR(dctx);
if (slbt_readlinkat(fdcwd,frelease ? dlnkname : slnkname,hosttag,sizeof(hosttag)))
@@ -517,40 +528,21 @@ static int slbt_exec_install_entry(
}
/* host/flabor */
- if (fstatic) {
- (void)0;
-
- } else if (!(host = strrchr(hosttag,'.'))) {
+ if (!(host = strrchr(hosttag,'.'))) {
return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
} else {
host++;
}
/* symlink-based alternate host */
- if (!fstatic) {
- if (slbt_set_alternate_host(dctx,host,host))
- return SLBT_NESTED_ERROR(dctx);
+ if (slbt_host_set_althost(dctx,host,host))
+ return SLBT_NESTED_ERROR(dctx);
- fpe = !strcmp(dctx->cctx->asettings.imagefmt,"pe");
- }
+ fpe = !strcmp(dctx->cctx->asettings.imagefmt,"pe");
/* libfoo.a --> libfoo.so */
strcpy(dot,dsosuffix);
- /* libfoo.a installation */
- if (!(dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_STATIC))
- farchive = true;
- else if (fstatic)
- farchive = true;
- else
- farchive = false;
-
- if (farchive)
- if (slbt_copy_file(dctx,ectx,
- srcfile,
- dest ? (char *)dest->arg : *dst))
- return SLBT_NESTED_ERROR(dctx);
-
/* basename */
if ((base = strrchr(slnkname,'/')))
base++;
@@ -559,17 +551,13 @@ static int slbt_exec_install_entry(
/* source (build) symlink target */
if (slbt_readlinkat(fdcwd,slnkname,target,sizeof(target)) < 0) {
- /* -all-static? */
- if (fstatic)
- return 0;
-
/* -avoid-version? */
if (fstatat(fdcwd,slnkname,&st,0))
return SLBT_SYSTEM_ERROR(dctx,slnkname);
/* dstfile */
- if ((size_t)snprintf(dstfile,sizeof(dstfile),"%s/%s",
- dstdir,base) >= sizeof(dstfile))
+ if (slbt_snprintf(dstfile,sizeof(dstfile),
+ "%s/%s",dstdir,base) < 0)
return SLBT_BUFFER_ERROR(dctx);
/* single spawn, no symlinks */
@@ -577,12 +565,18 @@ static int slbt_exec_install_entry(
*dst = dest ? 0 : dstfile;
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_install(dctx,ectx))
+ if (slbt_output_install(ectx))
return SLBT_NESTED_ERROR(dctx);
- if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
return SLBT_SPAWN_ERROR(dctx);
+ } else if (ectx->exitcode) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_INSTALL_ERROR);
+ }
+
return 0;
}
@@ -592,8 +586,8 @@ static int slbt_exec_install_entry(
/* dstfile */
if (!dest)
- if ((size_t)snprintf(dstfile,sizeof(dstfile),"%s/%s",
- dstdir,target) >= sizeof(dstfile))
+ if (slbt_snprintf(dstfile,sizeof(dstfile),
+ "%s/%s",dstdir,target) < 0)
return SLBT_BUFFER_ERROR(dctx);
/* spawn */
@@ -601,15 +595,21 @@ static int slbt_exec_install_entry(
*dst = dest ? 0 : dstfile;
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_install(dctx,ectx))
+ if (slbt_output_install(ectx))
return SLBT_NESTED_ERROR(dctx);
- if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
return SLBT_SPAWN_ERROR(dctx);
+ } else if (ectx->exitcode) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_INSTALL_ERROR);
+ }
+
/* destination symlink: dstdir/libfoo.so */
- if ((size_t)snprintf(dlnkname,sizeof(dlnkname),"%s/%s",
- dstdir,base) >= sizeof(dlnkname))
+ if (slbt_snprintf(dlnkname,sizeof(dlnkname),
+ "%s/%s",dstdir,base) < 0)
return SLBT_BUFFER_ERROR(dctx);
/* create symlink: libfoo.so --> libfoo.so.x.y.z */
@@ -655,14 +655,14 @@ static int slbt_exec_install_entry(
}
/* destination symlink: dstdir/libfoo.so.x */
- if ((size_t)snprintf(dlnkname,sizeof(dlnkname),"%s/%s",
- dstdir,slnkname) >= sizeof(dlnkname))
+ if (slbt_snprintf(dlnkname,sizeof(dlnkname),
+ "%s/%s",dstdir,slnkname) < 0)
return SLBT_BUFFER_ERROR(dctx);
if (fpe) {
/* copy: .libs/libfoo.so.x.y.z --> libfoo.so.x */
- if (slbt_copy_file(
- dctx,ectx,
+ if (slbt_util_copy_file(
+ ectx,
srcfile,
dlnkname))
return SLBT_NESTED_ERROR(dctx);
@@ -685,11 +685,8 @@ static int slbt_exec_install_entry(
return 0;
}
-int slbt_exec_install(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx)
+int slbt_exec_install(const struct slbt_driver_ctx * dctx)
{
- int ret;
int fdout;
char ** argv;
char ** iargv;
@@ -699,7 +696,7 @@ int slbt_exec_install(
char * optsh;
char * script;
char * shtool;
- struct slbt_exec_ctx * actx;
+ struct slbt_exec_ctx * ectx;
struct argv_meta * meta;
struct argv_entry * entry;
struct argv_entry * copy;
@@ -713,15 +710,11 @@ int slbt_exec_install(
return 0;
/* context */
- if (ectx)
- actx = 0;
- else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
- return ret;
- else
- actx = ectx;
+ if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
/* initial state, install mode skin */
- slbt_reset_arguments(ectx);
+ slbt_ectx_reset_arguments(ectx);
slbt_disable_placeholders(ectx);
iargv = ectx->cargv;
fdout = slbt_driver_fdout(dctx);
@@ -751,7 +744,7 @@ int slbt_exec_install(
}
/* missing arguments? */
- argv_optv_init(slbt_install_options,optv);
+ slbt_optv_init(slbt_install_options,optv);
if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
return slbt_install_usage(
@@ -761,14 +754,14 @@ int slbt_exec_install(
dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
/* <install> argv meta */
- if (!(meta = argv_get(
+ if (!(meta = slbt_argv_get(
iargv,optv,
dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
? ARGV_VERBOSITY_ERRORS
: ARGV_VERBOSITY_NONE,
fdout)))
return slbt_exec_install_fail(
- actx,meta,
+ ectx,meta,
SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FAIL));
/* dest, alternate argument vector options */
@@ -859,7 +852,7 @@ int slbt_exec_install(
/* dstdir */
if (slbt_exec_install_init_dstdir(dctx,dest,last,dstdir))
return slbt_exec_install_fail(
- actx,meta,
+ ectx,meta,
SLBT_NESTED_ERROR(dctx));
/* install entries one at a time */
@@ -871,7 +864,7 @@ int slbt_exec_install(
dest,dstdir,
src,dst))
return slbt_exec_install_fail(
- actx,meta,
+ ectx,meta,
SLBT_NESTED_ERROR(dctx));
} else {
/* using original argument vector */
@@ -880,17 +873,25 @@ int slbt_exec_install(
/* spawn */
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_install(dctx,ectx))
+ if (slbt_output_install(ectx))
return SLBT_NESTED_ERROR(dctx);
- if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
return slbt_exec_install_fail(
- actx,meta,
+ ectx,meta,
SLBT_SPAWN_ERROR(dctx));
+
+ } else if (ectx->exitcode) {
+ return slbt_exec_install_fail(
+ ectx,meta,
+ SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_INSTALL_ERROR));
+ }
}
- argv_free(meta);
- slbt_free_exec_ctx(actx);
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
return 0;
}
diff --git a/src/logic/slbt_exec_link.c b/src/logic/slbt_exec_link.c
index 70b4d26..50709d3 100644
--- a/src/logic/slbt_exec_link.c
+++ b/src/logic/slbt_exec_link.c
@@ -1,6 +1,6 @@
/*******************************************************************/
-/* slibtool: a skinny libtool implementation, written in C */
-/* Copyright (C) 2016--2021 Z. Gilboa */
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/
@@ -19,25 +19,20 @@
#include "slibtool_driver_impl.h"
#include "slibtool_dprintf_impl.h"
#include "slibtool_errinfo_impl.h"
+#include "slibtool_linkcmd_impl.h"
#include "slibtool_mapfile_impl.h"
#include "slibtool_metafile_impl.h"
#include "slibtool_readlink_impl.h"
+#include "slibtool_snprintf_impl.h"
#include "slibtool_symlink_impl.h"
-struct slbt_deps_meta {
- char ** altv;
- char * args;
- int depscnt;
- int infolen;
-};
-
/*******************************************************************/
/* */
/* -o <ltlib> switches input result */
/* ---------- --------------------- ----- ------ */
/* libfoo.a [-shared|-static] bar.lo libfoo.a */
/* */
-/* ar crs libfoo.a bar.o */
+/* ar -crs libfoo.a bar.o */
/* */
/*******************************************************************/
@@ -49,7 +44,7 @@ struct slbt_deps_meta {
/* .libs/libfoo.a */
/* .libs/libfoo.la (lnk) */
/* */
-/* ar crs .libs/libfoo.a .libs/bar.o */
+/* ar -crs .libs/libfoo.a .libs/bar.o */
/* (generate libfoo.la) */
/* ln -s ../libfoo.la .libs/libfoo.la */
/* */
@@ -63,1716 +58,12 @@ struct slbt_deps_meta {
/* .libs/libfoo.a */
/* .libs/libfoo.la (lnk) */
/* */
-/* ar crs .libs/libfoo.a bar.o */
+/* ar -crs .libs/libfoo.a bar.o */
/* (generate libfoo.la) */
/* ln -s ../libfoo.la .libs/libfoo.la */
/* */
/*******************************************************************/
-static int slbt_exec_link_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_get_deps_meta(
- const struct slbt_driver_ctx * dctx,
- char * libfilename,
- int fexternal,
- struct slbt_deps_meta * depsmeta)
-{
- int fdcwd;
- char * ch;
- char * cap;
- char * base;
- size_t libexlen;
- struct stat st;
- struct slbt_map_info * mapinfo;
- char depfile[PATH_MAX];
-
- /* fdcwd */
- fdcwd = slbt_driver_fdcwd(dctx);
-
- /* -rpath */
- if ((size_t)snprintf(depfile,sizeof(depfile),
- "%s.slibtool.rpath",
- libfilename)
- >= sizeof(depfile))
- return SLBT_BUFFER_ERROR(dctx);
-
- /* -Wl,%s */
- if (!fstatat(fdcwd,depfile,&st,AT_SYMLINK_NOFOLLOW)) {
- depsmeta->infolen += st.st_size + 4;
- depsmeta->infolen++;
- }
-
- /* .deps */
- if ((size_t)snprintf(depfile,sizeof(depfile),
- "%s.slibtool.deps",
- libfilename)
- >= sizeof(depfile))
- return SLBT_BUFFER_ERROR(dctx);
-
- /* mapinfo */
- if (!(mapinfo = slbt_map_file(fdcwd,depfile,SLBT_MAP_INPUT)))
- return (fexternal && (errno == ENOENT))
- ? 0 : SLBT_SYSTEM_ERROR(dctx,depfile);
-
- /* copied length */
- depsmeta->infolen += mapinfo->size;
- depsmeta->infolen++;
-
- /* libexlen */
- libexlen = (base = strrchr(libfilename,'/'))
- ? strlen(depfile) + 2 + (base - libfilename)
- : strlen(depfile) + 2;
-
- /* iterate */
- ch = mapinfo->addr;
- cap = mapinfo->cap;
-
- for (; ch<cap; ) {
- if (*ch++ == '\n') {
- depsmeta->infolen += libexlen;
- depsmeta->depscnt++;
- }
- }
-
- slbt_unmap_file(mapinfo);
-
- return 0;
-}
-
-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 ((size_t)snprintf(base,sizeof(base),"%s",
- slash) >= sizeof(base))
- 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 ((size_t)snprintf(base,sizeof(base),"%s",
- slash) >= sizeof(base))
- 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 ((size_t)snprintf(base,sizeof(base),"%s",
- slash) >= sizeof(base))
- 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,
- size_t dpfixup_size,
- char * wrapper)
-{
- char * p;
- char * q;
- char * wrapper_dname;
-
- /* obtain cwd-relative directory name of wrapper */
- for (p=cwd,q=wrapper; *p && *q && (*p==*q); p++,q++)
- (void)0;
-
- wrapper_dname = (*q == '/') ? (q + 1) : q;
-
- dpfixup[0] = 0; strncat(dpfixup,"${0%/*}",dpfixup_size - 1);
-
- /* append parent directory fixup for each level of depth in wrapper_dname */
- for (p=wrapper_dname,q=0; *p; ) {
- if ((p[0] == '.') && (p[1] == '/')) {
- p++; p++;
- } else if ((q = strchr(p, '/'))) {
- strncat(dpfixup,"/..",dpfixup_size-1); p = (q + 1);
- } else {
- break;
- }
- }
-
- 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 ((size_t)snprintf(arg,sizeof(arg),
- "%s",*carg)
- >= (sizeof(arg) - 4))
- 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,
- const char * target)
-{
- int fdcwd;
-
- (void)ectx;
-
- /* fdcwd */
- fdcwd = slbt_driver_fdcwd(dctx);
-
- /* remove target (if any) */
- if (!unlinkat(fdcwd,target,0) || (errno == ENOENT))
- return 0;
-
- return SLBT_SYSTEM_ERROR(dctx,0);
-}
-
-static int slbt_exec_link_create_dep_file(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx,
- char ** altv,
- const char * libfilename,
- bool farchive)
-{
- int ret;
- int deps;
- int fdcwd;
- char ** parg;
- char * popt;
- char * plib;
- char * path;
- char * mark;
- char * base;
- size_t size;
- size_t slen;
- char deplib [PATH_MAX];
- bool is_reladir;
- char reladir[PATH_MAX];
- char depfile[PATH_MAX];
- struct stat st;
- int ldepth;
- int fdyndep;
- struct slbt_map_info * mapinfo;
-
- /* fdcwd */
- fdcwd = slbt_driver_fdcwd(dctx);
-
- /* depfile */
- slen = snprintf(depfile,sizeof(depfile),
- "%s.slibtool.deps",
- libfilename);
-
- if (slen >= sizeof(depfile))
- return SLBT_BUFFER_ERROR(dctx);
-
- /* deps */
- if ((deps = openat(fdcwd,depfile,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0)
- return SLBT_SYSTEM_ERROR(dctx,depfile);
-
- /* iterate */
- for (parg=altv; *parg; parg++) {
- popt = 0;
- plib = 0;
- path = 0;
- mapinfo = 0;
-
- if (!strncmp(*parg,"-l",2)) {
- popt = *parg;
- plib = popt + 2;
-
- } else if (!strncmp(*parg,"-L",2)) {
- popt = *parg;
- path = popt + 2;
-
- } else if (!strncmp(*parg,"-f",2)) {
- (void)0;
-
- } else if ((popt = strrchr(*parg,'.')) && !strcmp(popt,".la")) {
- /* import dependency list */
- if ((base = strrchr(*parg,'/')))
- base++;
- else
- base = *parg;
-
- /* [relative .la directory] */
- if (base > *parg) {
- slen = snprintf(reladir,sizeof(reladir),
- "%s",*parg);
-
- if (slen >= sizeof(reladir)) {
- close(deps);
- return SLBT_BUFFER_ERROR(dctx);
- }
-
- is_reladir = true;
- reladir[base - *parg - 1] = 0;
- } else {
- is_reladir = false;
- reladir[0] = '.';
- reladir[1] = 0;
- }
-
-
- /* dynamic library dependency? */
- strcpy(depfile,*parg);
- mark = depfile + (base - *parg);
- size = sizeof(depfile) - (base - *parg);
- slen = snprintf(mark,size,".libs/%s",base);
-
- if (slen >= size) {
- close(deps);
- return SLBT_BUFFER_ERROR(dctx);
- }
-
- mark = strrchr(mark,'.');
- strcpy(mark,dctx->cctx->settings.dsosuffix);
-
- fdyndep = !fstatat(fdcwd,depfile,&st,0);
-
- /* [-L... as needed] */
- if (fdyndep && (ectx->ldirdepth >= 0)) {
- if (slbt_dprintf(deps,"-L") < 0) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,0);
- }
-
- for (ldepth=ectx->ldirdepth; ldepth; ldepth--) {
- if (slbt_dprintf(deps,"../") < 0) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,0);
- }
- }
-
- if (slbt_dprintf(deps,"%s%s.libs\n",
- (is_reladir ? reladir : ""),
- (is_reladir ? "/" : "")) < 0) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,0);
- }
- }
-
- /* -ldeplib */
- if (fdyndep) {
- *popt = 0;
- mark = base;
- mark += strlen(dctx->cctx->settings.dsoprefix);
-
- if (slbt_dprintf(deps,"-l%s\n",mark) < 0) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,0);
- }
-
- *popt = '.';
- }
-
- /* [open dependency list] */
- strcpy(depfile,*parg);
- mark = depfile + (base - *parg);
- size = sizeof(depfile) - (base - *parg);
- slen = snprintf(mark,size,".libs/%s",base);
-
- if (slen >= size) {
- close(deps);
- return SLBT_BUFFER_ERROR(dctx);
- }
-
- mapinfo = 0;
-
- mark = strrchr(mark,'.');
- size = sizeof(depfile) - (mark - depfile);
-
- if (!farchive) {
- slen = snprintf(mark,size,
- "%s.slibtool.deps",
- dctx->cctx->settings.dsosuffix);
-
- if (slen >= size) {
- close(deps);
- return SLBT_BUFFER_ERROR(dctx);
- }
-
- mapinfo = slbt_map_file(
- fdcwd,depfile,
- SLBT_MAP_INPUT);
-
- if (!mapinfo && (errno != ENOENT)) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,0);
- }
- }
-
- if (!mapinfo) {
- slen = snprintf(mark,size,
- ".a.slibtool.deps");
-
- if (slen >= size) {
- close(deps);
- return SLBT_BUFFER_ERROR(dctx);
- }
-
- mapinfo = slbt_map_file(
- fdcwd,depfile,
- SLBT_MAP_INPUT);
-
- if (!mapinfo) {
- strcpy(mark,".a.disabled");
-
- if (fstatat(fdcwd,depfile,&st,AT_SYMLINK_NOFOLLOW)) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,depfile);
- }
- }
- }
-
- /* [-l... as needed] */
- while (mapinfo && (mapinfo->mark < mapinfo->cap)) {
- ret = slbt_mapped_readline(
- dctx,mapinfo,
- deplib,sizeof(deplib));
-
- if (ret) {
- close(deps);
- return SLBT_NESTED_ERROR(dctx);
- }
-
- ret = ((deplib[0] == '-')
- && (deplib[1] == 'L')
- && (deplib[2] != '/'))
- ? slbt_dprintf(
- deps,"-L%s/%s",
- reladir,&deplib[2])
- : slbt_dprintf(
- deps,"%s",
- deplib);
-
- if (ret < 0) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,0);
- }
- }
-
- if (mapinfo)
- slbt_unmap_file(mapinfo);
- }
-
- if (plib && (slbt_dprintf(deps,"-l%s\n",plib) < 0)) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,0);
- }
-
- if (path && (slbt_dprintf(deps,"-L%s\n",path) < 0)) {
- close(deps);
- return SLBT_SYSTEM_ERROR(dctx,0);
- }
- }
-
- return 0;
-}
-
-static int slbt_exec_link_create_host_tag(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx,
- char * deffilename)
-{
- char * slash;
- char hosttag[PATH_MAX];
- char hostlnk[PATH_MAX];
-
- /* libfoo.so.def.{flavor} */
- if ((size_t)snprintf(hosttag,sizeof(hosttag),"%s.%s",
- deffilename,
- dctx->cctx->host.flavor) >= sizeof(hosttag))
- return SLBT_BUFFER_ERROR(dctx);
-
- if ((size_t)snprintf(hostlnk,sizeof(hostlnk),"%s.host",
- deffilename) >= sizeof(hostlnk))
- return SLBT_BUFFER_ERROR(dctx);
-
- /* libfoo.so.def is under .libs/ */
- if (!(slash = strrchr(deffilename,'/')))
- return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LINK_FLOW);
-
- if (slbt_create_symlink(
- dctx,ectx,
- deffilename,
- hosttag,
- SLBT_SYMLINK_DEFAULT))
- return SLBT_NESTED_ERROR(dctx);
-
- /* libfoo.so.def.{flavor} is under .libs/ */
- if (!(slash = strrchr(hosttag,'/')))
- return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LINK_FLOW);
-
- if (slbt_create_symlink(
- dctx,ectx,
- ++slash,
- hostlnk,
- SLBT_SYMLINK_DEFAULT))
- return SLBT_NESTED_ERROR(dctx);
-
- return 0;
-}
-
-static int slbt_exec_link_create_import_library(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx,
- char * impfilename,
- char * deffilename,
- char * soname)
-{
- int fmdso;
- char * eargv[8];
- char program[PATH_MAX];
-
- /* dlltool or mdso? */
- if (dctx->cctx->drvflags & SLBT_DRIVER_IMPLIB_DSOMETA)
- fmdso = 1;
-
- else if (dctx->cctx->drvflags & SLBT_DRIVER_IMPLIB_DSOMETA)
- fmdso = 0;
-
- else if (!(strcmp(dctx->cctx->host.flavor,"midipix")))
- fmdso = 1;
-
- else
- fmdso = 0;
-
- /* eargv */
- if (fmdso) {
- if ((size_t)snprintf(program,sizeof(program),"%s",
- dctx->cctx->host.mdso) >= sizeof(program))
- return SLBT_BUFFER_ERROR(dctx);
-
- eargv[0] = program;
- eargv[1] = "-i";
- eargv[2] = impfilename;
- eargv[3] = "-n";
- eargv[4] = soname;
- eargv[5] = deffilename;
- eargv[6] = 0;
- } else {
- if ((size_t)snprintf(program,sizeof(program),"%s",
- dctx->cctx->host.dlltool) >= sizeof(program))
- return SLBT_BUFFER_ERROR(dctx);
-
- eargv[0] = program;
- eargv[1] = "-l";
- eargv[2] = impfilename;
- eargv[3] = "-d";
- eargv[4] = deffilename;
- eargv[5] = "-D";
- eargv[6] = soname;
- eargv[7] = 0;
- }
-
- /* alternate argument vector */
- ectx->argv = eargv;
- ectx->program = program;
-
- /* step output */
- if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_link(dctx,ectx))
- return SLBT_NESTED_ERROR(dctx);
-
- /* dlltool/mdso spawn */
- if ((slbt_spawn(ectx,true) < 0) || ectx->exitcode)
- return SLBT_SPAWN_ERROR(dctx);
-
- return 0;
-}
-
-static int slbt_exec_link_create_noop_symlink(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx,
- const char * arfilename)
-{
- struct stat st;
- int fdcwd;
-
- /* fdcwd */
- fdcwd = slbt_driver_fdcwd(dctx);
-
- /* file exists? */
- if (!fstatat(fdcwd,arfilename,&st,AT_SYMLINK_NOFOLLOW))
- return 0;
-
- /* needed? */
- if (errno == ENOENT) {
- if (slbt_create_symlink(
- dctx,ectx,
- "/dev/null",
- arfilename,
- SLBT_SYMLINK_LITERAL))
- return SLBT_NESTED_ERROR(dctx);
- return 0;
- }
-
- return SLBT_SYSTEM_ERROR(dctx,arfilename);
-}
-
-static int slbt_exec_link_create_archive(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx,
- const char * arfilename,
- bool fpic)
-{
- int fdcwd;
- char ** aarg;
- char ** parg;
- char program[PATH_MAX];
- char output [PATH_MAX];
-
- /* -disable-static? */
- if (dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_STATIC)
- if (dctx->cctx->rpath)
- return slbt_exec_link_create_noop_symlink(
- dctx,ectx,arfilename);
-
- /* initial state */
- slbt_reset_arguments(ectx);
-
- /* placeholders */
- slbt_reset_placeholders(ectx);
-
- /* alternate program (ar, ranlib) */
- ectx->program = program;
-
- /* output */
- if ((size_t)snprintf(output,sizeof(output),"%s",
- arfilename) >= sizeof(output))
- return SLBT_BUFFER_ERROR(dctx);
-
- /* ar alternate argument vector */
- if ((size_t)snprintf(program,sizeof(program),"%s",
- dctx->cctx->host.ar) >= sizeof(program))
- return SLBT_BUFFER_ERROR(dctx);
-
-
- /* fdcwd */
- fdcwd = slbt_driver_fdcwd(dctx);
-
- /* input argument adjustment */
- aarg = ectx->altv;
- *aarg++ = program;
- *aarg++ = "crs";
- *aarg++ = output;
-
- for (parg=ectx->cargv; *parg; parg++)
- if (slbt_adjust_object_argument(*parg,fpic,!fpic,fdcwd))
- *aarg++ = *parg;
-
- *aarg = 0;
- ectx->argv = ectx->altv;
-
- /* step output */
- if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_link(dctx,ectx))
- return SLBT_NESTED_ERROR(dctx);
-
- /* remove old archive as needed */
- if (slbt_exec_link_remove_file(dctx,ectx,output))
- return SLBT_NESTED_ERROR(dctx);
-
- /* .deps */
- if (slbt_exec_link_create_dep_file(
- dctx,ectx,ectx->cargv,
- arfilename,true))
- return SLBT_NESTED_ERROR(dctx);
-
- /* ar spawn */
- if ((slbt_spawn(ectx,true) < 0) || ectx->exitcode)
- return SLBT_SPAWN_ERROR(dctx);
-
- /* input objects associated with .la archives */
- for (parg=ectx->cargv; *parg; parg++)
- if (slbt_adjust_wrapper_argument(*parg,true))
- if (slbt_archive_import(dctx,ectx,output,*parg))
- return SLBT_NESTED_ERROR(dctx);
-
- return 0;
-}
-
-static int slbt_exec_link_create_library(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx,
- const char * dsobasename,
- const char * dsofilename,
- const char * relfilename)
-{
- int fdcwd;
- char ** parg;
- char ** xarg;
- char * ccwrap;
- const char * laout;
- const char * dot;
- char cwd [PATH_MAX];
- char output [PATH_MAX];
- char soname [PATH_MAX];
- char symfile[PATH_MAX];
- struct slbt_deps_meta depsmeta = {0,0,0,0};
-
- /* initial state */
- slbt_reset_arguments(ectx);
-
- /* placeholders */
- slbt_reset_placeholders(ectx);
-
- /* fdcwd */
- fdcwd = slbt_driver_fdcwd(dctx);
-
- /* input argument adjustment */
- for (parg=ectx->cargv; *parg; parg++)
- slbt_adjust_object_argument(*parg,true,false,fdcwd);
-
- /* .deps */
- if (slbt_exec_link_create_dep_file(
- dctx,ectx,ectx->cargv,
- dsofilename,false))
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_NESTED_ERROR(dctx));
-
- /* linker argument adjustment */
- for (parg=ectx->cargv, xarg=ectx->xargv; *parg; parg++, xarg++)
- if (slbt_adjust_linker_argument(
- dctx,
- *parg,xarg,true,
- dctx->cctx->settings.dsosuffix,
- dctx->cctx->settings.arsuffix,
- &depsmeta) < 0)
- return SLBT_NESTED_ERROR(dctx);
-
- /* --no-undefined */
- if (dctx->cctx->drvflags & SLBT_DRIVER_NO_UNDEFINED)
- *ectx->noundef = "-Wl,--no-undefined";
-
- /* -soname */
- dot = strrchr(dctx->cctx->output,'.');
- laout = (dot && !strcmp(dot,".la"))
- ? dctx->cctx->output
- : 0;
-
- if ((dctx->cctx->drvflags & SLBT_DRIVER_IMAGE_MACHO)) {
- (void)0;
-
- } else if (!laout && (dctx->cctx->drvflags & SLBT_DRIVER_MODULE)) {
- if ((size_t)snprintf(soname,sizeof(soname),"-Wl,%s",
- dctx->cctx->output)
- >= sizeof(soname))
- return SLBT_BUFFER_ERROR(dctx);
-
- *ectx->soname = "-Wl,-soname";
- *ectx->lsoname = soname;
-
- } else if (relfilename && dctx->cctx->verinfo.verinfo) {
- if ((size_t)snprintf(soname,sizeof(soname),"-Wl,%s%s-%s%s.%d%s",
- ectx->sonameprefix,
- dctx->cctx->libname,
- dctx->cctx->release,
- dctx->cctx->settings.osdsuffix,
- dctx->cctx->verinfo.major,
- dctx->cctx->settings.osdfussix)
- >= sizeof(soname))
- return SLBT_BUFFER_ERROR(dctx);
-
- *ectx->soname = "-Wl,-soname";
- *ectx->lsoname = soname;
-
- } else if (relfilename) {
- if ((size_t)snprintf(soname,sizeof(soname),"-Wl,%s%s-%s%s",
- ectx->sonameprefix,
- dctx->cctx->libname,
- dctx->cctx->release,
- dctx->cctx->settings.dsosuffix)
- >= sizeof(soname))
- return SLBT_BUFFER_ERROR(dctx);
-
- *ectx->soname = "-Wl,-soname";
- *ectx->lsoname = soname;
-
- } else if (dctx->cctx->drvflags & SLBT_DRIVER_AVOID_VERSION) {
- if ((size_t)snprintf(soname,sizeof(soname),"-Wl,%s%s%s",
- ectx->sonameprefix,
- dctx->cctx->libname,
- dctx->cctx->settings.dsosuffix)
- >= sizeof(soname))
- return SLBT_BUFFER_ERROR(dctx);
-
- *ectx->soname = "-Wl,-soname";
- *ectx->lsoname = soname;
-
- } else {
- if ((size_t)snprintf(soname,sizeof(soname),"-Wl,%s%s%s.%d%s",
- ectx->sonameprefix,
- dctx->cctx->libname,
- dctx->cctx->settings.osdsuffix,
- dctx->cctx->verinfo.major,
- dctx->cctx->settings.osdfussix)
- >= sizeof(soname))
- return SLBT_BUFFER_ERROR(dctx);
-
- *ectx->soname = "-Wl,-soname";
- *ectx->lsoname = soname;
- }
-
- /* PE: --output-def */
- if (dctx->cctx->drvflags & SLBT_DRIVER_IMAGE_PE) {
- if ((size_t)snprintf(symfile,sizeof(symfile),"-Wl,%s",
- ectx->deffilename)
- >= sizeof(output))
- return SLBT_BUFFER_ERROR(dctx);
-
- *ectx->symdefs = "-Wl,--output-def";
- *ectx->symfile = symfile;
- }
-
- /* shared/static */
- if (dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC) {
- *ectx->dpic = "-static";
- } else if (dctx->cctx->settings.picswitch) {
- *ectx->dpic = "-shared";
- *ectx->fpic = dctx->cctx->settings.picswitch;
- } else {
- *ectx->dpic = "-shared";
- }
-
- /* output */
- if (!laout && dctx->cctx->drvflags & SLBT_DRIVER_MODULE) {
- strcpy(output,dctx->cctx->output);
- } else if (relfilename) {
- strcpy(output,relfilename);
- } else if (dctx->cctx->drvflags & SLBT_DRIVER_AVOID_VERSION) {
- strcpy(output,dsofilename);
- } else {
- if ((size_t)snprintf(output,sizeof(output),"%s%s.%d.%d.%d%s",
- dsobasename,
- dctx->cctx->settings.osdsuffix,
- dctx->cctx->verinfo.major,
- dctx->cctx->verinfo.minor,
- dctx->cctx->verinfo.revision,
- dctx->cctx->settings.osdfussix)
- >= sizeof(output))
- return SLBT_BUFFER_ERROR(dctx);
- }
-
- *ectx->lout[0] = "-o";
- *ectx->lout[1] = output;
-
- /* ldrpath */
- if (dctx->cctx->host.ldrpath) {
- if (slbt_exec_link_remove_file(dctx,ectx,ectx->rpathfilename))
- return SLBT_NESTED_ERROR(dctx);
-
- if (slbt_create_symlink(
- dctx,ectx,
- dctx->cctx->host.ldrpath,
- ectx->rpathfilename,
- SLBT_SYMLINK_LITERAL))
- return SLBT_NESTED_ERROR(dctx);
- }
-
- /* cwd */
- if (slbt_realpath(fdcwd,".",O_DIRECTORY,cwd,sizeof(cwd)))
- return SLBT_SYSTEM_ERROR(dctx,0);
-
- /* .libs/libfoo.so --> -L.libs -lfoo */
- if (slbt_exec_link_adjust_argument_vector(
- dctx,ectx,&depsmeta,cwd,true))
- return SLBT_NESTED_ERROR(dctx);
-
- /* using alternate argument vector */
- ccwrap = (char *)dctx->cctx->ccwrap;
- ectx->argv = depsmeta.altv;
- ectx->program = ccwrap ? ccwrap : depsmeta.altv[0];
-
- /* sigh */
- if (slbt_exec_link_finalize_argument_vector(dctx,ectx))
- return SLBT_NESTED_ERROR(dctx);
-
- /* step output */
- if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_link(dctx,ectx))
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_NESTED_ERROR(dctx));
-
- /* spawn */
- if ((slbt_spawn(ectx,true) < 0) || ectx->exitcode)
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_SPAWN_ERROR(dctx));
-
- return slbt_exec_link_exit(&depsmeta,0);
-}
-
-static int slbt_exec_link_create_executable(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx,
- const char * exefilename)
-{
- int fdcwd;
- int fdwrap;
- char ** parg;
- char ** xarg;
- char * base;
- char * ccwrap;
- char cwd [PATH_MAX];
- char dpfixup[PATH_MAX];
- char output [PATH_MAX];
- char wrapper[PATH_MAX];
- char wraplnk[PATH_MAX];
- bool fabspath;
- bool fpic;
- const struct slbt_source_version * verinfo;
- struct slbt_deps_meta depsmeta = {0,0,0,0};
- struct stat st;
-
- /* initial state */
- slbt_reset_arguments(ectx);
-
- /* placeholders */
- slbt_reset_placeholders(ectx);
-
- /* fdcwd */
- fdcwd = slbt_driver_fdcwd(dctx);
-
- /* fpic */
- fpic = !(dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC);
-
- /* input argument adjustment */
- for (parg=ectx->cargv; *parg; parg++)
- slbt_adjust_object_argument(*parg,fpic,true,fdcwd);
-
- /* linker argument adjustment */
- for (parg=ectx->cargv, xarg=ectx->xargv; *parg; parg++, xarg++)
- if (slbt_adjust_linker_argument(
- dctx,
- *parg,xarg,true,
- dctx->cctx->settings.dsosuffix,
- dctx->cctx->settings.arsuffix,
- &depsmeta) < 0)
- return SLBT_NESTED_ERROR(dctx);
-
- /* --no-undefined */
- if (dctx->cctx->drvflags & SLBT_DRIVER_NO_UNDEFINED)
- *ectx->noundef = "-Wl,--no-undefined";
-
- /* executable wrapper: create */
- if ((size_t)snprintf(wrapper,sizeof(wrapper),
- "%s.wrapper.tmp",
- dctx->cctx->output)
- >= sizeof(wrapper))
- return SLBT_BUFFER_ERROR(dctx);
-
- if ((fdwrap = openat(fdcwd,wrapper,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0)
- return SLBT_SYSTEM_ERROR(dctx,wrapper);
-
- slbt_exec_set_fdwrapper(ectx,fdwrap);
-
- /* executable wrapper: header */
- verinfo = slbt_source_version();
-
- /* cwd, DL_PATH fixup */
- if (slbt_realpath(fdcwd,".",O_DIRECTORY,cwd,sizeof(cwd)))
- return SLBT_SYSTEM_ERROR(dctx,0);
-
- slbt_emit_fdwrap_dl_path_fixup(
- cwd,dpfixup,sizeof(dpfixup),
- wrapper);
-
- if (slbt_dprintf(fdwrap,
- "#!/bin/sh\n"
- "# libtool compatible executable wrapper\n"
- "# Generated by %s (slibtool %d.%d.%d)\n"
- "# [commit reference: %s]\n\n"
-
- "if [ -z \"$%s\" ]; then\n"
- "\tDL_PATH=\n"
- "\tCOLON=\n"
- "\tLCOLON=\n"
- "else\n"
- "\tDL_PATH=\n"
- "\tCOLON=\n"
- "\tLCOLON=':'\n"
- "fi\n\n"
- "DL_PATH_FIXUP=\"%s\";\n\n",
-
- dctx->program,
- verinfo->major,verinfo->minor,verinfo->revision,
- verinfo->commit,
- dctx->cctx->settings.ldpathenv,
- dpfixup) < 0)
- return SLBT_SYSTEM_ERROR(dctx,0);
-
- /* output */
- if ((size_t)snprintf(output,sizeof(output),"%s",
- exefilename)
- >= sizeof(output))
- return SLBT_BUFFER_ERROR(dctx);
-
- *ectx->lout[0] = "-o";
- *ectx->lout[1] = output;
-
- /* static? */
- if (dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC)
- *ectx->dpic = "-static";
-
- /* .libs/libfoo.so --> -L.libs -lfoo */
- if (slbt_exec_link_adjust_argument_vector(
- dctx,ectx,&depsmeta,cwd,false))
- return SLBT_NESTED_ERROR(dctx);
-
- /* using alternate argument vector */
- ccwrap = (char *)dctx->cctx->ccwrap;
- ectx->argv = depsmeta.altv;
- ectx->program = ccwrap ? ccwrap : depsmeta.altv[0];
-
- /* executable wrapper symlink */
- if ((size_t)snprintf(wraplnk,sizeof(wraplnk),"%s.exe.wrapper",
- exefilename) >= sizeof(wraplnk))
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_BUFFER_ERROR(dctx));
-
- /* executable wrapper: base name */
- base = strrchr(wraplnk,'/');
- base++;
-
- /* executable wrapper: footer */
- fabspath = (exefilename[0] == '/');
-
- if (slbt_dprintf(fdwrap,
- "DL_PATH=\"${DL_PATH}${LCOLON}${%s}\"\n\n"
- "export %s=\"$DL_PATH\"\n\n"
- "if [ $(basename \"$0\") = \"%s\" ]; then\n"
- "\tprogram=\"$1\"; shift\n"
- "\texec \"$program\" \"$@\"\n"
- "fi\n\n"
- "exec %s/%s \"$@\"\n",
- dctx->cctx->settings.ldpathenv,
- dctx->cctx->settings.ldpathenv,
- base,
- fabspath ? "" : cwd,
- fabspath ? &exefilename[1] : exefilename) < 0)
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_SYSTEM_ERROR(dctx,0));
-
- /* sigh */
- if (slbt_exec_link_finalize_argument_vector(dctx,ectx))
- return SLBT_NESTED_ERROR(dctx);
-
- /* step output */
- if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_link(dctx,ectx))
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_NESTED_ERROR(dctx));
-
- /* spawn */
- if ((slbt_spawn(ectx,true) < 0) || ectx->exitcode)
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_SPAWN_ERROR(dctx));
-
- /* executable wrapper: finalize */
- slbt_exec_close_fdwrapper(ectx);
-
- if (slbt_create_symlink(
- dctx,ectx,
- dctx->cctx->output,wraplnk,
- SLBT_SYMLINK_WRAPPER))
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_NESTED_ERROR(dctx));
-
- if (fstatat(fdcwd,wrapper,&st,0))
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_SYSTEM_ERROR(dctx,wrapper));
-
- if (renameat(fdcwd,wrapper,fdcwd,dctx->cctx->output))
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_SYSTEM_ERROR(dctx,dctx->cctx->output));
-
- if (fchmodat(fdcwd,dctx->cctx->output,0755,0))
- return slbt_exec_link_exit(
- &depsmeta,
- SLBT_SYSTEM_ERROR(dctx,dctx->cctx->output));
-
- return slbt_exec_link_exit(&depsmeta,0);
-}
-
static int slbt_exec_link_create_library_symlink(
const struct slbt_driver_ctx * dctx,
struct slbt_exec_ctx * ectx,
@@ -1828,8 +119,8 @@ static int slbt_exec_link_create_library_symlink(
if (fmajor && (dctx->cctx->drvflags & SLBT_DRIVER_IMAGE_PE))
- return slbt_copy_file(
- dctx,ectx,
+ return slbt_util_copy_file(
+ ectx,
target,lnkname);
else
return slbt_create_symlink(
@@ -1838,20 +129,22 @@ static int slbt_exec_link_create_library_symlink(
SLBT_SYMLINK_DEFAULT);
}
-int slbt_exec_link(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx)
+int slbt_exec_link(const struct slbt_driver_ctx * dctx)
{
int ret;
const char * output;
char * dot;
- struct slbt_exec_ctx * actx;
+ char * slash;
+ struct slbt_exec_ctx * ectx;
+ char * arref;
+ char * dsoref;
bool fpic;
- bool fstaticonly;
+ bool fnodsolib;
+ bool fnoarchive;
+ bool fstaticobjs;
char soname[PATH_MAX];
char soxyz [PATH_MAX];
char solnk [PATH_MAX];
- char arname[PATH_MAX];
char target[PATH_MAX];
char lnkname[PATH_MAX];
@@ -1860,15 +153,16 @@ int slbt_exec_link(
return 0;
/* context */
- if (ectx)
- actx = 0;
- else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
+ if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
return SLBT_NESTED_ERROR(dctx);
- else
- actx = ectx;
+
+ /* .la wrapper */
+ arref = 0;
+ dsoref = 0;
/* libfoo.so.x.y.z */
- if ((size_t)snprintf(soxyz,sizeof(soxyz),"%s%s%s%s%s.%d.%d.%d%s",
+ if (slbt_snprintf(soxyz,sizeof(soxyz),
+ "%s%s%s%s%s.%d.%d.%d%s",
ectx->sonameprefix,
dctx->cctx->libname,
dctx->cctx->release ? "-" : "",
@@ -1877,9 +171,8 @@ int slbt_exec_link(
dctx->cctx->verinfo.major,
dctx->cctx->verinfo.minor,
dctx->cctx->verinfo.revision,
- dctx->cctx->settings.osdfussix)
- >= sizeof(soxyz)) {
- slbt_free_exec_ctx(actx);
+ dctx->cctx->settings.osdfussix) < 0) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_BUFFER_ERROR(dctx);
}
@@ -1899,12 +192,6 @@ int slbt_exec_link(
dctx->cctx->libname,
dctx->cctx->settings.dsosuffix);
- /* libfoo.a */
- sprintf(arname,"%s%s%s",
- dctx->cctx->settings.arprefix,
- dctx->cctx->libname,
- dctx->cctx->settings.arsuffix);
-
/* output suffix */
output = dctx->cctx->output;
dot = strrchr(output,'.');
@@ -1912,32 +199,49 @@ int slbt_exec_link(
/* .libs directory */
if (slbt_mkdir(dctx,ectx->ldirname)) {
ret = SLBT_SYSTEM_ERROR(dctx,ectx->ldirname);
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return ret;
}
/* non-pic libfoo.a */
if (dot && !strcmp(dot,".a"))
- if (slbt_exec_link_create_archive(dctx,ectx,output,false)) {
- slbt_free_exec_ctx(actx);
+ if (slbt_exec_link_create_archive(dctx,ectx,output,false,false)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
- /* fpic, fstaticonly */
+
+ /* fpic, fstaticobjs, fnodsolib, fnoarchive */
if (dctx->cctx->drvflags & SLBT_DRIVER_ALL_STATIC) {
- fstaticonly = true;
+ fstaticobjs = true;
+ fnodsolib = true;
+ fnoarchive = false;
fpic = false;
} else if (dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_SHARED) {
- fstaticonly = true;
+ fstaticobjs = true;
+ fnodsolib = true;
+ fnoarchive = false;
fpic = false;
- } else if (dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_STATIC) {
- fstaticonly = false;
- fpic = true;
} else if (dctx->cctx->drvflags & SLBT_DRIVER_SHARED) {
- fstaticonly = false;
+ fstaticobjs = false;
fpic = true;
+
+ if (dctx->cctx->libname && dctx->cctx->rpath) {
+ fnodsolib = false;
+ fnoarchive = (dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_STATIC);
+
+ } else if (dctx->cctx->libname) {
+ fnodsolib = true;
+ fnoarchive = false;
+
+ } else {
+ fnodsolib = true;
+ fnoarchive = true;
+ }
} else {
- fstaticonly = false;
+ fstaticobjs = false;
+ fnodsolib = true;
+ fnoarchive = false;
fpic = false;
}
@@ -1950,20 +254,26 @@ int slbt_exec_link(
}
/* pic libfoo.a */
- if (dot && !strcmp(dot,".la"))
+ if (dot && !strcmp(dot,".la") && !fnoarchive) {
if (slbt_exec_link_create_archive(
dctx,ectx,
ectx->arfilename,
- fpic)) {
- slbt_free_exec_ctx(actx);
+ fpic,true)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
+ arref = ectx->arfilename;
+
+ if ((slash = strrchr(arref,'/')))
+ arref = ++slash;
+ }
+
/* static-only libfoo.la */
- if (fstaticonly && dot && !strcmp(dot,".la")) {
+ if (fstaticobjs && dot && !strcmp(dot,".la")) {
const struct slbt_flavor_settings * dflavor;
- if (slbt_get_flavor_settings("default",&dflavor) < 0)
+ if (slbt_host_flavor_settings("default",&dflavor) < 0)
return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LINK_FLOW);
if (strcmp(dctx->cctx->settings.dsosuffix,dflavor->dsosuffix)) {
@@ -1992,43 +302,55 @@ int slbt_exec_link(
dctx,ectx,
"/dev/null",
ectx->deffilename,
- SLBT_SYMLINK_LITERAL|SLBT_SYMLINK_DEVNULL))
+ SLBT_SYMLINK_LITERAL))
return SLBT_NESTED_ERROR(dctx);
}
- /* -all-static library */
- if (fstaticonly && dctx->cctx->libname)
+ /* static archive or convenience library only? */
+ if (fnodsolib && ectx->dsofilename) {
if (slbt_create_symlink(
dctx,ectx,
"/dev/null",
ectx->dsofilename,
- SLBT_SYMLINK_LITERAL))
+ SLBT_SYMLINK_DEVNULL))
return SLBT_NESTED_ERROR(dctx);
+ }
+
+ /* disable static? */
+ if (fnoarchive && ectx->arfilename) {
+ if (slbt_create_symlink(
+ dctx,ectx,
+ "/dev/null",
+ ectx->arfilename,
+ SLBT_SYMLINK_DEVNULL))
+ return SLBT_NESTED_ERROR(dctx);
+ }
/* dynamic library via -module */
- if (dctx->cctx->rpath && !fstaticonly) {
+ if (dctx->cctx->rpath && !fstaticobjs) {
if (dctx->cctx->drvflags & SLBT_DRIVER_MODULE) {
if (!dot || strcmp(dot,".la")) {
if (slbt_exec_link_create_library(
dctx,ectx,
ectx->dsobasename,
ectx->dsofilename,
- ectx->relfilename)) {
- slbt_free_exec_ctx(actx);
+ ectx->relfilename,
+ false,true)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return 0;
}
}
}
/* dynamic library */
- if (dot && !strcmp(dot,".la") && dctx->cctx->rpath && !fstaticonly) {
+ if (dot && !strcmp(dot,".la") && dctx->cctx->rpath && !fstaticobjs) {
const struct slbt_flavor_settings * dflavor;
- if (slbt_get_flavor_settings("default",&dflavor) < 0)
+ if (slbt_host_flavor_settings("default",&dflavor) < 0)
return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LINK_FLOW);
/* -shrext support */
@@ -2079,8 +401,9 @@ int slbt_exec_link(
dctx,ectx,
ectx->dsobasename,
ectx->dsofilename,
- ectx->relfilename)) {
- slbt_free_exec_ctx(actx);
+ ectx->relfilename,
+ false,true)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
@@ -2089,7 +412,7 @@ int slbt_exec_link(
if (slbt_exec_link_create_library_symlink(
dctx,ectx,
true)) {
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
@@ -2097,7 +420,7 @@ int slbt_exec_link(
if (slbt_exec_link_create_library_symlink(
dctx,ectx,
false)) {
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
} else if (ectx->relfilename) {
@@ -2105,7 +428,7 @@ int slbt_exec_link(
if (slbt_exec_link_create_library_symlink(
dctx,ectx,
false)) {
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
}
@@ -2140,9 +463,11 @@ int slbt_exec_link(
dctx,ectx,
"/dev/null",
ectx->deffilename,
- SLBT_SYMLINK_LITERAL|SLBT_SYMLINK_DEVNULL))
+ SLBT_SYMLINK_LITERAL))
return SLBT_NESTED_ERROR(dctx);
}
+
+ dsoref = soname;
}
/* executable */
@@ -2151,22 +476,22 @@ int slbt_exec_link(
if (slbt_exec_link_create_executable(
dctx,ectx,
ectx->exefilename)) {
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
}
/* no wrapper? */
if (!dot || strcmp(dot,".la")) {
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return 0;
}
/* library wrapper */
if (slbt_create_library_wrapper(
dctx,ectx,
- arname,soname,soxyz,solnk)) {
- slbt_free_exec_ctx(actx);
+ arref,dsoref,soxyz,solnk)) {
+ slbt_ectx_free_exec_ctx(ectx);
return SLBT_NESTED_ERROR(dctx);
}
@@ -2179,7 +504,7 @@ int slbt_exec_link(
SLBT_NESTED_ERROR(dctx);
/* .lai wrapper symlink */
- if (ret == 0)
+ if ((ret == 0) && dctx->cctx->rpath)
if ((ret = slbt_create_symlink(
dctx,ectx,
output,
@@ -2188,7 +513,7 @@ int slbt_exec_link(
SLBT_NESTED_ERROR(dctx);
/* all done */
- slbt_free_exec_ctx(actx);
+ slbt_ectx_free_exec_ctx(ectx);
return ret;
}
diff --git a/src/logic/slbt_exec_stoolie.c b/src/logic/slbt_exec_stoolie.c
new file mode 100644
index 0000000..698faaa
--- /dev/null
+++ b/src/logic/slbt_exec_stoolie.c
@@ -0,0 +1,371 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <sys/stat.h>
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_output.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_stoolie_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_realpath_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_symlink_impl.h"
+#include "argv/argv.h"
+
+static const char slbt_this_dir[2] = {'.',0};
+
+static int slbt_stoolie_usage(
+ int fdout,
+ const char * program,
+ const char * arg,
+ const struct argv_option ** optv,
+ struct argv_meta * meta,
+ struct slbt_exec_ctx * ectx,
+ int noclr)
+{
+ char header[512];
+ bool stooliemode;
+
+ stooliemode = !strcmp(program,"slibtoolize");
+
+ snprintf(header,sizeof(header),
+ "Usage: %s%s [options] ...\n"
+ "Options:\n",
+ program,
+ stooliemode ? "" : " --mode=slibtoolize");
+
+ switch (noclr) {
+ case 0:
+ slbt_argv_usage(fdout,header,optv,arg);
+ break;
+
+ default:
+ slbt_argv_usage_plain(fdout,header,optv,arg);
+ break;
+ }
+
+ if (ectx)
+ slbt_ectx_free_exec_ctx(ectx);
+
+ slbt_argv_free(meta);
+
+ return SLBT_USAGE;
+}
+
+static int slbt_exec_stoolie_fail(
+ struct slbt_exec_ctx * ectx,
+ struct argv_meta * meta,
+ int ret)
+{
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
+ return ret;
+}
+
+static int slbt_exec_stoolie_remove_file(
+ const struct slbt_driver_ctx * dctx,
+ int fddst,
+ const char * target)
+{
+ /* remove target (if any) */
+ if (!unlinkat(fddst,target,0) || (errno == ENOENT))
+ return 0;
+
+ return SLBT_SYSTEM_ERROR(dctx,0);
+}
+
+static int slbt_exec_stoolie_perform_actions(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ struct slbt_stoolie_ctx * stctx)
+{
+ struct slbt_stoolie_ctx_impl * ictx;
+ struct stat st;
+ char m4dir [PATH_MAX];
+ char auxdir[PATH_MAX];
+ char slibm4[PATH_MAX];
+ char ltmain[PATH_MAX];
+ bool fslibm4;
+ bool fltmain;
+
+ ictx = slbt_get_stoolie_ictx(stctx);
+
+ /* source files */
+ if (slbt_snprintf(
+ slibm4,sizeof(slibm4),"%s/%s",
+ SLBT_PACKAGE_DATADIR,
+ "slibtool.m4") < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ if (slbt_snprintf(
+ ltmain,sizeof(slibm4),"%s/%s",
+ SLBT_PACKAGE_DATADIR,
+ "ltmain.sh") < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* --force? */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_STOOLIE_FORCE) {
+ if (ictx->fdm4 >= 0)
+ if (slbt_exec_stoolie_remove_file(dctx,ictx->fdm4,"slibtool.m4") < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (slbt_exec_stoolie_remove_file(dctx,ictx->fdaux,"ltmain.sh") < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ fslibm4 = (ictx->fdm4 >= 0);
+ fltmain = true;
+ } else {
+ if (ictx->fdm4 < 0) {
+ fslibm4 = false;
+
+ } else if (fstatat(ictx->fdm4,"slibtool.m4",&st,AT_SYMLINK_NOFOLLOW) == 0) {
+ fslibm4 = false;
+
+ } else if (errno == ENOENT) {
+ fslibm4 = true;
+
+ } else {
+ return SLBT_SYSTEM_ERROR(dctx,"slibtool.m4");
+ }
+
+ if (fstatat(ictx->fdaux,"ltmain.sh",&st,AT_SYMLINK_NOFOLLOW) == 0) {
+ fltmain = false;
+
+ } else if (errno == ENOENT) {
+ fltmain = true;
+
+ } else {
+ return SLBT_SYSTEM_ERROR(dctx,"ltmain.sh");
+ }
+ }
+
+ /* --copy? */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_STOOLIE_COPY) {
+ if (fslibm4) {
+ if (slbt_realpath(ictx->fdm4,".",0,m4dir,sizeof(m4dir)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (slbt_util_copy_file(ectx,slibm4,m4dir) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ if (fltmain) {
+ if (slbt_realpath(ictx->fdaux,".",0,auxdir,sizeof(auxdir)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (slbt_util_copy_file(ectx,ltmain,auxdir) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+ } else {
+ /* default to symlinks */
+ if (fslibm4)
+ if (slbt_create_symlink_ex(
+ dctx,ectx,
+ ictx->fdm4,
+ slibm4,
+ "slibtool.m4",
+ SLBT_SYMLINK_LITERAL) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (fltmain)
+ if (slbt_create_symlink_ex(
+ dctx,ectx,
+ ictx->fdaux,
+ ltmain,
+ "ltmain.sh",
+ SLBT_SYMLINK_LITERAL) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ return 0;
+}
+
+int slbt_exec_stoolie(const struct slbt_driver_ctx * dctx)
+{
+ int ret;
+ int fdout;
+ int fderr;
+ char ** argv;
+ char ** iargv;
+ struct slbt_exec_ctx * ectx;
+ struct slbt_driver_ctx_impl * ictx;
+ const struct slbt_common_ctx * cctx;
+ struct argv_meta * meta;
+ struct argv_entry * entry;
+ size_t nunits;
+ size_t cunits;
+ const char ** unitv;
+ const char ** unitp;
+ struct slbt_stoolie_ctx ** stctxv;
+ struct slbt_stoolie_ctx ** stctxp;
+ const struct argv_option * optv[SLBT_OPTV_ELEMENTS];
+
+ /* context */
+ if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* initial state, slibtoolize (stoolie) mode skin */
+ slbt_ectx_reset_arguments(ectx);
+ slbt_disable_placeholders(ectx);
+
+ ictx = slbt_get_driver_ictx(dctx);
+ cctx = dctx->cctx;
+ iargv = ectx->cargv;
+
+ fdout = slbt_driver_fdout(dctx);
+ fderr = slbt_driver_fderr(dctx);
+
+ (void)fderr;
+
+ /* <stoolie> argv meta */
+ slbt_optv_init(slbt_stoolie_options,optv);
+
+ if (!(meta = slbt_argv_get(
+ iargv,optv,
+ dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
+ ? ARGV_VERBOSITY_ERRORS
+ : ARGV_VERBOSITY_NONE,
+ fdout)))
+ return slbt_exec_stoolie_fail(
+ ectx,meta,
+ SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_AR_FAIL));
+
+ /* dest, alternate argument vector options */
+ argv = ectx->altv;
+ *argv++ = iargv[0];
+ nunits = 0;
+
+ for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
+ if (entry->fopt) {
+ switch (entry->tag) {
+ case TAG_STLE_HELP:
+ slbt_stoolie_usage(
+ fdout,
+ dctx->program,
+ 0,optv,0,ectx,
+ dctx->cctx->drvflags
+ & SLBT_DRIVER_ANNOTATE_NEVER);
+
+ ictx->cctx.drvflags |= SLBT_DRIVER_VERSION;
+ ictx->cctx.drvflags ^= SLBT_DRIVER_VERSION;
+
+ slbt_argv_free(meta);
+
+ return SLBT_OK;
+
+ case TAG_STLE_VERSION:
+ ictx->cctx.drvflags |= SLBT_DRIVER_VERSION;
+ break;
+
+ case TAG_STLE_COPY:
+ ictx->cctx.drvflags |= SLBT_DRIVER_STOOLIE_COPY;
+ break;
+
+ case TAG_STLE_FORCE:
+ ictx->cctx.drvflags |= SLBT_DRIVER_STOOLIE_FORCE;
+ break;
+
+ case TAG_STLE_INSTALL:
+ ictx->cctx.drvflags |= SLBT_DRIVER_STOOLIE_INSTALL;
+ break;
+
+ case TAG_STLE_DEBUG:
+ ictx->cctx.drvflags |= SLBT_DRIVER_DEBUG;
+ break;
+
+ case TAG_STLE_DRY_RUN:
+ ictx->cctx.drvflags |= SLBT_DRIVER_DRY_RUN;
+ break;
+
+ case TAG_STLE_SILENT:
+ ictx->cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_VERBOSE;
+ ictx->cctx.drvflags |= SLBT_DRIVER_SILENT;
+ break;
+
+ case TAG_STLE_VERBOSE:
+ ictx->cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_SILENT;
+ ictx->cctx.drvflags |= SLBT_DRIVER_VERBOSE;
+ break;
+ }
+
+ if (entry->fval) {
+ *argv++ = (char *)entry->arg;
+ }
+ } else {
+ nunits++;
+ };
+ }
+
+ /* defer --version printing to slbt_main() as needed */
+ if (cctx->drvflags & SLBT_DRIVER_VERSION) {
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
+ return SLBT_OK;
+ }
+
+ /* default to this-dir as needed */
+ if (!(cunits = nunits))
+ nunits++;
+
+ /* slibtoolize target directory vector allocation */
+ if (!(stctxv = calloc(nunits+1,sizeof(struct slbt_stoolie_ctx *))))
+ return slbt_exec_stoolie_fail(
+ ectx,meta,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ /* unit vector allocation */
+ if (!(unitv = calloc(nunits+1,sizeof(const char *)))) {
+ free (stctxv);
+
+ return slbt_exec_stoolie_fail(
+ ectx,meta,
+ SLBT_SYSTEM_ERROR(dctx,0));
+ }
+
+ /* unit vector initialization */
+ for (entry=meta->entries,unitp=unitv; entry->fopt || entry->arg; entry++)
+ if (!entry->fopt)
+ *unitp++ = entry->arg;
+
+ if (!cunits)
+ unitp[0] = slbt_this_dir;
+
+ /* slibtoolize target directory vector initialization */
+ for (unitp=unitv,stctxp=stctxv; *unitp; unitp++,stctxp++) {
+ if (slbt_st_get_stoolie_ctx(dctx,*unitp,stctxp) < 0) {
+ for (stctxp=stctxv; *stctxp; stctxp++)
+ slbt_st_free_stoolie_ctx(*stctxp);
+
+ free(unitv);
+ free(stctxv);
+
+ return slbt_exec_stoolie_fail(
+ ectx,meta,
+ SLBT_NESTED_ERROR(dctx));
+ }
+ }
+
+ /* slibtoolize operations */
+ for (ret=0,stctxp=stctxv; !ret && *stctxp; stctxp++)
+ ret = slbt_exec_stoolie_perform_actions(dctx,ectx,*stctxp);
+
+ /* all done */
+ for (stctxp=stctxv; *stctxp; stctxp++)
+ slbt_st_free_stoolie_ctx(*stctxp);
+
+ free(unitv);
+ free(stctxv);
+
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
+
+ return ret;
+}
+
+int slbt_exec_slibtoolize(const struct slbt_driver_ctx * dctx)
+{
+ return slbt_exec_stoolie(dctx);
+}
diff --git a/src/logic/slbt_exec_uninstall.c b/src/logic/slbt_exec_uninstall.c
index 0650232..98bd85b 100644
--- a/src/logic/slbt_exec_uninstall.c
+++ b/src/logic/slbt_exec_uninstall.c
@@ -1,6 +1,6 @@
/*******************************************************************/
-/* slibtool: a skinny libtool implementation, written in C */
-/* Copyright (C) 2016--2021 Z. Gilboa */
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/
@@ -11,12 +11,11 @@
#include <errno.h>
#include <sys/stat.h>
-#define ARGV_DRIVER
-
#include <slibtool/slibtool.h>
#include "slibtool_driver_impl.h"
#include "slibtool_uninstall_impl.h"
#include "slibtool_readlink_impl.h"
+#include "slibtool_snprintf_impl.h"
#include "slibtool_errinfo_impl.h"
#include "argv/argv.h"
@@ -37,26 +36,26 @@ static int slbt_uninstall_usage(
switch (noclr) {
case 0:
- argv_usage(fdout,header,optv,arg);
+ slbt_argv_usage(fdout,header,optv,arg);
break;
default:
- argv_usage_plain(fdout,header,optv,arg);
+ slbt_argv_usage_plain(fdout,header,optv,arg);
break;
}
- argv_free(meta);
+ slbt_argv_free(meta);
return SLBT_USAGE;
}
static int slbt_exec_uninstall_fail(
- struct slbt_exec_ctx * actx,
+ struct slbt_exec_ctx * ectx,
struct argv_meta * meta,
int ret)
{
- argv_free(meta);
- slbt_free_exec_ctx(actx);
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
return ret;
}
@@ -85,7 +84,7 @@ static int slbt_exec_uninstall_fs_entry(
*parg = path;
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
- if (slbt_output_uninstall(dctx,ectx))
+ if (slbt_output_uninstall(ectx))
return SLBT_NESTED_ERROR(dctx);
/* directory? */
@@ -172,8 +171,9 @@ static int slbt_exec_uninstall_entry(
char path [PATH_MAX];
char lpath[PATH_MAX];
- if ((size_t)snprintf(path,PATH_MAX,"%s",
- entry->arg) >= PATH_MAX-8)
+ if (slbt_snprintf(path,
+ PATH_MAX - 8,
+ "%s",entry->arg) < 0)
return SLBT_BUFFER_ERROR(dctx);
*parg = (char *)entry->arg;
@@ -264,16 +264,13 @@ static int slbt_exec_uninstall_entry(
return 0;
}
-int slbt_exec_uninstall(
- const struct slbt_driver_ctx * dctx,
- struct slbt_exec_ctx * ectx)
+int slbt_exec_uninstall(const struct slbt_driver_ctx * dctx)
{
- int ret;
int fdout;
char ** argv;
char ** iargv;
uint32_t flags;
- struct slbt_exec_ctx * actx;
+ struct slbt_exec_ctx * ectx;
struct argv_meta * meta;
struct argv_entry * entry;
const struct argv_option * optv[SLBT_OPTV_ELEMENTS];
@@ -283,21 +280,17 @@ int slbt_exec_uninstall(
return 0;
/* context */
- if (ectx)
- actx = 0;
- else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
- return ret;
- else
- actx = ectx;
+ if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
/* initial state, uninstall mode skin */
- slbt_reset_arguments(ectx);
+ slbt_ectx_reset_arguments(ectx);
slbt_disable_placeholders(ectx);
iargv = ectx->cargv;
fdout = slbt_driver_fdout(dctx);
/* missing arguments? */
- argv_optv_init(slbt_uninstall_options,optv);
+ slbt_optv_init(slbt_uninstall_options,optv);
if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
return slbt_uninstall_usage(
@@ -307,14 +300,14 @@ int slbt_exec_uninstall(
dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
/* <uninstall> argv meta */
- if (!(meta = argv_get(
+ if (!(meta = slbt_argv_get(
iargv,optv,
dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
? ARGV_VERBOSITY_ERRORS
: ARGV_VERBOSITY_NONE,
fdout)))
return slbt_exec_uninstall_fail(
- actx,meta,
+ ectx,meta,
SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_UNINSTALL_FAIL));
/* dest, alternate argument vector options */
@@ -374,11 +367,11 @@ int slbt_exec_uninstall(
if (!entry->fopt)
if (slbt_exec_uninstall_entry(dctx,ectx,entry,argv,flags))
return slbt_exec_uninstall_fail(
- actx,meta,
+ ectx,meta,
SLBT_NESTED_ERROR(dctx));
- argv_free(meta);
- slbt_free_exec_ctx(actx);
+ slbt_argv_free(meta);
+ slbt_ectx_free_exec_ctx(ectx);
return 0;
}