diff --git a/src/logic/linkcmd/slbt_linkcmd_executable.c b/src/logic/linkcmd/slbt_linkcmd_executable.c index 76c0b1d..e192b72 100644 --- a/src/logic/linkcmd/slbt_linkcmd_executable.c +++ b/src/logic/linkcmd/slbt_linkcmd_executable.c @@ -210,9 +210,9 @@ slbt_hidden int slbt_exec_link_create_executable( "export %s=\"$DL_PATH\"\n\n" "if [ $(basename \"$0\") = \"%s\" ]; then\n" "\tprogram=\"$1\"; shift\n" - "\texec \"$program\" \"$@\"\n" + "\texec -- \"$program\" \"$@\"\n" "fi\n\n" - "exec %s/%s \"$@\"\n", + "exec -- %s/%s \"$@\"\n", dctx->cctx->settings.ldpathenv, dctx->cctx->settings.ldpathenv, base, diff --git a/src/logic/slbt_exec_ctx.c b/src/logic/slbt_exec_ctx.c index cfcfc2a..0564218 100644 --- a/src/logic/slbt_exec_ctx.c +++ b/src/logic/slbt_exec_ctx.c @@ -89,11 +89,11 @@ static struct slbt_exec_ctx_impl * slbt_exec_ctx_alloc( /* internal driver context for host-specific tool arguments */ ctx = slbt_get_driver_ictx(dctx); - /* initial buffer size (cargv, -Wc), .libs/extras */ + /* initial buffer size (cargv, -Wc), .libs/.exe.wrapper */ argc = 0; csrc = 0; size = 0; - exts = 16; + exts = 20; for (parg=dctx->cctx->cargv; *parg; parg++, argc++) { if (!(strncmp("-Wc,",*parg,4))) { diff --git a/src/logic/slbt_exec_execute.c b/src/logic/slbt_exec_execute.c index 1bba779..68b3022 100644 --- a/src/logic/slbt_exec_execute.c +++ b/src/logic/slbt_exec_execute.c @@ -16,16 +16,113 @@ #include "slibtool_snprintf_impl.h" #include "slibtool_errinfo_impl.h" + +/*******************************************************************/ +/* --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 fdcwd; + int ret; + 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; + char exeprog[PATH_MAX]; + char argbuf [PATH_MAX]; struct slbt_exec_ctx * ectx; /* dry run */ @@ -38,57 +135,62 @@ int slbt_exec_execute(const struct slbt_driver_ctx * dctx) slbt_disable_placeholders(ectx); - /* 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 (slbt_snprintf(wrapper,sizeof(wrapper), - "%s.exe.wrapper", - exeref) < 0) { - slbt_ectx_free_exec_ctx(ectx); - return SLBT_BUFFER_ERROR(dctx); - } + /* original and alternate argument vectors */ + parg = ectx->cargv; + aarg = ectx->altv; - /* fdcwd */ - fdcwd = slbt_driver_fdcwd(dctx); + /* program (first non-slibtool argument) */ + if (!(program = ectx->cargv[0])) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); - /* 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; + /* 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); + + } else if (ret == 1) { + sprintf(wrapper,"%s.exe.wrapper",exeprog); + exeref = *parg; + *aarg++ = wrapper; } else { - script = program; + strcpy(*parg,argbuf); } + } - /* execute mode */ - ectx->program = script; - ectx->argv = ectx->cargv; - } else { - ectx->program = program; - ectx->argv = ectx->cargv; + /* 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); + + } 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 (!(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_ectx_free_exec_ctx(ectx); return SLBT_SYSTEM_ERROR(dctx,0);