diff options
Diffstat (limited to 'src/logic')
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_archive.c | 188 | ||||
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_argv.c | 1127 | ||||
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_deps.c | 788 | ||||
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_dsolib.c | 373 | ||||
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_executable.c | 278 | ||||
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_host.c | 70 | ||||
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_implib.c | 157 | ||||
-rw-r--r-- | src/logic/slbt_exec_ar.c | 431 | ||||
-rw-r--r-- | src/logic/slbt_exec_compile.c | 108 | ||||
-rw-r--r-- | src/logic/slbt_exec_ctx.c | 405 | ||||
-rw-r--r-- | src/logic/slbt_exec_execute.c | 223 | ||||
-rw-r--r-- | src/logic/slbt_exec_install.c | 231 | ||||
-rw-r--r-- | src/logic/slbt_exec_link.c | 1879 | ||||
-rw-r--r-- | src/logic/slbt_exec_stoolie.c | 371 | ||||
-rw-r--r-- | src/logic/slbt_exec_uninstall.c | 55 |
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; } |