diff options
Diffstat (limited to 'src/host/slbt_host_params.c')
-rw-r--r-- | src/host/slbt_host_params.c | 707 |
1 files changed, 707 insertions, 0 deletions
diff --git a/src/host/slbt_host_params.c b/src/host/slbt_host_params.c new file mode 100644 index 0000000..0a8bc11 --- /dev/null +++ b/src/host/slbt_host_params.c @@ -0,0 +1,707 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <fcntl.h> +#include <spawn.h> +#include <sys/wait.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" +#include "slibtool_ar_impl.h" + + +/* annotation strings */ +static const char cfgexplicit[] = "command-line argument"; +static const char cfghost[] = "derived from <host>"; +static const char cfgtarget[] = "derived from <target>"; +static const char cfgcompiler[] = "derived from <compiler>"; +static const char cfgnmachine[] = "native (cached in ccenv/host.mk)"; +static const char cfgxmachine[] = "foreign (derived from -dumpmachine)"; +static const char cfgnative[] = "native"; + +/* elf rpath */ +static const char*ldrpath_elf[] = { + "/lib", + "/lib/64", + "/usr/lib", + "/usr/lib64", + "/usr/local/lib", + "/usr/local/lib64", + 0}; + +/* flavor settings */ +#define SLBT_FLAVOR_SETTINGS(flavor, \ + bfmt,pic, \ + arp,ars,dsop,dsos,osds,osdf, \ + exep,exes,impp,imps, \ + ldenv) \ + static const struct slbt_flavor_settings flavor = { \ + bfmt,arp,ars,dsop,dsos,osds,osdf, \ + exep,exes,impp,imps, \ + ldenv,pic} + +SLBT_FLAVOR_SETTINGS(host_flavor_default, \ + "elf","-fPIC", \ + "lib",".a","lib",".so",".so","", \ + "","","","", \ + "LD_LIBRARY_PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_midipix, \ + "pe","-fPIC", \ + "lib",".a","lib",".so",".so","", \ + "","","lib",".lib.a", \ + "LD_LIBRARY_PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_mingw, \ + "pe",0, \ + "lib",".a","lib",".dll","",".dll", \ + "",".exe","lib",".dll.a", \ + "PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_cygwin, \ + "pe",0, \ + "lib",".a","lib",".dll","",".dll", \ + "",".exe","lib",".dll.a", \ + "PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_darwin, \ + "macho","-fPIC", \ + "lib",".a","lib",".dylib","",".dylib", \ + "","","","", \ + "DYLD_LIBRARY_PATH"); + + +static void slbt_get_host_quad( + char * hostbuf, + char ** hostquad) +{ + char * mark; + char * ch; + int i; + + for (i=0, ch=hostbuf, mark=hostbuf; *ch && i<4; ch++) { + if (*ch == '-') { + *ch = 0; + hostquad[i++] = mark; + mark = &ch[1]; + } + } + + if (i<4) + hostquad[i] = mark; + + if (i==3) { + hostquad[1] = hostquad[2]; + hostquad[2] = hostquad[3]; + hostquad[3] = 0; + } +} + + +static void slbt_spawn_ar(char ** argv, int * ecode) +{ + int estatus; + pid_t pid; + + *ecode = 127; + + if ((pid = fork()) < 0) { + return; + + } else if (pid == 0) { + execvp(argv[0],argv); + _exit(errno); + + } else { + waitpid(pid,&estatus,0); + + if (WIFEXITED(estatus)) + *ecode = WEXITSTATUS(estatus); + } +} + + +slbt_hidden int slbt_init_host_params( + const struct slbt_driver_ctx * dctx, + const struct slbt_common_ctx * cctx, + struct slbt_host_strs * drvhost, + struct slbt_host_params * host, + struct slbt_host_params * cfgmeta, + const char * cfgmeta_host, + const char * cfgmeta_ar, + const char * cfgmeta_as, + const char * cfgmeta_ranlib, + const char * cfgmeta_dlltool) +{ + int fdcwd; + int arprobe; + int arfd; + int ecode; + size_t toollen; + char * dash; + char * base; + char * mark; + const char * machine; + bool ftarget = false; + bool fhost = false; + bool fcompiler = false; + bool fnative = false; + bool fdumpmachine = false; + char buf [256]; + char hostbuf [256]; + char machinebuf [256]; + char * hostquad [4]; + char * machinequad[4]; + char * arprobeargv[4]; + char archivename[] = "/tmp/slibtool.ar.probe.XXXXXXXXXXXXXXXX"; + + /* base */ + if ((base = strrchr(cctx->cargv[0],'/'))) + base++; + else + base = cctx->cargv[0]; + + fdumpmachine = (cctx->mode == SLBT_MODE_COMPILE) + || (cctx->mode == SLBT_MODE_LINK) + || (cctx->mode == SLBT_MODE_INFO); + + fdumpmachine &= (!strcmp(base,"xgcc") + || !strcmp(base,"xg++")); + + /* support the portbld <--> unknown synonym */ + if (!(drvhost->machine = strdup(SLBT_MACHINE))) + return -1; + + if ((mark = strstr(drvhost->machine,"-portbld-"))) + memcpy(mark,"-unknown",8); + + /* host */ + if (host->host) { + cfgmeta->host = cfgmeta_host ? cfgmeta_host : cfgexplicit; + fhost = true; + + } else if (cctx->target) { + host->host = cctx->target; + cfgmeta->host = cfgtarget; + ftarget = true; + + } else if (strrchr(base,'-')) { + if (!(drvhost->host = strdup(cctx->cargv[0]))) + return -1; + + dash = strrchr(drvhost->host,'-'); + *dash = 0; + host->host = drvhost->host; + cfgmeta->host = cfgcompiler; + fcompiler = true; + + } else if (!fdumpmachine) { + host->host = drvhost->machine; + cfgmeta->host = cfgnmachine; + + } else if (slbt_util_dump_machine(cctx->cargv[0],buf,sizeof(buf)) < 0) { + if (dctx) + slbt_dprintf( + slbt_driver_fderr(dctx), + "%s: could not determine host " + "via -dumpmachine\n", + dctx->program); + return -1; + + } else { + if (!(drvhost->host = strdup(buf))) + return -1; + + host->host = drvhost->host; + fcompiler = true; + fnative = !strcmp(host->host,drvhost->machine); + cfgmeta->host = fnative ? cfgnmachine : cfgxmachine; + + if (!fnative) { + strcpy(hostbuf,host->host); + strcpy(machinebuf,drvhost->machine); + + slbt_get_host_quad(hostbuf,hostquad); + slbt_get_host_quad(machinebuf,machinequad); + + if (hostquad[2] && machinequad[2]) + fnative = !strcmp(hostquad[0],machinequad[0]) + && !strcmp(hostquad[1],machinequad[1]) + && !strcmp(hostquad[2],machinequad[2]); + } + } + + /* flavor */ + if (host->flavor) { + cfgmeta->flavor = cfgexplicit; + } else { + if (fhost) { + machine = host->host; + cfgmeta->flavor = cfghost; + } else if (ftarget) { + machine = cctx->target; + cfgmeta->flavor = cfgtarget; + } else if (fcompiler) { + machine = drvhost->host; + cfgmeta->flavor = cfgcompiler; + } else { + machine = drvhost->machine; + cfgmeta->flavor = cfgnmachine; + } + + dash = strrchr(machine,'-'); + cfgmeta->flavor = cfghost; + + if ((dash && !strcmp(dash,"-bsd")) || strstr(machine,"-bsd-")) + host->flavor = "bsd"; + else if ((dash && !strcmp(dash,"-cygwin")) || strstr(machine,"-cygwin-")) + host->flavor = "cygwin"; + else if ((dash && !strcmp(dash,"-darwin")) || strstr(machine,"-darwin")) + host->flavor = "darwin"; + else if ((dash && !strcmp(dash,"-linux")) || strstr(machine,"-linux-")) + host->flavor = "linux"; + else if ((dash && !strcmp(dash,"-midipix")) || strstr(machine,"-midipix-")) + host->flavor = "midipix"; + else if ((dash && !strcmp(dash,"-mingw")) || strstr(machine,"-mingw-")) + host->flavor = "mingw"; + else if ((dash && !strcmp(dash,"-mingw32")) || strstr(machine,"-mingw32-")) + host->flavor = "mingw"; + else if ((dash && !strcmp(dash,"-mingw64")) || strstr(machine,"-mingw64-")) + host->flavor = "mingw"; + else if ((dash && !strcmp(dash,"-windows")) || strstr(machine,"-windows-")) + host->flavor = "mingw"; + else { + host->flavor = "default"; + cfgmeta->flavor = "fallback, unverified"; + } + + if (fcompiler && !fnative) + if ((mark = strstr(drvhost->machine,host->flavor))) + if (mark > drvhost->machine) + fnative = (*--mark == '-'); + } + + /* toollen */ + toollen = fnative ? 0 : strlen(host->host); + toollen += strlen("-utility-name"); + + /* ar */ + if (host->ar) + cfgmeta->ar = cfgmeta_ar ? cfgmeta_ar : cfgexplicit; + else { + if (!(drvhost->ar = calloc(1,toollen))) + return -1; + + if (fnative) { + strcpy(drvhost->ar,"ar"); + cfgmeta->ar = cfgnative; + arprobe = 0; + } else if (cctx->mode == SLBT_MODE_LINK) { + arprobe = true; + } else if (cctx->mode == SLBT_MODE_INFO) { + arprobe = true; + } else { + arprobe = false; + } + + /* arprobe */ + if (arprobe) { + sprintf(drvhost->ar,"%s-ar",host->host); + cfgmeta->ar = cfghost; + ecode = 127; + + /* empty archive */ + if ((arfd = mkstemp(archivename)) >= 0) { + slbt_dprintf(arfd,"!<arch>\n"); + + arprobeargv[0] = drvhost->ar; + arprobeargv[1] = "-t"; + arprobeargv[2] = archivename; + arprobeargv[3] = 0; + + /* <target>-ar */ + slbt_spawn_ar( + arprobeargv, + &ecode); + } + + /* <target>-<compiler>-ar */ + if (ecode && !strchr(base,'-')) { + sprintf(drvhost->ar,"%s-%s-ar",host->host,base); + + slbt_spawn_ar( + arprobeargv, + &ecode); + } + + /* <compiler>-ar */ + if (ecode && !strchr(base,'-')) { + sprintf(drvhost->ar,"%s-ar",base); + + slbt_spawn_ar( + arprobeargv, + &ecode); + } + + /* if target is the native target, fallback to native ar */ + if (ecode && !strcmp(host->host,SLBT_MACHINE)) { + strcpy(drvhost->ar,"ar"); + cfgmeta->ar = cfgnative; + } + + /* fdcwd */ + fdcwd = slbt_driver_fdcwd(dctx); + + /* clean up */ + if (arfd >= 0) { + unlinkat(fdcwd,archivename,0); + close(arfd); + } + } + + host->ar = drvhost->ar; + } + + /* as */ + if (host->as) + cfgmeta->as = cfgmeta_as ? cfgmeta_as : cfgexplicit; + else { + if (!(drvhost->as = calloc(1,toollen))) + return -1; + + if (fnative) { + strcpy(drvhost->as,"as"); + cfgmeta->as = cfgnative; + } else { + sprintf(drvhost->as,"%s-as",host->host); + cfgmeta->as = cfghost; + } + + host->as = drvhost->as; + } + + /* ranlib */ + if (host->ranlib) + cfgmeta->ranlib = cfgmeta_ranlib ? cfgmeta_ranlib : cfgexplicit; + else { + if (!(drvhost->ranlib = calloc(1,toollen))) + return -1; + + if (fnative) { + strcpy(drvhost->ranlib,"ranlib"); + cfgmeta->ranlib = cfgnative; + } else { + sprintf(drvhost->ranlib,"%s-ranlib",host->host); + cfgmeta->ranlib = cfghost; + } + + host->ranlib = drvhost->ranlib; + } + + /* windres */ + if (host->windres) + cfgmeta->windres = cfgexplicit; + + else if (strcmp(host->flavor,"cygwin") + && strcmp(host->flavor,"midipix") + && strcmp(host->flavor,"mingw")) { + host->windres = ""; + cfgmeta->windres = "not applicable"; + + } else { + if (!(drvhost->windres = calloc(1,toollen))) + return -1; + + if (fnative) { + strcpy(drvhost->windres,"windres"); + cfgmeta->windres = cfgnative; + } else { + sprintf(drvhost->windres,"%s-windres",host->host); + cfgmeta->windres = cfghost; + } + + host->windres = drvhost->windres; + } + + /* dlltool */ + if (host->dlltool) + cfgmeta->dlltool = cfgmeta_dlltool ? cfgmeta_dlltool : cfgexplicit; + + else if (strcmp(host->flavor,"cygwin") + && strcmp(host->flavor,"midipix") + && strcmp(host->flavor,"mingw")) { + host->dlltool = ""; + cfgmeta->dlltool = "not applicable"; + + } else { + if (!(drvhost->dlltool = calloc(1,toollen))) + return -1; + + if (fnative) { + strcpy(drvhost->dlltool,"dlltool"); + cfgmeta->dlltool = cfgnative; + } else { + sprintf(drvhost->dlltool,"%s-dlltool",host->host); + cfgmeta->dlltool = cfghost; + } + + host->dlltool = drvhost->dlltool; + } + + /* mdso */ + if (host->mdso) + cfgmeta->mdso = cfgexplicit; + + else if (strcmp(host->flavor,"cygwin") + && strcmp(host->flavor,"midipix") + && strcmp(host->flavor,"mingw")) { + host->mdso = ""; + cfgmeta->mdso = "not applicable"; + + } else { + if (!(drvhost->mdso = calloc(1,toollen))) + return -1; + + if (fnative) { + strcpy(drvhost->mdso,"mdso"); + cfgmeta->mdso = cfgnative; + } else { + sprintf(drvhost->mdso,"%s-mdso",host->host); + cfgmeta->mdso = cfghost; + } + + host->mdso = drvhost->mdso; + } + + return 0; +} + +static void slbt_free_host_tool_argv(char ** argv) +{ + char ** parg; + + if (!argv) + return; + + for (parg=argv; *parg; parg++) + free(*parg); + + free(argv); +} + +slbt_hidden void slbt_free_host_params(struct slbt_host_strs * host) +{ + if (host->machine) + free(host->machine); + + if (host->host) + free(host->host); + + if (host->flavor) + free(host->flavor); + + if (host->ar) + free(host->ar); + + if (host->as) + free(host->as); + + if (host->ranlib) + free(host->ranlib); + + if (host->windres) + free(host->windres); + + if (host->dlltool) + free(host->dlltool); + + if (host->mdso) + free(host->mdso); + + slbt_free_host_tool_argv(host->ar_argv); + slbt_free_host_tool_argv(host->as_argv); + slbt_free_host_tool_argv(host->ranlib_argv); + slbt_free_host_tool_argv(host->windres_argv); + slbt_free_host_tool_argv(host->dlltool_argv); + slbt_free_host_tool_argv(host->mdso_argv); + + memset(host,0,sizeof(*host)); +} + + +slbt_hidden void slbt_init_flavor_settings( + struct slbt_common_ctx * cctx, + const struct slbt_host_params * ahost, + struct slbt_flavor_settings * psettings) +{ + const struct slbt_host_params * host; + const struct slbt_flavor_settings * settings; + + host = ahost ? ahost : &cctx->host; + + if (!strcmp(host->flavor,"midipix")) + settings = &host_flavor_midipix; + else if (!strcmp(host->flavor,"mingw")) + settings = &host_flavor_mingw; + else if (!strcmp(host->flavor,"cygwin")) + settings = &host_flavor_cygwin; + else if (!strcmp(host->flavor,"darwin")) + settings = &host_flavor_darwin; + else + settings = &host_flavor_default; + + if (!ahost) { + if (!strcmp(settings->imagefmt,"elf")) + cctx->drvflags |= SLBT_DRIVER_IMAGE_ELF; + else if (!strcmp(settings->imagefmt,"pe")) + cctx->drvflags |= SLBT_DRIVER_IMAGE_PE; + else if (!strcmp(settings->imagefmt,"macho")) + cctx->drvflags |= SLBT_DRIVER_IMAGE_MACHO; + } + + memcpy(psettings,settings,sizeof(*settings)); + + if (cctx->shrext) + psettings->dsosuffix = cctx->shrext; +} + + +slbt_hidden int slbt_init_ldrpath( + struct slbt_common_ctx * cctx, + struct slbt_host_params * host) +{ + char * buf; + const char ** ldrpath; + + if (!cctx->rpath || !(cctx->drvflags & SLBT_DRIVER_IMAGE_ELF)) { + host->ldrpath = 0; + return 0; + } + + /* common? */ + for (ldrpath=ldrpath_elf; *ldrpath; ldrpath ++) + if (!(strcmp(cctx->rpath,*ldrpath))) { + host->ldrpath = 0; + return 0; + } + + /* buf */ + if (!(buf = malloc(12 + strlen(cctx->host.host)))) + return -1; + + /* /usr/{host}/lib */ + sprintf(buf,"/usr/%s/lib",cctx->host.host); + + if (!(strcmp(cctx->rpath,buf))) { + host->ldrpath = 0; + free(buf); + return 0; + } + + /* /usr/{host}/lib64 */ + sprintf(buf,"/usr/%s/lib64",cctx->host.host); + + if (!(strcmp(cctx->rpath,buf))) { + host->ldrpath = 0; + free(buf); + return 0; + } + + host->ldrpath = cctx->rpath; + + free(buf); + return 0; +} + + +void slbt_host_reset_althost(const struct slbt_driver_ctx * ctx) +{ + struct slbt_driver_ctx_alloc * ictx; + uintptr_t addr; + + addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_alloc,ctx); + addr = addr - offsetof(struct slbt_driver_ctx_impl,ctx); + ictx = (struct slbt_driver_ctx_alloc *)addr; + + slbt_free_host_params(&ictx->ctx.ahost); +} + +int slbt_host_set_althost( + const struct slbt_driver_ctx * ctx, + const char * host, + const char * flavor) +{ + struct slbt_driver_ctx_alloc * ictx; + uintptr_t addr; + + addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_alloc,ctx); + addr = addr - offsetof(struct slbt_driver_ctx_impl,ctx); + ictx = (struct slbt_driver_ctx_alloc *)addr; + slbt_free_host_params(&ictx->ctx.ahost); + + if (!(ictx->ctx.ahost.host = strdup(host))) + return SLBT_SYSTEM_ERROR(ctx,0); + + if (!(ictx->ctx.ahost.flavor = strdup(flavor))) { + slbt_free_host_params(&ictx->ctx.ahost); + return SLBT_SYSTEM_ERROR(ctx,0); + } + + ictx->ctx.cctx.ahost.host = ictx->ctx.ahost.host; + ictx->ctx.cctx.ahost.flavor = ictx->ctx.ahost.flavor; + + if (slbt_init_host_params( + 0, + ctx->cctx, + &ictx->ctx.ahost, + &ictx->ctx.cctx.ahost, + &ictx->ctx.cctx.acfgmeta, + 0,0,0,0,0)) { + slbt_free_host_params(&ictx->ctx.ahost); + return SLBT_CUSTOM_ERROR(ctx,SLBT_ERR_HOST_INIT); + } + + slbt_init_flavor_settings( + &ictx->ctx.cctx, + &ictx->ctx.cctx.ahost, + &ictx->ctx.cctx.asettings); + + if (slbt_init_ldrpath( + &ictx->ctx.cctx, + &ictx->ctx.cctx.ahost)) { + slbt_free_host_params(&ictx->ctx.ahost); + return SLBT_CUSTOM_ERROR(ctx,SLBT_ERR_LDRPATH_INIT); + } + + return 0; +} + +int slbt_host_flavor_settings( + const char * flavor, + const struct slbt_flavor_settings ** settings) +{ + if (!strcmp(flavor,"midipix")) + *settings = &host_flavor_midipix; + else if (!strcmp(flavor,"mingw")) + *settings = &host_flavor_mingw; + else if (!strcmp(flavor,"cygwin")) + *settings = &host_flavor_cygwin; + else if (!strcmp(flavor,"darwin")) + *settings = &host_flavor_darwin; + else if (!strcmp(flavor,"default")) + *settings = &host_flavor_default; + else + *settings = 0; + + return *settings ? 0 : -1; +} |