From 11c887f27092c96b1d2529929685c85716708ba5 Mon Sep 17 00:00:00 2001 From: midipix Date: Feb 10 2024 04:33:08 +0000 Subject: link mode: move the executable creation logic to its own translation unit. --- diff --git a/project/common.mk b/project/common.mk index 93bffbb..ead6410 100644 --- a/project/common.mk +++ b/project/common.mk @@ -32,6 +32,7 @@ API_SRCS = \ src/logic/linkcmd/slbt_linkcmd_argv.c \ src/logic/linkcmd/slbt_linkcmd_deps.c \ src/logic/linkcmd/slbt_linkcmd_dsolib.c \ + src/logic/linkcmd/slbt_linkcmd_executable.c \ src/logic/linkcmd/slbt_linkcmd_host.c \ src/logic/linkcmd/slbt_linkcmd_implib.c \ src/output/slbt_output_config.c \ diff --git a/src/internal/slibtool_linkcmd_impl.h b/src/internal/slibtool_linkcmd_impl.h index 4ee6a1a..85d1e13 100644 --- a/src/internal/slibtool_linkcmd_impl.h +++ b/src/internal/slibtool_linkcmd_impl.h @@ -76,4 +76,9 @@ int slbt_exec_link_create_library( const char * dsofilename, const char * relfilename); +int slbt_exec_link_create_executable( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + const char * exefilename); + #endif diff --git a/src/logic/linkcmd/slbt_linkcmd_executable.c b/src/logic/linkcmd/slbt_linkcmd_executable.c new file mode 100644 index 0000000..a602c8e --- /dev/null +++ b/src/logic/linkcmd/slbt_linkcmd_executable.c @@ -0,0 +1,273 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#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" + +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); +} + +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 (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_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(dctx,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/slbt_exec_link.c b/src/logic/slbt_exec_link.c index 2fa1050..b2ddce1 100644 --- a/src/logic/slbt_exec_link.c +++ b/src/logic/slbt_exec_link.c @@ -64,257 +64,6 @@ /* */ /*******************************************************************/ -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 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_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 (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_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_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->pid < 0)) { - return slbt_exec_link_exit( - &depsmeta, - SLBT_SPAWN_ERROR(dctx)); - - } else if (ectx->exitcode) { - return slbt_exec_link_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_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,