diff options
127 files changed, 15039 insertions, 3947 deletions
diff --git a/COPYING.SLIBTOOL b/COPYING.SLIBTOOL index 55d7daf..131c254 100644 --- a/COPYING.SLIBTOOL +++ b/COPYING.SLIBTOOL @@ -1,8 +1,8 @@ /*****************************************************************************/ /* */ -/* slibtool: a skinny libtool implementation, written in C */ +/* slibtool: a strong libtool implementation, written in C */ /* */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/COPYING.SOFORT b/COPYING.SOFORT index 5e75bb6..75a98e1 100644 --- a/COPYING.SOFORT +++ b/COPYING.SOFORT @@ -2,7 +2,7 @@ /* */ /* sofort: portable software project skeleton */ /* */ -/* Copyright (C) 2015--2021 SysDeer Technologies, LLC */ +/* Copyright (C) 2015--2023 SysDeer Technologies, LLC */ /* */ /* sofort provides a build system that can be incorporated into Works */ /* which may or may not be covered by a copyleft license. THE FOLLOWING */ diff --git a/Makefile.in b/Makefile.in index 4e0f9e9..5ad6ff0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -84,7 +84,6 @@ CFLAGS_DEBUG += @cflags_debug@ CFLAGS_CMDLINE += @cflags_cmdline@ CFLAGS_CONFIG += @cflags_config@ CFLAGS_SYSROOT += @cflags_sysroot@ -CFLAGS_OS += @cflags_os@ CFLAGS_SITE += @cflags_site@ CFLAGS_PATH += @cflags_path@ CFLAGS_STRICT += @cflags_strict@ @@ -1,3 +1,62 @@ +0.5.36: + +This (pinky promise, for real now) absolutely final patch release +in the 0.5.x entails a large number of semantic fixes, several bug +fixes, and also the entirely new slibtool-ar execution mode. We +would still like to consider it a patch release since much of the +above was needed for slibtool to correctly act as a gnu libtool +drop-in replacement. As of this patch release, slibtool can be +used with virtually all packages covered by a common Gentoo world +build (as tested by @orbea, consisting of more than 900 packages +and pending some fixes of incorrect usage bugs that were exposed +by slibtool and filed with the respective upstream projects). +Then again, slibtool continues to successfully build all packages +included in a typical Midipix distro build, as well as all other +packages that we have been able to test. Due to the large number +of commits between the previous patch release and this one, only +the most significant changes are listed below. + +- ar api: new in-memory archiver backend (parse & merge). +- ar mode: new execution mode: archiver front-end. +- driver: heuristics: support argv of ar, nm, dlltool, etc. +- driver: correct precedence of heuristics-derived flag bits. +- driver: added --info mode. +- driver: corrected --config mode to be backward compatible. +- compile mode: added --tag=ASM. +- compile mode: properly handle custom compiler drivers. +- compile mode: de-duplicate header search directory arguments. +- link mode: general overhaul and refactoring of the code. +- link mode: correct object selection with -static and -shared. +- link mode: enhanced, tracebale dependency files. +- link mode: support -export-symbols and -export-symbols-regex. +- link mode: support -dlopen and -dlpreopen (self, force, libfoo). +- link mode: handle convenience libraries using correct semantics. +- link mode: cygwin & mingw support: enhanced dlltool semantics. +- link mode: darwin support: implemented additional special cases. +- execute mode: send informational output to stderr. +- execute mode: reimplemented with well-formed semantics. +- install mode: refactor, properly handle .so placeholder symlinks. +- install mode: enhanced logging of file operation errors. +- library: refactored, introduced secondary interface name-spaces. +- library: utilize the visibility attribute on non-PE targets. + +0.5.35: + +This post-last patch release in the 0.5.x series includes fixes to +bugs that were discovered since release 0.5.34. In addition, this +release introduces several new features in slibtool's driver, as +well as some minor improvements in the implementation of existing +program functionality. + +- driver: properly handle --help after --mode. +- driver: handle --version as only (repeated) argument more elegantly. +- driver: modify the cfgnmachine string for accuracy (-dumpmachine or --cchost). +- driver: added --dumpmachine support. +- driver: added -weak support, currently a no-op. +- driver: added -objectlist support. +- driver: -version-info suport: strictly verify the version info argument. +- helper: added slbt_map_input(), slbt_unmap_input(). + 0.5.34: This is the last patch release in the 0.5.x series. As of this release, @@ -1,4 +1,4 @@ -# slibtool: a skinny libtool implementation, written in C +# slibtool: a strong libtool implementation, written in C `slibtool` is an independent reimplementation of the widely used libtool, written in C. `slibtool` is designed to be a clean, fast, easy-to-use @@ -1,3 +1,14 @@ +0.5.36: + +Getting slibtool to the point where it could build a vast number of +packages while applying correct semantics would have never been +possible if it weren't for @orbea, who's still the true engine behind +the project. Many thanks also to Sam James from the Gentoo community +for following up on many of the issues that were encountered and +fixed throughout the process, and likewise to Redfoxmoon for filing +incorrect-usage bugs with upstream projects, and for helping everyone +retain the great spirit on slibtool's irc channel. + 0.5.33: This release (as well as the previous one) follows extensive testing diff --git a/aux/ltmain.sh b/aux/ltmain.sh new file mode 100755 index 0000000..64b4cde --- /dev/null +++ b/aux/ltmain.sh @@ -0,0 +1,2 @@ +#!/dev/null +# << this script should never be invoked >> diff --git a/config.project b/config.project index c8b6eef..9dcef5b 100644 --- a/config.project +++ b/config.project @@ -13,7 +13,7 @@ mb_disable_static=yes mb_disable_shared=yes # custom config step -mb_use_custom_cfgdefs=no +mb_use_custom_cfgdefs=yes mb_use_custom_cfginit=no mb_use_custom_cfgfini=yes mb_use_custom_cfgtest=no @@ -25,7 +25,7 @@ mb_makemode= # pkgconfig mb_pkgname='slibtool' -mb_pkgdesc='a surrogate libtool implementation, written in C' +mb_pkgdesc='a strong libtool implementation, written in C' mb_pkgusrc='https://dl.foss21.org/slibtool/' mb_pkgrepo='https://git.foss21.org/slibtool' mb_pkgpsrc= diff --git a/config.usage b/config.usage index 33d1e58..41fe629 100644 --- a/config.usage +++ b/config.usage @@ -143,7 +143,7 @@ supported variables: TOOLCHAIN SYSROOT CROSS_COMPILE - SHELL + CONFIG_SHELL PKGCONF PKGCONFIG @@ -33,7 +33,12 @@ usage() " ___________________________________________" \ "__________________________________" - cat "$mb_project_dir"/project/config/cfgdefs.usage + if [ -f "$mb_project_dir"/project/config/cfgdefs.usage ]; then + cat "$mb_project_dir"/project/config/cfgdefs.usage + else + printf '%s\n\n' \ + "[ info: this project does not provide a project-specific cfgdefs.usage file. ]" + fi fi exit 0 @@ -275,7 +280,7 @@ init_vars() mb_toolchain=$TOOLCHAIN mb_sysroot=$SYSROOT mb_cross_compile=$CROSS_COMPILE - mb_shell=$SHELL + mb_shell=$CONFIG_SHELL # pkgconf mb_pkgconf=$PKGCONF @@ -713,7 +718,7 @@ config_flags() # ccstrict if [ _$mb_ccstrict = _yes ]; then - mb_cflags_strict='$(_CFLAGS_Wall) $(_CFLAGS_Werror) $(_CFLAGS_Wextra) $(_CFLAGS_Wundef)' + mb_cflags_strict='$(_CFLAGS_Wall) $(_CFLAGS_Werror) $(_CFLAGS_Wextra) $(_CFLAGS_Wundef) $(_CFLAGS_Wpedantic)' fi # ldstrict @@ -842,26 +847,9 @@ config_ccenv() error_msg "${mb_pretty} forcing native mode when cross-building is strictly prohibited." fi - # add the include and library directories to the compiler and linker search path - if [ "$mb_cchost" = "$mb_native_cchost" ]; then - mb_cflags_last="$mb_cflags_last -I$mb_includedir" - mb_ldflags_last="$mb_ldflags_last -L$mb_libdir" - else - case "$mb_libdir" in - /*) - mb_cflags_last="$mb_cflags_last -I$mb_sysroot/.$mb_includedir" - mb_ldflags_last="$mb_ldflags_last -L$mb_sysroot/.$mb_libdir" - ;; - *) - mb_cflags_last="$mb_cflags_last -I$mb_includedir" - mb_ldflags_last="$mb_ldflags_last -L$mb_libdir" - esac - fi - # re-generate Makefile.tmp output_section_break config_copy - } config_custom_cfgdefs() @@ -944,7 +932,7 @@ config_host() mb_cfghost_cflags="$mb_cfghost_cflags -ffreestanding" mb_cfghost_cflags="$mb_cfghost_cflags -nostdlib" else - printf 'int main(void){return 0;}' \ + printf 'int main(void){return 0;}\n' \ > "$mb_cfghost_tmpname" fi diff --git a/include/slibtool/slibtool.h b/include/slibtool/slibtool.h index ee34b9a..d428e54 100644 --- a/include/slibtool/slibtool.h +++ b/include/slibtool/slibtool.h @@ -1,12 +1,14 @@ #ifndef SLIBTOOL_H #define SLIBTOOL_H +#include <fcntl.h> #include <stdint.h> #include <stddef.h> #include <stdio.h> #include <unistd.h> #include "slibtool_api.h" +#include "slibtool_arbits.h" #ifdef __cplusplus extern "C" { @@ -36,7 +38,7 @@ extern "C" { #define SLBT_DRIVER_VERSION 0x0010 #define SLBT_DRIVER_DRY_RUN 0x0020 -#define SLBT_DRIVER_CONFIG 0x0040 +#define SLBT_DRIVER_INFO 0x0040 #define SLBT_DRIVER_DEBUG 0x0080 #define SLBT_DRIVER_FEATURES 0x0100 #define SLBT_DRIVER_DEPS 0x0200 @@ -70,6 +72,29 @@ extern "C" { #define SLBT_DRIVER_EXPORT_DYNAMIC SLBT_DRIVER_XFLAG(0x0010) #define SLBT_DRIVER_STATIC_LIBTOOL_LIBS SLBT_DRIVER_XFLAG(0x0100) #define SLBT_DRIVER_OUTPUT_MACHINE SLBT_DRIVER_XFLAG(0x1000) +#define SLBT_DRIVER_OUTPUT_CONFIG SLBT_DRIVER_XFLAG(0x2000) + +#define SLBT_DRIVER_MODE_AR SLBT_DRIVER_XFLAG(0x010000) +#define SLBT_DRIVER_MODE_AR_CHECK SLBT_DRIVER_XFLAG(0x020000) +#define SLBT_DRIVER_MODE_AR_MERGE SLBT_DRIVER_XFLAG(0x040000) + +#define SLBT_DRIVER_MODE_STOOLIE SLBT_DRIVER_XFLAG(0x080000) +#define SLBT_DRIVER_MODE_SLIBTOOLIZE SLBT_DRIVER_XFLAG(0x080000) + +#define SLBT_DRIVER_PREFER_SHARED SLBT_DRIVER_XFLAG(0x100000) +#define SLBT_DRIVER_PREFER_STATIC SLBT_DRIVER_XFLAG(0x200000) + +#define SLBT_DRIVER_STOOLIE_COPY SLBT_DRIVER_XFLAG(0x01000000) +#define SLBT_DRIVER_STOOLIE_FORCE SLBT_DRIVER_XFLAG(0x02000000) +#define SLBT_DRIVER_STOOLIE_INSTALL SLBT_DRIVER_XFLAG(0x04000000) + +#define SLBT_DRIVER_DLOPEN_SELF SLBT_DRIVER_XFLAG(0x10000000) +#define SLBT_DRIVER_DLOPEN_FORCE SLBT_DRIVER_XFLAG(0x20000000) +#define SLBT_DRIVER_DLPREOPEN_SELF SLBT_DRIVER_XFLAG(0x40000000) +#define SLBT_DRIVER_DLPREOPEN_FORCE SLBT_DRIVER_XFLAG(0x80000000) + +/* unit action flags */ +#define SLBT_ACTION_MAP_READWRITE 0x0001 /* error flags */ #define SLBT_ERROR_TOP_LEVEL 0x0001 @@ -80,6 +105,13 @@ extern "C" { enum slbt_custom_error { SLBT_ERR_FLOW_ERROR, SLBT_ERR_FLEE_ERROR, + SLBT_ERR_COMPILE_ERROR, + SLBT_ERR_LINK_ERROR, + SLBT_ERR_INSTALL_ERROR, + SLBT_ERR_AR_ERROR, + SLBT_ERR_COPY_ERROR, + SLBT_ERR_MDSO_ERROR, + SLBT_ERR_DLLTOOL_ERROR, SLBT_ERR_ARCHIVE_IMPORT, SLBT_ERR_HOST_INIT, SLBT_ERR_INSTALL_FAIL, @@ -93,11 +125,33 @@ enum slbt_custom_error { SLBT_ERR_LCONF_OPEN, SLBT_ERR_LCONF_MAP, SLBT_ERR_LCONF_PARSE, + SLBT_ERR_AR_FAIL, + SLBT_ERR_AR_EMPTY_FILE, + SLBT_ERR_AR_INVALID_SIGNATURE, + SLBT_ERR_AR_INVALID_HEADER, + SLBT_ERR_AR_TRUNCATED_DATA, + SLBT_ERR_AR_DUPLICATE_LONG_NAMES, + SLBT_ERR_AR_DUPLICATE_ARMAP_MEMBER, + SLBT_ERR_AR_MISPLACED_ARMAP_MEMBER, + SLBT_ERR_AR_NO_ACTION_SPECIFIED, + SLBT_ERR_AR_NO_INPUT_SPECIFIED, + SLBT_ERR_AR_DRIVER_MISMATCH, + SLBT_ERR_AR_ARMAP_MISMATCH, + SLBT_ERR_AR_INVALID_ARMAP_NUMBER_OF_SYMS, + SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_REFS, + SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_STRS, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE, + SLBT_ERR_AR_INVALID_ARMAP_MEMBER_OFFSET, + SLBT_ERR_AR_INVALID_ARMAP_NAME_OFFSET, + SLBT_ERR_AR_DLUNIT_NOT_SPECIFIED, + SLBT_ERR_AR_OUTPUT_NOT_SPECIFIED, + SLBT_ERR_AR_OUTPUT_NOT_APPLICABLE, }; /* execution modes */ enum slbt_mode { SLBT_MODE_UNKNOWN, + SLBT_MODE_CONFIG, SLBT_MODE_INFO, SLBT_MODE_CLEAN, SLBT_MODE_COMPILE, @@ -106,6 +160,8 @@ enum slbt_mode { SLBT_MODE_INSTALL, SLBT_MODE_LINK, SLBT_MODE_UNINSTALL, + SLBT_MODE_AR, + SLBT_MODE_STOOLIE, }; enum slbt_tag { @@ -114,6 +170,7 @@ enum slbt_tag { SLBT_TAG_CXX, SLBT_TAG_FC, SLBT_TAG_F77, + SLBT_TAG_ASM, SLBT_TAG_NASM, SLBT_TAG_RC, }; @@ -125,6 +182,11 @@ enum slbt_warning_level { SLBT_WARNING_LEVEL_NONE, }; +struct slbt_input { + void * addr; + size_t size; +}; + struct slbt_source_version { int major; int minor; @@ -144,44 +206,67 @@ struct slbt_fd_ctx { struct slbt_exec_ctx { char * program; char * compiler; + char ** cargv; char ** xargv; char ** argv; char ** envp; char ** altv; + char ** dpic; char ** fpic; + char ** cass; char ** noundef; char ** soname; char ** lsoname; + char ** symdefs; char ** symfile; + + char ** explarg; + char ** expsyms; + char ** lout[2]; char ** mout[2]; char ** rpath[2]; + char ** sentinel; char * csrc; + int ldirdepth; char * ldirname; char * lbasename; + char * lobjname; char * aobjname; char * ltobjname; + + char * dlunit; + char * dlopensrc; + char * dlopenobj; + char * dlpreopen; + char * arfilename; char * lafilename; char * laifilename; + char * dsobasename; char * dsofilename; + char * relfilename; char * dsorellnkname; char * deffilename; + char * mapfilename; char * rpathfilename; + char * dimpfilename; char * pimpfilename; char * vimpfilename; + char * exefilename; char * sonameprefix; + pid_t pid; int exitcode; }; @@ -208,6 +293,8 @@ struct slbt_host_params { const char * host; const char * flavor; const char * ar; + const char * as; + const char * nm; const char * ranlib; const char * windres; const char * dlltool; @@ -227,6 +314,7 @@ struct slbt_flavor_settings { const char * exesuffix; const char * impprefix; const char * impsuffix; + const char * mapsuffix; const char * ldpathenv; char * picswitch; }; @@ -248,6 +336,7 @@ struct slbt_common_ctx { char ** cargv; char ** targv; char * libname; + const char * dlunit; const char * ccwrap; const char * target; const char * output; @@ -255,7 +344,7 @@ struct slbt_common_ctx { const char * rpath; const char * sysroot; const char * release; - const char * symfile; + const char * expsyms; const char * regex; const char * user; }; @@ -268,63 +357,185 @@ struct slbt_driver_ctx { void * any; }; +struct slbt_raw_archive { + void * map_addr; + size_t map_size; +}; + +struct slbt_archive_meta { + struct slbt_raw_archive r_archive; + struct ar_raw_signature * r_signature; + + struct ar_meta_signature * m_signature; + + struct ar_meta_member_info ** a_memberv; + struct ar_meta_member_info * a_arref_longnames; + struct ar_meta_armap_info a_armap_primary; + struct ar_meta_armap_info a_armap_pecoff; +}; + +struct slbt_archive_ctx { + const char * const * path; + const struct slbt_raw_archive * map; + const struct slbt_archive_meta *meta; + void * any; +}; + +struct slbt_symlist_ctx { + const char * const * path; + const char ** symstrv; +}; + +struct slbt_txtfile_ctx { + const char * const * path; + const char ** txtlinev; +}; + +struct slbt_stoolie_ctx { + const char * const * path; + const struct slbt_txtfile_ctx * acinc; + const struct slbt_txtfile_ctx * cfgac; + const struct slbt_txtfile_ctx * makam; + const char * const * auxarg; + const char * const * m4arg; +}; + +/* raw input api */ +slbt_api int slbt_fs_map_input (const struct slbt_driver_ctx *, + int, const char *, int, + struct slbt_input *); + +slbt_api int slbt_fs_unmap_input (struct slbt_input *); + /* driver api */ -slbt_api int slbt_get_driver_ctx (char ** argv, char ** envp, uint32_t flags, +slbt_api int slbt_lib_get_driver_ctx (char ** argv, char ** envp, uint64_t flags, const struct slbt_fd_ctx *, struct slbt_driver_ctx **); -slbt_api void slbt_free_driver_ctx (struct slbt_driver_ctx *); +slbt_api void slbt_lib_free_driver_ctx (struct slbt_driver_ctx *); + +slbt_api int slbt_lib_get_driver_fdctx (const struct slbt_driver_ctx *, struct slbt_fd_ctx *); -slbt_api int slbt_get_driver_fdctx (const struct slbt_driver_ctx *, struct slbt_fd_ctx *); -slbt_api int slbt_set_driver_fdctx (struct slbt_driver_ctx *, const struct slbt_fd_ctx *); +slbt_api int slbt_lib_set_driver_fdctx (struct slbt_driver_ctx *, const struct slbt_fd_ctx *); -/* execution context api */ -slbt_api int slbt_get_exec_ctx (const struct slbt_driver_ctx *, struct slbt_exec_ctx **); -slbt_api void slbt_free_exec_ctx (struct slbt_exec_ctx *); -slbt_api void slbt_reset_argvector (struct slbt_exec_ctx *); -slbt_api void slbt_reset_arguments (struct slbt_exec_ctx *); -slbt_api void slbt_reset_placeholders (struct slbt_exec_ctx *); -slbt_api void slbt_disable_placeholders (struct slbt_exec_ctx *); +slbt_api int slbt_lib_get_symlist_ctx (const struct slbt_driver_ctx *, const char *, struct slbt_symlist_ctx **); + +slbt_api void slbt_lib_free_symlist_ctx (struct slbt_symlist_ctx *); + +slbt_api int slbt_lib_get_txtfile_ctx (const struct slbt_driver_ctx *, const char *, struct slbt_txtfile_ctx **); + +slbt_api void slbt_lib_free_txtfile_ctx (struct slbt_txtfile_ctx *); + +/* command execution context api */ +slbt_api int slbt_ectx_get_exec_ctx (const struct slbt_driver_ctx *, struct slbt_exec_ctx **); +slbt_api void slbt_ectx_free_exec_ctx (struct slbt_exec_ctx *); +slbt_api void slbt_ectx_reset_argvector (struct slbt_exec_ctx *); +slbt_api void slbt_ectx_reset_arguments (struct slbt_exec_ctx *); /* core api */ -slbt_api int slbt_exec_compile (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); -slbt_api int slbt_exec_execute (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); -slbt_api int slbt_exec_install (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); -slbt_api int slbt_exec_link (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); -slbt_api int slbt_exec_uninstall (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); +slbt_api int slbt_exec_compile (const struct slbt_driver_ctx *); +slbt_api int slbt_exec_execute (const struct slbt_driver_ctx *); +slbt_api int slbt_exec_install (const struct slbt_driver_ctx *); +slbt_api int slbt_exec_link (const struct slbt_driver_ctx *); +slbt_api int slbt_exec_uninstall (const struct slbt_driver_ctx *); +slbt_api int slbt_exec_ar (const struct slbt_driver_ctx *); +slbt_api int slbt_exec_stoolie (const struct slbt_driver_ctx *); +slbt_api int slbt_exec_slibtoolize (const struct slbt_driver_ctx *); + +/* host and flavor interfaces */ +slbt_api int slbt_host_set_althost (const struct slbt_driver_ctx *, const char * host, const char * flavor); -slbt_api int slbt_set_alternate_host (const struct slbt_driver_ctx *, const char * host, const char * flavor); -slbt_api void slbt_reset_alternate_host (const struct slbt_driver_ctx *); +slbt_api void slbt_host_reset_althost (const struct slbt_driver_ctx *); -slbt_api int slbt_get_flavor_settings (const char *, const struct slbt_flavor_settings **); +slbt_api int slbt_host_objfmt_is_coff (const struct slbt_driver_ctx *); -/* helper api */ -slbt_api int slbt_archive_import (const struct slbt_driver_ctx *, struct slbt_exec_ctx *, +slbt_api int slbt_host_objfmt_is_macho (const struct slbt_driver_ctx *); + +slbt_api int slbt_host_group_is_winnt (const struct slbt_driver_ctx *); + +slbt_api int slbt_host_group_is_darwin (const struct slbt_driver_ctx *); + +slbt_api int slbt_host_flavor_settings (const char *, const struct slbt_flavor_settings **); + +/* utility helper interfaces */ +slbt_api int slbt_util_import_archive (const struct slbt_exec_ctx *, char * dstarchive, char * srcarchive); -slbt_api int slbt_copy_file (const struct slbt_driver_ctx *, struct slbt_exec_ctx *, - char * src, char * dst); -slbt_api int slbt_dump_machine (const char * compiler, char * machine, size_t bufsize); -slbt_api int slbt_realpath (int, const char *, int, char *, size_t); + +slbt_api int slbt_util_copy_file (struct slbt_exec_ctx *, + const char * from, const char * to); + +slbt_api int slbt_util_create_mapfile (const struct slbt_symlist_ctx *, const char *, mode_t); + +slbt_api int slbt_util_create_symfile (const struct slbt_symlist_ctx *, const char *, mode_t); + +slbt_api int slbt_util_dump_machine (const char * compiler, char * machine, size_t bufsize); + +slbt_api int slbt_util_real_path (int, const char *, int, char *, size_t); + +/* archiver api */ +slbt_api int slbt_ar_get_archive_ctx (const struct slbt_driver_ctx *, const char * path, + struct slbt_archive_ctx **); + +slbt_api void slbt_ar_free_archive_ctx (struct slbt_archive_ctx *); + +slbt_api int slbt_ar_get_varchive_ctx (const struct slbt_driver_ctx *, + struct slbt_archive_ctx **); + +slbt_api int slbt_ar_get_archive_meta (const struct slbt_driver_ctx *, + const struct slbt_raw_archive *, + struct slbt_archive_meta **); + +slbt_api void slbt_ar_free_archive_meta (struct slbt_archive_meta *); + +slbt_api int slbt_ar_merge_archives (struct slbt_archive_ctx * const [], + struct slbt_archive_ctx **); + +slbt_api int slbt_ar_store_archive (struct slbt_archive_ctx *, + const char *, mode_t); + +slbt_api int slbt_ar_create_mapfile (const struct slbt_archive_meta *, const char *, mode_t); + +slbt_api int slbt_ar_create_symfile (const struct slbt_archive_meta *, const char *, mode_t); + +slbt_api int slbt_ar_create_dlsyms (struct slbt_archive_ctx **, const char *, const char *, mode_t); + +/* slibtoolize api */ +slbt_api int slbt_st_get_stoolie_ctx (const struct slbt_driver_ctx *, const char * path, + struct slbt_stoolie_ctx **); + +slbt_api void slbt_st_free_stoolie_ctx (struct slbt_stoolie_ctx *); /* utility api */ slbt_api int slbt_main (char **, char **, const struct slbt_fd_ctx *); +slbt_api int slbt_output_info (const struct slbt_driver_ctx *); slbt_api int slbt_output_config (const struct slbt_driver_ctx *); slbt_api int slbt_output_machine (const struct slbt_driver_ctx *); slbt_api int slbt_output_features (const struct slbt_driver_ctx *); slbt_api int slbt_output_fdcwd (const struct slbt_driver_ctx *); -slbt_api int slbt_output_exec (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *, const char *); -slbt_api int slbt_output_compile (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *); -slbt_api int slbt_output_execute (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *); -slbt_api int slbt_output_install (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *); -slbt_api int slbt_output_link (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *); -slbt_api int slbt_output_uninstall (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *); -slbt_api int slbt_output_error_record (const struct slbt_driver_ctx *, const struct slbt_error_info *); + +slbt_api int slbt_output_exec (const struct slbt_exec_ctx *, const char *); +slbt_api int slbt_output_compile (const struct slbt_exec_ctx *); +slbt_api int slbt_output_execute (const struct slbt_exec_ctx *); +slbt_api int slbt_output_install (const struct slbt_exec_ctx *); +slbt_api int slbt_output_link (const struct slbt_exec_ctx *); +slbt_api int slbt_output_uninstall (const struct slbt_exec_ctx *); +slbt_api int slbt_output_mapfile (const struct slbt_symlist_ctx *); + slbt_api int slbt_output_error_vector (const struct slbt_driver_ctx *); +slbt_api int slbt_output_error_record (const struct slbt_driver_ctx *, const struct slbt_error_info *); + +/* archiver utility api */ +slbt_api int slbt_au_output_arname (const struct slbt_archive_ctx *); +slbt_api int slbt_au_output_members (const struct slbt_archive_meta *); +slbt_api int slbt_au_output_symbols (const struct slbt_archive_meta *); +slbt_api int slbt_au_output_mapfile (const struct slbt_archive_meta *); + +slbt_api int slbt_au_output_dlsyms (struct slbt_archive_ctx **, const char *); /* package info */ -slbt_api const struct slbt_source_version * slbt_source_version(void); +slbt_api const struct slbt_source_version * slbt_api_source_version(void); #ifdef __cplusplus } diff --git a/include/slibtool/slibtool_arbits.h b/include/slibtool/slibtool_arbits.h new file mode 100644 index 0000000..8ab8d0c --- /dev/null +++ b/include/slibtool/slibtool_arbits.h @@ -0,0 +1,187 @@ +#ifndef SLIBTOOL_ARBITS_H +#define SLIBTOOL_ARBITS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> + +#define AR_SIGNATURE "!<arch>\n" + +#define AR_MEMBER_ATTR_DEFAULT (0x00) +#define AR_MEMBER_ATTR_ASCII (0x01) +#define AR_MEMBER_ATTR_UTF8 (0x02) +#define AR_MEMBER_ATTR_OBJECT (0x04) +#define AR_MEMBER_ATTR_ARCHIVE (0x08) +#define AR_MEMBER_ATTR_ARMAP (0x10) +#define AR_MEMBER_ATTR_NAMESTRS (0x20) +#define AR_MEMBER_ATTR_LINKINFO (0x40) + +#define AR_HEADER_ATTR_DEFAULT (0x00) +#define AR_HEADER_ATTR_FILE_ID (0x01) +#define AR_HEADER_ATTR_NAME_REF (0x02) +#define AR_HEADER_ATTR_BSD (0x10) +#define AR_HEADER_ATTR_SYSV (0x20) + +#define AR_ARMAP_ATTR_PLAIN (0x0000) +#define AR_ARMAP_ATTR_SORTED (0x0001) +#define AR_ARMAP_ATTR_BSD (0x0010) +#define AR_ARMAP_ATTR_SYSV (0x0020) +#define AR_ARMAP_ATTR_COFF (0x0040) +#define AR_ARMAP_ATTR_LE_32 (0x0100) +#define AR_ARMAP_ATTR_LE_64 (0x0200) +#define AR_ARMAP_ATTR_BE_32 (0x0400) +#define AR_ARMAP_ATTR_BE_64 (0x0800) + +#define AR_OBJECT_ATTR_NONE (0X0000) +#define AR_OBJECT_ATTR_ELF (0x0001) +#define AR_OBJECT_ATTR_COFF (0x0002) +#define AR_OBJECT_ATTR_MACHO (0x0004) +#define AR_OBJECT_ATTR_LE_32 (0x0100) +#define AR_OBJECT_ATTR_LE_64 (0x0200) +#define AR_OBJECT_ATTR_BE_32 (0x0400) +#define AR_OBJECT_ATTR_BE_64 (0x0800) + +struct ar_raw_signature { + char ar_signature [0x08]; /* 0x00 */ +}; + +struct ar_raw_file_header { + char ar_file_id [0x10]; /* 0x00 */ + char ar_time_date_stamp [0x0c]; /* 0x10 */ + char ar_uid [0x06]; /* 0x1c */ + char ar_gid [0x06]; /* 0x22 */ + char ar_file_mode [0x08]; /* 0x28 */ + char ar_file_size [0x0a]; /* 0x30 */ + char ar_end_tag [0x02]; /* 0x3a */ +}; + +struct ar_raw_armap_ref_32 { + unsigned char ar_name_offset [0x04]; /* 0x00 */ + unsigned char ar_member_offset [0x04]; /* 0x04 */ +}; + +struct ar_raw_armap_ref_64 { + unsigned char ar_name_offset [0x08]; /* 0x00 */ + unsigned char ar_member_offset [0x08]; /* 0x08 */ +}; + +struct ar_raw_armap_bsd_32 { + unsigned char (*ar_size_of_refs) [0x04]; + unsigned char (*ar_first_name_offset) [0x04]; + unsigned char (*ar_size_of_strs) [0x04]; + const char * (*ar_string_table); +}; + +struct ar_raw_armap_bsd_64 { + unsigned char (*ar_size_of_refs) [0x08]; + unsigned char (*ar_first_name_offset) [0x08]; + unsigned char (*ar_size_of_strs) [0x08]; + const char * (*ar_string_table); +}; + +struct ar_raw_armap_sysv_32 { + unsigned char (*ar_num_of_syms) [0x04]; + unsigned char (*ar_first_ref_offset) [0x04]; + const char * (*ar_string_table); +}; + +struct ar_raw_armap_sysv_64 { + unsigned char (*ar_num_of_syms) [0x08]; + unsigned char (*ar_first_ref_offset) [0x08]; + const char * (*ar_string_table); +}; + +struct ar_raw_armap_xcoff_32 { + unsigned char (*ar_num_of_members) [0x04]; + unsigned char (*ar_first_member_offset) [0x04]; + unsigned char (*ar_num_of_symbols) [0x04]; + unsigned char (*ar_sym_member_indices) [0x02]; + char (*ar_string_table) []; +}; + +struct ar_meta_signature { + const char * ar_signature; +}; + +struct ar_meta_file_header { + const char * ar_member_name; + uint32_t ar_header_attr; + uint32_t ar_uid; + uint32_t ar_gid; + uint32_t ar_file_mode; + uint64_t ar_file_size; + uint64_t ar_time_date_stamp; +}; + +struct ar_meta_member_info { + struct ar_meta_file_header ar_file_header; + struct ar_raw_file_header * ar_member_data; + uint32_t ar_member_attr; + uint32_t ar_object_attr; + uint64_t ar_object_size; + void * ar_object_data; +}; + +struct ar_meta_armap_ref_32 { + uint32_t ar_name_offset; + uint32_t ar_member_offset; +}; + +struct ar_meta_armap_ref_64 { + uint64_t ar_name_offset; + uint64_t ar_member_offset; +}; + +struct ar_meta_armap_common_32 { + struct ar_meta_member_info * ar_member; + struct ar_meta_armap_ref_32 * ar_symrefs; + struct ar_raw_armap_bsd_32 * ar_armap_bsd; + struct ar_raw_armap_sysv_32 * ar_armap_sysv; + struct ar_raw_armap_xcoff_32 * ar_armap_xcoff; + uint32_t ar_armap_attr; + uint32_t ar_num_of_symbols; + uint32_t ar_num_of_members; + uint32_t ar_first_member_offset; + uint32_t ar_size_of_refs; + uint32_t ar_size_of_strs; + uint16_t * ar_sym_member_indices; + const char * ar_string_table; +}; + +struct ar_meta_armap_common_64 { + struct ar_meta_member_info * ar_member; + struct ar_meta_armap_ref_64 * ar_symrefs; + struct ar_raw_armap_bsd_64 * ar_armap_bsd; + struct ar_raw_armap_sysv_64 * ar_armap_sysv; + void * ar_armap_xcoff; + uint32_t ar_armap_attr; + uint64_t ar_num_of_symbols; + uint64_t ar_num_of_members; + uint64_t ar_first_member_offset; + uint64_t ar_size_of_refs; + uint64_t ar_size_of_strs; + uint16_t * ar_sym_member_indices; + const char * ar_string_table; +}; + +struct ar_meta_symbol_info { + const char * ar_archive_name; + const char * ar_object_name; + const char * ar_symbol_name; + const char * ar_symbol_type; + uint64_t ar_symbol_value; + uint64_t ar_symbol_size; +}; + +struct ar_meta_armap_info { + const struct ar_meta_armap_common_32 * ar_armap_common_32; + const struct ar_meta_armap_common_64 * ar_armap_common_64; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/slibtool/slibtool_output.h b/include/slibtool/slibtool_output.h new file mode 100644 index 0000000..263e4d7 --- /dev/null +++ b/include/slibtool/slibtool_output.h @@ -0,0 +1,23 @@ +#ifndef SLIBTOOL_OUTPUT_H +#define SLIBTOOL_OUTPUT_H + +#include <stdint.h> + +#define SLBT_PRETTY(x) ((uint64_t)x << 32) + +/* output actions */ +#define SLBT_OUTPUT_ARCHIVE_MEMBERS 0x00000001 +#define SLBT_OUTPUT_ARCHIVE_HEADERS 0x00000002 +#define SLBT_OUTPUT_ARCHIVE_SYMBOLS 0x00000004 +#define SLBT_OUTPUT_ARCHIVE_ARMAPS 0x00000008 +#define SLBT_OUTPUT_ARCHIVE_MAPFILE 0x00000010 +#define SLBT_OUTPUT_ARCHIVE_DLSYMS 0x00000020 +#define SLBT_OUTPUT_ARCHIVE_NOSORT 0x00000040 + +/* pretty-printer flags */ +#define SLBT_PRETTY_YAML SLBT_PRETTY(0x00000001) +#define SLBT_PRETTY_POSIX SLBT_PRETTY(0x00000002) +#define SLBT_PRETTY_HEXDATA SLBT_PRETTY(0x00000004) +#define SLBT_PRETTY_VERBOSE SLBT_PRETTY(0x00000008) + +#endif diff --git a/m4/slibtool.m4 b/m4/slibtool.m4 index ffce017..aecd2c5 100644 --- a/m4/slibtool.m4 +++ b/m4/slibtool.m4 @@ -2,7 +2,7 @@ # # # slibtool.m4: native slibtool integration for autoconf-based projects # # # -# Copyright (C) 2021 SysDeer Technologies, LLC # +# Copyright (C) 2016--2024 SysDeer Technologies, LLC # # # # Permission is hereby granted, free of charge, to any person obtaining # # a copy of this software and associated documentation files (the # @@ -44,6 +44,29 @@ slibtool_pic_mode_default='default' slibtool_sysroot_default= ]) +# slibtool: refined logic for ar, nm, ranlib, etc. +# +m4_ifdef([SLIBTOOL_INIT],[],[ +# +m4_ifdef([AC_PROG_AR], [m4_undefine([AC_PROG_AR])]) +m4_ifdef([AM_PROG_AR], [m4_undefine([AM_PROG_AR])]) + +m4_ifdef([AC_PROG_NM], [m4_undefine([AC_PROG_NM])]) +m4_ifdef([AM_PROG_NM], [m4_undefine([AM_PROG_NM])]) + +m4_ifdef([AC_PROG_RANLIB], [m4_undefine([AC_PROG_RANLIB])]) +m4_ifdef([AM_PROG_RANLIB], [m4_undefine([AM_PROG_RANLIB])]) + +m4_ifdef([AC_PROG_LEX], [m4_undefine([AC_PROG_LEX])]) +m4_ifdef([AM_PROG_LEX], [m4_undefine([AM_PROG_LEX])]) + +m4_ifdef([LT_LIB_M], [m4_undefine([LT_LIB_M])]) +m4_ifdef([LT_LIB_DLLOAD], [m4_undefine([LT_LIB_DLLOAD])]) +]) + +# _SLIBTOOL_CONVENIENCE +# --------------------- +AC_DEFUN([LT_DEVAL],[$1]=[$2]) # _SLIBTOOL_ARGUMENT_HANDLING # --------------------------- @@ -266,17 +289,119 @@ slibtool_options="${slibtool_options} disable-static" ]) +# SLIBTOOL_PROG_AR +# ---------------- +AC_DEFUN([SLIBTOOL_PROG_AR],[ + +# slibtool: SLIBTOOL_PROG_AR +# -------------------------- +if [[ -n "${host_alias}" ]]; then + AC_CHECK_PROG([AR],"${host_alias}-"[ar],"${host_alias}-"[ar]) +fi + +if [[ -n "${host}" ]] && [[ "${host}" != "${host_alias:-}" ]] && [[ -z "${AR}" ]]; then + AC_CHECK_PROG([AR],"${host}-"[ar],"${host}-"[ar]) +fi + +if [[ -n "${host}" ]] && [[ -z "${AR}" ]]; then + AC_CHECK_PROG([AR],[llvm-ar],[llvm-ar]) +fi + +if [[ -z "${host}" ]]; then + AC_CHECK_PROG([AR],[ar],[ar]) +fi +]) + + +# SLIBTOOL_PROG_RANLIB +# -------------------- +AC_DEFUN([SLIBTOOL_PROG_RANLIB],[ + +# slibtool: SLIBTOOL_PROG_RANLIB +# ------------------------------ +if [[ -n "${host_alias}" ]]; then + AC_CHECK_PROG([RANLIB],"${host_alias}-"[ranlib],"${host_alias}-"[ranlib]) +fi + +if [[ -n "${host}" ]] && [[ "${host}" != "${host_alias:-}" ]] && [[ -z "${RANLIB}" ]]; then + AC_CHECK_PROG([RANLIB],"${host}-"[ranlib],"${host}-"[ranlib]) +fi + +if [[ -n "${host}" ]] && [[ -z "${RANLIB}" ]]; then + AC_CHECK_PROG([RANLIB],[llvm-ranlib],[llvm-ranlib]) +fi + +if [[ -z "${host}" ]]; then + AC_CHECK_PROG([RANLIB],[ranlib],[ranlib]) +fi +]) + + # SLIBTOOL_PROG_NM # ---------------- AC_DEFUN([SLIBTOOL_PROG_NM],[ # slibtool: SLIBTOOL_PROG_NM # -------------------------- -if [[ -z "${NM:-}" ]]; then - NM="${RANLIB%ranlib}nm" +if [[ -n "${host_alias}" ]]; then + AC_CHECK_PROG([NM],"${host_alias}-"[nm],"${host_alias}-"[nm]) fi -AC_SUBST([NM]) +if [[ -n "${host}" ]] && [[ "${host}" != "${host_alias:-}" ]] && [[ -z "${NM}" ]]; then + AC_CHECK_PROG([NM],"${host}-"[nm],"${host}-"[nm]) +fi + +if [[ -n "${host}" ]] && [[ -z "${NM}" ]]; then + AC_CHECK_PROG([NM],[llvm-nm],[llvm-nm]) +fi + +if [[ -z "${host}" ]]; then + AC_CHECK_PROG([NM],[nm],[nm]) +fi +]) + + +# SLIBTOOL_PROG_LEX +# ----------------- +AC_DEFUN([SLIBTOOL_PROG_LEX],[ + +# slibtool: SLIBTOOL_PROG_LEX +# --------------------------- +if [[ -n "${LEX}" ]]; then + AC_CHECK_PROG([LEX],[flex]) +fi + +if [[ -z "${LEX}" ]]; then + AC_CHECK_PROG([LEX],[flex],[flex]) +fi + +if [[ -z "${LEX}" ]]; then + AC_CHECK_PROG([LEX],[lex],[lex]) +fi + +AC_SUBST([LEX]) +AC_SUBST([LEXLIB]) +]) + + +# SLIBTOOL_LFLAG_LIBM +# ------------------- +AC_DEFUN([SLIBTOOL_LFLAG_LIBM],[ + +# slibtool: SLIBTOOL_LFLAG_LIBM +# ----------------------------- +LT_DEVAL([LIBM],[-lm]) +AC_SUBST([LIBM]) +]) + + +# SLIBTOOL_LFLAG_LTDL +# ------------------- +AC_DEFUN([SLIBTOOL_LFLAG_LTDL],[ + +# slibtool: SLIBTOOL_LFLAG_LTDL +# ----------------------------- +# (always use the system lib[s]ltdl) ]) @@ -290,6 +415,14 @@ AC_REQUIRE([_SLIBTOOL_SET_FLAVOR]) AC_REQUIRE([_SLIBTOOL_ARGUMENT_HANDLING]) +# slibtool: tame legacy early invocation +AC_DEFUN([AC_PROG_LEX]) +AC_DEFUN([AM_PROG_LEX]) + +AC_DEFUN([AC_PROG_RANLIB]) +AC_DEFUN([AM_PROG_RANLIB]) + + # slibtool: package defaults # --------------------- slbt_cfg_ifs="${IFS}" @@ -370,7 +503,6 @@ LIBTOOL='$(SLIBTOOL)' AC_SUBST([LIBTOOL]) AC_SUBST([SLIBTOOL]) AC_SUBST([SLIBTOOL_SYSROOT]) -m4_define([SLIBTOOL_INIT]) ]) @@ -378,57 +510,42 @@ m4_define([SLIBTOOL_INIT]) # ------------------------- AC_DEFUN([SLIBTOOL_LANG],[ AC_REQUIRE([SLIBTOOL_PREREQ]) -]) - - -# SLIBTOOL_PREREQ(_version_) -# -------------------------- -AC_DEFUN([SLIBTOOL_PREREQ],[ - -AC_REQUIRE([AC_PROG_CC]) -AC_REQUIRE([AC_PROG_CPP]) -AC_REQUIRE([AC_PROG_CXX]) -AC_REQUIRE([AC_PROG_CXXCPP]) - -AC_REQUIRE([AC_PROG_OBJC]) -AC_REQUIRE([AC_PROG_OBJCPP]) -AC_REQUIRE([AC_PROG_FC]) -AC_REQUIRE([AC_PROG_F77]) - -AC_REQUIRE([AC_PROG_AWK]) -AC_REQUIRE([AC_PROG_LEX]) -AC_REQUIRE([AC_PROG_SED]) -AC_REQUIRE([AC_PROG_YACC]) - -AC_REQUIRE([AC_PROG_RANLIB]) - -AC_REQUIRE([AC_PROG_LN_S]) -AC_REQUIRE([AC_PROG_MKDIR_P]) +# slibtool: SLIBTOOL_LANG(C) +m4_if([$1],[C],[ +AC_PROG_CC +AC_PROG_CPP +]) -m4_ifndef([AC_PROG_OBJCXX], [AC_DEFUN([AC_PROG_OBJCXX],[AC_SUBST([OBJCXX])])]) -m4_ifndef([AC_PROG_OBJCXXCPP], [AC_DEFUN([AC_PROG_OBJCXXCPP],[AC_SUBST([OBJCXXCPP])])]) +m4_if([$1],[C++],[ +# slibtool: SLIBTOOL_LANG(C++) AC_PROG_CC AC_PROG_CPP AC_PROG_CXX AC_PROG_CXXCPP +]) -AC_PROG_OBJC -AC_PROG_OBJCPP -AC_PROG_OBJCXX -AC_PROG_OBJCXXCPP - +m4_if([$1],[Fortran 77],[ +# slibtool: SLIBTOOL_LANG(Fortran 77) AC_PROG_FC AC_PROG_F77 +]) +]) + + +# SLIBTOOL_PREREQ(_version_) +# -------------------------- +AC_DEFUN([SLIBTOOL_PREREQ],[ AC_PROG_AWK AC_PROG_LEX AC_PROG_SED AC_PROG_YACC -AC_PROG_RANLIB +AC_PROG_AR AC_PROG_NM +AC_PROG_RANLIB AC_PROG_LN_S AC_PROG_MKDIR_P @@ -444,9 +561,18 @@ AC_DEFUN([LT_PREREQ], [SLIBTOOL_PREREQ($@)]) AC_DEFUN([AC_PROG_LIBTOOL], [SLIBTOOL_INIT($@)]) AC_DEFUN([AM_PROG_LIBTOOL], [SLIBTOOL_INIT($@)]) +AC_DEFUN([AC_PROG_AR], [SLIBTOOL_PROG_AR($@)]) +AC_DEFUN([AM_PROG_AR], [SLIBTOOL_PROG_AR($@)]) + AC_DEFUN([AC_PROG_NM], [SLIBTOOL_PROG_NM($@)]) AC_DEFUN([AM_PROG_NM], [SLIBTOOL_PROG_NM($@)]) +AC_DEFUN([AC_PROG_RANLIB], [SLIBTOOL_PROG_RANLIB($@)]) +AC_DEFUN([AM_PROG_RANLIB], [SLIBTOOL_PROG_RANLIB($@)]) + +AC_DEFUN([AC_PROG_LEX], [SLIBTOOL_PROG_LEX($@)]) +AC_DEFUN([AM_PROG_LEX], [SLIBTOOL_PROG_LEX($@)]) + AC_DEFUN([AC_ENABLE_SHARED], [SLIBTOOL_ENABLE_SHARED($@)]) AC_DEFUN([AM_ENABLE_SHARED], [SLIBTOOL_ENABLE_SHARED($@)]) @@ -459,9 +585,19 @@ AC_DEFUN([AM_DISABLE_SHARED], [SLIBTOOL_DISABLE_SHARED($@)]) AC_DEFUN([AC_DISABLE_STATIC], [SLIBTOOL_DISABLE_STATIC($@)]) AC_DEFUN([AM_DISABLE_STATIC], [SLIBTOOL_DISABLE_STATIC($@)]) +AC_DEFUN([LT_LIB_M], [SLIBTOOL_LFLAG_LIBM($@)]) +AC_DEFUN([LT_LIB_DLLOAD], [SLIBTOOL_LFLAG_LTDL($@)]) + # deprecated and no-op macros # --------------------------- AC_DEFUN([AC_LIBTOOL_DLOPEN],[]) AC_DEFUN([AC_LIBTOOL_WIN32_DLL],[]) AC_DEFUN([AC_DISABLE_FAST_INSTALL],[]) +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],[]) + +AC_DEFUN([LT_PATH_AR],[]) +AC_DEFUN([LT_PATH_AS],[]) +AC_DEFUN([LT_PATH_LD],[]) +AC_DEFUN([LT_PATH_NM],[]) +AC_DEFUN([LT_PATH_RANLIB],[]) diff --git a/project/common.mk b/project/common.mk index 4893b49..ace734f 100644 --- a/project/common.mk +++ b/project/common.mk @@ -1,34 +1,87 @@ API_SRCS = \ + src/arbits/slbt_archive_ctx.c \ + src/arbits/slbt_archive_dlsyms.c \ + src/arbits/slbt_archive_mapfile.c \ + src/arbits/slbt_archive_mapstrv.c \ + src/arbits/slbt_archive_merge.c \ + src/arbits/slbt_archive_meta.c \ + src/arbits/slbt_archive_store.c \ + src/arbits/slbt_archive_symfile.c \ + src/arbits/slbt_archive_syminfo.c \ + src/arbits/slbt_armap_bsd_32.c \ + src/arbits/slbt_armap_bsd_64.c \ + src/arbits/slbt_armap_sysv_32.c \ + src/arbits/slbt_armap_sysv_64.c \ + src/arbits/output/slbt_au_output_arname.c \ + src/arbits/output/slbt_au_output_dlsyms.c \ + src/arbits/output/slbt_au_output_mapfile.c \ + src/arbits/output/slbt_au_output_members.c \ + src/arbits/output/slbt_au_output_symbols.c \ src/driver/slbt_amain.c \ src/driver/slbt_driver_ctx.c \ - src/helper/slbt_archive_import.c \ - src/helper/slbt_copy_file.c \ - src/helper/slbt_dump_machine.c \ - src/helper/slbt_realpath.c \ + src/driver/slbt_link_params.c \ + src/driver/slbt_split_argv.c \ + src/driver/slbt_symlist_ctx.c \ + src/driver/slbt_txtfile_ctx.c \ + src/driver/slbt_version_info.c \ + src/host/slbt_host_flavor.c \ + src/host/slbt_host_params.c \ + src/util/slbt_archive_import.c \ + src/util/slbt_create_mapfile.c \ + src/util/slbt_create_symfile.c \ + src/util/slbt_copy_file.c \ + src/util/slbt_dump_machine.c \ + src/util/slbt_map_input.c \ + src/util/slbt_realpath.c \ + src/logic/slbt_exec_ar.c \ src/logic/slbt_exec_compile.c \ src/logic/slbt_exec_ctx.c \ src/logic/slbt_exec_execute.c \ src/logic/slbt_exec_install.c \ src/logic/slbt_exec_link.c \ + src/logic/slbt_exec_stoolie.c \ src/logic/slbt_exec_uninstall.c \ + src/logic/linkcmd/slbt_linkcmd_archive.c \ + 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 \ src/output/slbt_output_error.c \ src/output/slbt_output_exec.c \ src/output/slbt_output_fdcwd.c \ src/output/slbt_output_features.c \ + src/output/slbt_output_info.c \ src/output/slbt_output_machine.c \ + src/output/slbt_output_mapfile.c \ + src/skin/slbt_skin_ar.c \ src/skin/slbt_skin_default.c \ src/skin/slbt_skin_install.c \ + src/skin/slbt_skin_stoolie.c \ src/skin/slbt_skin_uninstall.c \ + src/stoolie/slbt_stoolie_ctx.c \ + +FALLBACK_SRCS = \ + src/fallback/slbt_archive_import_mri.c \ INTERNAL_SRCS = \ + src/internal/$(PACKAGE)_coff_impl.c \ src/internal/$(PACKAGE)_dprintf_impl.c \ src/internal/$(PACKAGE)_errinfo_impl.c \ src/internal/$(PACKAGE)_lconf_impl.c \ src/internal/$(PACKAGE)_libmeta_impl.c \ + src/internal/$(PACKAGE)_m4fake_impl.c \ src/internal/$(PACKAGE)_mapfile_impl.c \ + src/internal/$(PACKAGE)_objlist_impl.c \ src/internal/$(PACKAGE)_objmeta_impl.c \ + src/internal/$(PACKAGE)_pecoff_impl.c \ + src/internal/$(PACKAGE)_realpath_impl.c \ + src/internal/$(PACKAGE)_snprintf_impl.c \ src/internal/$(PACKAGE)_symlink_impl.c \ + src/internal/$(PACKAGE)_tmpfile_impl.c \ + src/internal/$(PACKAGE)_txtline_impl.c \ APP_SRCS = \ src/slibtool.c diff --git a/project/config/cfgdefs.in b/project/config/cfgdefs.in new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/project/config/cfgdefs.in diff --git a/project/config/cfgdefs.sh b/project/config/cfgdefs.sh new file mode 100644 index 0000000..0d851ea --- /dev/null +++ b/project/config/cfgdefs.sh @@ -0,0 +1,66 @@ +# in projects where [ $mb_use_custom_cfgdefs = yes ], +# cfgdefs.sh is invoked from within ./configure via +# . $mb_project_dir/project/cfgdefs.sh + +# a successful return from cfgdefs.sh will be followed +# by a second invocation of the config_copy() function, +# reflecting any changes to common config variables +# made by cfgdefs.sh. + +# finally, cfgdefs.sh may update the contents of the +# config-time generated cfgdefs.mk. + + +# sofort's config test framework +. "$mb_project_dir/sofort/cfgtest/cfgtest.sh" + + +for arg ; do + case "$arg" in + *) + error_msg ${arg#}: "unsupported config argument." + exit 2 + esac +done + + +cfgdefs_output_custom_defs() +{ + cat "$mb_project_dir/project/config/cfgdefs.in" > cfgdefs.mk +} + + +cfgdefs_perform_common_tests() +{ + # headers + cfgtest_header_presence 'sys/syscall.h' +} + + +cfgdefs_perform_target_tests() +{ + # init + cfgtest_newline + cfgtest_host_section + + # common tests + cfgdefs_perform_common_tests + + # pretty cfgdefs.mk + cfgtest_newline +} + +# cfgdefs.in --> cfgdefs.mk +cfgdefs_output_custom_defs + +# strict: some tests might fail +set +e + +# target-specific tests +cfgdefs_perform_target_tests + +# strict: restore mode +set -e + +# all done +return 0 diff --git a/project/extras.mk b/project/extras.mk index 6765339..804a7cc 100644 --- a/project/extras.mk +++ b/project/extras.mk @@ -3,7 +3,10 @@ CFLAGS_STATIC_ATTR += -DSLBT_PRE_ALPHA -DSLBT_STATIC CFLAGS_APP_ATTR += -DSLBT_APP CFLAGS_MACHINE := -DSLBT_MACHINE=\"$(CC_HOST)\" +CFLAGS_PKGDATA := -DSLBT_PACKAGE_DATADIR=\"$(DESTDIR)$(DATADIR)/$(PACKAGE)\" CFLAGS_CONFIG += $(CFLAGS_MACHINE) +CFLAGS_CONFIG += $(CFLAGS_PKGDATA) +CFLAGS_CONFIG += $(CFLAGS_ATTR_VISIBILITY_HIDDEN) src/driver/slbt_driver_ctx.o: version.tag src/driver/slbt_driver_ctx.lo: version.tag @@ -14,54 +17,80 @@ RAPUNZEL = rlibtool RAPUNCEL = rclibtool RAPUNDEL = rdlibtool RAPUNJEL = rdclibtool +STOOLIE = slibtoolize + +install-app-extras: install-slibtoolize install-app-extras: mkdir -p $(DESTDIR)$(BINDIR) rm -f bin/$(NICKNAME)-shared$(OS_APP_SUFFIX).tmp rm -f bin/$(NICKNAME)-static$(OS_APP_SUFFIX).tmp + rm -f bin/$(NICKNAME)-ar$(OS_APP_SUFFIX).tmp rm -f bin/$(DBGNAME)$(OS_APP_SUFFIX).tmp rm -f bin/$(DBGNAME)-shared$(OS_APP_SUFFIX).tmp rm -f bin/$(DBGNAME)-static$(OS_APP_SUFFIX).tmp + rm -f bin/$(DBGNAME)-ar$(OS_APP_SUFFIX).tmp rm -f bin/$(LEGABITS)$(OS_APP_SUFFIX).tmp rm -f bin/$(LEGABITS)-shared$(OS_APP_SUFFIX).tmp rm -f bin/$(LEGABITS)-static$(OS_APP_SUFFIX).tmp + rm -f bin/$(LEGABITS)-ar$(OS_APP_SUFFIX).tmp rm -f bin/$(RAPUNZEL)$(OS_APP_SUFFIX).tmp rm -f bin/$(RAPUNCEL)$(OS_APP_SUFFIX).tmp rm -f bin/$(RAPUNDEL)$(OS_APP_SUFFIX).tmp rm -f bin/$(RAPUNJEL)$(OS_APP_SUFFIX).tmp + rm -f bin/$(STOOLIE)$(OS_APP_SUFFIX).tmp + ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME)-shared$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME)-static$(OS_APP_SUFFIX).tmp + ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME)-ar$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(DBGNAME)$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(DBGNAME)-shared$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(DBGNAME)-static$(OS_APP_SUFFIX).tmp + ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(DBGNAME)-ar$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(LEGABITS)$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(LEGABITS)-shared$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(LEGABITS)-static$(OS_APP_SUFFIX).tmp + ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(LEGABITS)-ar$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(RAPUNZEL)$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(RAPUNCEL)$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(RAPUNDEL)$(OS_APP_SUFFIX).tmp ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(RAPUNJEL)$(OS_APP_SUFFIX).tmp + ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(STOOLIE)$(OS_APP_SUFFIX).tmp + mv bin/$(NICKNAME)-shared$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME)-shared$(OS_APP_SUFFIX) mv bin/$(NICKNAME)-static$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME)-static$(OS_APP_SUFFIX) + mv bin/$(NICKNAME)-ar$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME)-ar$(OS_APP_SUFFIX) mv bin/$(DBGNAME)$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(DBGNAME)$(OS_APP_SUFFIX) mv bin/$(DBGNAME)-shared$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(DBGNAME)-shared$(OS_APP_SUFFIX) mv bin/$(DBGNAME)-static$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(DBGNAME)-static$(OS_APP_SUFFIX) + mv bin/$(DBGNAME)-ar$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(DBGNAME)-ar$(OS_APP_SUFFIX) mv bin/$(LEGABITS)$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(LEGABITS)$(OS_APP_SUFFIX) mv bin/$(LEGABITS)-shared$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(LEGABITS)-shared$(OS_APP_SUFFIX) mv bin/$(LEGABITS)-static$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(LEGABITS)-static$(OS_APP_SUFFIX) + mv bin/$(LEGABITS)-ar$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(LEGABITS)-ar$(OS_APP_SUFFIX) mv bin/$(RAPUNZEL)$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(RAPUNZEL)$(OS_APP_SUFFIX) mv bin/$(RAPUNCEL)$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(RAPUNCEL)$(OS_APP_SUFFIX) mv bin/$(RAPUNDEL)$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(RAPUNDEL)$(OS_APP_SUFFIX) mv bin/$(RAPUNJEL)$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(RAPUNJEL)$(OS_APP_SUFFIX) + + mv bin/$(STOOLIE)$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(STOOLIE)$(OS_APP_SUFFIX) + +install-slibtoolize: + mkdir -p $(DESTDIR)$(DATADIR)/$(PACKAGE) + + cp -p $(SOURCE_DIR)/m4/slibtool.m4 $(DESTDIR)$(DATADIR)/$(PACKAGE) + cp -p $(SOURCE_DIR)/aux/ltmain.sh $(DESTDIR)$(DATADIR)/$(PACKAGE) + +.PHONY: install-slibtoolize diff --git a/project/headers.mk b/project/headers.mk index 62b6f52..1b77743 100644 --- a/project/headers.mk +++ b/project/headers.mk @@ -1,20 +1,34 @@ API_HEADERS = \ $(PROJECT_DIR)/include/$(PACKAGE)/slibtool.h \ $(PROJECT_DIR)/include/$(PACKAGE)/slibtool_api.h \ + $(PROJECT_DIR)/include/$(PACKAGE)/slibtool_arbits.h \ + $(PROJECT_DIR)/include/$(PACKAGE)/slibtool_output.h \ INTERNAL_HEADERS = \ $(PROJECT_DIR)/src/internal/argv/argv.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_ar_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_coff_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_dprintf_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_driver_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_errinfo_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_install_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_lconf_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_linkcmd_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_m4fake_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_mapfile_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_metafile_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_mkdir_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_objlist_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_pecoff_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_readlink_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_realpath_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_snprintf_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_spawn_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_stoolie_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_symlink_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_tmpfile_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_txtline_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_uninstall_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_visibility_impl.h \ ALL_HEADERS = $(API_HEADERS) $(INTERNAL_HEADERS) diff --git a/project/tagver.mk b/project/tagver.mk index 6b79598..2595fde 100644 --- a/project/tagver.mk +++ b/project/tagver.mk @@ -2,4 +2,4 @@ VER_NAMESPACE = SLBT VER_MAJOR = 0 VER_MINOR = 5 -VER_PATCH = 34 +VER_PATCH = 36 diff --git a/project/tree.mk b/project/tree.mk index 42564b8..f855e82 100644 --- a/project/tree.mk +++ b/project/tree.mk @@ -1,9 +1,15 @@ tree.tag: mkdir -p src + mkdir -p src/arbits mkdir -p src/driver - mkdir -p src/helper + mkdir -p src/fallback + mkdir -p src/host + mkdir -p src/util mkdir -p src/internal mkdir -p src/logic mkdir -p src/output mkdir -p src/skin + mkdir -p src/stoolie + mkdir -p src/arbits/output + mkdir -p src/logic/linkcmd touch tree.tag diff --git a/sofort/ccenv/ccenv.in b/sofort/ccenv/ccenv.in index 441f8ab..8e5f0e0 100644 --- a/sofort/ccenv/ccenv.in +++ b/sofort/ccenv/ccenv.in @@ -84,8 +84,13 @@ PKGCONF = @ccenv_pkgconf@ AS = @ccenv_as@ LD = @ccenv_ld@ +# @ccenv_cfgtype@ visibility attributes +CFLAGS_ATTR_VISIBILITY_DEFAULT = -D_ATTR_VISIBILITY_DEFAULT=@ccenv_attr_visibility_default@ +CFLAGS_ATTR_VISIBILITY_HIDDEN = -D_ATTR_VISIBILITY_HIDDEN=@ccenv_attr_visibility_hidden@ +CFLAGS_ATTR_VISIBILITY_INTERNAL = -D_ATTR_VISIBILITY_INTERNAL=@ccenv_attr_visibility_internal@ +CFLAGS_ATTR_VISIBILITY_PROTECTED = -D_ATTR_VISIBILITY_PROTECTED=@ccenv_attr_visibility_protected@ + # @ccenv_cfgtype@ cflags -CFLAGS_OS += -DOS_LIB_SUFFIX=\"@ccenv_os_lib_suffix@\" +CFLAGS_OS += -DSO_LIB_SUFFIX=\"@ccenv_os_lib_suffix@\" CFLAGS_OS += @ccenv_cflags_os@ CFLAGS_PIC += @ccenv_cflags_pic@ - diff --git a/sofort/ccenv/ccenv.sh b/sofort/ccenv/ccenv.sh index a13aa07..d975c6b 100644 --- a/sofort/ccenv/ccenv.sh +++ b/sofort/ccenv/ccenv.sh @@ -1118,14 +1118,20 @@ ccenv_set_os() fi case "$ccenv_cchost" in - *-*-*-* ) - ccenv_tip=${ccenv_cchost%-*} - ccenv_os=${ccenv_tip#*-*-} - ;; *-*-musl | *-*-gnu ) ccenv_tip=${ccenv_cchost%-*} ccenv_os=${ccenv_tip#*-} ;; + *-*-solaris* ) + ccenv_os='solaris' + ;; + *-*-*bsd* | *-*-dragonfly* ) + ccenv_os='bsd' + ;; + *-*-*-* ) + ccenv_tip=${ccenv_cchost%-*} + ccenv_os=${ccenv_tip#*-*-} + ;; *-*-* ) ccenv_os=${ccenv_cchost#*-*-} ;; @@ -1412,6 +1418,42 @@ ccenv_set_os_pe_switches() ;; esac fi + + if [ "$ccenv_cc_binfmt" = 'PE' ]; then + if ! cfgtest_macro_definition '__PE__'; then + ccenv_cflags_os="${ccenv_cflags_os} -D__PE__" + fi + + if ! cfgtest_macro_definition '__dllexport'; then + ccenv_cflags_os="${ccenv_cflags_os} -D__dllexport=__attribute__\(\(__dllexport__\)\)" + fi + + if ! cfgtest_macro_definition '__dllimport'; then + ccenv_cflags_os="${ccenv_cflags_os} -D__dllimport=__attribute__\(\(__dllimport__\)\)" + fi + fi +} + +ccenv_set_os_gate_switches() +{ + if [ "$ccenv_os" = 'solaris' ]; then + if ! cfgtest_macro_definition 'AT_FDCWD'; then + ccenv_cflags_os="${ccenv_cflags_os} -D__EXTENSIONS__" + fi + fi +} + +ccenv_set_os_bsd_switches() +{ + if [ "$ccenv_os" = 'bsd' ]; then + mb_cfgtest_headers='sys/mman.h' + + if ! cfgtest_macro_definition 'MAP_ANON'; then + ccenv_cflags_os="${ccenv_cflags_os} -D__BSD_VISIBLE" + fi + + mb_cfgtest_headers= + fi } ccenv_output_defs() @@ -1654,6 +1696,25 @@ ccenv_set_cc_linker_switch_vars() done } +ccenv_set_cc_attr_visibility_vars() +{ + if cfgtest_attr_visibility 'default'; then + ccenv_attr_visibility_default="$mb_cfgtest_attr" + fi + + if cfgtest_attr_visibility 'hidden'; then + ccenv_attr_visibility_hidden="$mb_cfgtest_attr" + fi + + if cfgtest_attr_visibility 'internal'; then + ccenv_attr_visibility_internal="$mb_cfgtest_attr" + fi + + if cfgtest_attr_visibility 'protected'; then + ccenv_attr_visibility_protected="$mb_cfgtest_attr" + fi +} + ccenv_dso_verify() { ccenv_str='int foo(int x){return ++x;}' @@ -1760,6 +1821,9 @@ ccenv_set_toolchain_variables() ccenv_set_os_dso_linkage ccenv_set_os_dso_patterns ccenv_set_os_pe_switches + ccenv_set_os_gate_switches + ccenv_set_os_bsd_switches + ccenv_set_cc_attr_visibility_vars ccenv_output_defs ccenv_clean_up diff --git a/sofort/ccenv/ccenv.vars b/sofort/ccenv/ccenv.vars index 41eb327..054b638 100644 --- a/sofort/ccenv/ccenv.vars +++ b/sofort/ccenv/ccenv.vars @@ -82,6 +82,12 @@ ccenv_windrc= ccenv_pkgconf= +# visibility attributes +ccenv_attr_visibility_default= +ccenv_attr_visibility_hidden= +ccenv_attr_visibility_internal= +ccenv_attr_visibility_protected= + # cflags ccenv_cflags_os= ccenv_cflags_pic= diff --git a/sofort/ccenv/ccswitch.strs b/sofort/ccenv/ccswitch.strs index 0a76f03..277e02e 100644 --- a/sofort/ccenv/ccswitch.strs +++ b/sofort/ccenv/ccswitch.strs @@ -34,6 +34,7 @@ -Werror -Wextra -Wundef +-Wpedantic # debugging -g diff --git a/sofort/cfgtest/cfgtest.sh b/sofort/cfgtest/cfgtest.sh index debdb8c..8e1db07 100644 --- a/sofort/cfgtest/cfgtest.sh +++ b/sofort/cfgtest/cfgtest.sh @@ -15,6 +15,7 @@ # mb_cfgtest_cfgtype: the type of the current test (host/native) # mb_cfgtest_makevar: the make variable affected by the current test # mb_cfgtest_headers: headers for ad-hoc inclusion with the current test +# mb_cfgtest_attr: if supported, the compiler-specific attribute definition cfgtest_newline() @@ -131,6 +132,15 @@ cfgtest_epilog() return 1 fi + if [ "${1}" = 'attr' ] && [ "${2}" = '(error)' ]; then + printf '\n\ncfgtest: the %s compiler %s %s_ attribute.\n' \ + "$mb_cfgtest_cfgtype" \ + 'does not appear to support the _' \ + "${3}" >&3 + printf '%s\n' '------------------------' >&3 + return 1 + fi + if [ "${2}" = '-----' ] || [ "${2}" = '(missing)' ]; then printf '\n\ncfgtest: %s %s is missing or cannot be found.\n' "${1}" "${3}" >&3 printf '%s\n' '------------------------' >&3 @@ -246,6 +256,8 @@ cfgtest_common_init() fi elif [ "$cfgtest_type" = 'asm' ]; then cfgtest_fmt='%s -c -xc - -o a.out' + elif [ "$cfgtest_type" = 'attr' ]; then + cfgtest_fmt='%s -c -xc - -o a.out -Werror' elif [ "$cfgtest_type" = 'lib' ]; then cfgtest_fmt='%s -xc - -o a.out' elif [ "$cfgtest_type" = 'ldflag' ]; then @@ -330,11 +342,16 @@ cfgtest_header_presence() cfgtest_prolog 'header' "${1}" cfgtest_code_snippet=$(printf '#include <%s>\n' "${1}") + cfgtest_code_onedecl='int fn(void){return 0;}' + + cfgtest_code_snippet=$(printf '%s\n%s\n' \ + "$cfgtest_code_snippet" \ + "$cfgtest_code_onedecl") cfgtest_common_init # execute - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ || cfgtest_epilog 'header' '-----' "<${1}>" \ @@ -365,11 +382,16 @@ cfgtest_header_absence() cfgtest_prolog 'header absence' "${1}" cfgtest_code_snippet=$(printf '#include <%s>\n' "${1}") + cfgtest_code_onedecl='int fn(void){return 0;}' + + cfgtest_code_snippet=$(printf '%s\n%s\n' \ + "$cfgtest_code_snippet" \ + "$cfgtest_code_onedecl") cfgtest_common_init # execute - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ && printf 'cfgtest: %s header <%s>: no error.' \ @@ -406,7 +428,7 @@ cfgtest_interface_presence() cfgtest_common_init # execute - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ || cfgtest_epilog 'interface' '(error)' "${1}" \ @@ -443,7 +465,7 @@ cfgtest_decl_presence() cfgtest_common_init # execute - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ || cfgtest_epilog 'decl' '(error)' "${1}" \ @@ -496,7 +518,7 @@ cfgtest_type_size() cfgtest_common_init - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ && mb_internal_size=$mb_internal_guess @@ -534,6 +556,39 @@ cfgtest_type_size() } +cfgtest_attr_visibility() +{ + # init + cfgtest_prolog 'compiler visibility attr' "${1}" + + cfgtest_attr_syntax='__attribute__((__visibility__("'"${1}"'")))' + cfgtest_code_snippet="$cfgtest_attr_syntax"' int f_'"${1}"'(void);' + + cfgtest_common_init 'attr' + + # execute + cfgtest_ret=1 + + printf '%s\n' "$cfgtest_src" \ + | eval $(printf '%s' "$cfgtest_cmd") \ + > /dev/null 2>&3 \ + || cfgtest_epilog 'attr' '(error)' "${1}" \ + || return + + # result + mb_cfgtest_attr=$(printf '__attribute__\\(\\(__visibility__\\(\\"%s\\"\\)\\)\\)' "${1}") + + cfgtest_ret=0 + + printf 'cfgtest: %s compiler: above attribute is supported; see also ccenv/%s.mk.\n\n' \ + "$mb_cfgtest_cfgtype" "$mb_cfgtest_cfgtype" >&3 + + cfgtest_epilog 'attr' '(ok)' + + return 0 +} + + cfgtest_code_snippet_asm() { # init @@ -546,7 +601,7 @@ cfgtest_code_snippet_asm() # execute cfgtest_ret=1 - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ || cfgtest_epilog 'snippet' '(error)' \ @@ -579,7 +634,7 @@ cfgtest_macro_definition() # execute cfgtest_ret=1 - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ || cfgtest_epilog 'macro' '(error)' "${1}" \ @@ -627,7 +682,7 @@ cfgtest_library_presence() cfgtest_common_init 'lib' # execute - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ || cfgtest_epilog 'library' '-----' "$@" \ @@ -805,20 +860,20 @@ cfgtest_compiler_switch() ;; *) - cfgtest_code_snippet= + cfgtest_code_snippet='int fn(void){return 0;}' cfgtest_common_init 'switch' ;; esac # execute - printf '%s' "$cfgtest_src" \ + printf '%s\n' "$cfgtest_src" \ | eval $(printf '%s' "$cfgtest_cmd") \ > /dev/null 2>&3 \ || cfgtest_epilog 'switch' '(error)' "$@" \ || return 1 # result - printf 'cfgtest: the switch `%s was accepted by the compier.\n' \ + printf 'cfgtest: the switch `%s was accepted by the compiler.\n' \ "$cfgtest_switches'" >&3 printf '%s\n' '------------------------' >&3 diff --git a/sofort/config/config.vars b/sofort/config/config.vars index 0c01a29..38d5616 100644 --- a/sofort/config/config.vars +++ b/sofort/config/config.vars @@ -54,6 +54,7 @@ zealous sysroot freestanding cross_compile +config_shell shell pkgconf diff --git a/src/arbits/output/slbt_au_output_arname.c b/src/arbits/output/slbt_au_output_arname.c new file mode 100644 index 0000000..28e081d --- /dev/null +++ b/src/arbits/output/slbt_au_output_arname.c @@ -0,0 +1,86 @@ +/*******************************************************************/ +/* 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_dprintf_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_ar_impl.h" + +#define SLBT_PRETTY_FLAGS (SLBT_PRETTY_YAML \ + | SLBT_PRETTY_POSIX \ + | SLBT_PRETTY_HEXDATA) + +static int slbt_au_output_arname_impl( + const struct slbt_driver_ctx * dctx, + const struct slbt_archive_ctx * actx, + const struct slbt_fd_ctx * fdctx, + const char * fmt) +{ + const char * path; + const char mema[] = "<memory_object>"; + + path = actx->path && *actx->path ? *actx->path : mema; + + if (slbt_dprintf(fdctx->fdout,fmt,path) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + return 0; +} + +static int slbt_au_output_arname_posix( + const struct slbt_driver_ctx * dctx, + const struct slbt_archive_ctx * actx, + const struct slbt_fd_ctx * fdctx) +{ + if (slbt_au_output_arname_impl( + dctx,actx,fdctx, + "%s:\n") < 0) + return SLBT_NESTED_ERROR(dctx); + + return 0; +} + +static int slbt_au_output_arname_yaml( + const struct slbt_driver_ctx * dctx, + const struct slbt_archive_ctx * actx, + const struct slbt_fd_ctx * fdctx) +{ + if (slbt_au_output_arname_impl( + dctx,actx,fdctx, + "Archive:\n" + " - Meta:\n" + " - [ name: %s ]\n\n") < 0) + return SLBT_NESTED_ERROR(dctx); + + return 0; +} + +int slbt_au_output_arname(const struct slbt_archive_ctx * actx) +{ + const struct slbt_driver_ctx * dctx; + struct slbt_fd_ctx fdctx; + + dctx = (slbt_get_archive_ictx(actx))->dctx; + + if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) { + case SLBT_PRETTY_YAML: + return slbt_au_output_arname_yaml( + dctx,actx,&fdctx); + + case SLBT_PRETTY_POSIX: + return slbt_au_output_arname_posix( + dctx,actx,&fdctx); + + default: + return slbt_au_output_arname_yaml( + dctx,actx,&fdctx); + } +} diff --git a/src/arbits/output/slbt_au_output_dlsyms.c b/src/arbits/output/slbt_au_output_dlsyms.c new file mode 100644 index 0000000..512f60f --- /dev/null +++ b/src/arbits/output/slbt_au_output_dlsyms.c @@ -0,0 +1,12 @@ +/*******************************************************************/ +/* 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> + +int slbt_au_output_dlsyms(struct slbt_archive_ctx ** arctxv, const char * dlunit) +{ + return slbt_ar_create_dlsyms(arctxv,dlunit,0,0); +} diff --git a/src/arbits/output/slbt_au_output_mapfile.c b/src/arbits/output/slbt_au_output_mapfile.c new file mode 100644 index 0000000..fb470df --- /dev/null +++ b/src/arbits/output/slbt_au_output_mapfile.c @@ -0,0 +1,12 @@ +/*******************************************************************/ +/* 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> + +int slbt_au_output_mapfile(const struct slbt_archive_meta * meta) +{ + return slbt_ar_create_mapfile(meta,0,0); +} diff --git a/src/arbits/output/slbt_au_output_members.c b/src/arbits/output/slbt_au_output_members.c new file mode 100644 index 0000000..88937b0 --- /dev/null +++ b/src/arbits/output/slbt_au_output_members.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 <time.h> +#include <locale.h> +#include <inttypes.h> +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_output.h> +#include "slibtool_driver_impl.h" +#include "slibtool_dprintf_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_ar_impl.h" + +#define SLBT_PRETTY_FLAGS (SLBT_PRETTY_YAML \ + | SLBT_PRETTY_POSIX \ + | SLBT_PRETTY_HEXDATA) + +#define PPRIU64 "%"PRIu64 + +const char slbt_ar_perm_strs[8][4] = { + {'-','-','-','\0'}, + {'-','-','x','\0'}, + {'-','w','-','\0'}, + {'-','w','x','\0'}, + {'r','-','-','\0'}, + {'r','-','x','\0'}, + {'r','w','-','\0'}, + {'r','w','x','\0'} +}; + +static unsigned slbt_au_output_decimal_len_from_val(size_t val, unsigned min) +{ + unsigned ret; + + for (ret=0; val; ret++) + val /= 10; + + return (ret > min) ? ret : min; +} + +static int slbt_au_output_one_member_posix( + int fdout, + struct ar_meta_member_info * memberp) +{ + return slbt_dprintf( + fdout,"%s\n", + memberp->ar_file_header.ar_member_name); +} + +static int slbt_au_output_one_member_posix_verbose( + int fdout, + struct ar_meta_member_info * memberp, + const char * fmtstr, + locale_t arlocale) +{ + unsigned ownerbits; + unsigned groupbits; + unsigned worldbits; + time_t artimeval; + struct tm artimeloc; + char artimestr[64] = {0}; + + ownerbits = (memberp->ar_file_header.ar_file_mode & 0700) >> 6; + groupbits = (memberp->ar_file_header.ar_file_mode & 0070) >> 3; + worldbits = (memberp->ar_file_header.ar_file_mode & 0007); + artimeval = memberp->ar_file_header.ar_time_date_stamp; + + if (localtime_r(&artimeval,&artimeloc)) + strftime_l( + artimestr,sizeof(artimestr), + "%b %e %H:%M %Y",&artimeloc, + arlocale); + + return slbt_dprintf( + fdout,fmtstr, + slbt_ar_perm_strs[ownerbits], + slbt_ar_perm_strs[groupbits], + slbt_ar_perm_strs[worldbits], + memberp->ar_file_header.ar_uid, + memberp->ar_file_header.ar_gid, + memberp->ar_object_size, + artimestr, + memberp->ar_file_header.ar_member_name); +} + +static int slbt_au_output_members_posix( + const struct slbt_driver_ctx * dctx, + const struct slbt_archive_meta * meta, + const struct slbt_fd_ctx * fdctx) +{ + struct ar_meta_member_info ** memberp; + int fdout; + size_t testval; + size_t sizelen; + size_t uidlen; + size_t gidlen; + locale_t arloc; + char fmtstr[64]; + + fdout = fdctx->fdout; + arloc = 0; + + if (dctx->cctx->fmtflags & SLBT_PRETTY_VERBOSE) { + for (sizelen=0,memberp=meta->a_memberv; *memberp; memberp++) + if ((testval = memberp[0]->ar_object_size) > sizelen) + sizelen = testval; + + for (uidlen=0,memberp=meta->a_memberv; *memberp; memberp++) + if ((testval = memberp[0]->ar_file_header.ar_uid) > uidlen) + uidlen = testval; + + for (gidlen=0,memberp=meta->a_memberv; *memberp; memberp++) + if ((testval = memberp[0]->ar_file_header.ar_gid) > gidlen) + gidlen = testval; + + sizelen = slbt_au_output_decimal_len_from_val(sizelen,6); + uidlen = slbt_au_output_decimal_len_from_val(uidlen,1); + gidlen = slbt_au_output_decimal_len_from_val(gidlen,1); + arloc = newlocale(LC_ALL,setlocale(LC_ALL,0),0); + + sprintf( + fmtstr, + "%%s%%s%%s " + "%%" PPRIU64 "u" + "/%%-" PPRIU64 "u " + "%%" PPRIU64 "u " + "%%s " + "%%s\n", + uidlen, + gidlen, + sizelen); + } + + for (memberp=meta->a_memberv; *memberp; memberp++) { + switch ((*memberp)->ar_member_attr) { + case AR_MEMBER_ATTR_ARMAP: + case AR_MEMBER_ATTR_LINKINFO: + case AR_MEMBER_ATTR_NAMESTRS: + break; + + default: + if (arloc) { + if (slbt_au_output_one_member_posix_verbose( + fdout,*memberp,fmtstr,arloc) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else { + if (slbt_au_output_one_member_posix( + fdout,*memberp) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + } + + if (arloc) + freelocale(arloc); + + return 0; +} + +static int slbt_au_output_one_member_yaml( + int fdout, + struct ar_meta_member_info * memberp) +{ + return slbt_dprintf( + fdout, + " - [ member: %s ]\n", + memberp->ar_file_header.ar_member_name); +} + +static int slbt_au_output_one_member_yaml_verbose( + int fdout, + struct ar_meta_member_info * memberp, + locale_t arlocale) +{ + time_t artimeval; + struct tm artimeloc; + char artimestr[64] = {0}; + + artimeval = memberp->ar_file_header.ar_time_date_stamp; + + if (localtime_r(&artimeval,&artimeloc)) + strftime_l( + artimestr,sizeof(artimestr), + "%Y/%m/%d @ %H:%M",&artimeloc, + arlocale); + + return slbt_dprintf( + fdout, + " - Member:\n" + " - [ name: " "%s" " ]\n" + " - [ timestamp: " "%s" " ]\n" + " - [ filesize: " PPRIU64 " ]\n" + " - [ uid: " "%d" " ]\n" + " - [ gid: " "%d" " ]\n" + " - [ mode: " "%d" " ]\n\n", + memberp->ar_file_header.ar_member_name, + artimestr, + memberp->ar_object_size, + memberp->ar_file_header.ar_uid, + memberp->ar_file_header.ar_gid, + memberp->ar_file_header.ar_file_mode); +} + +static int slbt_au_output_members_yaml( + const struct slbt_driver_ctx * dctx, + const struct slbt_archive_meta * meta, + const struct slbt_fd_ctx * fdctx) +{ + struct ar_meta_member_info ** memberp; + int fdout; + locale_t arloc; + + fdout = fdctx->fdout; + arloc = 0; + + if (dctx->cctx->fmtflags & SLBT_PRETTY_VERBOSE) { + arloc = newlocale(LC_ALL,setlocale(LC_ALL,0),0); + } + + if (slbt_dprintf(fdctx->fdout," - Members:\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + for (memberp=meta->a_memberv; *memberp; memberp++) { + switch ((*memberp)->ar_member_attr) { + case AR_MEMBER_ATTR_ARMAP: + case AR_MEMBER_ATTR_LINKINFO: + case AR_MEMBER_ATTR_NAMESTRS: + break; + + default: + if (arloc) { + if (slbt_au_output_one_member_yaml_verbose( + fdout,*memberp,arloc) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else { + if (slbt_au_output_one_member_yaml( + fdout,*memberp) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + } + + if (arloc) + freelocale(arloc); + + return 0; +} + +int slbt_au_output_members(const struct slbt_archive_meta * meta) +{ + const struct slbt_driver_ctx * dctx; + struct slbt_fd_ctx fdctx; + + dctx = (slbt_archive_meta_ictx(meta))->dctx; + + if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (!meta->a_memberv) + return 0; + + switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) { + case SLBT_PRETTY_YAML: + return slbt_au_output_members_yaml( + dctx,meta,&fdctx); + + case SLBT_PRETTY_POSIX: + return slbt_au_output_members_posix( + dctx,meta,&fdctx); + + default: + return slbt_au_output_members_yaml( + dctx,meta,&fdctx); + } +} diff --git a/src/arbits/output/slbt_au_output_symbols.c b/src/arbits/output/slbt_au_output_symbols.c new file mode 100644 index 0000000..950cde8 --- /dev/null +++ b/src/arbits/output/slbt_au_output_symbols.c @@ -0,0 +1,201 @@ +/*******************************************************************/ +/* 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 <time.h> +#include <locale.h> +#include <regex.h> +#include <inttypes.h> +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_output.h> +#include "slibtool_driver_impl.h" +#include "slibtool_dprintf_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_pecoff_impl.h" +#include "slibtool_tmpfile_impl.h" +#include "slibtool_ar_impl.h" + +#define SLBT_PRETTY_FLAGS (SLBT_PRETTY_YAML \ + | SLBT_PRETTY_POSIX \ + | SLBT_PRETTY_HEXDATA) + +static int slbt_au_output_symbols_posix( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * mctx, + int fdout) +{ + bool fsort; + bool fcoff; + const char * dot; + const char * mark; + const char * regex; + const char ** symv; + const char ** symstrv; + regex_t regctx; + regmatch_t pmatch[2] = {{0,0},{0,0}}; + char strbuf[4096]; + + fsort = !(dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_NOSORT); + fcoff = (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + if (fsort && !mctx->mapstrv) + if (slbt_update_mapstrv(dctx,mctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if ((regex = dctx->cctx->regex)) + if (regcomp(®ctx,regex,REG_EXTENDED|REG_NEWLINE)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + symstrv = fsort ? mctx->mapstrv : mctx->symstrv; + + for (symv=symstrv; *symv; symv++) { + if (!fcoff || slbt_is_strong_coff_symbol(*symv)) { + if (!regex || !regexec(®ctx,*symv,1,pmatch,0)) { + if (slbt_dprintf(fdout,"%s\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + + /* coff weak symbols: expsym = .weak.alias.strong */ + } else if (fcoff && !strncmp(*symv,".weak.",6)) { + mark = &(*symv)[6]; + dot = strchr(mark,'.'); + + strncpy(strbuf,mark,dot-mark); + strbuf[dot-mark] = '\0'; + + if (!regex || !regexec(®ctx,strbuf,1,pmatch,0)) + if (slbt_dprintf(fdout,"%s\n",strbuf) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + + if (regex) + regfree(®ctx); + + return 0; +} + +static int slbt_au_output_one_symbol_yaml( + int fdout, + struct slbt_archive_meta_impl * mctx, + const char * symname) +{ + struct ar_meta_symbol_info ** syminfv; + + for (syminfv=mctx->syminfv; *syminfv; syminfv++) + if (!strcmp(syminfv[0]->ar_symbol_name,symname)) + return slbt_dprintf( + fdout, + " - Symbol:\n" + " - [ object_name: " "%s" " ]\n" + " - [ symbol_name: " "%s" " ]\n" + " - [ symbol_type: " "%s" " ]\n\n", + syminfv[0]->ar_object_name, + symname, + syminfv[0]->ar_symbol_type); + + return 0; +} + +static int slbt_au_output_symbols_yaml( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * mctx, + int fdout) +{ + int fdtmp; + bool fsort; + bool fcoff; + const char * dot; + const char * mark; + const char * regex; + const char ** symv; + const char ** symstrv; + regex_t regctx; + regmatch_t pmatch[2] = {{0,0},{0,0}}; + char strbuf[4096]; + + fsort = !(dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_NOSORT); + fcoff = (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + if ((fdtmp = slbt_tmpfile()) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (fsort && !mctx->mapstrv) + if (slbt_update_mapstrv(dctx,mctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (slbt_ar_update_syminfo_ex(mctx->actx,fdtmp) < 0) + return SLBT_NESTED_ERROR(dctx); + + if ((regex = dctx->cctx->regex)) + if (regcomp(®ctx,regex,REG_EXTENDED|REG_NEWLINE)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + symstrv = fsort ? mctx->mapstrv : mctx->symstrv; + + if (slbt_dprintf(fdout," - Symbols:\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + for (symv=symstrv; *symv; symv++) { + if (!fcoff || slbt_is_strong_coff_symbol(*symv)) { + if (!regex || !regexec(®ctx,*symv,1,pmatch,0)) { + if (slbt_au_output_one_symbol_yaml( + fdout,mctx,*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + + /* coff weak symbols: expsym = .weak.alias.strong */ + } else if (fcoff && !strncmp(*symv,".weak.",6)) { + mark = &(*symv)[6]; + dot = strchr(mark,'.'); + + strncpy(strbuf,mark,dot-mark); + strbuf[dot-mark] = '\0'; + + if (!regex || !regexec(®ctx,strbuf,1,pmatch,0)) + if (slbt_au_output_one_symbol_yaml( + fdout,mctx,strbuf) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + + if (regex) + regfree(®ctx); + + return 0; +} + +int slbt_au_output_symbols(const struct slbt_archive_meta * meta) +{ + struct slbt_archive_meta_impl * mctx; + const struct slbt_driver_ctx * dctx; + int fdout; + + mctx = slbt_archive_meta_ictx(meta); + dctx = (slbt_archive_meta_ictx(meta))->dctx; + + fdout = slbt_driver_fdout(dctx); + + if (!meta->a_memberv) + return 0; + + switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) { + case SLBT_PRETTY_YAML: + return slbt_au_output_symbols_yaml( + dctx,mctx,fdout); + + case SLBT_PRETTY_POSIX: + return slbt_au_output_symbols_posix( + dctx,mctx,fdout); + + default: + return slbt_au_output_symbols_yaml( + dctx,mctx,fdout); + } +} diff --git a/src/arbits/slbt_archive_ctx.c b/src/arbits/slbt_archive_ctx.c new file mode 100644 index 0000000..575374c --- /dev/null +++ b/src/arbits/slbt_archive_ctx.c @@ -0,0 +1,117 @@ +/*******************************************************************/ +/* 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 <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_ar_impl.h" + +static int slbt_map_raw_archive( + const struct slbt_driver_ctx * dctx, + int fd, + const char * path, + int prot, + struct slbt_raw_archive * map) +{ + struct slbt_input mapinfo = {0,0}; + + if (slbt_fs_map_input(dctx,fd,path,prot,&mapinfo) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (mapinfo.size == 0) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_EMPTY_FILE); + + map->map_addr = mapinfo.addr; + map->map_size = mapinfo.size; + + return 0; +} + +static int slbt_unmap_raw_archive(struct slbt_raw_archive * map) +{ + struct slbt_input mapinfo; + + mapinfo.addr = map->map_addr; + mapinfo.size = map->map_size; + + return slbt_fs_unmap_input(&mapinfo); +} + +static int slbt_ar_free_archive_ctx_impl(struct slbt_archive_ctx_impl * ctx, int ret) +{ + if (ctx) { + slbt_ar_free_archive_meta(ctx->meta); + slbt_unmap_raw_archive(&ctx->map); + free(ctx->pathbuf); + free(ctx); + } + + return ret; +} + +int slbt_ar_get_archive_ctx( + const struct slbt_driver_ctx * dctx, + const char * path, + struct slbt_archive_ctx ** pctx) +{ + struct slbt_archive_ctx_impl * ctx; + struct slbt_archive_meta_impl * mctx; + int prot; + + if (!(ctx = calloc(1,sizeof(*ctx)))) + return SLBT_BUFFER_ERROR(dctx); + + slbt_driver_set_arctx( + dctx,0,path); + + prot = (dctx->cctx->actflags & SLBT_ACTION_MAP_READWRITE) + ? PROT_READ | PROT_WRITE + : PROT_READ; + + if (slbt_map_raw_archive(dctx,-1,path,prot,&ctx->map)) + return slbt_ar_free_archive_ctx_impl(ctx, + SLBT_NESTED_ERROR(dctx)); + + if (slbt_ar_get_archive_meta(dctx,&ctx->map,&ctx->meta)) + return slbt_ar_free_archive_ctx_impl(ctx, + SLBT_NESTED_ERROR(dctx)); + + if (!(ctx->pathbuf = strdup(path))) + return slbt_ar_free_archive_ctx_impl(ctx, + SLBT_NESTED_ERROR(dctx)); + + mctx = slbt_archive_meta_ictx(ctx->meta); + + ctx->dctx = dctx; + ctx->path = ctx->pathbuf; + ctx->actx.path = &ctx->path; + ctx->actx.map = &ctx->map; + ctx->actx.meta = ctx->meta; + mctx->actx = &ctx->actx; + + *pctx = &ctx->actx; + return 0; +} + +void slbt_ar_free_archive_ctx(struct slbt_archive_ctx * ctx) +{ + struct slbt_archive_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct slbt_archive_ctx_impl,actx); + ictx = (struct slbt_archive_ctx_impl *)addr; + slbt_ar_free_archive_ctx_impl(ictx,0); + } +} diff --git a/src/arbits/slbt_archive_dlsyms.c b/src/arbits/slbt_archive_dlsyms.c new file mode 100644 index 0000000..ed07602 --- /dev/null +++ b/src/arbits/slbt_archive_dlsyms.c @@ -0,0 +1,458 @@ +/*******************************************************************/ +/* 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_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_snprintf_impl.h" +#include "slibtool_errinfo_impl.h" + +static const char * slbt_strong_symname( + const char * symname, + bool fcoff, + char (*strbuf)[4096]) +{ + const char * dot; + const char * mark; + char * sym; + + if (fcoff) { + if (!strncmp(symname,"__imp_",6)) + return 0; + + if (strncmp(symname,".weak.",6)) + return symname; + + sym = *strbuf; + mark = &symname[6]; + dot = strchr(mark,'.'); + + strncpy(sym,mark,dot-mark); + sym[dot-mark] = '\0'; + + return sym; + } + + return symname; +} + + +static int slbt_ar_dlsyms_define_by_type( + int fdout, + const char * arname, + struct slbt_archive_meta_impl * mctx, + const char * desc, + const char stype) +{ + uint64_t idx; + uint64_t nsyms; + bool fcoff; + const char * symname; + char strbuf[4096]; + + for (idx=0,nsyms=0; idx<mctx->armaps.armap_nsyms; idx++) + if (mctx->syminfv[idx]->ar_symbol_type[0] == stype) + nsyms++; + + if (nsyms == 0) + return 0; + + fcoff = slbt_host_objfmt_is_coff(mctx->dctx); + fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + if (slbt_dprintf(fdout,"/* %s (%s) */\n",desc,arname) < 0) + return SLBT_SYSTEM_ERROR(mctx->dctx,0); + + for (idx=0; idx<mctx->armaps.armap_nsyms; idx++) + if (mctx->syminfv[idx]->ar_symbol_type[0] == stype) + if ((symname = slbt_strong_symname( + mctx->syminfv[idx]->ar_symbol_name, + fcoff,&strbuf))) + if (slbt_dprintf(fdout, + (stype == 'T') + ? "extern int %s();\n" + : "extern char %s[];\n", + symname) < 0) + return SLBT_SYSTEM_ERROR(mctx->dctx,0); + + if (slbt_dprintf(fdout,"\n") < 0) + return SLBT_SYSTEM_ERROR(mctx->dctx,0); + + return 0; +} + +static int slbt_ar_dlsyms_get_max_len_by_type( + int mlen, + struct slbt_archive_meta_impl * mctx, + const char stype) +{ + int len; + uint64_t idx; + bool fcoff; + const char * symname; + char strbuf[4096]; + + fcoff = slbt_host_objfmt_is_coff(mctx->dctx); + fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + for (idx=0; idx<mctx->armaps.armap_nsyms; idx++) + if (mctx->syminfv[idx]->ar_symbol_type[0] == stype) + if ((symname = slbt_strong_symname( + mctx->syminfv[idx]->ar_symbol_name, + fcoff,&strbuf))) + if ((len = strlen(symname)) > mlen) + mlen = len; + + return mlen; +} + +static int slbt_ar_dlsyms_add_by_type( + int fdout, + struct slbt_archive_meta_impl * mctx, + const char * fmt, + const char stype, + char (*namebuf)[4096]) +{ + uint64_t idx; + uint64_t nsyms; + bool fcoff; + const char * symname; + char strbuf[4096]; + + nsyms = 0; + symname = *namebuf; + + fcoff = slbt_host_objfmt_is_coff(mctx->dctx); + fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + for (idx=0; idx<mctx->armaps.armap_nsyms; idx++) + if (mctx->syminfv[idx]->ar_symbol_type[0] == stype) + nsyms++; + + if (nsyms == 0) + return 0; + + if (slbt_dprintf(fdout,"\n") < 0) + return SLBT_SYSTEM_ERROR(mctx->dctx,0); + + for (idx=0; idx<mctx->armaps.armap_nsyms; idx++) { + if (mctx->syminfv[idx]->ar_symbol_type[0] == stype) { + symname = slbt_strong_symname( + mctx->syminfv[idx]->ar_symbol_name, + fcoff,&strbuf); + + if (symname) { + if (slbt_snprintf(*namebuf,sizeof(*namebuf), + "%s\",",symname) < 0) + return SLBT_SYSTEM_ERROR(mctx->dctx,0); + + if (slbt_dprintf(fdout,fmt, + *namebuf, + (stype == 'T') ? "&" : "", + symname) < 0) + return SLBT_NESTED_ERROR(mctx->dctx); + } + } + } + + return 0; +} + + +static int slbt_ar_output_dlsyms_impl( + int fdout, + const struct slbt_driver_ctx * dctx, + struct slbt_archive_ctx ** arctxv, + const char * dsounit) +{ + int ret; + int idx; + unsigned len; + unsigned cmp; + const char * arname; + const char * soname; + struct slbt_archive_ctx * actx; + struct slbt_archive_ctx ** parctx; + struct slbt_archive_ctx_impl * ictx; + struct slbt_archive_meta_impl * mctx; + const struct slbt_source_version * verinfo; + char dlsymfmt[32]; + char cline[6][73]; + char symname[4096]; + + /* init */ + actx = arctxv[0]; + verinfo = slbt_api_source_version(); + + /* preamble */ + memset(cline[0],'*',72); + memset(cline[1],' ',72); + memset(cline[2],' ',72); + memset(cline[3],' ',72); + memset(cline[4],'*',72); + + memset(cline[5],0,72); + cline[5][0] = '\n'; + + len = snprintf(&cline[1][3],69, + "backward-compatible dlsym table"); + + cline[1][3+len] = ' '; + + len = snprintf(&cline[2][3],69, + "Generated by %s (slibtool %d.%d.%d)", + dctx->program, + verinfo->major,verinfo->minor,verinfo->revision); + + cline[2][3+len] = ' '; + + len = snprintf(&cline[3][3],69, + "[commit reference: %s]", + verinfo->commit); + + cline[3][3+len] = ' '; + + for (idx=0; idx<5; idx++) { + cline[idx][0] = '/'; + cline[idx][1] = '*'; + + cline[idx][70] = '*'; + cline[idx][71] = '/'; + + cline[idx][72] = '\n'; + } + + if (slbt_dprintf(fdout,"%s",&cline[0]) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_dprintf(fdout, + "#ifdef __cplusplus\n" + "extern \"C\" {\n" + "#endif\n\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + /* declarations */ + for (parctx=arctxv; *parctx; parctx++) { + actx = *parctx; + ictx = slbt_get_archive_ictx(actx); + mctx = slbt_archive_meta_ictx(ictx->meta); + + if ((arname = strrchr(*actx->path,'/'))) + arname++; + + if (!arname) + arname = *actx->path; + + ret = slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Absolute Values", 'A'); + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: BSS Section", 'B'); + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Common Section", 'C'); + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Initialized Data", 'D'); + + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Small Globals", 'G'); + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Indirect References", 'I'); + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Read-Only Section", 'R'); + + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Small Objects", 'S'); + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Weak Symbols", 'W'); + + ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Text Section: Public Interfaces", 'T'); + + if (ret < 0) + return SLBT_NESTED_ERROR(dctx); + + } + + /* vtable struct definition */ + if (slbt_dprintf(fdout, + "/* name-address Public ABI struct definition */\n" + "struct lt_dlsym_symdef {\n" + "\tconst char * dlsym_name;\n" + "\tvoid * dlsym_addr;\n" + "};\n\n") < 0) + return SLBT_NESTED_ERROR(dctx); + + soname = (strcmp(dsounit,"@PROGRAM@")) ? dsounit : "_PROGRAM_"; + + if (slbt_dprintf(fdout, + "/* dlsym vtable */\n" + "extern const struct lt_dlsym_symdef " + "lt_%s_LTX_preloaded_symbols[];\n\n" + "const struct lt_dlsym_symdef " + "lt_%s_LTX_preloaded_symbols[] = {\n", + soname,soname) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* align dlsym_name and dlsym_addr columsn (because we can) */ + for (parctx=arctxv,len=0; *parctx; parctx++) { + actx = *parctx; + ictx = slbt_get_archive_ictx(actx); + mctx = slbt_archive_meta_ictx(ictx->meta); + + if ((arname = strrchr(*actx->path,'/'))) + arname++; + + if (!arname) + arname = *actx->path; + + if (len < (cmp = strlen(arname))) + len = cmp; + + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'A'); + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'B'); + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'C'); + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'D'); + + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'G'); + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'I'); + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'R'); + + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'S'); + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'T'); + len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'W'); + } + + /* quote, comma */ + len += 2; + + if (len >= sizeof(symname)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + /* aligned print format */ + snprintf(dlsymfmt,sizeof(dlsymfmt),"\t{\"%%-%ds %%s%%s},\n",len); + + /* dso unit */ + if (slbt_snprintf(symname,sizeof(symname),"%s\",",dsounit) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_dprintf(fdout,dlsymfmt,symname,"","0") < 0) + return SLBT_NESTED_ERROR(dctx); + + /* (-dlopen force) */ + if (!arctxv[0]->meta->a_memberv) + if (!strcmp(*arctxv[0]->path,"@PROGRAM@")) + arctxv++; + + /* at long last */ + for (parctx=arctxv; *parctx; parctx++) { + actx = *parctx; + ictx = slbt_get_archive_ictx(actx); + mctx = slbt_archive_meta_ictx(ictx->meta); + + if ((arname = strrchr(*actx->path,'/'))) + arname++; + + if (!arname) + arname = *actx->path; + + if (slbt_dprintf(fdout,"\n") < 0) + return SLBT_NESTED_ERROR(mctx->dctx); + + if (slbt_snprintf(symname,sizeof(symname),"%s\",",arname) < 0) + return SLBT_SYSTEM_ERROR(mctx->dctx,0); + + if (slbt_dprintf(fdout,dlsymfmt,symname,"","0") < 0) + return SLBT_NESTED_ERROR(mctx->dctx); + + ret = slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'A',&symname); + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'B',&symname); + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'C',&symname); + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'D',&symname); + + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'G',&symname); + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'I',&symname); + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'R',&symname); + + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'S',&symname); + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'S',&symname); + ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'T',&symname); + + if (ret < 0) + return SLBT_NESTED_ERROR(dctx); + } + + /* null-terminate the vtable */ + if (slbt_dprintf(fdout,"\n\t{%d,%*c%d}\n",0,len,' ',0) < 0) + return SLBT_NESTED_ERROR(mctx->dctx); + + /* close vtable, wrap translation unit */ + if (slbt_dprintf(fdout, + "};\n\n" + "#ifdef __cplusplus\n" + "}\n" + "#endif\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + return 0; +} + + +static int slbt_ar_create_dlsyms_impl( + struct slbt_archive_ctx ** arctxv, + const char * dlunit, + const char * path, + mode_t mode) +{ + int ret; + struct slbt_archive_ctx ** actx; + struct slbt_exec_ctx * ectx; + struct slbt_archive_meta_impl * mctx; + const struct slbt_driver_ctx * dctx; + struct slbt_fd_ctx fdctx; + int fdout; + + mctx = slbt_archive_meta_ictx(arctxv[0]->meta); + dctx = mctx->dctx; + ectx = 0; + + if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (path) { + if ((fdout = openat( + fdctx.fdcwd,path, + O_WRONLY|O_CREAT|O_TRUNC, + mode)) < 0) + return SLBT_SYSTEM_ERROR(dctx,path); + } else { + fdout = fdctx.fdout; + } + + for (actx=arctxv; *actx; actx++) { + mctx = slbt_archive_meta_ictx((*actx)->meta); + + if (!mctx->syminfo && !ectx) + if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (!mctx->syminfo) + if (slbt_ar_update_syminfo(*actx) < 0) + return SLBT_NESTED_ERROR(dctx); + } + + if (ectx) + slbt_ectx_free_exec_ctx(ectx); + + ret = slbt_ar_output_dlsyms_impl( + fdout,dctx,arctxv,dlunit); + + if (path) { + close(fdout); + } + + return ret; +} + + +int slbt_ar_create_dlsyms( + struct slbt_archive_ctx ** arctxv, + const char * dlunit, + const char * path, + mode_t mode) +{ + return slbt_ar_create_dlsyms_impl(arctxv,dlunit,path,mode); +} diff --git a/src/arbits/slbt_archive_mapfile.c b/src/arbits/slbt_archive_mapfile.c new file mode 100644 index 0000000..18f94dc --- /dev/null +++ b/src/arbits/slbt_archive_mapfile.c @@ -0,0 +1,162 @@ +/*******************************************************************/ +/* 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 <time.h> +#include <locale.h> +#include <regex.h> +#include <inttypes.h> +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_output.h> +#include "slibtool_driver_impl.h" +#include "slibtool_dprintf_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_pecoff_impl.h" +#include "slibtool_ar_impl.h" + +/********************************************************/ +/* Generate a symbol mapfile (aka version script) that */ +/* could be passed to the host linker. */ +/* */ +/* Since the symbol list is directly derived from the */ +/* archive's armap member, prepending symbol names with */ +/* an underscore (where relevant) is not necessary. */ +/********************************************************/ + +static int slbt_ar_output_mapfile_impl( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * mctx, + int fdout) +{ + bool fsort; + bool fcoff; + bool fmach; + const char * dot; + const char * mark; + const char * regex; + const char ** symv; + const char ** symstrv; + regex_t regctx; + regmatch_t pmatch[2] = {{0,0},{0,0}}; + char strbuf[4096]; + + fsort = !(dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_NOSORT); + + fmach = slbt_host_objfmt_is_macho(dctx); + fmach |= (mctx->ofmtattr & AR_OBJECT_ATTR_MACHO); + + fcoff = slbt_host_objfmt_is_coff(dctx); + fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + if (fcoff) { + if (slbt_dprintf(fdout,"EXPORTS\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else if (fmach) { + if (slbt_dprintf(fdout,"# export_list, armap underscores\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else { + if (slbt_dprintf(fdout,"{\n" "\t" "global:\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + + if (fsort && !mctx->mapstrv) + if (slbt_update_mapstrv(dctx,mctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if ((regex = dctx->cctx->regex)) + if (regcomp(®ctx,regex,REG_EXTENDED|REG_NEWLINE)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + symstrv = fsort ? mctx->mapstrv : mctx->symstrv; + + for (symv=symstrv; *symv; symv++) { + if (!fcoff || slbt_is_strong_coff_symbol(*symv)) { + if (!regex || !regexec(®ctx,*symv,1,pmatch,0)) { + if (fcoff) { + if (slbt_dprintf(fdout," %s\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else if (fmach) { + if (slbt_dprintf(fdout,"%s\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else { + if (slbt_dprintf(fdout,"\t\t%s;\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + /* coff weak symbols: expsym = .weak.alias.strong */ + } else if (fcoff && !strncmp(*symv,".weak.",6)) { + mark = &(*symv)[6]; + dot = strchr(mark,'.'); + + strncpy(strbuf,mark,dot-mark); + strbuf[dot-mark] = '\0'; + + if (!regex || !regexec(®ctx,strbuf,1,pmatch,0)) + if (slbt_dprintf(fdout," %s = %s\n",strbuf,++dot) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + + if (regex) + regfree(®ctx); + + if (!fcoff && !fmach) + if (slbt_dprintf(fdout,"\n\t" "local:\n" "\t\t*;\n" "};\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + return 0; +} + + +static int slbt_ar_create_mapfile_impl( + const struct slbt_archive_meta * meta, + const char * path, + mode_t mode) +{ + int ret; + struct slbt_archive_meta_impl * mctx; + const struct slbt_driver_ctx * dctx; + struct slbt_fd_ctx fdctx; + int fdout; + + mctx = slbt_archive_meta_ictx(meta); + dctx = (slbt_archive_meta_ictx(meta))->dctx; + + if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (!meta->a_memberv) + return 0; + + if (path) { + if ((fdout = openat( + fdctx.fdcwd,path, + O_WRONLY|O_CREAT|O_TRUNC, + mode)) < 0) + return SLBT_SYSTEM_ERROR(dctx,path); + } else { + fdout = fdctx.fdout; + } + + ret = slbt_ar_output_mapfile_impl( + dctx,mctx,fdout); + + if (path) { + close(fdout); + } + + return ret; +} + + +int slbt_ar_create_mapfile( + const struct slbt_archive_meta * meta, + const char * path, + mode_t mode) +{ + return slbt_ar_create_mapfile_impl(meta,path,mode); +} diff --git a/src/arbits/slbt_archive_mapstrv.c b/src/arbits/slbt_archive_mapstrv.c new file mode 100644 index 0000000..e97db76 --- /dev/null +++ b/src/arbits/slbt_archive_mapstrv.c @@ -0,0 +1,47 @@ +/*******************************************************************/ +/* 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 <inttypes.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" +#include "slibtool_coff_impl.h" + +static int slbt_qsort_strcmp(const void * a, const void * b) +{ + return strcmp(*(const char **)a,*(const char **)b); +} + +slbt_hidden int slbt_update_mapstrv( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * mctx) +{ + bool fcoff; + size_t nsyms; + const char ** symv; + const char ** mapstrv; + + fcoff = slbt_host_objfmt_is_coff(dctx); + fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + for (nsyms=0,symv=mctx->symstrv; *symv; symv++) + nsyms++; + + if (!(mapstrv = calloc(nsyms+1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + for (nsyms=0,symv=mctx->symstrv; *symv; symv++) + mapstrv[nsyms++] = *symv; + + qsort(mapstrv,nsyms,sizeof(const char *),fcoff ? slbt_coff_qsort_strcmp : slbt_qsort_strcmp); + + mctx->mapstrv = mapstrv; + + return 0; +} diff --git a/src/arbits/slbt_archive_merge.c b/src/arbits/slbt_archive_merge.c new file mode 100644 index 0000000..5f29235 --- /dev/null +++ b/src/arbits/slbt_archive_merge.c @@ -0,0 +1,734 @@ +/*******************************************************************/ +/* 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 <time.h> +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <sys/mman.h> +#include <sys/types.h> + +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_arbits.h> +#include "slibtool_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" + +/* anonymous fun */ +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +/* time stamp format specifier */ +#define PPRII64 "%"PRIi64 + +/* file size format specifier */ +#define PPRIU64 "%"PRIu64 + +/* dlopen self/force */ +static const char slbt_ar_self_dlunit[] = "@PROGRAM@"; + +struct armap_buffer_32 { + uint32_t moffset; + const char * symname; + uint32_t baseidx; +}; + +struct armap_buffer_64 { + uint64_t moffset; + const char * symname; + uint64_t baseidx; +}; + +static const char ar_signature[] = AR_SIGNATURE; + +static int slbt_create_anonymous_archive_ctx( + const struct slbt_driver_ctx * dctx, + size_t size, + struct slbt_archive_ctx ** pctx) +{ + struct slbt_archive_ctx_impl * ctx; + + if (!(ctx = calloc(1,sizeof(*ctx)))) + return SLBT_BUFFER_ERROR(dctx); + + ctx->map.map_size = size; + ctx->map.map_addr = mmap( + 0,size, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + -1,0); + + if (ctx->map.map_addr == MAP_FAILED) { + free(ctx); + return SLBT_SYSTEM_ERROR(dctx,0); + } + + ctx->dctx = dctx; + ctx->actx.map = &ctx->map; + + *pctx = &ctx->actx; + + return 0; +} + +static off_t slbt_armap_write_be_32(unsigned char * mark, uint32_t val) +{ + mark[0] = val >> 24; + mark[1] = val >> 16; + mark[2] = val >> 8; + mark[3] = val; + + return sizeof(uint32_t); +} + +static off_t slbt_armap_write_le_32(unsigned char * mark, uint32_t val) +{ + mark[0] = val; + mark[1] = val >> 8; + mark[2] = val >> 16; + mark[3] = val >> 24; + + return sizeof(uint32_t); +} + +static off_t slbt_armap_write_be_64(unsigned char * mark, uint64_t val) +{ + slbt_armap_write_be_32(&mark[0],val >> 32); + slbt_armap_write_be_32(&mark[4],val); + + return sizeof(uint64_t); +} + +static off_t slbt_armap_write_le_64(unsigned char * mark, uint64_t val) +{ + slbt_armap_write_be_32(&mark[0],val); + slbt_armap_write_be_32(&mark[4],val >> 32); + + return sizeof(uint64_t); +} + + +static int slbt_ar_merge_archives_fail( + struct slbt_archive_ctx * arctx, + struct armap_buffer_32 * bsdmap32, + struct armap_buffer_64 * bsdmap64, + int ret) +{ + if (bsdmap32) + free(bsdmap32); + + if (bsdmap64) + free(bsdmap64); + + if (arctx) + slbt_ar_free_archive_ctx(arctx); + + return ret; +} + + +int slbt_ar_merge_archives( + struct slbt_archive_ctx * const arctxv[], + struct slbt_archive_ctx ** arctxm) +{ + struct slbt_archive_ctx * const * arctxp; + struct slbt_archive_ctx * arctx; + + const struct slbt_driver_ctx * dctx; + const struct slbt_archive_meta * meta; + + struct ar_raw_file_header * arhdr; + struct ar_meta_member_info ** memberp; + struct ar_meta_member_info * meminfo; + + struct ar_meta_member_info * armap; + struct ar_meta_member_info * arnames; + + const struct ar_meta_armap_common_32 * armap32; + const struct ar_meta_armap_common_64 * armap64; + const struct ar_meta_armap_ref_32 * symref32; + const struct ar_meta_armap_ref_64 * symref64; + + struct armap_buffer_32 * bsdmap32; + struct armap_buffer_64 * bsdmap64; + struct armap_buffer_32 * bsdsort32; + struct armap_buffer_64 * bsdsort64; + + size_t nbytes; + ssize_t nwritten; + + uint32_t mapattr; + uint64_t nmembers; + uint64_t nsymrefs; + + uint64_t sarmap; + uint64_t sarname; + uint64_t sarchive; + uint64_t smembers; + uint64_t ssymrefs; + uint64_t ssymstrs; + uint64_t snamestrs; + + int64_t omembers; + int64_t osymrefs; + int64_t onamestrs; + int64_t omemfixup; + + char * base; + unsigned char * ubase; + + char * ch; + unsigned char * uch; + + char * namebase; + char * namestr; + char * strtbl; + + uint64_t idx; + uint64_t mapidx; + uint64_t cmpidx; + + off_t (*armap_write_uint32)( + unsigned char *, + uint32_t); + + off_t (*armap_write_uint64)( + unsigned char *, + uint64_t); + + /* init */ + nmembers = nsymrefs = ssymstrs = mapattr = 0; + sarchive = smembers = ssymrefs = snamestrs = 0; + omembers = osymrefs = onamestrs = 0; + + if (!arctxv || !arctxv[0]) + return -1; + + if (!(dctx = slbt_get_archive_ictx(arctxv[0])->dctx)) + return -1; + + /* determine armap type and size of archive elements */ + for (armap=0,arnames=0,arctxp=arctxv; *arctxp; arctxp++) { + if (slbt_get_archive_ictx(*arctxp)->dctx != dctx) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_DRIVER_MISMATCH); + + meta = (*arctxp)->meta; + armap32 = meta->a_armap_primary.ar_armap_common_32; + armap64 = meta->a_armap_primary.ar_armap_common_64; + + for (memberp=meta->a_memberv; memberp && *memberp; memberp++) { + meminfo = *memberp; + + switch (meminfo->ar_member_attr) { + case AR_MEMBER_ATTR_ARMAP: + if (armap32) { + if (mapattr == 0) { + armap = meminfo; + mapattr = armap32->ar_armap_attr; + } else if (mapattr != armap32->ar_armap_attr) { + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_ARMAP_MISMATCH); + } + + nsymrefs += armap32->ar_num_of_symbols; + ssymstrs += armap32->ar_size_of_strs; + + } else if (armap64) { + if (mapattr == 0) { + armap = meminfo; + mapattr = armap64->ar_armap_attr; + } else if (mapattr != armap64->ar_armap_attr) { + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_ARMAP_MISMATCH); + } + + nsymrefs += armap64->ar_num_of_symbols; + } + + break; + + case AR_MEMBER_ATTR_LINKINFO: + break; + + case AR_MEMBER_ATTR_NAMESTRS: + snamestrs += meminfo->ar_object_size; + + if (!arnames) + arnames = meminfo; + + break; + + default: + smembers += sizeof(struct ar_raw_file_header); + smembers += meminfo->ar_file_header.ar_file_size; + smembers += 1; + smembers |= 1; + smembers ^= 1; + nmembers++; + + break; + } + } + } + + /* armap size */ + if (sarmap = 0, sarname = 0, (mapattr == 0)) { + (void)0; + + } else if (mapattr & AR_ARMAP_ATTR_SYSV) { + if (mapattr & (AR_ARMAP_ATTR_LE_32|AR_ARMAP_ATTR_BE_32)) { + sarmap += sizeof(uint32_t); + sarmap += sizeof(uint32_t) * nsymrefs; + } else { + sarmap += sizeof(uint64_t); + sarmap += sizeof(uint64_t) * nsymrefs; + } + + } else if (mapattr & AR_ARMAP_ATTR_BSD) { + if (mapattr & (AR_ARMAP_ATTR_LE_32|AR_ARMAP_ATTR_BE_32)) { + sarmap += 2 * sizeof(uint32_t); + sarmap += 2 * sizeof(uint32_t) * nsymrefs; + } else { + sarmap += 2 * sizeof(uint64_t); + sarmap += 2 * sizeof(uint64_t) * nsymrefs; + } + + sarname += armap->ar_file_header.ar_file_size; + sarname -= armap->ar_object_size; + } else { + return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR); + } + + ssymstrs += 1; + ssymstrs |= 1; + ssymstrs ^= 1; + + /* (debugging) */ + (void)nmembers; + + /* long-names member alignment */ + snamestrs += 1; + snamestrs |= 1; + snamestrs ^= 1; + + /* archive size */ + sarchive = sizeof(struct ar_raw_signature); + sarchive += armap ? sizeof(struct ar_raw_file_header) : 0; + sarchive += arnames ? sizeof(struct ar_raw_file_header) : 0; + sarchive += sarname; + sarchive += sarmap; + sarchive += ssymstrs; + sarchive += snamestrs; + sarchive += smembers; + + /* offset from archive base to first public member */ + omembers = sarchive; + omembers -= smembers; + + + /* create in-memory archive */ + if (slbt_create_anonymous_archive_ctx(dctx,sarchive,&arctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + + /* get ready for writing */ + base = arctx->map->map_addr; + ubase = arctx->map->map_addr; + + + /* archive header */ + ch = base; + memcpy(ch,ar_signature,sizeof(struct ar_raw_signature)); + ch += sizeof(struct ar_raw_signature); + + + /* armap header */ + if (armap) { + arhdr = (struct ar_raw_file_header *)ch; + memcpy(arhdr,armap->ar_member_data,sizeof(*arhdr)+sarname); + + nwritten = armap->ar_file_header.ar_time_date_stamp + ? sprintf(arhdr->ar_time_date_stamp,PPRII64,time(0)) + : 0; + + if (nwritten < 0) + return slbt_ar_merge_archives_fail( + arctx,0,0, + SLBT_SYSTEM_ERROR(dctx,0)); + + for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_time_date_stamp); nbytes++) + arhdr->ar_time_date_stamp[nbytes] = AR_DEC_PADDING; + + nwritten = sprintf( + arhdr->ar_file_size,PPRIU64, + sarname + sarmap + ssymstrs); + + if (nwritten < 0) + return slbt_ar_merge_archives_fail( + arctx,0,0, + SLBT_SYSTEM_ERROR(dctx,0)); + + for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_size); nbytes++) + arhdr->ar_file_size[nbytes] = AR_DEC_PADDING; + } + + + /* arnames header (sysv only) */ + if (arnames) { + ch = base; + ch += omembers; + ch -= snamestrs; + ch -= sizeof(struct ar_raw_file_header); + + namebase = ch; + namebase += sizeof(struct ar_raw_file_header); + + memset(namebase,0,snamestrs); + namestr = namebase; + + arhdr = (struct ar_raw_file_header *)ch; + memcpy(arhdr,arnames->ar_member_data,sizeof(*arhdr)); + + nwritten = arnames->ar_file_header.ar_time_date_stamp + ? sprintf(arhdr->ar_time_date_stamp,PPRII64,time(0)) + : 0; + + if (nwritten < 0) + return slbt_ar_merge_archives_fail( + arctx,0,0, + SLBT_SYSTEM_ERROR(dctx,0)); + + for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_time_date_stamp); nbytes++) + arhdr->ar_time_date_stamp[nbytes] = AR_DEC_PADDING; + + nwritten = sprintf( + arhdr->ar_file_size,PPRIU64, + snamestrs); + + if (nwritten < 0) + return slbt_ar_merge_archives_fail( + arctx,0,0, + SLBT_SYSTEM_ERROR(dctx,0)); + + for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_size); nbytes++) + arhdr->ar_file_size[nbytes] = AR_DEC_PADDING; + } + + + /* armap data (preparation) */ + armap_write_uint32 = 0; + armap_write_uint64 = 0; + + bsdmap32 = 0; + bsdmap64 = 0; + + if (mapattr & AR_ARMAP_ATTR_BE_32) + armap_write_uint32 = slbt_armap_write_be_32; + + else if (mapattr & AR_ARMAP_ATTR_LE_32) + armap_write_uint32 = slbt_armap_write_le_32; + + else if (mapattr & AR_ARMAP_ATTR_BE_64) + armap_write_uint64 = slbt_armap_write_be_64; + + else if (mapattr & AR_ARMAP_ATTR_LE_64) + armap_write_uint64 = slbt_armap_write_le_64; + + uch = ubase; + uch += sizeof(struct ar_raw_signature); + uch += sizeof(struct ar_raw_file_header); + uch += sarname; + + if (mapattr & AR_ARMAP_ATTR_SYSV) { + if (armap_write_uint32) { + uch += armap_write_uint32(uch,nsymrefs); + + ch = base; + ch += uch - ubase; + ch += sizeof(uint32_t) * nsymrefs; + } else { + uch += armap_write_uint64(uch,nsymrefs); + + ch = base; + ch += uch - ubase; + ch += sizeof(uint64_t) * nsymrefs; + } + + } else if (mapattr & AR_ARMAP_ATTR_BSD) { + strtbl = base; + strtbl += omembers; + strtbl -= ssymstrs; + + memset(strtbl,0,ssymstrs); + + if (armap_write_uint32) { + if (!(bsdmap32 = calloc(2*nsymrefs,sizeof(struct armap_buffer_32)))) + return slbt_ar_merge_archives_fail( + arctx,0,0, + SLBT_SYSTEM_ERROR(dctx,0)); + + bsdsort32 = &bsdmap32[nsymrefs]; + + } else { + if (!(bsdmap64 = calloc(2*nsymrefs,sizeof(struct armap_buffer_64)))) + return slbt_ar_merge_archives_fail( + arctx,0,0, + SLBT_SYSTEM_ERROR(dctx,0)); + + bsdsort64 = &bsdmap64[nsymrefs]; + } + } + + /* main iteration (armap data, long-names, public members) */ + for (mapidx=0,arctxp=arctxv; *arctxp; arctxp++) { + meta = (*arctxp)->meta; + armap32 = meta->a_armap_primary.ar_armap_common_32; + armap64 = meta->a_armap_primary.ar_armap_common_64; + + if ((memberp = meta->a_memberv)) { + for (omemfixup=0; *memberp && !omemfixup; memberp++) { + meminfo = *memberp; + + switch (meminfo->ar_member_attr) { + case AR_MEMBER_ATTR_ARMAP: + case AR_MEMBER_ATTR_LINKINFO: + case AR_MEMBER_ATTR_NAMESTRS: + break; + + default: + omemfixup = (int64_t)meminfo->ar_member_data; + omemfixup -= (int64_t)meta->r_archive.map_addr; + break; + } + } + } + + for (memberp=meta->a_memberv; memberp && *memberp; memberp++) { + meminfo = *memberp; + + switch (meminfo->ar_member_attr) { + case AR_MEMBER_ATTR_ARMAP: + if (armap32 && (mapattr & AR_ARMAP_ATTR_SYSV)) { + symref32 = armap32->ar_symrefs; + + for (idx=0; idx<armap32->ar_num_of_symbols; idx++) { + uch += armap_write_uint32( + uch, + symref32[idx].ar_member_offset + omembers - omemfixup); + + strcpy(ch,&armap32->ar_string_table[symref32[idx].ar_name_offset]); + ch += strlen(ch); + ch++; + } + + } else if (armap64 && (mapattr & AR_ARMAP_ATTR_SYSV)) { + symref64 = armap64->ar_symrefs; + + for (idx=0; idx<armap64->ar_num_of_symbols; idx++) { + uch += armap_write_uint64( + uch, + symref64[idx].ar_member_offset + omembers - omemfixup); + + strcpy(ch,&armap64->ar_string_table[symref64[idx].ar_name_offset]); + ch += strlen(ch); + ch++; + } + + } else if (armap32 && (mapattr & AR_ARMAP_ATTR_BSD)) { + symref32 = armap32->ar_symrefs; + + for (idx=0; idx<armap32->ar_num_of_symbols; idx++) { + bsdmap32[mapidx].moffset = symref32[idx].ar_member_offset; + bsdmap32[mapidx].moffset += omembers - omemfixup; + + bsdmap32[mapidx].symname = armap32->ar_string_table; + bsdmap32[mapidx].symname += symref32[idx].ar_name_offset; + + mapidx++; + } + + } else if (armap64 && (mapattr & AR_ARMAP_ATTR_BSD)) { + symref64 = armap64->ar_symrefs; + + for (idx=0; idx<armap64->ar_num_of_symbols; idx++) { + bsdmap64[mapidx].moffset = symref64[idx].ar_member_offset; + bsdmap64[mapidx].moffset += omembers - omemfixup; + + bsdmap64[mapidx].symname = armap64->ar_string_table; + bsdmap64[mapidx].symname += symref64[idx].ar_name_offset; + + mapidx++; + } + } + + break; + + case AR_MEMBER_ATTR_LINKINFO: + break; + + case AR_MEMBER_ATTR_NAMESTRS: + break; + + default: + arhdr = meminfo->ar_member_data; + + memcpy( + &base[omembers],arhdr, + sizeof(*arhdr) + meminfo->ar_file_header.ar_file_size); + + if (meminfo->ar_file_header.ar_header_attr & AR_HEADER_ATTR_SYSV) { + if (meminfo->ar_file_header.ar_header_attr & AR_HEADER_ATTR_NAME_REF) { + nwritten = sprintf( + &base[omembers],"/"PPRII64, + namestr - namebase); + + if (nwritten < 0) + SLBT_SYSTEM_ERROR(dctx,0); + + for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_id); nbytes++) + base[omembers + nbytes] = AR_DEC_PADDING; + + strcpy(namestr,meminfo->ar_file_header.ar_member_name); + namestr += strlen(namestr); + *namestr++ = '/'; + *namestr++ = AR_OBJ_PADDING; + } + } + + omembers += sizeof(*arhdr); + omembers += meminfo->ar_file_header.ar_file_size; + omembers += 1; + omembers |= 1; + omembers ^= 1; + break; + } + } + } + + /* bsd variant: also sort the string table (because we can:=)) */ + if (bsdmap32) { + for (mapidx=0; mapidx<nsymrefs; mapidx++) + for (cmpidx=0; cmpidx<nsymrefs; cmpidx++) + if (strcmp(bsdmap32[cmpidx].symname,bsdmap32[mapidx].symname) < 0) + bsdmap32[mapidx].baseidx++; + + /* a symbol might be present in more than one member; */ + /* see whether ar_member_offset has already been set) */ + for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) { + idx = bsdmap32[mapidx].baseidx; + + for (; bsdsort32[idx].moffset; ) + idx++; + + bsdsort32[idx].moffset = bsdmap32[mapidx].moffset; + bsdsort32[idx].symname = bsdmap32[mapidx].symname; + } + + uch += armap_write_uint32(uch,2*sizeof(uint32_t)*nsymrefs); + + for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) { + uch += armap_write_uint32(uch,ch-strtbl); + uch += armap_write_uint32(uch,bsdsort32[mapidx].moffset); + + strcpy(ch,bsdsort32[mapidx].symname); + ch += strlen(ch); + ch++; + } + + uch += armap_write_uint32(uch,ssymstrs); + + free(bsdmap32); + + } else if (bsdmap64) { + for (mapidx=0; mapidx<nsymrefs; mapidx++) + for (cmpidx=0; cmpidx<nsymrefs; cmpidx++) + if (strcmp(bsdmap64[cmpidx].symname,bsdmap64[mapidx].symname) < 0) + bsdmap64[mapidx].baseidx++; + + /* a symbol might be present in more than one member; */ + /* see whether ar_member_offset has already been set) */ + for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) { + idx = bsdmap64[mapidx].baseidx; + + for (; bsdsort64[idx].moffset; ) + idx++; + + bsdsort64[idx].moffset = bsdmap64[mapidx].moffset; + bsdsort64[idx].symname = bsdmap64[mapidx].symname; + } + + uch += armap_write_uint64(uch,2*sizeof(uint64_t)*nsymrefs); + + for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) { + uch += armap_write_uint64(uch,ch-strtbl); + uch += armap_write_uint64(uch,bsdsort64[mapidx].moffset); + + strcpy(ch,bsdsort64[mapidx].symname); + ch += strlen(ch); + ch++; + } + + uch += armap_write_uint64(uch,ssymstrs); + + free(bsdmap64); + } + + struct slbt_archive_ctx_impl * ictx; + ictx = slbt_get_archive_ictx(arctx); + + if (slbt_ar_get_archive_meta(dctx,arctx->map,&ictx->meta) < 0) + return slbt_ar_merge_archives_fail( + arctx,0,0, + SLBT_NESTED_ERROR(dctx)); + + ictx->actx.meta = ictx->meta; + + *arctxm = arctx; + + return 0; +} + + +int slbt_ar_get_varchive_ctx( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_ctx ** pctx) +{ + struct slbt_archive_ctx * ctx; + struct slbt_archive_ctx_impl * ictx; + void * base; + size_t size; + + size = sizeof(struct ar_raw_signature); + + if (slbt_create_anonymous_archive_ctx(dctx,size,&ctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + ictx = slbt_get_archive_ictx(ctx); + + base = ctx->map->map_addr; + memcpy(base,ar_signature,size); + + if (slbt_ar_get_archive_meta(dctx,ctx->map,&ictx->meta) < 0) { + slbt_ar_free_archive_ctx(ctx); + return SLBT_NESTED_ERROR(dctx); + } + + ictx->path = slbt_ar_self_dlunit; + ictx->actx.meta = ictx->meta; + ictx->actx.path = &ictx->path; + + *pctx = ctx; + + return 0; +} diff --git a/src/arbits/slbt_archive_meta.c b/src/arbits/slbt_archive_meta.c new file mode 100644 index 0000000..8ef816c --- /dev/null +++ b/src/arbits/slbt_archive_meta.c @@ -0,0 +1,888 @@ +/*******************************************************************/ +/* 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 <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> + +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_arbits.h> +#include "slibtool_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" + +/* transient header info vector */ +struct ar_header_info { + struct ar_raw_file_header * phdr; + uint32_t attr; +}; + +static const char ar_signature[] = AR_SIGNATURE; + +static int slbt_ar_free_archive_meta_impl(struct slbt_archive_meta_impl * meta, int ret) +{ + if (meta) { + if (meta->armaps.armap_symrefs_32) + free(meta->armaps.armap_symrefs_32); + + if (meta->armaps.armap_symrefs_64) + free(meta->armaps.armap_symrefs_64); + + if (meta->hdrinfov) + free(meta->hdrinfov); + + if (meta->namestrs) + free(meta->namestrs); + + if (meta->syminfo) + free(meta->syminfo); + + if (meta->syminfv) + free(meta->syminfv); + + if (meta->memberv) + free(meta->memberv); + + if (meta->offsetv) + free(meta->offsetv); + + if (meta->members) + free(meta->members); + + if (meta->symstrv) + free(meta->symstrv); + + if (meta->mapstrv) + free(meta->mapstrv); + + if (meta->nminfo) + slbt_lib_free_txtfile_ctx(meta->nminfo); + + free(meta); + } + + return ret; +} + + +static int slbt_ar_read_octal(const char * mark, int len, uint32_t * dec) +{ + int i; + uint64_t res; + + for (; len && (mark[len-1]==AR_DEC_PADDING); ) + len--; + + for (i=0,res=0; i<len; i++) { + if ((mark[i] >= '0') && (mark[i] <= '7')) { + res *= 8; + res += (mark[i] - '0'); + } else { + return -1; + } + } + + *dec = res; + + return 0; +} + +static int slbt_ar_read_decimal_64(const char * mark, int len, uint64_t * dec) +{ + int i; + uint64_t res; + + for (; len && (mark[len-1]==AR_DEC_PADDING); ) + len--; + + for (i=0,res=0; i<len; i++) { + if ((mark[i] >= '0') && (mark[i] <= '9')) { + res *= 10; + res += (mark[i] - '0'); + } else { + return -1; + } + } + + *dec = res; + + return 0; +} + +static int slbt_ar_read_decimal_32(const char * mark, int len, uint32_t * dec) +{ + uint64_t res; + + if (slbt_ar_read_decimal_64(mark,len,&res) < 0) + return -1; + + *dec = res; + + return 0; +} + +static uint32_t slbt_ar_get_member_attr(struct ar_meta_member_info * m) +{ + const char * hdrname; + uint32_t hdrattr; + const char * data; + const char * data_cap; + const unsigned char * udata; + unsigned char uch; + const size_t siglen = sizeof(struct ar_raw_signature); + + hdrname = m->ar_file_header.ar_member_name; + hdrattr = m->ar_file_header.ar_header_attr; + + data = m->ar_object_data; + data_cap = &data[m->ar_file_header.ar_file_size]; + + if (hdrattr & AR_HEADER_ATTR_SYSV) { + /* long names member? */ + if ((hdrname[0] == '/') && (hdrname[1] == '/')) + return AR_MEMBER_ATTR_NAMESTRS; + + /* mips 64-bit armap member? */ + else if (!strncmp(hdrname,"/SYM64/",7)) + return AR_MEMBER_ATTR_ARMAP; + + /* armap member? */ + else if (hdrname[0] == '/' && (hdrname[1] == '\0')) + return AR_MEMBER_ATTR_ARMAP; + + /* nested archive? */ + else if (m->ar_file_header.ar_file_size >= siglen) + if (!strncmp(data,ar_signature,siglen)) + return AR_MEMBER_ATTR_ARCHIVE; + + } else if (hdrattr & AR_HEADER_ATTR_BSD) { + if (!strcmp(hdrname,"__.SYMDEF")) + return AR_MEMBER_ATTR_ARMAP; + + else if (!strcmp(hdrname,"__.SYMDEF SORTED")) + return AR_MEMBER_ATTR_ARMAP; + + else if (!strcmp(hdrname,"__.SYMDEF_64")) + return AR_MEMBER_ATTR_ARMAP; + + else if (!strcmp(hdrname,"__.SYMDEF_64 SORTED")) + return AR_MEMBER_ATTR_ARMAP; + } + + /* ascii only data? */ + for (; data<data_cap; ) { + if ((uch = *data) >= 0x80) + break; + + data++; + } + + if (data == data_cap) + return AR_MEMBER_ATTR_ASCII; + + data = m->ar_object_data; + udata = (unsigned char *)data; + + /* elf object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 5) + if ((udata[0] == 0x7f) + && (udata[1] == 'E') + && (udata[2] == 'L') + && (udata[3] == 'F')) + if ((m->ar_object_attr = AR_OBJECT_ATTR_ELF)) + return AR_MEMBER_ATTR_OBJECT; + + /* coff i386 object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 2) + if ((udata[0] == 0x4c) && (udata[1] == 0x01)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_COFF)) + return AR_MEMBER_ATTR_OBJECT; + + /* coff x86_64 object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 2) + if ((udata[0] == 0x64) && (udata[1] == 0x86)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_COFF)) + return AR_MEMBER_ATTR_OBJECT; + + /* big endian 32-bit macho object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 4) + if ((udata[0] == 0xfe) && (udata[1] == 0xed)) + if ((udata[2] == 0xfa) && (udata[3] == 0xce)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO)) + return AR_MEMBER_ATTR_OBJECT; + + /* big endian 64-bit macho object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 4) + if ((udata[0] == 0xfe) && (udata[1] == 0xed)) + if ((udata[2] == 0xfa) && (udata[3] == 0xcf)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO)) + return AR_MEMBER_ATTR_OBJECT; + + /* little endian 32-bit macho object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 4) + if ((udata[3] == 0xfe) && (udata[2] == 0xed)) + if ((udata[1] == 0xfa) && (udata[0] == 0xce)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO)) + return AR_MEMBER_ATTR_OBJECT; + + /* little endian 64-bit macho object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 4) + if ((udata[3] == 0xfe) && (udata[2] == 0xed)) + if ((udata[1] == 0xfa) && (udata[0] == 0xcf)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO)) + return AR_MEMBER_ATTR_OBJECT; + + /* all other */ + return AR_MEMBER_ATTR_DEFAULT; +} + +static int slbt_ar_parse_primary_armap( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) + +{ + struct ar_meta_member_info * memberp; + const char * hdrname; + uint32_t hdrattr; + + memberp = m->memberv[0]; + hdrname = memberp->ar_file_header.ar_member_name; + hdrattr = memberp->ar_file_header.ar_header_attr; + + if (!(memberp->ar_member_attr & AR_MEMBER_ATTR_ARMAP)) + return 0; + + if (hdrattr & AR_HEADER_ATTR_SYSV) { + /* mips 64-bit armap member? */ + if (!strncmp(hdrname,"/SYM64/",7)) + return slbt_ar_parse_primary_armap_sysv_64( + dctx,m); + + /* sysv 32-bit armap member */ + return slbt_ar_parse_primary_armap_sysv_32( + dctx,m); + + } else if (hdrattr & AR_HEADER_ATTR_BSD) { + if (!strcmp(hdrname,"__.SYMDEF")) + return slbt_ar_parse_primary_armap_bsd_32( + dctx,m); + + else if (!strcmp(hdrname,"__.SYMDEF SORTED")) + return slbt_ar_parse_primary_armap_bsd_32( + dctx,m); + + else if (!strcmp(hdrname,"__.SYMDEF_64")) + return slbt_ar_parse_primary_armap_bsd_64( + dctx,m); + + else if (!strcmp(hdrname,"__.SYMDEF_64 SORTED")) + return slbt_ar_parse_primary_armap_bsd_64( + dctx,m); + } + + return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR); +} + +slbt_hidden struct ar_meta_member_info * slbt_archive_member_from_offset( + struct slbt_archive_meta_impl * meta, + off_t offset) +{ + intptr_t l,r,m; + off_t * offsetv; + + l = 0; + r = meta->nentries - 1; + + offsetv = meta->offsetv; + + while (l != r) { + m = (l + r) / 2; + m += (l + r) % 2; + + if (offsetv[m] > offset) { + r = --m; + } else { + l = m; + } + } + + return (offsetv[l] == offset) ? meta->memberv[l] : 0; +} + +int slbt_ar_get_archive_meta( + const struct slbt_driver_ctx * dctx, + const struct slbt_raw_archive * archive, + struct slbt_archive_meta ** meta) +{ + const char * mark; + const char * cap; + struct slbt_archive_meta_impl * m; + const char * slash; + const char * ch; + const char * fldcap; + size_t nelements; + uint64_t nentries; + uint64_t nmembers; + uint64_t stblsize; + uint64_t filesize; + uint64_t namelen; + uint64_t nameoff; + uint32_t attr; + void * s_addr; + void * m_addr; + const char * s_ptr; + const char * m_ptr; + struct ar_raw_file_header * arhdr; + struct ar_raw_file_header * arlongnames; + struct ar_meta_member_info * memberp; + char * longnamep; + size_t idx; + struct ar_meta_armap_ref_32 * symrefs_32; + struct ar_meta_armap_ref_64 * symrefs_64; + struct ar_header_info * hdrinfov; + struct ar_header_info * hdrinfov_cap; + struct ar_header_info * hdrinfov_next; + struct ar_header_info hdrinfobuf[AR_STACK_VECTOR_ELEMENTS]; + + /* init */ + hdrinfov = hdrinfobuf; + hdrinfov_cap = &hdrinfobuf[AR_STACK_VECTOR_ELEMENTS]; + nelements = AR_STACK_VECTOR_ELEMENTS; + + memset(hdrinfobuf,0,sizeof(hdrinfobuf)); + + mark = archive->map_addr; + cap = &mark[archive->map_size]; + + /* preliminary validation */ + if (archive->map_size < sizeof(struct ar_raw_signature)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_SIGNATURE); + + else if (strncmp(mark,ar_signature,sizeof(struct ar_raw_signature))) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_SIGNATURE); + + /* alloc */ + if (!(m = calloc(1,sizeof(*m)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + /* associated driver context */ + m->dctx = dctx; + + /* archive map info */ + m->armeta.r_archive.map_addr = archive->map_addr; + m->armeta.r_archive.map_size = archive->map_size; + + /* archive signature */ + m->armeta.r_signature = (struct ar_raw_signature *)mark; + m->armeta.m_signature = (struct ar_meta_signature *)ar_signature; + + /* signature only? */ + if (archive->map_size == sizeof(struct ar_raw_signature)) { + *meta = &m->armeta; + return 0; + } + + mark += sizeof(struct ar_raw_signature); + + /* only trailing null characters past the signature? */ + if (cap < &mark[sizeof(*arhdr)]) + for (ch=mark; ch<cap; ch++) + if (*ch) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + /* count entries, calculate string table size */ + for (nentries=0,stblsize=0,arlongnames=0; mark<cap; nentries++) { + arhdr = (struct ar_raw_file_header *)mark; + + /* file size */ + if ((slbt_ar_read_decimal_64( + arhdr->ar_file_size, + sizeof(arhdr->ar_file_size), + &filesize)) < 0) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + mark += sizeof(struct ar_raw_file_header); + + /* stblsize, member name type */ + fldcap = &arhdr->ar_file_id[sizeof(arhdr->ar_file_id)]; + + /* sysv long names table? */ + if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) { + for (ch=&arhdr->ar_file_id[2]; ch<fldcap; ch++) + if (*ch != AR_DEC_PADDING) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + if (slbt_ar_read_decimal_64( + arhdr->ar_file_size, + sizeof(arhdr->ar_file_size), + &namelen) < 0) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + + /* duplicate long names member? */ + if (arlongnames) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_DUPLICATE_LONG_NAMES)); + + attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV; + + stblsize++; + stblsize++; + stblsize++; + + stblsize += namelen; + + arlongnames = arhdr; + + /* the /SYM64/ string must be special cased, also below when it gets copied */ + } else if (!strncmp(arhdr->ar_file_id,"/SYM64/",7)) { + for (ch=&arhdr->ar_file_id[7]; ch<fldcap; ch++) + if (*ch != AR_DEC_PADDING) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV; + stblsize += 8; + + /* sysv armap member or sysv long name reference? */ + } else if (arhdr->ar_file_id[0] == '/') { + if (slbt_ar_read_decimal_64( + &arhdr->ar_file_id[1], + sizeof(arhdr->ar_file_id)-1, + &nameoff) < 0) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + if (arhdr->ar_file_id[1] == AR_DEC_PADDING) { + attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV; + stblsize++; + stblsize++; + } else { + attr = AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_SYSV; + } + + /* bsd long name reference? */ + } else if ((arhdr->ar_file_id[0] == '#') + && (arhdr->ar_file_id[1] == '1') + && (arhdr->ar_file_id[2] == '/')) { + if (slbt_ar_read_decimal_64( + &arhdr->ar_file_id[3], + sizeof(arhdr->ar_file_id)-3, + &namelen) < 0) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + attr = AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD; + + stblsize += namelen + 1; + + /* must be either a sysv short member name, or a (legacy) bsd short name */ + } else { + for (ch=arhdr->ar_file_id,slash=0; (ch<fldcap) && !slash; ch++) + if (*ch == '/') + slash = ch; + + if (slash) { + attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV; + stblsize += (slash - arhdr->ar_file_id) + 1; + } else { + attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD; + stblsize += sizeof(arhdr->ar_file_id) + 1; + } + + for (; ch<fldcap; ) + if (*ch++ != AR_DEC_PADDING) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + } + + /* truncated data? */ + if (cap < &mark[filesize]) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_TRUNCATED_DATA)); + + /* ar member alignment */ + filesize += 1; + filesize |= 1; + filesize ^= 1; + + mark += filesize; + + /* only trailing null characters past the signature? */ + if (cap < &mark[sizeof(*arhdr)]) + for (; mark<cap; ) + if (*mark++) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + /* transient header info vector */ + if (&hdrinfov[nentries] == hdrinfov_cap) { + nelements = (nelements == AR_STACK_VECTOR_ELEMENTS) + ? (nelements << 4) : (nelements << 1); + + if (!(hdrinfov_next = calloc(nelements,sizeof(*hdrinfov)))) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_TRUNCATED_DATA)); + + for (idx=0; idx<nentries; idx++) { + hdrinfov_next[idx].phdr = hdrinfov[idx].phdr; + hdrinfov_next[idx].attr = hdrinfov[idx].attr; + }; + + if (hdrinfov != hdrinfobuf) + free(hdrinfov); + + hdrinfov = hdrinfov_next; + hdrinfov_cap = &hdrinfov_next[nelements]; + m->hdrinfov = hdrinfov; + } + + hdrinfov[nentries].phdr = arhdr; + hdrinfov[nentries].attr = attr; + } + + /* allocate name strings, member vector */ + if (!(m->namestrs = calloc(1,stblsize))) + return slbt_ar_free_archive_meta_impl( + m,SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(m->offsetv = calloc(nentries+1,sizeof(*m->offsetv)))) + return slbt_ar_free_archive_meta_impl( + m,SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(m->memberv = calloc(nentries+1,sizeof(*m->memberv)))) + return slbt_ar_free_archive_meta_impl( + m,SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(m->members = calloc(nentries,sizeof(*m->members)))) + return slbt_ar_free_archive_meta_impl( + m,SLBT_SYSTEM_ERROR(dctx,0)); + + /* archive signature reference */ + s_addr = archive->map_addr; + s_ptr = s_addr; + + /* iterate, store meta data in library-friendly form */ + for (idx=0,longnamep=m->namestrs; idx<nentries; idx++) { + arhdr = hdrinfov[idx].phdr; + attr = hdrinfov[idx].attr; + + m_addr = arhdr; + m_ptr = m_addr; + + memberp = &m->members[idx]; + m->offsetv[idx] = m_ptr - s_ptr; + m->memberv[idx] = memberp; + + memberp->ar_file_header.ar_header_attr = attr; + + slbt_ar_read_decimal_64( + arhdr->ar_time_date_stamp, + sizeof(arhdr->ar_time_date_stamp), + &memberp->ar_file_header.ar_time_date_stamp); + + slbt_ar_read_decimal_32( + arhdr->ar_uid, + sizeof(arhdr->ar_uid), + &memberp->ar_file_header.ar_uid); + + slbt_ar_read_decimal_32( + arhdr->ar_gid, + sizeof(arhdr->ar_gid), + &memberp->ar_file_header.ar_gid); + + slbt_ar_read_octal( + arhdr->ar_file_mode, + sizeof(arhdr->ar_file_mode), + &memberp->ar_file_header.ar_file_mode); + + slbt_ar_read_decimal_64( + arhdr->ar_file_size, + sizeof(arhdr->ar_file_size), + &memberp->ar_file_header.ar_file_size); + + memberp->ar_file_header.ar_member_name = longnamep; + + if (attr == (AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV)) { + if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) { + *longnamep++ = '/'; + *longnamep++ = '/'; + longnamep++; + + } else if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == 'S')) { + *longnamep++ = '/'; + *longnamep++ = 'S'; + *longnamep++ = 'Y'; + *longnamep++ = 'M'; + *longnamep++ = '6'; + *longnamep++ = '4'; + *longnamep++ = '/'; + longnamep++; + + } else if (arhdr->ar_file_id[0] == '/') { + *longnamep++ = '/'; + longnamep++; + + } else { + ch = arhdr->ar_file_id; + + for (; (*ch != '/'); ) + *longnamep++ = *ch++; + + longnamep++; + } + + } else if (attr == (AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD)) { + ch = arhdr->ar_file_id; + fldcap = &ch[sizeof(arhdr->ar_file_id)]; + + for (; (ch<fldcap) && (*ch != AR_DEC_PADDING); ) + *longnamep++ = *ch++; + + longnamep++; + + } else if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_SYSV)) { + slbt_ar_read_decimal_64( + &arhdr->ar_file_id[1], + sizeof(arhdr->ar_file_id) - 1, + &nameoff); + + ch = arlongnames->ar_file_id; + ch += sizeof(*arlongnames); + ch += nameoff; + + for (; *ch && (*ch != '/') && (*ch != AR_OBJ_PADDING); ) + *longnamep++ = *ch++; + + longnamep++; + + } else if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD)) { + slbt_ar_read_decimal_64( + &arhdr->ar_file_id[3], + sizeof(arhdr->ar_file_id) - 3, + &namelen); + + mark = arhdr->ar_file_id; + mark += sizeof(*arhdr); + + memcpy(longnamep,mark,namelen); + + longnamep += namelen; + longnamep++; + } + + /* member raw header, object size, object data */ + mark = arhdr->ar_file_id; + mark += sizeof(*arhdr); + namelen = 0; + + if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD)) { + slbt_ar_read_decimal_64( + &arhdr->ar_file_id[3], + sizeof(arhdr->ar_file_id)-3, + &namelen); + + namelen += 1; + namelen |= 1; + namelen ^= 1; + + mark += namelen; + }; + + memberp->ar_member_data = arhdr; + memberp->ar_object_data = (void *)mark; + memberp->ar_object_size = memberp->ar_file_header.ar_file_size - namelen; + + /* member attribute */ + memberp->ar_member_attr = slbt_ar_get_member_attr(memberp); + + /* pe/coff second linker member? */ + if ((idx == 1) && (memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP)) + if (hdrinfov[0].attr & AR_HEADER_ATTR_SYSV) + if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP) + if (attr & AR_HEADER_ATTR_SYSV) + memberp->ar_member_attr = AR_MEMBER_ATTR_LINKINFO; + + /* armap member must be the first */ + if ((memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP) && (idx > 0)) { + if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_DUPLICATE_ARMAP_MEMBER)); + + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_MISPLACED_ARMAP_MEMBER)); + } + } + + /* number of archive members, including internal ones */ + m->nentries = nentries; + + /* primary armap (first linker member) */ + if (slbt_ar_parse_primary_armap(dctx,m) < 0) + return slbt_ar_free_archive_meta_impl( + m,SLBT_NESTED_ERROR(dctx)); + + for (idx=0,ch=m->symstrs; idx<m->armaps.armap_nsyms; idx++) { + m->symstrv[idx] = ch; + ch += strlen(ch); + ch++; + } + + if (m->armaps.armap_common_32.ar_member) { + symrefs_32 = m->armaps.armap_symrefs_32; + + for (idx=0; idx<m->armaps.armap_nsyms; idx++) { + if (m->armaps.armap_common_32.ar_armap_attr & AR_ARMAP_ATTR_SYSV) + symrefs_32[idx].ar_name_offset = m->symstrv[idx] - m->symstrv[0]; + + if (!slbt_archive_member_from_offset(m,symrefs_32[idx].ar_member_offset)) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_MEMBER_OFFSET)); + + if (symrefs_32[idx].ar_name_offset) { + ch = &m->symstrs[symrefs_32[idx].ar_name_offset]; + + if ((ch > m->symstrv[m->armaps.armap_nsyms - 1]) || *--ch) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_NAME_OFFSET)); + } + + } + } + + if (m->armaps.armap_common_64.ar_member) { + symrefs_64 = m->armaps.armap_symrefs_64; + + for (idx=0; idx<m->armaps.armap_nsyms; idx++) { + if (m->armaps.armap_common_64.ar_armap_attr & AR_ARMAP_ATTR_SYSV) + symrefs_64[idx].ar_name_offset = m->symstrv[idx] - m->symstrv[0]; + + if (!slbt_archive_member_from_offset(m,symrefs_64[idx].ar_member_offset)) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_MEMBER_OFFSET)); + + if (symrefs_64[idx].ar_name_offset) { + ch = &m->symstrs[symrefs_64[idx].ar_name_offset]; + + if ((ch > m->symstrv[m->armaps.armap_nsyms - 1]) || *--ch) + return slbt_ar_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_NAME_OFFSET)); + } + + } + } + + /* number of public archive members */ + for (idx=0,nmembers=0; idx<nentries; idx++) { + switch (m->memberv[idx]->ar_member_attr) { + case AR_MEMBER_ATTR_ARMAP: + case AR_MEMBER_ATTR_LINKINFO: + case AR_MEMBER_ATTR_NAMESTRS: + break; + + default: + nmembers++; + } + } + + if (m->armaps.armap_common_32.ar_member) + m->armaps.armap_common_32.ar_num_of_members = nmembers; + + if (m->armaps.armap_common_64.ar_member) + m->armaps.armap_common_64.ar_num_of_members = nmembers; + + /* pe/coff armap attributes (second linker member) */ + (void)m->armeta.a_armap_pecoff; + + /* reference to the long names member */ + if (arlongnames) + for (idx=0; idx<nentries && !m->armeta.a_arref_longnames; idx++) + if (m->memberv[idx]->ar_member_data == arlongnames) + m->armeta.a_arref_longnames = m->memberv[idx]; + + /* common binary format (information only) */ + for (idx=0,nmembers=0; idx<nentries; idx++) { + if (m->memberv[idx]->ar_member_attr == AR_MEMBER_ATTR_OBJECT) { + if (m->ofmtattr && (m->ofmtattr != m->memberv[idx]->ar_object_attr)) { + m->ofmtattr = 0; + idx = nentries; + } else if (!m->ofmtattr) { + m->ofmtattr = m->memberv[idx]->ar_object_attr; + } + } + } + + /* member vector */ + m->armeta.a_memberv = m->memberv; + + /* all done */ + if (m->hdrinfov) { + free(m->hdrinfov); + m->hdrinfov = 0; + } + + *meta = &m->armeta; + + return 0; +} + +void slbt_ar_free_archive_meta(struct slbt_archive_meta * meta) +{ + struct slbt_archive_meta_impl * m; + + if (meta) { + m = slbt_archive_meta_ictx(meta); + slbt_ar_free_archive_meta_impl(m,0); + } +} diff --git a/src/arbits/slbt_archive_store.c b/src/arbits/slbt_archive_store.c new file mode 100644 index 0000000..d09a3f0 --- /dev/null +++ b/src/arbits/slbt_archive_store.c @@ -0,0 +1,145 @@ +/*******************************************************************/ +/* 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 <time.h> +#include <fcntl.h> +#include <stdio.h> +#include <stddef.h> +#include <limits.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <inttypes.h> +#include <sys/stat.h> + +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_arbits.h> +#include "slibtool_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" + +/****************************************************/ +/* As elsewhere in slibtool, file-system operations */ +/* utilizie the _at variants of the relevant posix */ +/* interfaces. In the case of archives, that means */ +/* passing dctx->fdctx->fdcwd as the _fdat_ param, */ +/* where dctx is the driver context which was used */ +/* with slbt_ar_get_archive_ctx(). */ +/************************************************** */ + +#define PPRIX64 "%"PRIx64 + +int slbt_ar_store_archive( + struct slbt_archive_ctx * arctx, + const char * path, + mode_t mode) +{ + const struct slbt_driver_ctx * dctx; + struct stat st; + int fdat; + int fdtmp; + void * addr; + char * mark; + char * slash; + size_t buflen; + size_t nbytes; + ssize_t written; + char buf[PATH_MAX]; + + /* init dctx */ + if (!(dctx = slbt_get_archive_ictx(arctx)->dctx)) + return -1; + + /* validation */ + if (strlen(path) >= PATH_MAX) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + /**************************************************/ + /* create temporary file in the target directory */ + /* */ + /* the tmpfile name pattern involes the inode */ + /* of the target directory, a local stack address */ + /* in the calling thread, the current time, and */ + /* finally the pid of the current process. */ + /**************************************************/ + + memset(buf,0,sizeof(buf)); + strcpy(buf,path); + + fdat = slbt_driver_fdcwd(dctx); + + addr = buf; + mark = (slash = strrchr(buf,'/')) + ? slash : buf; + + if (slash) { + *++mark = '\0'; + + if (fstatat(fdat,buf,&st,0) < 0) + return SLBT_SYSTEM_ERROR( + dctx,buf); + } else { + if (fstatat(fdat,".",&st,0) < 0) + return SLBT_SYSTEM_ERROR( + dctx,0); + } + + buflen = sizeof(buf) - (mark - buf); + nbytes = snprintf( + mark, + buflen, + ".slibtool.tmpfile" + ".inode."PPRIX64 + ".time."PPRIX64 + ".salt.%p" + ".pid.%d" + ".tmp", + st.st_ino, + time(0),addr, + getpid()); + + if (nbytes >= buflen) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + if ((fdtmp = openat(fdat,buf,O_WRONLY|O_CREAT|O_EXCL,mode)) < 0) + return SLBT_SYSTEM_ERROR(dctx,buf); + + /* set archive size */ + if (ftruncate(fdtmp,arctx->map->map_size) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + /* write archive */ + mark = arctx->map->map_addr; + nbytes = arctx->map->map_size; + + for (; nbytes; ) { + written = write(fdtmp,mark,nbytes); + + while ((written < 0) && (errno == EINTR)) + written = write(fdtmp,mark,nbytes); + + if (written < 0) { + unlinkat(fdat,buf,0); + return SLBT_SYSTEM_ERROR(dctx,0); + }; + + nbytes -= written; + mark += written; + } + + /* finalize (atomically) */ + if (renameat(fdat,buf,fdat,path) < 0) { + unlinkat(fdat,buf,0); + return SLBT_SYSTEM_ERROR(dctx,buf); + } + + /* yay */ + return 0; +} diff --git a/src/arbits/slbt_archive_symfile.c b/src/arbits/slbt_archive_symfile.c new file mode 100644 index 0000000..49d2ff0 --- /dev/null +++ b/src/arbits/slbt_archive_symfile.c @@ -0,0 +1,138 @@ +/*******************************************************************/ +/* 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 <time.h> +#include <locale.h> +#include <regex.h> +#include <inttypes.h> +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_output.h> +#include "slibtool_driver_impl.h" +#include "slibtool_dprintf_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_pecoff_impl.h" +#include "slibtool_ar_impl.h" + +/********************************************************/ +/* Generate a symbol list that could be used by a build */ +/* system for code generation or any other purpose. */ +/* */ +/* The output matches the -Wposix variant of symbol */ +/* printing, but the interface should be kept separate */ +/* since the _au_output_ functions implement several */ +/* output format, whereas here only a single, plain */ +/* output is expected. */ +/********************************************************/ + +static int slbt_ar_output_symfile_impl( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * mctx, + int fdout) +{ + bool fsort; + bool fcoff; + const char * dot; + const char * mark; + const char * regex; + const char ** symv; + const char ** symstrv; + regex_t regctx; + regmatch_t pmatch[2] = {{0,0},{0,0}}; + char strbuf[4096]; + + fsort = !(dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_NOSORT); + + fcoff = slbt_host_objfmt_is_coff(dctx); + fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + if (fsort && !mctx->mapstrv) + if (slbt_update_mapstrv(dctx,mctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if ((regex = dctx->cctx->regex)) + if (regcomp(®ctx,regex,REG_EXTENDED|REG_NEWLINE)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + symstrv = fsort ? mctx->mapstrv : mctx->symstrv; + + for (symv=symstrv; *symv; symv++) { + if (!fcoff || slbt_is_strong_coff_symbol(*symv)) { + if (!regex || !regexec(®ctx,*symv,1,pmatch,0)) { + if (slbt_dprintf(fdout,"%s\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + + /* coff weak symbols: expsym = .weak.alias.strong */ + } else if (fcoff && !strncmp(*symv,".weak.",6)) { + mark = &(*symv)[6]; + dot = strchr(mark,'.'); + + strncpy(strbuf,mark,dot-mark); + strbuf[dot-mark] = '\0'; + + if (!regex || !regexec(®ctx,strbuf,1,pmatch,0)) + if (slbt_dprintf(fdout," %s = %s\n",strbuf,++dot) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + + if (regex) + regfree(®ctx); + + return 0; +} + + +static int slbt_ar_create_symfile_impl( + const struct slbt_archive_meta * meta, + const char * path, + mode_t mode) +{ + int ret; + struct slbt_archive_meta_impl * mctx; + const struct slbt_driver_ctx * dctx; + struct slbt_fd_ctx fdctx; + int fdout; + + mctx = slbt_archive_meta_ictx(meta); + dctx = (slbt_archive_meta_ictx(meta))->dctx; + + if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (!meta->a_memberv) + return 0; + + if (path) { + if ((fdout = openat( + fdctx.fdcwd,path, + O_WRONLY|O_CREAT|O_TRUNC, + mode)) < 0) + return SLBT_SYSTEM_ERROR(dctx,path); + } else { + fdout = fdctx.fdout; + } + + ret = slbt_ar_output_symfile_impl( + dctx,mctx,fdout); + + if (path) { + close(fdout); + } + + return ret; +} + + +int slbt_ar_create_symfile( + const struct slbt_archive_meta * meta, + const char * path, + mode_t mode) +{ + return slbt_ar_create_symfile_impl(meta,path,mode); +} diff --git a/src/arbits/slbt_archive_syminfo.c b/src/arbits/slbt_archive_syminfo.c new file mode 100644 index 0000000..09c90a8 --- /dev/null +++ b/src/arbits/slbt_archive_syminfo.c @@ -0,0 +1,345 @@ +/*******************************************************************/ +/* 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 <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <limits.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <slibtool/slibtool.h> +#include "slibtool_ar_impl.h" +#include "slibtool_coff_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_dprintf_impl.h" +#include "slibtool_spawn_impl.h" +#include "slibtool_snprintf_impl.h" +#include "slibtool_errinfo_impl.h" + +static const char ar_symbol_type_A[] = "A"; +static const char ar_symbol_type_B[] = "B"; +static const char ar_symbol_type_C[] = "C"; +static const char ar_symbol_type_D[] = "D"; +static const char ar_symbol_type_G[] = "G"; +static const char ar_symbol_type_I[] = "I"; +static const char ar_symbol_type_R[] = "R"; +static const char ar_symbol_type_S[] = "S"; +static const char ar_symbol_type_T[] = "T"; +static const char ar_symbol_type_W[] = "W"; + +static const char * const ar_symbol_type['Z'-'A'] = { + ['A'-'A'] = ar_symbol_type_A, + ['B'-'A'] = ar_symbol_type_B, + ['C'-'A'] = ar_symbol_type_C, + ['D'-'A'] = ar_symbol_type_D, + ['G'-'A'] = ar_symbol_type_G, + ['I'-'A'] = ar_symbol_type_I, + ['R'-'A'] = ar_symbol_type_R, + ['S'-'A'] = ar_symbol_type_S, + ['T'-'A'] = ar_symbol_type_T, + ['W'-'A'] = ar_symbol_type_W, +}; + +static void slbt_ar_update_syminfo_child( + char * program, + char * arname, + int fdout) +{ + char * argv[6]; + + argv[0] = program; + argv[1] = "-P"; + argv[2] = "-A"; + argv[3] = "-g"; + argv[4] = arname; + argv[5] = 0; + + if (dup2(fdout,1) == 1) + execvp(program,argv); + + _exit(EXIT_FAILURE); +} + +static int slbt_obtain_nminfo( + struct slbt_archive_ctx_impl * ictx, + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * mctx, + int fdout) +{ + int ret; + int pos; + int fdcwd; + int fdarg; + pid_t pid; + pid_t rpid; + int ecode; + char ** argv; + char arname [PATH_MAX]; + char output [PATH_MAX]; + char program[PATH_MAX]; + + /* fdcwd */ + fdcwd = slbt_driver_fdcwd(dctx); + + /* tool-specific argument vector */ + argv = (slbt_get_driver_ictx(dctx))->host.nm_argv; + + /* ar alternate argument vector */ + if (argv) { + if (slbt_snprintf(program,sizeof(program), + "%s",argv[0]) < 0) + return SLBT_BUFFER_ERROR(dctx); + } else { + if (slbt_snprintf(program,sizeof(program), + "%s",dctx->cctx->host.nm) < 0) + return SLBT_BUFFER_ERROR(dctx); + } + + /* arname (.nm suffix, buf treat as .syminfo) */ + pos = slbt_snprintf( + arname,sizeof(arname)-8,"%s", + ictx->path); + + /* output */ + if ((fdarg = fdout) < 0) { + strcpy(output,arname); + strcpy(&output[pos],".nm"); + + if ((fdout = openat(fdcwd,output,O_CREAT|O_TRUNC|O_RDWR,0644)) < 0) + return SLBT_SYSTEM_ERROR(dctx,output); + } else { + strcpy(output,"@nminfo@"); + } + + /* fork */ + if ((pid = slbt_fork()) < 0) { + close(fdout); + return SLBT_SYSTEM_ERROR(dctx,0); + } + + /* child */ + if (pid == 0) + slbt_ar_update_syminfo_child( + program,arname,fdout); + + /* parent */ + rpid = waitpid( + pid, + &ecode, + 0); + + /* nm output */ + if ((rpid > 0) && (ecode == 0)) + ret = slbt_impl_get_txtfile_ctx( + dctx,output,fdout, + &mctx->nminfo); + + if (fdarg < 0) + close(fdout); + + if (rpid < 0) { + return SLBT_SYSTEM_ERROR(dctx,0); + + } else if (ecode) { + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + } + + return (ret < 0) ? SLBT_NESTED_ERROR(dctx) : 0; +} + +static int slbt_get_symbol_nm_info( + struct slbt_archive_ctx * actx, + struct slbt_archive_meta_impl * mctx, + uint64_t idx) +{ + int cint; + const char ** pline; + const char * mark; + const char * cap; + const char * objname; + const char * symname; + struct ar_meta_symbol_info * syminfo; + struct ar_meta_member_info ** pmember; + + symname = mctx->symstrv[idx]; + syminfo = &mctx->syminfo[idx]; + + for (pline=mctx->nminfo->txtlinev; *pline; pline++) { + mark = *pline; + + if (!(mark = strchr(mark,']'))) + return -1; + + if ((*++mark != ':') || (*++mark != ' ')) + return -1; + + cap = ++mark; + + for (; *cap && !isspace((cint = *cap)); ) + cap++; + + if (*cap != ' ') + return -1; + + if (!(strncmp(symname,mark,cap-mark))) { + mark = ++cap; + + /* space only according to posix, but ... */ + if (mark[1] && (mark[1] != ' ')) + return -1; + + switch (mark[0]) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'G': + case 'I': + case 'R': + case 'S': + case 'T': + case 'W': + syminfo->ar_symbol_type = ar_symbol_type[mark[0]-'A']; + break; + + default: + break; + } + + if (syminfo->ar_symbol_type) { + syminfo->ar_archive_name = *actx->path; + syminfo->ar_symbol_name = symname; + + if (!(mark = strchr(*pline,'['))) + return -1; + + if (!(cap = strchr(++mark,']'))) + return -1; + } + + pmember = mctx->memberv; + + for (; *pmember && !syminfo->ar_object_name; ) { + objname = (*pmember)->ar_file_header.ar_member_name; + + if (!(strncmp(objname,mark,cap-mark))) + syminfo->ar_object_name = objname; + + pmember++; + } + + mctx->syminfv[idx] = syminfo; + } + } + + return (mctx->syminfv[idx] ? 0 : (-1)); +} + +static int slbt_qsort_syminfo_cmp(const void * a, const void * b) +{ + struct ar_meta_symbol_info ** syminfoa; + struct ar_meta_symbol_info ** syminfob; + + syminfoa = (struct ar_meta_symbol_info **)a; + syminfob = (struct ar_meta_symbol_info **)b; + + return strcmp( + (*syminfoa)->ar_symbol_name, + (*syminfob)->ar_symbol_name); +} + +static int slbt_coff_qsort_syminfo_cmp(const void * a, const void * b) +{ + struct ar_meta_symbol_info ** syminfoa; + struct ar_meta_symbol_info ** syminfob; + + syminfoa = (struct ar_meta_symbol_info **)a; + syminfob = (struct ar_meta_symbol_info **)b; + + return slbt_coff_qsort_strcmp( + &(*syminfoa)->ar_symbol_name, + &(*syminfob)->ar_symbol_name); +} + +static int slbt_ar_update_syminfo_impl( + struct slbt_archive_ctx * actx, + int fdout) +{ + const struct slbt_driver_ctx * dctx; + struct slbt_archive_ctx_impl * ictx; + struct slbt_archive_meta_impl * mctx; + uint64_t idx; + bool fcoff; + + /* driver context, etc. */ + ictx = slbt_get_archive_ictx(actx); + mctx = slbt_archive_meta_ictx(ictx->meta); + dctx = ictx->dctx; + + /* nm -P -A -g */ + if (mctx->armaps.armap_nsyms) { + if (slbt_obtain_nminfo(ictx,dctx,mctx,fdout) < 0) + return SLBT_NESTED_ERROR(dctx); + } else { + if (slbt_lib_get_txtfile_ctx( + dctx,"/dev/null", + &mctx->nminfo) < 0) + return SLBT_NESTED_ERROR(dctx); + } + + /* free old syminfo vector */ + if (mctx->syminfv) + free(mctx->syminfv); + + /* syminfo vector: armap symbols only */ + if (!(mctx->syminfo = calloc( + mctx->armaps.armap_nsyms + 1, + sizeof(*mctx->syminfo)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (!(mctx->syminfv = calloc( + mctx->armaps.armap_nsyms + 1, + sizeof(*mctx->syminfv)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + /* do the thing */ + for (idx=0; idx<mctx->armaps.armap_nsyms; idx++) + if (slbt_get_symbol_nm_info(actx,mctx,idx) < 0) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + /* coff-aware sorting */ + fcoff = slbt_host_objfmt_is_coff(dctx); + fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF); + + qsort(mctx->syminfv,mctx->armaps.armap_nsyms,sizeof(*mctx->syminfv), + fcoff ? slbt_coff_qsort_syminfo_cmp : slbt_qsort_syminfo_cmp); + + /* yay */ + return 0; +} + +slbt_hidden int slbt_ar_update_syminfo( + struct slbt_archive_ctx * actx) +{ + return slbt_ar_update_syminfo_impl(actx,(-1)); +} + +slbt_hidden int slbt_ar_update_syminfo_ex( + struct slbt_archive_ctx * actx, + int fdout) +{ + return slbt_ar_update_syminfo_impl(actx,fdout); +} diff --git a/src/arbits/slbt_armap_bsd_32.c b/src/arbits/slbt_armap_bsd_32.c new file mode 100644 index 0000000..ee94b70 --- /dev/null +++ b/src/arbits/slbt_armap_bsd_32.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 <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_arbits.h> +#include "slibtool_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" + +slbt_hidden int slbt_ar_parse_primary_armap_bsd_32( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) + +{ + struct ar_raw_armap_bsd_32 * armap; + struct ar_meta_member_info * memberp; + struct ar_meta_armap_common_32 *armapref; + struct ar_meta_armap_ref_32 * symrefs; + uint32_t idx; + uint32_t uref; + uint32_t attr; + uint32_t nsyms; + uint32_t nstrs; + uint32_t sizeofrefs_le; + uint32_t sizeofrefs_be; + uint32_t sizeofrefs; + uint32_t sizeofstrs; + const char * ch; + const char * cap; + unsigned char * uch; + unsigned char (*mark)[0x04]; + + armap = &m->armaps.armap_bsd_32; + memberp = m->memberv[0]; + + mark = memberp->ar_object_data; + + armap->ar_size_of_refs = mark; + uch = *mark++; + + armap->ar_first_name_offset = mark; + + sizeofrefs_le = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + sizeofrefs_be = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + + if (sizeofrefs_le < memberp->ar_object_size - sizeof(*mark)) { + sizeofrefs = sizeofrefs_le; + attr = AR_ARMAP_ATTR_LE_32; + + } else if (sizeofrefs_be < memberp->ar_object_size - sizeof(*mark)) { + sizeofrefs = sizeofrefs_be; + attr = AR_ARMAP_ATTR_BE_32; + } else { + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_REFS); + } + + nsyms = sizeofrefs / sizeof(struct ar_raw_armap_ref_32); + mark += (sizeofrefs / sizeof(*mark)); + + armap->ar_size_of_strs = mark; + uch = *mark++; + + sizeofstrs = (attr == AR_ARMAP_ATTR_LE_32) + ? (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0] + : (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + + if (sizeofstrs > memberp->ar_object_size - 2*sizeof(*mark) - sizeofrefs) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_STRS); + + m->symstrs = (const char *)mark; + + cap = m->symstrs; + cap += sizeofstrs; + + if ((cap == m->symstrs) && nsyms) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (nsyms && !m->symstrs[0]) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + for (ch=&m->symstrs[1],nstrs=0; ch<cap; ch++) { + if (!ch[0] && !ch[-1] && (nstrs < nsyms)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (!ch[0] && ch[-1] && (nstrs < nsyms)) + nstrs++; + } + + if (nstrs != nsyms) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (!(m->armaps.armap_symrefs_32 = calloc(nsyms + 1,sizeof(*symrefs)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + mark = armap->ar_first_name_offset; + symrefs = m->armaps.armap_symrefs_32; + + for (idx=0; idx<nsyms; idx++) { + uch = *mark++; + + uref = (attr == AR_ARMAP_ATTR_BE_32) + ? (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3] + : (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + + symrefs[idx].ar_name_offset = uref; + + uch = *mark++; + + uref = (attr == AR_ARMAP_ATTR_BE_32) + ? (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3] + : (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + + symrefs[idx].ar_member_offset = uref; + } + + armap->ar_string_table = m->symstrv; + + armapref = &m->armaps.armap_common_32; + armapref->ar_member = memberp; + armapref->ar_symrefs = symrefs; + armapref->ar_armap_bsd = armap; + armapref->ar_armap_attr = AR_ARMAP_ATTR_BSD | attr; + armapref->ar_num_of_symbols = nsyms; + armapref->ar_size_of_refs = sizeofrefs; + armapref->ar_size_of_strs = sizeofstrs; + armapref->ar_string_table = m->symstrs; + + m->armaps.armap_nsyms = nsyms; + + m->armeta.a_armap_primary.ar_armap_common_32 = armapref; + + return 0; +} diff --git a/src/arbits/slbt_armap_bsd_64.c b/src/arbits/slbt_armap_bsd_64.c new file mode 100644 index 0000000..8f214b9 --- /dev/null +++ b/src/arbits/slbt_armap_bsd_64.c @@ -0,0 +1,174 @@ +/*******************************************************************/ +/* 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 <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_arbits.h> +#include "slibtool_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" + +slbt_hidden int slbt_ar_parse_primary_armap_bsd_64( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) +{ + struct ar_raw_armap_bsd_64 * armap; + struct ar_meta_member_info * memberp; + struct ar_meta_armap_common_64 *armapref; + struct ar_meta_armap_ref_64 * symrefs; + uint64_t idx; + uint64_t uref_hi; + uint64_t uref_lo; + uint32_t attr; + uint64_t u64_lo; + uint64_t u64_hi; + uint64_t nsyms; + uint64_t nstrs; + uint64_t sizeofrefs_le; + uint64_t sizeofrefs_be; + uint64_t sizeofrefs; + uint64_t sizeofstrs; + const char * ch; + const char * cap; + unsigned char * uch; + unsigned char (*mark)[0x08]; + + armap = &m->armaps.armap_bsd_64; + memberp = m->memberv[0]; + + mark = memberp->ar_object_data; + + armap->ar_size_of_refs = mark; + uch = *mark++; + + armap->ar_first_name_offset = mark; + + u64_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + u64_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4]; + + sizeofrefs_le = u64_lo + (u64_hi << 32); + + u64_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + u64_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7]; + + sizeofrefs_be = (u64_hi << 32) + u64_lo; + + if (sizeofrefs_le < memberp->ar_object_size - sizeof(*mark)) { + sizeofrefs = sizeofrefs_le; + attr = AR_ARMAP_ATTR_LE_64; + + } else if (sizeofrefs_be < memberp->ar_object_size - sizeof(*mark)) { + sizeofrefs = sizeofrefs_be; + attr = AR_ARMAP_ATTR_BE_64; + } else { + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_REFS); + } + + nsyms = sizeofrefs / sizeof(struct ar_raw_armap_ref_64); + mark += (sizeofrefs / sizeof(*mark)); + + armap->ar_size_of_strs = mark; + uch = *mark++; + + if (attr == AR_ARMAP_ATTR_LE_64) { + u64_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + u64_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4]; + } else { + u64_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + u64_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7]; + } + + sizeofstrs = u64_lo + (u64_hi << 32); + m->symstrs = (const char *)mark; + + cap = m->symstrs; + cap += sizeofstrs; + + if ((cap == m->symstrs) && nsyms) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (nsyms && !m->symstrs[0]) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + for (ch=&m->symstrs[1],nstrs=0; ch<cap; ch++) { + if (!ch[0] && !ch[-1] && (nstrs < nsyms)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (!ch[0] && ch[-1] && (nstrs < nsyms)) + nstrs++; + } + + if (nstrs != nsyms) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (!(m->armaps.armap_symrefs_64 = calloc(nsyms + 1,sizeof(*symrefs)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + mark = armap->ar_first_name_offset; + symrefs = m->armaps.armap_symrefs_64; + + for (idx=0; idx<nsyms; idx++) { + uch = *mark++; + + if (attr == AR_ARMAP_ATTR_BE_64) { + uref_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + uref_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7]; + } else { + uref_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + uref_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4]; + } + + symrefs[idx].ar_name_offset = (uref_hi << 32) + uref_lo; + + uch = *mark++; + + if (attr == AR_ARMAP_ATTR_BE_64) { + uref_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + uref_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7]; + } else { + uref_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + uref_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4]; + } + + symrefs[idx].ar_member_offset = (uref_hi << 32) + uref_lo; + } + + armap->ar_string_table = m->symstrv; + + armapref = &m->armaps.armap_common_64; + armapref->ar_member = memberp; + armapref->ar_symrefs = symrefs; + armapref->ar_armap_bsd = armap; + armapref->ar_armap_attr = AR_ARMAP_ATTR_BSD | attr; + armapref->ar_num_of_symbols = nsyms; + armapref->ar_size_of_refs = sizeofrefs; + armapref->ar_size_of_strs = sizeofstrs; + armapref->ar_string_table = m->symstrs; + + m->armaps.armap_nsyms = nsyms; + + m->armeta.a_armap_primary.ar_armap_common_64 = armapref; + + return 0; +} diff --git a/src/arbits/slbt_armap_sysv_32.c b/src/arbits/slbt_armap_sysv_32.c new file mode 100644 index 0000000..bc5a0d5 --- /dev/null +++ b/src/arbits/slbt_armap_sysv_32.c @@ -0,0 +1,120 @@ +/*******************************************************************/ +/* 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 <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_arbits.h> +#include "slibtool_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" + +slbt_hidden int slbt_ar_parse_primary_armap_sysv_32( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) +{ + struct ar_raw_armap_sysv_32 * armap; + struct ar_meta_member_info * memberp; + struct ar_meta_armap_common_32 *armapref; + struct ar_meta_armap_ref_32 * symrefs; + uint32_t idx; + uint32_t uref; + uint32_t nsyms; + uint32_t nstrs; + const char * ch; + const char * cap; + unsigned char * uch; + unsigned char (*mark)[0x04]; + + armap = &m->armaps.armap_sysv_32; + memberp = m->memberv[0]; + + mark = memberp->ar_object_data; + + armap->ar_num_of_syms = mark; + uch = *mark++; + + armap->ar_first_ref_offset = mark; + + nsyms = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + mark += nsyms; + + if (memberp->ar_object_size < (sizeof(*mark) + (nsyms * sizeof(*mark)))) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_NUMBER_OF_SYMS); + + m->symstrs = (const char *)mark; + + cap = memberp->ar_object_data; + cap += memberp->ar_object_size; + + if ((cap == m->symstrs) && nsyms) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (nsyms && !m->symstrs[0]) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + for (ch=&m->symstrs[1],nstrs=0; ch<cap; ch++) { + if (!ch[0] && !ch[-1] && (nstrs < nsyms)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (!ch[0] && ch[-1]) + nstrs++; + } + + if (nstrs != nsyms) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (cap[-1]) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (!(m->armaps.armap_symrefs_32 = calloc(nsyms + 1,sizeof(*symrefs)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + mark = armap->ar_first_ref_offset; + symrefs = m->armaps.armap_symrefs_32; + + for (idx=0,uch=*mark; idx<nsyms; idx++,uch=*++mark) { + uref = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + symrefs[idx].ar_member_offset = uref; + } + + armap->ar_string_table = m->symstrv; + + armapref = &m->armaps.armap_common_32; + armapref->ar_member = memberp; + armapref->ar_symrefs = symrefs; + armapref->ar_armap_sysv = armap; + armapref->ar_armap_attr = AR_ARMAP_ATTR_SYSV | AR_ARMAP_ATTR_BE_32; + armapref->ar_num_of_symbols = nsyms; + armapref->ar_size_of_refs = nsyms * sizeof(*mark); + armapref->ar_size_of_strs = cap - m->symstrs; + armapref->ar_string_table = m->symstrs; + + m->armaps.armap_nsyms = nsyms; + + m->armeta.a_armap_primary.ar_armap_common_32 = armapref; + + return 0; +} diff --git a/src/arbits/slbt_armap_sysv_64.c b/src/arbits/slbt_armap_sysv_64.c new file mode 100644 index 0000000..961ee20 --- /dev/null +++ b/src/arbits/slbt_armap_sysv_64.c @@ -0,0 +1,128 @@ +/*******************************************************************/ +/* 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 <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_arbits.h> +#include "slibtool_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" + +slbt_hidden int slbt_ar_parse_primary_armap_sysv_64( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) +{ + struct ar_raw_armap_sysv_64 * armap; + struct ar_meta_member_info * memberp; + struct ar_meta_armap_common_64 *armapref; + struct ar_meta_armap_ref_64 * symrefs; + uint64_t idx; + uint64_t uref_hi; + uint64_t uref_lo; + uint64_t nsyms_hi; + uint64_t nsyms_lo; + uint64_t nsyms; + uint64_t nstrs; + const char * ch; + const char * cap; + unsigned char * uch; + unsigned char (*mark)[0x08]; + + armap = &m->armaps.armap_sysv_64; + memberp = m->memberv[0]; + + mark = memberp->ar_object_data; + + armap->ar_num_of_syms = mark; + uch = *mark++; + + armap->ar_first_ref_offset = mark; + + nsyms_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + nsyms_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7]; + + nsyms = (nsyms_hi << 32) + nsyms_lo; + mark += nsyms; + + if (memberp->ar_object_size < (sizeof(*mark) + (nsyms * sizeof(*mark)))) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_NUMBER_OF_SYMS); + + m->symstrs = (const char *)mark; + + cap = memberp->ar_object_data; + cap += memberp->ar_object_size; + + if ((cap == m->symstrs) && nsyms) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (nsyms && !m->symstrs[0]) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + for (ch=&m->symstrs[1],nstrs=0; ch<cap; ch++) { + if (!ch[0] && !ch[-1] && (nstrs < nsyms)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (!ch[0] && ch[-1]) + nstrs++; + } + + if (nstrs != nsyms) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (cap[-1]) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE); + + if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (!(m->armaps.armap_symrefs_64 = calloc(nsyms + 1,sizeof(*symrefs)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + mark = armap->ar_first_ref_offset; + symrefs = m->armaps.armap_symrefs_64; + + for (idx=0,uch=*mark; idx<nsyms; idx++,uch=*++mark) { + uref_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + uref_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7]; + + symrefs[idx].ar_member_offset = (uref_hi << 32) + uref_lo; + } + + armap->ar_string_table = m->symstrv; + + armapref = &m->armaps.armap_common_64; + armapref->ar_member = memberp; + armapref->ar_symrefs = symrefs; + armapref->ar_armap_sysv = armap; + armapref->ar_armap_attr = AR_ARMAP_ATTR_SYSV | AR_ARMAP_ATTR_BE_64; + armapref->ar_num_of_symbols = nsyms; + armapref->ar_size_of_refs = nsyms * sizeof(*mark); + armapref->ar_size_of_strs = cap - m->symstrs; + armapref->ar_string_table = m->symstrs; + + m->armaps.armap_nsyms = nsyms; + + m->armeta.a_armap_primary.ar_armap_common_64 = armapref; + + return 0; +} diff --git a/src/driver/slbt_amain.c b/src/driver/slbt_amain.c index eff2b45..73d1462 100644 --- a/src/driver/slbt_amain.c +++ b/src/driver/slbt_amain.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ @@ -41,7 +41,7 @@ static ssize_t slbt_version(struct slbt_driver_ctx * dctx, int fdout) const char * const * verclr; bool gitver; - verinfo = slbt_source_version(); + verinfo = slbt_api_source_version(); verclr = isatty(fdout) ? slbt_ver_color : slbt_ver_plain; gitver = strcmp(verinfo->commit,"unknown"); @@ -59,32 +59,41 @@ static ssize_t slbt_version(struct slbt_driver_ctx * dctx, int fdout) static void slbt_perform_driver_actions(struct slbt_driver_ctx * dctx) { - if (dctx->cctx->drvflags & SLBT_DRIVER_CONFIG) - slbt_output_config(dctx); + if (dctx->cctx->drvflags & SLBT_DRIVER_INFO) + slbt_output_info(dctx); if (dctx->cctx->drvflags & SLBT_DRIVER_FEATURES) slbt_output_features(dctx); + if (dctx->cctx->mode == SLBT_MODE_CONFIG) + slbt_output_config(dctx); + if (dctx->cctx->mode == SLBT_MODE_COMPILE) - slbt_exec_compile(dctx,0); + slbt_exec_compile(dctx); if (dctx->cctx->mode == SLBT_MODE_EXECUTE) - slbt_exec_execute(dctx,0); + slbt_exec_execute(dctx); if (dctx->cctx->mode == SLBT_MODE_INSTALL) - slbt_exec_install(dctx,0); + slbt_exec_install(dctx); if (dctx->cctx->mode == SLBT_MODE_LINK) - slbt_exec_link(dctx,0); + slbt_exec_link(dctx); if (dctx->cctx->mode == SLBT_MODE_UNINSTALL) - slbt_exec_uninstall(dctx,0); + slbt_exec_uninstall(dctx); + + if (dctx->cctx->mode == SLBT_MODE_AR) + slbt_exec_ar(dctx); + + if (dctx->cctx->mode == SLBT_MODE_STOOLIE) + slbt_exec_stoolie(dctx); } static int slbt_exit(struct slbt_driver_ctx * dctx, int ret) { slbt_output_error_vector(dctx); - slbt_free_driver_ctx(dctx); + slbt_lib_free_driver_ctx(dctx); return ret; } @@ -122,6 +131,17 @@ int slbt_main(char ** argv, char ** envp, const struct slbt_fd_ctx * fdctx) else if (!(strcmp(dash,"static"))) flags = SLBT_DRIVER_FLAGS | SLBT_DRIVER_DISABLE_SHARED; + /* internal ar mode */ + else if (!(strcmp(dash,"ar"))) + flags |= SLBT_DRIVER_MODE_AR; + + /* slibtoolize (stoolie) mode */ + if (!(strcmp(program,"stoolie"))) + flags |= SLBT_DRIVER_MODE_STOOLIE; + + else if (!(strcmp(program,"slibtoolize"))) + flags |= SLBT_DRIVER_MODE_STOOLIE; + /* debug */ if (!(strcmp(program,"dlibtool"))) flags |= SLBT_DRIVER_DEBUG; @@ -159,7 +179,7 @@ int slbt_main(char ** argv, char ** envp, const struct slbt_fd_ctx * fdctx) | SLBT_DRIVER_LEGABITS); /* driver context */ - if ((ret = slbt_get_driver_ctx(argv,envp,flags|noclr,fdctx,&dctx))) + if ((ret = slbt_lib_get_driver_ctx(argv,envp,flags|noclr,fdctx,&dctx))) return (ret == SLBT_USAGE) ? !argv || !argv[0] || !argv[1] || !argv[2] : SLBT_ERROR; @@ -169,12 +189,22 @@ int slbt_main(char ** argv, char ** envp, const struct slbt_fd_ctx * fdctx) return slbt_output_machine(dctx) ? SLBT_ERROR : SLBT_OK; - /* --version is always the first action */ + /* --version must be the first (and only) action */ if (dctx->cctx->drvflags & SLBT_DRIVER_VERSION) - if ((slbt_version(dctx,fdout)) < 0) - return slbt_exit(dctx,SLBT_ERROR); + if (dctx->cctx->mode != SLBT_MODE_AR) + if (dctx->cctx->mode != SLBT_MODE_STOOLIE) + return (slbt_version(dctx,fdout) < 0) + ? slbt_exit(dctx,SLBT_ERROR) + : slbt_exit(dctx,SLBT_OK); + /* perform all other actions */ slbt_perform_driver_actions(dctx); + /* print --version on behalf of a secondary tool as needed */ + if (dctx->cctx->drvflags & SLBT_DRIVER_VERSION) + return (slbt_version(dctx,fdout) < 0) + ? slbt_exit(dctx,SLBT_ERROR) + : slbt_exit(dctx,SLBT_OK); + return slbt_exit(dctx,dctx->errv[0] ? SLBT_ERROR : SLBT_OK); } diff --git a/src/driver/slbt_driver_ctx.c b/src/driver/slbt_driver_ctx.c index 4a5bf62..85c75d2 100644 --- a/src/driver/slbt_driver_ctx.c +++ b/src/driver/slbt_driver_ctx.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,6 +11,7 @@ #include <stdbool.h> #include <fcntl.h> #include <spawn.h> +#include <sys/mman.h> #include <sys/wait.h> #define ARGV_DRIVER @@ -18,12 +19,20 @@ #include <slibtool/slibtool.h> #include "slibtool_version.h" #include "slibtool_driver_impl.h" +#include "slibtool_objlist_impl.h" #include "slibtool_errinfo_impl.h" #include "slibtool_lconf_impl.h" +#include "slibtool_txtline_impl.h" +#include "slibtool_stoolie_impl.h" +#include "slibtool_ar_impl.h" #include "argv/argv.h" extern char ** environ; +/* annotation strings */ +static const char cfgexplicit[] = "command-line argument"; +static const char cfglconf[] = "derived from <libtool>"; + /* package info */ static const struct slbt_source_version slbt_src_version = { SLBT_TAG_VER_MAJOR, @@ -42,91 +51,24 @@ static const struct slbt_fd_ctx slbt_default_fdctx = { .fdlog = (-1), }; -/* 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 const char aclr_reset [] = "\x1b[0m"; +static const char aclr_bold [] = "\x1b[1m"; +static const char aclr_red [] = "\x1b[31m"; +static const char aclr_green [] = "\x1b[32m"; +static const char aclr_yellow [] = "\x1b[33m"; +static const char aclr_blue [] = "\x1b[34m"; +static const char aclr_magenta [] = "\x1b[35m"; +static const char aclr_cyan [] = "\x1b[36m"; +static const char aclr_white [] = "\x1b[37m"; -/* 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"; - - -/* default compiler argv */ -static char * slbt_default_cargv[] = {"cc",0}; - -/* elf rpath */ -static const char*ldrpath_elf[] = { - "/lib", - "/lib/64", - "/usr/lib", - "/usr/lib64", - "/usr/local/lib", - "/usr/local/lib64", - 0}; - -static const char aclr_reset [] = "\x1b[0m"; -static const char aclr_bold [] = "\x1b[1m"; -static const char aclr_red [] = "\x1b[31m"; -static const char aclr_green [] = "\x1b[32m"; -static const char aclr_yellow[] = "\x1b[33m"; -static const char aclr_blue [] = "\x1b[34m"; -static const char aclr_cyan [] = "\x1b[36m"; -static const char aclr_white [] = "\x1b[37m"; - -struct slbt_driver_ctx_alloc { - struct argv_meta * meta; - struct slbt_driver_ctx_impl ctx; - uint64_t guard; -}; static void slbt_output_raw_vector(int fderr, char ** argv, char ** envp, bool fcolor) { char ** parg; char * dot; const char * color; + const char * prev; + const char * prog; (void)envp; @@ -135,19 +77,68 @@ static void slbt_output_raw_vector(int fderr, char ** argv, char ** envp, bool f slbt_dprintf(fderr,"\n\n\n%s",argv[0]); - for (parg=&argv[1]; *parg; parg++) { - if (!fcolor) + for (prev=0,prog=0,parg=&argv[1]; *parg; parg++) { + dot = strrchr(*parg,'.'); + + if (!fcolor) { color = ""; - else if (*parg[0] == '-') - color = aclr_blue; - else if (!(dot = strrchr(*parg,'.'))) + + } else if (!prog && (parg[0][0] != '-')) { + color = aclr_magenta; + prog = *parg; + prev = 0; + + } else if (!strcmp(parg[0],"-o")) { + color = aclr_white; + prev = color; + + } else if (!strcmp(parg[0],"-c")) { color = aclr_green; - else if (!(strcmp(dot,".lo"))) + prev = color; + + } else if (!strncmp(parg[0],"-Wl,",4)) { + color = aclr_magenta; + prev = 0; + + } else if (prev == aclr_white) { + color = prev; + prev = 0; + + } else if (dot && !strcmp(dot,".o")) { color = aclr_cyan; - else if (!(strcmp(dot,".la"))) + prev = 0; + + } else if (dot && !strcmp(dot,".lo")) { + color = aclr_cyan; + prev = 0; + + } else if (dot && !strcmp(dot,".la")) { color = aclr_yellow; - else - color = aclr_white; + prev = 0; + + } else if (!strcmp(parg[0],"-dlopen")) { + color = aclr_yellow; + prev = color; + + } else if (!strcmp(parg[0],"-dlpreopen")) { + color = aclr_yellow; + prev = color; + + } else if (!strcmp(parg[0],"-objectlist")) { + color = aclr_yellow; + prev = color; + + } else if (*parg[0] == '-') { + color = aclr_blue; + prev = color; + + } else if (prev) { + color = prev; + prev = 0; + + } else { + color = aclr_yellow; + } slbt_dprintf(fderr," %s%s",color,*parg); } @@ -155,7 +146,67 @@ static void slbt_output_raw_vector(int fderr, char ** argv, char ** envp, bool f slbt_dprintf(fderr,"%s\n\n",fcolor ? aclr_reset : ""); } -static uint32_t slbt_argv_flags(uint32_t flags) +slbt_hidden const char * slbt_program_name(const char * path) +{ + return argv_program_name(path); +} + + +slbt_hidden int slbt_optv_init( + const struct argv_option options[], + const struct argv_option ** optv) +{ + return argv_optv_init(options,optv); +} + + +slbt_hidden void slbt_argv_scan( + char ** argv, + const struct argv_option ** optv, + struct argv_ctx * ctx, + struct argv_meta * meta) +{ + argv_scan(argv,optv,ctx,meta); +} + + +slbt_hidden struct argv_meta * slbt_argv_get( + char ** argv, + const struct argv_option ** optv, + int flags, + int fd) +{ + return argv_get(argv,optv,flags,fd); +} + + +slbt_hidden void slbt_argv_free(struct argv_meta * meta) +{ + argv_free(meta); +} + + +slbt_hidden void slbt_argv_usage( + int fd, + const char * header, + const struct argv_option ** optv, + const char * mode) +{ + argv_usage(fd,header,optv,mode); +} + + +slbt_hidden void slbt_argv_usage_plain( + int fd, + const char * header, + const struct argv_option ** optv, + const char * mode) +{ + argv_usage_plain(fd,header,optv,mode); +} + + +slbt_hidden uint64_t slbt_argv_flags(uint64_t flags) { uint32_t ret = 0; @@ -171,8 +222,12 @@ static uint32_t slbt_argv_flags(uint32_t flags) return ret; } -static int slbt_free_argv_buffer(struct slbt_split_vector * sargv) +static int slbt_free_argv_buffer( + struct slbt_split_vector * sargv, + struct slbt_obj_list * objlistv) { + struct slbt_obj_list * objlistp; + if (sargv->dargs) free(sargv->dargs); @@ -182,16 +237,26 @@ static int slbt_free_argv_buffer(struct slbt_split_vector * sargv) if (sargv->targv) free(sargv->targv); + if (objlistv) { + for (objlistp=objlistv; objlistp->name; objlistp++) { + free(objlistp->objv); + free(objlistp->addr); + } + + free(objlistv); + } + return -1; } -static int slbt_driver_usage( +slbt_hidden int slbt_driver_usage( int fdout, const char * program, const char * arg, const struct argv_option ** optv, struct argv_meta * meta, struct slbt_split_vector * sargv, + struct slbt_obj_list * objlistv, int noclr) { char header[512]; @@ -211,17 +276,18 @@ static int slbt_driver_usage( } argv_free(meta); - slbt_free_argv_buffer(sargv); + slbt_free_argv_buffer(sargv,objlistv); return SLBT_USAGE; } static struct slbt_driver_ctx_impl * slbt_driver_ctx_alloc( - struct argv_meta * meta, const struct slbt_fd_ctx * fdctx, const struct slbt_common_ctx * cctx, struct slbt_split_vector * sargv, - char ** envp) + struct slbt_obj_list * objlistv, + char ** envp, + size_t ndlopen) { struct slbt_driver_ctx_alloc * ictx; size_t size; @@ -230,10 +296,20 @@ static struct slbt_driver_ctx_impl * slbt_driver_ctx_alloc( size = sizeof(struct slbt_driver_ctx_alloc); if (!(ictx = calloc(1,size))) { - slbt_free_argv_buffer(sargv); + slbt_free_argv_buffer(sargv,objlistv); return 0; } + if (ndlopen) { + if (!(ictx->ctx.dlopenv = calloc(ndlopen+1,sizeof(*ictx->ctx.dlopenv)))) { + free(ictx); + slbt_free_argv_buffer(sargv,objlistv); + return 0; + } + + ictx->ctx.ndlopen = ndlopen; + } + ictx->ctx.dargs = sargv->dargs; ictx->ctx.dargv = sargv->dargv; ictx->ctx.targv = sargv->targv; @@ -248,18 +324,20 @@ static struct slbt_driver_ctx_impl * slbt_driver_ctx_alloc( ictx->ctx.errinfp = &ictx->ctx.erriptr[0]; ictx->ctx.erricap = &ictx->ctx.erriptr[--elements]; - ictx->meta = meta; - ictx->ctx.ctx.errv = ictx->ctx.errinfp; + ictx->ctx.objlistv = objlistv; + + ictx->ctx.ctx.errv = ictx->ctx.errinfp; + return &ictx->ctx; } -static int slbt_get_driver_ctx_fail( +static int slbt_lib_get_driver_ctx_fail( struct slbt_driver_ctx * dctx, struct argv_meta * meta) { if (dctx) { slbt_output_error_vector(dctx); - slbt_free_driver_ctx(dctx); + slbt_lib_free_driver_ctx(dctx); } else { argv_free(meta); } @@ -267,1042 +345,6 @@ static int slbt_get_driver_ctx_fail( return -1; } -static int slbt_split_argv( - char ** argv, - uint32_t flags, - struct slbt_split_vector * sargv, - int fderr) -{ - int i; - int argc; - const char * program; - char * compiler; - char * csysroot; - char ** dargv; - char ** targv; - char ** cargv; - char * dst; - bool flast; - bool fcopy; - size_t size; - const char * base; - struct argv_meta * meta; - struct argv_entry * entry; - struct argv_entry * mode; - struct argv_entry * help; - struct argv_entry * version; - struct argv_entry * config; - struct argv_entry * finish; - struct argv_entry * features; - struct argv_entry * ccwrap; - struct argv_entry * dumpmachine; - const struct argv_option ** popt; - const struct argv_option ** optout; - const struct argv_option * optv[SLBT_OPTV_ELEMENTS]; - struct argv_ctx ctx = {ARGV_VERBOSITY_NONE, - ARGV_MODE_SCAN, - 0,0,0,0,0,0,0}; - - program = argv_program_name(argv[0]); - - /* missing arguments? */ - argv_optv_init(slbt_default_options,optv); - - if (!argv[1] && (flags & SLBT_DRIVER_VERBOSITY_USAGE)) - return slbt_driver_usage( - fderr,program, - 0,optv,0,sargv, - !!getenv("NO_COLOR")); - - /* initial argv scan: ... --mode=xxx ... <compiler> ... */ - argv_scan(argv,optv,&ctx,0); - - /* invalid slibtool arguments? */ - if (ctx.erridx && !ctx.unitidx) { - if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) - argv_get( - argv,optv, - slbt_argv_flags(flags), - fderr); - return -1; - } - - /* obtain slibtool's own arguments */ - if (ctx.unitidx) { - compiler = argv[ctx.unitidx]; - argv[ctx.unitidx] = 0; - - meta = argv_get(argv,optv,ARGV_VERBOSITY_NONE,fderr); - argv[ctx.unitidx] = compiler; - } else { - meta = argv_get(argv,optv,ARGV_VERBOSITY_NONE,fderr); - } - - /* missing all of --mode, --help, --version, --config, --dumpmachine, --features, and --finish? */ - mode = help = version = config = finish = features = ccwrap = dumpmachine = 0; - - for (entry=meta->entries; entry->fopt; entry++) - if (entry->tag == TAG_MODE) - mode = entry; - else if (entry->tag == TAG_HELP) - help = entry; - else if (entry->tag == TAG_VERSION) - version = entry; - else if (entry->tag == TAG_CONFIG) - config = entry; - else if (entry->tag == TAG_FINISH) - finish = entry; - else if (entry->tag == TAG_FEATURES) - features = entry; - else if (entry->tag == TAG_CCWRAP) - ccwrap = entry; - else if (entry->tag == TAG_DUMPMACHINE) - dumpmachine = entry; - - argv_free(meta); - - if (!mode && !help && !version && !config && !finish && !features && !dumpmachine) { - slbt_dprintf(fderr, - "%s: error: --mode must be specified.\n", - program); - return -1; - } - - /* missing compiler? */ - if (!ctx.unitidx && !help && !version && !finish && !features && !dumpmachine) { - if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) - slbt_dprintf(fderr, - "%s: error: <compiler> is missing.\n", - program); - return -1; - } - - /* clone and normalize the argv vector (-l, --library) */ - for (argc=0,size=0,dargv=argv; *dargv; argc++,dargv++) - size += strlen(*dargv) + 1; - - if (!(sargv->dargv = calloc(argc+1,sizeof(char *)))) - return -1; - - else if (!(sargv->dargs = calloc(1,size+1))) - return -1; - - csysroot = 0; - - for (i=0,flast=false,dargv=sargv->dargv,dst=sargv->dargs; i<argc; i++) { - if ((fcopy = flast)) { - (void)0; - - } else if (!strcmp(argv[i],"--")) { - flast = true; - fcopy = true; - - } else if (!strcmp(argv[i],"-l")) { - *dargv++ = dst; - *dst++ = '-'; - *dst++ = 'l'; - strcpy(dst,argv[++i]); - dst += strlen(dst)+1; - - } else if (!strncmp(argv[i],"-l",2)) { - fcopy = true; - - } else if (!strcmp(argv[i],"--library")) { - *dargv++ = dst; - *dst++ = '-'; - *dst++ = 'l'; - strcpy(dst,argv[++i]); - dst += strlen(dst)+1; - - } else if (!strncmp(argv[i],"--library=",10)) { - *dargv++ = dst; - *dst++ = '-'; - *dst++ = 'l'; - strcpy(dst,&argv[++i][10]); - dst += strlen(dst)+1; - - } else if (!strcmp(argv[i],"-L")) { - *dargv++ = dst; - *dst++ = '-'; - *dst++ = 'L'; - strcpy(dst,argv[++i]); - dst += strlen(dst)+1; - - } else if (!strncmp(argv[i],"-L",2)) { - fcopy = true; - - } else if (!strcmp(argv[i],"-Xlinker")) { - *dargv++ = dst; - *dst++ = '-'; - *dst++ = 'W'; - *dst++ = 'l'; - *dst++ = ','; - strcpy(dst,argv[++i]); - dst += strlen(dst)+1; - - } else if (!strcmp(argv[i],"--library-path")) { - *dargv++ = dst; - *dst++ = '-'; - *dst++ = 'L'; - strcpy(dst,argv[++i]); - dst += strlen(dst)+1; - - } else if (!strncmp(argv[i],"--library-path=",15)) { - *dargv++ = dst; - *dst++ = '-'; - *dst++ = 'L'; - strcpy(dst,&argv[i][15]); - dst += strlen(dst)+1; - - } else if (!strcmp(argv[i],"--sysroot") && (i<ctx.unitidx)) { - *dargv++ = dst; - csysroot = dst; - strcpy(dst,argv[i]); - dst[9] = '='; - strcpy(&dst[10],argv[++i]); - dst += strlen(dst)+1; - ctx.unitidx--; - - } else if (!strncmp(argv[i],"--sysroot=",10) && (i<ctx.unitidx)) { - *dargv++ = dst; - csysroot = dst; - strcpy(dst,argv[i]); - dst += strlen(dst)+1; - - } else { - fcopy = true; - } - - if (fcopy) { - *dargv++ = dst; - strcpy(dst,argv[i]); - dst += strlen(dst)+1; - } - } - - /* update argc,argv */ - argc = dargv - sargv->dargv; - argv = sargv->dargv; - - /* allocate split vectors, account for cargv's added sysroot */ - if ((sargv->targv = calloc(2*(argc+3),sizeof(char *)))) - sargv->cargv = sargv->targv + argc + 2; - else - return -1; - - /* --features and no <compiler>? */ - if (ctx.unitidx) { - (void)0; - - } else if (help || version || features || dumpmachine) { - for (i=0; i<argc; i++) - sargv->targv[i] = argv[i]; - - sargv->cargv = slbt_default_cargv; - - return 0; - } - - /* split vectors: slibtool's own options */ - for (i=0; i<ctx.unitidx; i++) - sargv->targv[i] = argv[i]; - - /* split vector marks */ - targv = sargv->targv + i; - cargv = sargv->cargv; - - /* known wrappers */ - if (ctx.unitidx && !ccwrap) { - if ((base = strrchr(argv[i],'/'))) - base++; - else if ((base = strrchr(argv[i],'\\'))) - base++; - else - base = argv[i]; - - if (!strcmp(base,"ccache") - || !strcmp(base,"distcc") - || !strcmp(base,"compiler") - || !strcmp(base,"purify")) { - *targv++ = "--ccwrap"; - *targv++ = argv[i++]; - } - } - - /* split vectors: legacy mixture */ - for (optout=optv; optout[0]->tag != TAG_OUTPUT; optout++) - (void)0; - - /* compiler */ - *cargv++ = argv[i++]; - - /* sysroot */ - if (csysroot) - *cargv++ = csysroot; - - /* remaining vector */ - for (; i<argc; i++) { - if (argv[i][0] != '-') { - if (argv[i+1] && (argv[i+1][0] == '+') - && (argv[i+1][1] == '=') - && (argv[i+1][2] == 0) - && !(strrchr(argv[i],'.'))) - /* libfoo_la_LDFLAGS += -Wl,.... */ - i++; - else - *cargv++ = argv[i]; - - } else if (argv[i][1] == 'o') { - *targv++ = argv[i]; - - if (argv[i][2] == 0) - *targv++ = argv[++i]; - } else if ((argv[i][1] == 'W') && (argv[i][2] == 'c')) { - *cargv++ = argv[i]; - - } else if (!(strcmp("Xcompiler",&argv[i][1]))) { - *cargv++ = argv[++i]; - - } else if (!(strcmp("XCClinker",&argv[i][1]))) { - *cargv++ = argv[++i]; - - } else if ((argv[i][1] == 'R') && (argv[i][2] == 0)) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (argv[i][1] == 'R') { - *targv++ = argv[i]; - - } else if (!(strncmp("-target=",&argv[i][1],8))) { - *cargv++ = argv[i]; - *targv++ = argv[i]; - - } else if (!(strcmp("-target",&argv[i][1]))) { - *cargv++ = argv[i]; - *targv++ = argv[i++]; - - *cargv++ = argv[i]; - *targv++ = argv[i]; - - } else if (!(strncmp("-sysroot=",&argv[i][1],9))) { - *cargv++ = argv[i]; - *targv++ = argv[i]; - - } else if (!(strcmp("-sysroot",&argv[i][1]))) { - *cargv++ = argv[i]; - *targv++ = argv[i++]; - - *cargv++ = argv[i]; - *targv++ = argv[i]; - - } else if (!(strcmp("bindir",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("shrext",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("rpath",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("release",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("dlopen",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("weak",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("static-libtool-libs",&argv[i][1]))) { - *targv++ = argv[i]; - - } else if (!(strcmp("export-dynamic",&argv[i][1]))) { - *targv++ = argv[i]; - - } else if (!(strcmp("export-symbols",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("export-symbols-regex",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("version-info",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("version-number",&argv[i][1]))) { - *targv++ = argv[i++]; - *targv++ = argv[i]; - - } else if (!(strcmp("dlpreopen",&argv[i][1]))) { - (void)0; - - } else { - for (popt=optout; popt[0] && popt[0]->long_name; popt++) - if (!(strcmp(popt[0]->long_name,&argv[i][1]))) - break; - - if (popt[0] && popt[0]->long_name) - *targv++ = argv[i]; - else - *cargv++ = argv[i]; - } - } - - return 0; -} - -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); - } -} - -static 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) -{ - 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 = 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_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 = 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; - } - - /* ranlib */ - if (host->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 = 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_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->ranlib) - free(host->ranlib); - - if (host->windres) - free(host->windres); - - if (host->dlltool) - free(host->dlltool); - - if (host->mdso) - free(host->mdso); - - memset(host,0,sizeof(*host)); -} - -static 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; -} - -static 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; -} - -static int slbt_init_version_info( - struct slbt_driver_ctx_impl * ictx, - struct slbt_version_info * verinfo) -{ - int current; - int revision; - int age; - - if (!verinfo->verinfo && !verinfo->vernumber) - return 0; - - if (verinfo->vernumber) { - sscanf(verinfo->vernumber,"%d:%d:%d", - &verinfo->major, - &verinfo->minor, - &verinfo->revision); - return 0; - } - - current = revision = age = 0; - - sscanf(verinfo->verinfo,"%d:%d:%d", - ¤t,&revision,&age); - - if (current < age) { - if (ictx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) - slbt_dprintf(ictx->fdctx.fderr, - "%s: error: invalid version info: " - "<current> may not be smaller than <age>.\n", - argv_program_name(ictx->cctx.targv[0])); - return -1; - } - - verinfo->major = current - age; - verinfo->minor = age; - verinfo->revision = revision; - - return 0; -} - -static int slbt_init_link_params(struct slbt_driver_ctx_impl * ctx) -{ - const char * program; - const char * libname; - const char * prefix; - const char * base; - char * dot; - bool fmodule; - int fderr; - - fderr = ctx->fdctx.fderr; - program = argv_program_name(ctx->cctx.targv[0]); - libname = 0; - prefix = 0; - fmodule = false; - - /* output */ - if (!(ctx->cctx.output)) { - if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) - slbt_dprintf(fderr, - "%s: error: output file must be " - "specified in link mode.\n", - program); - return -1; - } - - /* executable? */ - if (!(dot = strrchr(ctx->cctx.output,'.'))) - if (!(ctx->cctx.drvflags & SLBT_DRIVER_MODULE)) - return 0; - - /* todo: archive? library? wrapper? inlined function, avoid repetition */ - if ((base = strrchr(ctx->cctx.output,'/'))) - base++; - else - base = ctx->cctx.output; - - /* archive? */ - if (dot && !strcmp(dot,ctx->cctx.settings.arsuffix)) { - prefix = ctx->cctx.settings.arprefix; - - if (!strncmp(prefix,base,strlen(prefix))) - libname = base; - else { - if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) - slbt_dprintf(fderr, - "%s: error: output file prefix does " - "not match its (archive) suffix; " - "the expected prefix was '%s'\n", - program,prefix); - return -1; - } - } - - /* library? */ - else if (dot && !strcmp(dot,ctx->cctx.settings.dsosuffix)) { - prefix = ctx->cctx.settings.dsoprefix; - - if (!strncmp(prefix,base,strlen(prefix))) { - libname = base; - - } else if (ctx->cctx.drvflags & SLBT_DRIVER_MODULE) { - libname = base; - fmodule = true; - - } else { - if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) - slbt_dprintf(fderr, - "%s: error: output file prefix does " - "not match its (shared library) suffix; " - "the expected prefix was '%s'\n", - program,prefix); - return -1; - } - } - - /* wrapper? */ - else if (dot && !strcmp(dot,".la")) { - prefix = ctx->cctx.settings.dsoprefix; - - if (!strncmp(prefix,base,strlen(prefix))) { - libname = base; - fmodule = !!(ctx->cctx.drvflags & SLBT_DRIVER_MODULE); - } else if (ctx->cctx.drvflags & SLBT_DRIVER_MODULE) { - libname = base; - fmodule = true; - } else { - if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) - slbt_dprintf(fderr, - "%s: error: output file prefix does " - "not match its (libtool wrapper) suffix; " - "the expected prefix was '%s'\n", - program,prefix); - return -1; - } - } else - return 0; - - /* libname alloc */ - if (!fmodule) - libname += strlen(prefix); - - if (!(ctx->libname = strdup(libname))) - return -1; - - if ((dot = strrchr(ctx->libname,'.'))) - *dot = 0; - - ctx->cctx.libname = ctx->libname; - - return 0; -} static int slbt_driver_fail_incompatible_args( int fderr, @@ -1335,17 +377,25 @@ static int slbt_driver_fail_incompatible_args( aclr_reset); } - return slbt_get_driver_ctx_fail(0,meta); + return slbt_lib_get_driver_ctx_fail(0,meta); } -int slbt_get_driver_ctx( + +static int slbt_driver_parse_tool_argv(const char * tool, char *** tool_argv) +{ + return slbt_txtline_to_string_vector(tool,tool_argv); +} + + +int slbt_lib_get_driver_ctx( char ** argv, char ** envp, - uint32_t flags, + uint64_t flags, const struct slbt_fd_ctx * fdctx, struct slbt_driver_ctx ** pctx) { struct slbt_split_vector sargv; + struct slbt_obj_list * objlistv; struct slbt_driver_ctx_impl * ctx; struct slbt_common_ctx cctx; const struct argv_option * optv[SLBT_OPTV_ELEMENTS]; @@ -1358,8 +408,24 @@ int slbt_get_driver_ctx( const char * program; const char * lconf; uint64_t lflags; + size_t ndlopen; + struct argv_entry ** dlopenv; + const char * cfgmeta_host; + const char * cfgmeta_ar; + const char * cfgmeta_as; + const char * cfgmeta_nm; + const char * cfgmeta_ranlib; + const char * cfgmeta_dlltool; + + if (flags & SLBT_DRIVER_MODE_AR) { + argv_optv_init(slbt_ar_options,optv); - argv_optv_init(slbt_default_options,optv); + } else if (flags & SLBT_DRIVER_MODE_STOOLIE) { + argv_optv_init(slbt_stoolie_options,optv); + + } else { + argv_optv_init(slbt_default_options,optv); + } if (!fdctx) fdctx = &slbt_default_fdctx; @@ -1368,23 +434,39 @@ int slbt_get_driver_ctx( sargv.dargv = 0; sargv.targv = 0; sargv.cargv = 0; + objlistv = 0; + ndlopen = 0; - if (slbt_split_argv(argv,flags,&sargv,fdctx->fderr)) - return slbt_free_argv_buffer(&sargv); + switch (slbt_split_argv(argv,flags,&sargv,&objlistv,fdctx->fderr,fdctx->fdcwd)) { + case SLBT_OK: + break; + + case SLBT_USAGE: + return SLBT_USAGE; + + default: + return slbt_free_argv_buffer(&sargv,objlistv); + } if (!(meta = argv_get( sargv.targv,optv, slbt_argv_flags(flags), fdctx->fderr))) - return slbt_free_argv_buffer(&sargv); + return slbt_free_argv_buffer(&sargv,objlistv); lconf = 0; program = argv_program_name(argv[0]); memset(&cctx,0,sizeof(cctx)); - /* shared and static objects: enable by default, disable by ~switch */ - cctx.drvflags = flags | SLBT_DRIVER_SHARED | SLBT_DRIVER_STATIC; + if (flags & SLBT_DRIVER_MODE_AR) + cctx.mode = SLBT_MODE_AR; + + else if (flags & SLBT_DRIVER_MODE_STOOLIE) + cctx.mode = SLBT_MODE_STOOLIE; + + /* default flags (set at compile time and derived from symlink) */ + cctx.drvflags = flags; /* full annotation when annotation is on; */ if (!(cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER)) @@ -1396,6 +478,13 @@ int slbt_get_driver_ctx( cmdnostatic = 0; cmdnoshared = 0; + cfgmeta_host = 0; + cfgmeta_ar = 0; + cfgmeta_as = 0; + cfgmeta_nm = 0; + cfgmeta_ranlib = 0; + cfgmeta_dlltool = 0; + /* get options */ for (entry=meta->entries; entry->fopt || entry->arg; entry++) { if (entry->fopt) { @@ -1405,6 +494,8 @@ int slbt_get_driver_ctx( switch (cctx.mode) { case SLBT_MODE_INSTALL: case SLBT_MODE_UNINSTALL: + case SLBT_MODE_AR: + case SLBT_MODE_STOOLIE: break; default: @@ -1412,7 +503,7 @@ int slbt_get_driver_ctx( ? slbt_driver_usage( fdctx->fdout,program, entry->arg,optv, - meta,&sargv, + meta,&sargv,objlistv, (cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER)) : SLBT_USAGE; } @@ -1449,6 +540,15 @@ int slbt_get_driver_ctx( else if (!strcmp("uninstall",entry->arg)) cctx.mode = SLBT_MODE_UNINSTALL; + + else if (!strcmp("ar",entry->arg)) + cctx.mode = SLBT_MODE_AR; + + else if (!strcmp("stoolie",entry->arg)) + cctx.mode = SLBT_MODE_STOOLIE; + + else if (!strcmp("slibtoolize",entry->arg)) + cctx.mode = SLBT_MODE_STOOLIE; break; case TAG_FINISH: @@ -1472,6 +572,9 @@ int slbt_get_driver_ctx( else if (!strcmp("F77",entry->arg)) cctx.tag = SLBT_TAG_F77; + else if (!strcmp("ASM",entry->arg)) + cctx.tag = SLBT_TAG_ASM; + else if (!strcmp("NASM",entry->arg)) cctx.tag = SLBT_TAG_NASM; @@ -1485,8 +588,12 @@ int slbt_get_driver_ctx( cmdnoshared = entry; break; + case TAG_INFO: + cctx.drvflags |= SLBT_DRIVER_INFO; + break; + case TAG_CONFIG: - cctx.drvflags |= SLBT_DRIVER_CONFIG; + cctx.drvflags |= SLBT_DRIVER_OUTPUT_CONFIG; break; case TAG_DUMPMACHINE: @@ -1572,6 +679,7 @@ int slbt_get_driver_ctx( case TAG_HOST: cctx.host.host = entry->arg; + cfgmeta_host = cfgexplicit; break; case TAG_FLAVOR: @@ -1580,10 +688,22 @@ int slbt_get_driver_ctx( case TAG_AR: cctx.host.ar = entry->arg; + cfgmeta_ar = cfgexplicit; + break; + + case TAG_AS: + cctx.host.as = entry->arg; + cfgmeta_as = cfgexplicit; + break; + + case TAG_NM: + cctx.host.nm = entry->arg; + cfgmeta_nm = cfgexplicit; break; case TAG_RANLIB: cctx.host.ranlib = entry->arg; + cfgmeta_ranlib = cfgexplicit; break; case TAG_WINDRES: @@ -1592,6 +712,7 @@ int slbt_get_driver_ctx( case TAG_DLLTOOL: cctx.host.dlltool = entry->arg; + cfgmeta_dlltool = cfgexplicit; break; case TAG_MDSO: @@ -1619,6 +740,8 @@ int slbt_get_driver_ctx( break; case TAG_DLOPEN: + case TAG_DLPREOPEN: + ndlopen++; break; case TAG_STATIC_LIBTOOL_LIBS: @@ -1629,11 +752,11 @@ int slbt_get_driver_ctx( cctx.drvflags |= SLBT_DRIVER_EXPORT_DYNAMIC; break; - case TAG_EXPSYM_FILE: - cctx.symfile = entry->arg; + case TAG_EXPSYMS_FILE: + cctx.expsyms = entry->arg; break; - case TAG_EXPSYM_REGEX: + case TAG_EXPSYMS_REGEX: cctx.regex = entry->arg; break; @@ -1683,10 +806,12 @@ int slbt_get_driver_ctx( case TAG_SHARED: cmdshared = entry; + cctx.drvflags |= SLBT_DRIVER_PREFER_SHARED; break; case TAG_STATIC: cmdstatic = entry; + cctx.drvflags |= SLBT_DRIVER_PREFER_STATIC; break; case TAG_WEAK: @@ -1695,6 +820,15 @@ int slbt_get_driver_ctx( } } + /* enable both shared and static targets by default as appropriate */ + if (!(cctx.drvflags & SLBT_DRIVER_HEURISTICS)) { + if (!cmdnoshared) + cctx.drvflags |= SLBT_DRIVER_SHARED; + + if (!cmdnostatic) + cctx.drvflags |= SLBT_DRIVER_STATIC; + } + /* incompatible command-line arguments? */ if (cmdstatic && cmdshared) return slbt_driver_fail_incompatible_args( @@ -1767,8 +901,12 @@ int slbt_get_driver_ctx( cctx.output = 0; } + /* config mode */ + if (cctx.drvflags & SLBT_DRIVER_OUTPUT_CONFIG) + cctx.mode = SLBT_MODE_CONFIG; + /* info mode */ - if (cctx.drvflags & (SLBT_DRIVER_CONFIG | SLBT_DRIVER_FEATURES)) + if (cctx.drvflags & (SLBT_DRIVER_INFO | SLBT_DRIVER_FEATURES)) cctx.mode = SLBT_MODE_INFO; /* --tag */ @@ -1776,9 +914,13 @@ int slbt_get_driver_ctx( if (cctx.tag == SLBT_TAG_UNKNOWN) cctx.tag = SLBT_TAG_CC; + /* dlopen/dlpreopen: first vector member is a virtual archive */ + if (ndlopen) + ndlopen++; + /* driver context */ - if (!(ctx = slbt_driver_ctx_alloc(meta,fdctx,&cctx,&sargv,envp))) - return slbt_get_driver_ctx_fail(0,meta); + if (!(ctx = slbt_driver_ctx_alloc(fdctx,&cctx,&sargv,objlistv,envp,ndlopen))) + return slbt_lib_get_driver_ctx_fail(0,meta); /* ctx */ ctx->ctx.program = program; @@ -1786,11 +928,30 @@ int slbt_get_driver_ctx( ctx->cctx.targv = sargv.targv; ctx->cctx.cargv = sargv.cargv; + ctx->meta = meta; /* heuristics */ if (cctx.drvflags & SLBT_DRIVER_HEURISTICS) { if (slbt_get_lconf_flags(&ctx->ctx,lconf,&lflags) < 0) - return slbt_get_driver_ctx_fail(&ctx->ctx,0); + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + + if (ctx->cctx.host.host && !cfgmeta_host) + cfgmeta_host = cfglconf; + + if (ctx->cctx.host.ar && !cfgmeta_ar) + cfgmeta_ar = cfglconf; + + if (ctx->cctx.host.as && !cfgmeta_as) + cfgmeta_as = cfglconf; + + if (ctx->cctx.host.nm && !cfgmeta_nm) + cfgmeta_nm = cfglconf; + + if (ctx->cctx.host.ranlib && !cfgmeta_ranlib) + cfgmeta_ranlib = cfglconf; + + if (ctx->cctx.host.dlltool && !cfgmeta_dlltool) + cfgmeta_dlltool = cfglconf; if (cmdnoshared) lflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC; @@ -1800,18 +961,6 @@ int slbt_get_driver_ctx( cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC; cctx.drvflags |= lflags; - cctx.drvflags |= SLBT_DRIVER_SHARED; - cctx.drvflags |= SLBT_DRIVER_STATIC; - - if (cmdstatic) { - cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED; - cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC; - } - - if (cmdshared) { - cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC; - cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_SHARED; - } /* -disable-static? */ if (cctx.drvflags & SLBT_DRIVER_DISABLE_STATIC) @@ -1830,8 +979,33 @@ int slbt_get_driver_ctx( &ctx->cctx, &ctx->host, &ctx->cctx.host, - &ctx->cctx.cfgmeta)) - return slbt_get_driver_ctx_fail(&ctx->ctx,0); + &ctx->cctx.cfgmeta, + cfgmeta_host, + cfgmeta_ar, + cfgmeta_as, + cfgmeta_nm, + cfgmeta_ranlib, + cfgmeta_dlltool)) + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + + /* host tool arguments */ + if (slbt_driver_parse_tool_argv(ctx->cctx.host.ar,&ctx->host.ar_argv) < 0) + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + + if (slbt_driver_parse_tool_argv(ctx->cctx.host.nm,&ctx->host.nm_argv) < 0) + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + + if (slbt_driver_parse_tool_argv(ctx->cctx.host.ranlib,&ctx->host.ranlib_argv) < 0) + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + + if (slbt_driver_parse_tool_argv(ctx->cctx.host.as,&ctx->host.as_argv) < 0) + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + + if (slbt_driver_parse_tool_argv(ctx->cctx.host.dlltool,&ctx->host.dlltool_argv) < 0) + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + + if (slbt_driver_parse_tool_argv(ctx->cctx.host.mdso,&ctx->host.mdso_argv) < 0) + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); /* flavor settings */ slbt_init_flavor_settings( @@ -1840,26 +1014,83 @@ int slbt_get_driver_ctx( /* ldpath */ if (slbt_init_ldrpath(&ctx->cctx,&ctx->cctx.host)) - return slbt_get_driver_ctx_fail(&ctx->ctx,0); + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); /* version info */ if (slbt_init_version_info(ctx,&ctx->cctx.verinfo)) - return slbt_get_driver_ctx_fail(&ctx->ctx,0); + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); /* link params */ if (cctx.mode == SLBT_MODE_LINK) if (slbt_init_link_params(ctx)) - return slbt_get_driver_ctx_fail(&ctx->ctx,0); + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + + /* dlpreopen */ + if ((dlopenv = ctx->dlopenv)) { + for (entry=meta->entries; entry->fopt || entry->arg; entry++) { + if (entry->fopt) { + switch (entry->tag) { + case TAG_DLOPEN: + if (!strcmp(entry->arg,"self")) { + ctx->cctx.drvflags |= SLBT_DRIVER_DLOPEN_FORCE; + + } else if (!strcmp(entry->arg,"force")) { + ctx->cctx.drvflags |= SLBT_DRIVER_DLOPEN_FORCE; + + } else { + *dlopenv++ = entry; + } + + break; + case TAG_DLPREOPEN: + if (!strcmp(entry->arg,"self")) { + ctx->cctx.drvflags |= SLBT_DRIVER_DLPREOPEN_SELF; + + } else if (!strcmp(entry->arg,"force")) { + ctx->cctx.drvflags |= SLBT_DRIVER_DLPREOPEN_FORCE; + + } else { + *dlopenv++ = entry; + } + + break; + + default: + break; + } + } + } + } + + /* -dlopen & -dlpreopen semantic validation */ + uint64_t fmask; + + fmask = SLBT_DRIVER_DLOPEN_SELF | SLBT_DRIVER_DLPREOPEN_SELF; + fmask |= SLBT_DRIVER_DLOPEN_FORCE | SLBT_DRIVER_DLPREOPEN_FORCE; + + if (ctx->cctx.libname && (cctx.drvflags & fmask)) { + slbt_dprintf(ctx->fdctx.fderr, + "%s: error: -dlopen/-dlpreopen: " + "the special 'self' and 'force' arguments " + "may only be used when linking a program.\n", + ctx->ctx.program); + + return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0); + } + + /* all ready */ *pctx = &ctx->ctx; return 0; } -static void slbt_free_driver_ctx_impl(struct slbt_driver_ctx_alloc * ictx) + +static void slbt_lib_free_driver_ctx_impl(struct slbt_driver_ctx_alloc * ictx) { struct slbt_error_info ** perr; struct slbt_error_info * erri; + struct slbt_obj_list * objlistp; for (perr=ictx->ctx.errinfp; *perr; perr++) { erri = *perr; @@ -1868,21 +1099,40 @@ static void slbt_free_driver_ctx_impl(struct slbt_driver_ctx_alloc * ictx) free(erri->eany); } - if (ictx->ctx.libname) free(ictx->ctx.libname); + if (ictx->ctx.dlopenv) + free(ictx->ctx.dlopenv); + + if (ictx->ctx.lconf.addr) + munmap( + ictx->ctx.lconf.addr, + ictx->ctx.lconf.size); + + if (ictx->ctx.lconfctx) + slbt_lib_free_txtfile_ctx(ictx->ctx.lconfctx); + + for (objlistp=ictx->ctx.objlistv; objlistp->name; objlistp++) { + free(objlistp->objv); + free(objlistp->addr); + } + + free(ictx->ctx.objlistv); + free(ictx->ctx.dargs); free(ictx->ctx.dargv); free(ictx->ctx.targv); slbt_free_host_params(&ictx->ctx.host); slbt_free_host_params(&ictx->ctx.ahost); - argv_free(ictx->meta); + argv_free(ictx->ctx.meta); + free(ictx); } -void slbt_free_driver_ctx(struct slbt_driver_ctx * ctx) + +void slbt_lib_free_driver_ctx(struct slbt_driver_ctx * ctx) { struct slbt_driver_ctx_alloc * ictx; uintptr_t addr; @@ -1891,97 +1141,18 @@ void slbt_free_driver_ctx(struct slbt_driver_ctx * ctx) addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_impl,ctx); addr = addr - offsetof(struct slbt_driver_ctx_alloc,ctx); ictx = (struct slbt_driver_ctx_alloc *)addr; - slbt_free_driver_ctx_impl(ictx); + slbt_lib_free_driver_ctx_impl(ictx); } } -void slbt_reset_alternate_host(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_set_alternate_host( - 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)) { - 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_get_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; -} - -const struct slbt_source_version * slbt_source_version(void) +const struct slbt_source_version * slbt_api_source_version(void) { return &slbt_src_version; } -int slbt_get_driver_fdctx( + +int slbt_lib_get_driver_fdctx( const struct slbt_driver_ctx * dctx, struct slbt_fd_ctx * fdctx) { @@ -1999,7 +1170,8 @@ int slbt_get_driver_fdctx( return 0; } -int slbt_set_driver_fdctx( + +int slbt_lib_set_driver_fdctx( struct slbt_driver_ctx * dctx, const struct slbt_fd_ctx * fdctx) { diff --git a/src/driver/slbt_link_params.c b/src/driver/slbt_link_params.c new file mode 100644 index 0000000..f76a225 --- /dev/null +++ b/src/driver/slbt_link_params.c @@ -0,0 +1,131 @@ +/*******************************************************************/ +/* 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 <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> + +#include <slibtool/slibtool.h> +#include "slibtool_version.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" + + +slbt_hidden int slbt_init_link_params(struct slbt_driver_ctx_impl * ctx) +{ + const char * program; + const char * libname; + const char * prefix; + const char * base; + char * dot; + bool fmodule; + int fderr; + + fderr = ctx->fdctx.fderr; + program = slbt_program_name(ctx->cctx.targv[0]); + libname = 0; + prefix = 0; + fmodule = false; + + /* output */ + if (!(ctx->cctx.output)) { + if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: error: output file must be " + "specified in link mode.\n", + program); + return -1; + } + + /* executable? */ + if (!(dot = strrchr(ctx->cctx.output,'.'))) + if (!(ctx->cctx.drvflags & SLBT_DRIVER_MODULE)) + return 0; + + /* todo: archive? library? wrapper? inlined function, avoid repetition */ + if ((base = strrchr(ctx->cctx.output,'/'))) + base++; + else + base = ctx->cctx.output; + + /* archive? */ + if (dot && !strcmp(dot,ctx->cctx.settings.arsuffix)) { + prefix = ctx->cctx.settings.arprefix; + + if (!strncmp(prefix,base,strlen(prefix))) + libname = base; + else { + if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: error: output file prefix does " + "not match its (archive) suffix; " + "the expected prefix was '%s'\n", + program,prefix); + return -1; + } + } + + /* library? */ + else if (dot && !strcmp(dot,ctx->cctx.settings.dsosuffix)) { + prefix = ctx->cctx.settings.dsoprefix; + + if (!strncmp(prefix,base,strlen(prefix))) { + libname = base; + + } else if (ctx->cctx.drvflags & SLBT_DRIVER_MODULE) { + libname = base; + fmodule = true; + + } else { + if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: error: output file prefix does " + "not match its (shared library) suffix; " + "the expected prefix was '%s'\n", + program,prefix); + return -1; + } + } + + /* wrapper? */ + else if (dot && !strcmp(dot,".la")) { + prefix = ctx->cctx.settings.dsoprefix; + + if (!strncmp(prefix,base,strlen(prefix))) { + libname = base; + fmodule = !!(ctx->cctx.drvflags & SLBT_DRIVER_MODULE); + } else if (ctx->cctx.drvflags & SLBT_DRIVER_MODULE) { + libname = base; + fmodule = true; + } else { + if (ctx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: error: output file prefix does " + "not match its (libtool wrapper) suffix; " + "the expected prefix was '%s'\n", + program,prefix); + return -1; + } + } else + return 0; + + /* libname alloc */ + if (!fmodule) + libname += strlen(prefix); + + if (!(ctx->libname = strdup(libname))) + return -1; + + if ((dot = strrchr(ctx->libname,'.'))) + *dot = 0; + + ctx->cctx.libname = ctx->libname; + + return 0; +} diff --git a/src/driver/slbt_split_argv.c b/src/driver/slbt_split_argv.c new file mode 100644 index 0000000..7ad20a3 --- /dev/null +++ b/src/driver/slbt_split_argv.c @@ -0,0 +1,556 @@ +/*******************************************************************/ +/* 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 <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> + +#include <slibtool/slibtool.h> +#include "slibtool_version.h" +#include "slibtool_driver_impl.h" +#include "slibtool_objlist_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" +#include "slibtool_stoolie_impl.h" +#include "slibtool_ar_impl.h" +#include "argv/argv.h" + +static char * slbt_default_cargv[] = {"cc",0}; + +slbt_hidden int slbt_split_argv( + char ** argv, + uint64_t flags, + struct slbt_split_vector * sargv, + struct slbt_obj_list ** aobjlistv, + int fderr, + int fdcwd) +{ + int i; + int argc; + int objc; + const char * program; + char * compiler; + char * csysroot; + char ** dargv; + char ** targv; + char ** cargv; + char ** objp; + struct slbt_obj_list * objlistv; + struct slbt_obj_list * objlistp; + char * dst; + bool flast; + bool fcopy; + bool altmode; + size_t size; + const char * base; + struct argv_meta * meta; + struct argv_entry * entry; + struct argv_entry * mode; + struct argv_entry * help; + struct argv_entry * version; + struct argv_entry * info; + struct argv_entry * config; + struct argv_entry * finish; + struct argv_entry * features; + struct argv_entry * ccwrap; + struct argv_entry * dumpmachine; + struct argv_entry * aropt; + struct argv_entry * stoolieopt; + const struct argv_option ** popt; + const struct argv_option ** optout; + const struct argv_option * optv[SLBT_OPTV_ELEMENTS]; + struct argv_ctx ctx = {ARGV_VERBOSITY_NONE, + ARGV_MODE_SCAN, + 0,0,0,0,0,0,0}; + + program = slbt_program_name(argv[0]); + + /* missing arguments? */ + if ((altmode = (flags & SLBT_DRIVER_MODE_AR))) { + slbt_optv_init(slbt_ar_options,optv); + } else if ((altmode = (flags & SLBT_DRIVER_MODE_STOOLIE))) { + slbt_optv_init(slbt_stoolie_options,optv); + } else { + slbt_optv_init(slbt_default_options,optv); + } + + + if (!argv[1] && !altmode && (flags & SLBT_DRIVER_VERBOSITY_USAGE)) + return slbt_driver_usage( + fderr,program, + 0,optv,0,sargv,0, + !!getenv("NO_COLOR")); + + /* initial argv scan: ... --mode=xxx ... <compiler> ... */ + slbt_argv_scan(argv,optv,&ctx,0); + + /* invalid slibtool arguments? */ + if (ctx.erridx && !ctx.unitidx && altmode) { + if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_argv_get( + argv,optv, + slbt_argv_flags(flags), + fderr); + return -1; + } + + /* error possibly due to an altmode argument? */ + if (ctx.erridx && !ctx.unitidx) + ctx.unitidx = ctx.erridx; + + /* obtain slibtool's own arguments */ + if (ctx.unitidx) { + compiler = argv[ctx.unitidx]; + argv[ctx.unitidx] = 0; + + meta = slbt_argv_get(argv,optv,ARGV_VERBOSITY_NONE,fderr); + argv[ctx.unitidx] = compiler; + } else { + meta = slbt_argv_get(argv,optv,ARGV_VERBOSITY_NONE,fderr); + } + + if (!meta) { + if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_argv_get( + argv,optv, + slbt_argv_flags(flags), + fderr); + return -1; + } + + /* missing all of --mode, --help, --version, --info, --config, --dumpmachine, --features, and --finish? */ + mode = help = version = info = config = finish = features = ccwrap = dumpmachine = aropt = stoolieopt = 0; + + for (entry=meta->entries; entry->fopt; entry++) + if (entry->tag == TAG_MODE) + mode = entry; + else if (entry->tag == TAG_HELP) + help = entry; + else if (entry->tag == TAG_VERSION) + version = entry; + else if (entry->tag == TAG_INFO) + info = entry; + else if (entry->tag == TAG_CONFIG) + config = entry; + else if (entry->tag == TAG_FINISH) + finish = entry; + else if (entry->tag == TAG_FEATURES) + features = entry; + else if (entry->tag == TAG_CCWRAP) + ccwrap = entry; + else if (entry->tag == TAG_DUMPMACHINE) + dumpmachine = entry; + + /* alternate execusion mode? */ + if (!altmode && mode && !strcmp(mode->arg,"ar")) + aropt = mode; + + if (!altmode && mode && !strcmp(mode->arg,"stoolie")) + stoolieopt = mode; + + if (!altmode && mode && !strcmp(mode->arg,"slibtoolize")) + stoolieopt = mode; + + /* release temporary argv meta context */ + slbt_argv_free(meta); + + /* error not due to an altmode argument? */ + if (!aropt && !stoolieopt && ctx.erridx && (ctx.erridx == ctx.unitidx)) { + if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_argv_get( + argv,optv, + slbt_argv_flags(flags), + fderr); + return -1; + } + + if (!mode && !help && !version && !info && !config && !finish && !features && !dumpmachine && !altmode) { + slbt_dprintf(fderr, + "%s: error: --mode must be specified.\n", + program); + return -1; + } + + /* missing compiler? */ + if (!ctx.unitidx && !help && !info && !config && !version && !finish && !features && !dumpmachine) { + if (!altmode && !aropt && !stoolieopt) { + if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: error: <compiler> is missing.\n", + program); + return -1; + } + } + + /* clone and normalize the argv vector */ + for (argc=0,size=0,dargv=argv; *dargv; argc++,dargv++) + size += strlen(*dargv) + 1; + + if (!(sargv->dargv = calloc(argc+1,sizeof(char *)))) + return -1; + + else if (!(sargv->dargs = calloc(1,size+1))) + return -1; + + else if (!(*aobjlistv = calloc(argc,sizeof(**aobjlistv)))) { + free(sargv->dargv); + free(sargv->dargs); + return -1; + } + + objlistv = *aobjlistv; + objlistp = objlistv; + csysroot = 0; + + for (i=0,flast=false,dargv=sargv->dargv,dst=sargv->dargs; i<argc; i++) { + if ((fcopy = (flast || altmode || aropt || stoolieopt))) { + (void)0; + + } else if (!strcmp(argv[i],"--")) { + flast = true; + fcopy = true; + + } else if (!strcmp(argv[i],"-I")) { + *dargv++ = dst; + *dst++ = '-'; + *dst++ = 'I'; + strcpy(dst,argv[++i]); + dst += strlen(dst)+1; + + } else if (!strncmp(argv[i],"-I",2)) { + fcopy = true; + + } else if (!strcmp(argv[i],"-l")) { + *dargv++ = dst; + *dst++ = '-'; + *dst++ = 'l'; + strcpy(dst,argv[++i]); + dst += strlen(dst)+1; + + } else if (!strncmp(argv[i],"-l",2)) { + fcopy = true; + + } else if (!strcmp(argv[i],"--library")) { + *dargv++ = dst; + *dst++ = '-'; + *dst++ = 'l'; + strcpy(dst,argv[++i]); + dst += strlen(dst)+1; + + } else if (!strncmp(argv[i],"--library=",10)) { + *dargv++ = dst; + *dst++ = '-'; + *dst++ = 'l'; + strcpy(dst,&argv[++i][10]); + dst += strlen(dst)+1; + + } else if (!strcmp(argv[i],"-L")) { + *dargv++ = dst; + *dst++ = '-'; + *dst++ = 'L'; + strcpy(dst,argv[++i]); + dst += strlen(dst)+1; + + } else if (!strncmp(argv[i],"-L",2)) { + fcopy = true; + + } else if (!strcmp(argv[i],"-Xlinker")) { + *dargv++ = dst; + *dst++ = '-'; + *dst++ = 'W'; + *dst++ = 'l'; + *dst++ = ','; + strcpy(dst,argv[++i]); + dst += strlen(dst)+1; + + } else if (!strcmp(argv[i],"--library-path")) { + *dargv++ = dst; + *dst++ = '-'; + *dst++ = 'L'; + strcpy(dst,argv[++i]); + dst += strlen(dst)+1; + + } else if (!strncmp(argv[i],"--library-path=",15)) { + *dargv++ = dst; + *dst++ = '-'; + *dst++ = 'L'; + strcpy(dst,&argv[i][15]); + dst += strlen(dst)+1; + + } else if (!strcmp(argv[i],"--sysroot") && (i<ctx.unitidx)) { + *dargv++ = dst; + csysroot = dst; + strcpy(dst,argv[i]); + dst[9] = '='; + strcpy(&dst[10],argv[++i]); + dst += strlen(dst)+1; + ctx.unitidx--; + + } else if (!strncmp(argv[i],"--sysroot=",10) && (i<ctx.unitidx)) { + *dargv++ = dst; + csysroot = dst; + strcpy(dst,argv[i]); + dst += strlen(dst)+1; + + } else if (!strcmp(argv[i],"-objectlist")) { + *dargv++ = dst; + strcpy(dst,argv[i++]); + dst += strlen(dst)+1; + + objlistp->name = dst; + objlistp++; + fcopy = true; + + } else { + fcopy = true; + } + + if (fcopy) { + *dargv++ = dst; + strcpy(dst,argv[i]); + dst += strlen(dst)+1; + } + } + + /* update argc,argv */ + argc = dargv - sargv->dargv; + argv = sargv->dargv; + + /* iterate through the object list vector: map, parse, store */ + for (objlistp=objlistv; objlistp->name; objlistp++) + if (slbt_objlist_read(fdcwd,objlistp) < 0) + return -1; + + for (objc=0,objlistp=objlistv; objlistp->name; objlistp++) + objc += objlistp->objc; + + /* allocate split vectors, account for cargv's added sysroot */ + if ((sargv->targv = calloc(objc + 2*(argc+3),sizeof(char *)))) + sargv->cargv = sargv->targv + argc + 2; + else + return -1; + + /* --features and no <compiler>? */ + if (ctx.unitidx) { + (void)0; + + } else if (help || version || features || info || config || dumpmachine || altmode) { + for (i=0; i<argc; i++) + sargv->targv[i] = argv[i]; + + sargv->cargv = altmode ? sargv->targv : slbt_default_cargv; + + return 0; + } + + /* --mode=ar and no ar-specific arguments? */ + if (aropt && !ctx.unitidx) + ctx.unitidx = argc; + + /* --mode=slibtoolize and no slibtoolize-specific arguments? */ + if (stoolieopt && !ctx.unitidx) + ctx.unitidx = argc; + + /* split vectors: slibtool's own options */ + for (i=0; i<ctx.unitidx; i++) + sargv->targv[i] = argv[i]; + + /* split vector marks */ + targv = sargv->targv + i; + cargv = sargv->cargv; + + /* known wrappers */ + if (ctx.unitidx && !ccwrap && !aropt && !stoolieopt) { + if ((base = strrchr(argv[i],'/'))) + base++; + else if ((base = strrchr(argv[i],'\\'))) + base++; + else + base = argv[i]; + + if (!strcmp(base,"ccache") + || !strcmp(base,"distcc") + || !strcmp(base,"compiler") + || !strcmp(base,"purify")) { + *targv++ = "--ccwrap"; + *targv++ = argv[i++]; + } + } + + /* split vectors: legacy mixture */ + for (optout=optv; optout[0] && (optout[0]->tag != TAG_OUTPUT); optout++) + (void)0; + + /* compiler, archiver, etc. */ + if (altmode) { + i = 0; + } else if (aropt) { + *cargv++ = argv[0]; + } else if (stoolieopt) { + *cargv++ = argv[0]; + } else { + *cargv++ = argv[i++]; + } + + /* sysroot */ + if (csysroot) + *cargv++ = csysroot; + + /* remaining vector */ + for (objlistp=objlistv; i<argc; i++) { + if (aropt && (i >= ctx.unitidx)) { + *cargv++ = argv[i]; + + } else if (stoolieopt && (i >= ctx.unitidx)) { + *cargv++ = argv[i]; + + } else if (argv[i][0] != '-') { + if (argv[i+1] && (argv[i+1][0] == '+') + && (argv[i+1][1] == '=') + && (argv[i+1][2] == 0) + && !(strrchr(argv[i],'.'))) + /* libfoo_la_LDFLAGS += -Wl,.... */ + i++; + else + *cargv++ = argv[i]; + + /* must capture -objectlist prior to -o */ + } else if (!(strcmp("objectlist",&argv[i][1]))) { + for (objp=objlistp->objv; *objp; objp++) + *cargv++ = *objp; + + i++; + objlistp++; + + } else if (argv[i][1] == 'o') { + *targv++ = argv[i]; + + if (argv[i][2] == 0) + *targv++ = argv[++i]; + } else if ((argv[i][1] == 'W') && (argv[i][2] == 'c')) { + *cargv++ = argv[i]; + + } else if (!(strcmp("Xcompiler",&argv[i][1]))) { + *cargv++ = argv[++i]; + + } else if (!(strcmp("XCClinker",&argv[i][1]))) { + *cargv++ = argv[++i]; + + } else if ((argv[i][1] == 'R') && (argv[i][2] == 0)) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (argv[i][1] == 'R') { + *targv++ = argv[i]; + + } else if (!(strncmp("-target=",&argv[i][1],8))) { + *cargv++ = argv[i]; + *targv++ = argv[i]; + + } else if (!(strcmp("-target",&argv[i][1]))) { + *cargv++ = argv[i]; + *targv++ = argv[i++]; + + *cargv++ = argv[i]; + *targv++ = argv[i]; + + } else if (!(strcmp("target",&argv[i][1]))) { + *cargv++ = argv[i]; + *targv++ = argv[i++]; + + *cargv++ = argv[i]; + *targv++ = argv[i]; + + } else if (!(strncmp("-sysroot=",&argv[i][1],9))) { + *cargv++ = argv[i]; + *targv++ = argv[i]; + + } else if (!(strcmp("-sysroot",&argv[i][1]))) { + *cargv++ = argv[i]; + *targv++ = argv[i++]; + + *cargv++ = argv[i]; + *targv++ = argv[i]; + + } else if (!(strcmp("bindir",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("shrext",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("rpath",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("release",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("weak",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("static-libtool-libs",&argv[i][1]))) { + *targv++ = argv[i]; + + } else if (!(strcmp("export-dynamic",&argv[i][1]))) { + *targv++ = argv[i]; + + } else if (!(strcmp("export-symbols",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("export-symbols-regex",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("version-info",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("version-number",&argv[i][1]))) { + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("dlopen",&argv[i][1]))) { + if (!argv[i+1]) + return -1; + + *targv++ = argv[i++]; + *targv++ = argv[i]; + + } else if (!(strcmp("dlpreopen",&argv[i][1]))) { + if (!argv[i+1]) + return -1; + + if (strcmp(argv[i+1],"self") && strcmp(argv[i+1],"force")) { + *cargv++ = argv[i]; + *targv++ = argv[i++]; + + *cargv++ = argv[i]; + *targv++ = argv[i]; + } else { + *targv++ = argv[i++]; + *targv++ = argv[i]; + } + } else { + for (popt=optout; popt[0] && popt[0]->long_name; popt++) + if (!(strcmp(popt[0]->long_name,&argv[i][1]))) + break; + + if (popt[0] && popt[0]->long_name) + *targv++ = argv[i]; + else + *cargv++ = argv[i]; + } + } + + return 0; +} diff --git a/src/driver/slbt_symlist_ctx.c b/src/driver/slbt_symlist_ctx.c new file mode 100644 index 0000000..7c8171c --- /dev/null +++ b/src/driver/slbt_symlist_ctx.c @@ -0,0 +1,150 @@ +/*******************************************************************/ +/* 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 <ctype.h> +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" + +static int slbt_lib_free_symlist_ctx_impl( + struct slbt_symlist_ctx_impl * ctx, + struct slbt_input * mapinfo, + int ret) +{ + if (mapinfo) + slbt_fs_unmap_input(mapinfo); + + if (ctx) { + if (ctx->pathbuf) + free(ctx->pathbuf); + + if (ctx->symstrs) + free(ctx->symstrs); + + if (ctx->symstrv) + free(ctx->symstrv); + + free(ctx); + } + + return ret; +} + +int slbt_lib_get_symlist_ctx( + const struct slbt_driver_ctx * dctx, + const char * path, + struct slbt_symlist_ctx ** pctx) +{ + struct slbt_symlist_ctx_impl * ctx; + struct slbt_input mapinfo; + size_t nsyms; + char * ch; + char * cap; + char * src; + const char ** psym; + char dummy; + int cint; + bool fvalid; + + /* map symlist file temporarily */ + if (slbt_fs_map_input(dctx,-1,path,PROT_READ,&mapinfo) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* alloc context */ + if (!(ctx = calloc(1,sizeof(*ctx)))) + return slbt_lib_free_symlist_ctx_impl( + ctx,&mapinfo, + SLBT_BUFFER_ERROR(dctx)); + + /* count symbols */ + src = mapinfo.size ? mapinfo.addr : &dummy; + cap = &src[mapinfo.size]; + + for (; (src<cap) && isspace((cint=*src)); ) + src++; + + for (ch=src,nsyms=0; ch<cap; nsyms++) { + for (; (ch<cap) && !isspace((cint=*ch)); ) + ch++; + + fvalid = false; + + for (; (ch<cap) && isspace((cint=*ch)); ) + fvalid = (*ch++ == '\n') || fvalid; + + if (!fvalid) + return slbt_lib_free_symlist_ctx_impl( + ctx,&mapinfo, + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR)); + } + + /* clone path, alloc string buffer and symbol vector */ + if (!(ctx->pathbuf = strdup(path))) + return slbt_lib_free_symlist_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(ctx->symstrs = calloc(mapinfo.size+1,1))) + return slbt_lib_free_symlist_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(ctx->symstrv = calloc(nsyms+1,sizeof(char *)))) + return slbt_lib_free_symlist_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + /* copy the source to the allocated string buffer */ + memcpy(ctx->symstrs,mapinfo.addr,mapinfo.size); + slbt_fs_unmap_input(&mapinfo); + + /* populate the symbol vector, handle whitespace */ + src = ctx->symstrs; + cap = &src[mapinfo.size]; + + for (; (src<cap) && isspace((cint=*src)); ) + src++; + + for (ch=src,psym=ctx->symstrv; ch<cap; psym++) { + *psym = ch; + + for (; (ch<cap) && !isspace((cint=*ch)); ) + ch++; + + for (; (ch<cap) && isspace((cint=*ch)); ) + *ch++ = '\0'; + } + + /* all done */ + ctx->dctx = dctx; + ctx->path = ctx->pathbuf; + ctx->sctx.path = &ctx->path; + ctx->sctx.symstrv = ctx->symstrv; + + *pctx = &ctx->sctx; + + return 0; +} + +void slbt_lib_free_symlist_ctx(struct slbt_symlist_ctx * ctx) +{ + struct slbt_symlist_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct slbt_symlist_ctx_impl,sctx); + ictx = (struct slbt_symlist_ctx_impl *)addr; + slbt_lib_free_symlist_ctx_impl(ictx,0,0); + } +} diff --git a/src/driver/slbt_txtfile_ctx.c b/src/driver/slbt_txtfile_ctx.c new file mode 100644 index 0000000..53cce0f --- /dev/null +++ b/src/driver/slbt_txtfile_ctx.c @@ -0,0 +1,172 @@ +/*******************************************************************/ +/* 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 <ctype.h> +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" + +/********************************************************/ +/* Read a text file, and create an in-memory vecotr of */ +/* normalized text lines, stripped of both leading and */ +/* trailing white space. */ +/********************************************************/ + +static int slbt_lib_free_txtfile_ctx_impl( + struct slbt_txtfile_ctx_impl * ctx, + struct slbt_input * mapinfo, + int ret) +{ + if (mapinfo) + slbt_fs_unmap_input(mapinfo); + + if (ctx) { + if (ctx->pathbuf) + free(ctx->pathbuf); + + if (ctx->txtlines) + free(ctx->txtlines); + + if (ctx->txtlinev) + free(ctx->txtlinev); + + free(ctx); + } + + return ret; +} + +static int slbt_lib_get_txtfile_ctx_impl( + const struct slbt_driver_ctx * dctx, + const char * path, + int fdsrc, + struct slbt_txtfile_ctx ** pctx) +{ + struct slbt_txtfile_ctx_impl * ctx; + struct slbt_input mapinfo; + size_t nlines; + char * ch; + char * cap; + char * src; + char * mark; + const char ** pline; + char dummy; + int cint; + + /* map txtfile file temporarily */ + if (slbt_fs_map_input(dctx,fdsrc,path,PROT_READ,&mapinfo) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* alloc context */ + if (!(ctx = calloc(1,sizeof(*ctx)))) + return slbt_lib_free_txtfile_ctx_impl( + ctx,&mapinfo, + SLBT_BUFFER_ERROR(dctx)); + + /* count lines */ + src = mapinfo.size ? mapinfo.addr : &dummy; + cap = &src[mapinfo.size]; + + for (; (src<cap) && isspace((cint=*src)); ) + src++; + + for (ch=src,nlines=0; ch<cap; ch++) + nlines += (*ch == '\n'); + + nlines += (ch[-1] != '\n'); + + /* clone path, alloc string buffer and line vector */ + if (!(ctx->pathbuf = strdup(path))) + return slbt_lib_free_txtfile_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(ctx->txtlines = calloc(mapinfo.size+1,1))) + return slbt_lib_free_txtfile_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(ctx->txtlinev = calloc(nlines+1,sizeof(char *)))) + return slbt_lib_free_txtfile_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + /* copy the source to the allocated string buffer */ + memcpy(ctx->txtlines,mapinfo.addr,mapinfo.size); + slbt_fs_unmap_input(&mapinfo); + + /* populate the line vector, handle whitespace */ + src = ctx->txtlines; + cap = &src[mapinfo.size]; + + for (; (src<cap) && isspace((cint=*src)); ) + *src++ = '\0'; + + for (ch=src,pline=ctx->txtlinev; ch<cap; pline++) { + for (; (ch<cap) && isspace((cint = *ch)); ) + ch++; + + if (ch < cap) + *pline = ch; + + for (; (ch<cap) && (*ch != '\n'); ) + ch++; + + mark = ch; + + for (--ch; (ch > *pline) && isspace((cint = *ch)); ch--) + *ch = '\0'; + + if ((ch = mark) < cap) + *ch++ = '\0'; + } + + /* all done */ + ctx->dctx = dctx; + ctx->path = ctx->pathbuf; + ctx->tctx.path = &ctx->path; + ctx->tctx.txtlinev = ctx->txtlinev; + + *pctx = &ctx->tctx; + + return 0; +} + +slbt_hidden int slbt_impl_get_txtfile_ctx( + const struct slbt_driver_ctx * dctx, + const char * path, + int fdsrc, + struct slbt_txtfile_ctx ** pctx) +{ + return slbt_lib_get_txtfile_ctx_impl(dctx,path,fdsrc,pctx); +} + +int slbt_lib_get_txtfile_ctx( + const struct slbt_driver_ctx * dctx, + const char * path, + struct slbt_txtfile_ctx ** pctx) +{ + return slbt_lib_get_txtfile_ctx_impl(dctx,path,(-1),pctx); +} + +void slbt_lib_free_txtfile_ctx(struct slbt_txtfile_ctx * ctx) +{ + struct slbt_txtfile_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct slbt_txtfile_ctx_impl,tctx); + ictx = (struct slbt_txtfile_ctx_impl *)addr; + slbt_lib_free_txtfile_ctx_impl(ictx,0,0); + } +} diff --git a/src/driver/slbt_version_info.c b/src/driver/slbt_version_info.c new file mode 100644 index 0000000..c21863e --- /dev/null +++ b/src/driver/slbt_version_info.c @@ -0,0 +1,74 @@ +/*******************************************************************/ +/* 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 <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> + +#include <slibtool/slibtool.h> +#include "slibtool_version.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" +#include "argv/argv.h" + + +slbt_hidden int slbt_init_version_info( + struct slbt_driver_ctx_impl * ictx, + struct slbt_version_info * verinfo) +{ + int current; + int revision; + int age; + int colons; + int fmtcnt; + const char * ch; + + if (!verinfo->verinfo && !verinfo->vernumber) + return 0; + + if (verinfo->vernumber) { + sscanf(verinfo->vernumber,"%d:%d:%d", + &verinfo->major, + &verinfo->minor, + &verinfo->revision); + return 0; + } + + current = revision = age = 0; + + for (colons=0, ch=verinfo->verinfo; *ch; ch++) + if (*ch == ':') + colons++; + + fmtcnt = sscanf(verinfo->verinfo,"%d:%d:%d", + ¤t,&revision,&age); + + if (!fmtcnt || (fmtcnt > 3) || (fmtcnt != colons + 1)) { + slbt_dprintf(ictx->fdctx.fderr, + "%s: error: invalid version info: " + "supported argument format is %%d[:%%d[:%%d]].\n", + slbt_program_name(ictx->cctx.targv[0])); + return -1; + } + + if (current < age) { + if (ictx->cctx.drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(ictx->fdctx.fderr, + "%s: error: invalid version info: " + "<current> may not be smaller than <age>.\n", + slbt_program_name(ictx->cctx.targv[0])); + return -1; + } + + verinfo->major = current - age; + verinfo->minor = age; + verinfo->revision = revision; + + return 0; +} diff --git a/src/helper/slbt_archive_import.c b/src/fallback/slbt_archive_import_mri.c index e8ea5aa..320d6d1 100644 --- a/src/helper/slbt_archive_import.c +++ b/src/fallback/slbt_archive_import_mri.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,6 +11,8 @@ #include <string.h> #include <stdlib.h> #include <stdbool.h> +#include <inttypes.h> +#include <sys/stat.h> #include <sys/wait.h> #include <slibtool/slibtool.h> @@ -19,14 +21,17 @@ #include "slibtool_dprintf_impl.h" #include "slibtool_symlink_impl.h" #include "slibtool_readlink_impl.h" +#include "slibtool_realpath_impl.h" +#include "slibtool_snprintf_impl.h" #include "slibtool_errinfo_impl.h" +#define PPRIX64 "%"PRIx64 + static char * slbt_mri_argument( int fdat, char * arg, char * buf) { - int i; char * lnk; char * target; char mricwd[PATH_MAX]; @@ -35,23 +40,41 @@ static char * slbt_mri_argument( if ((!(strchr(arg,'+'))) && (!(strchr(arg,'-')))) return arg; - if (arg[0] == '/') + if (arg[0] == '/') { target = arg; - else { - if (slbt_realpath(fdat,".",O_DIRECTORY,mricwd,sizeof(mricwd))) + } else { + if (slbt_realpath( + fdat,".",O_DIRECTORY, + mricwd,sizeof(mricwd)) < 0) return 0; - if ((size_t)snprintf(dstbuf,sizeof(dstbuf),"%s/%s", - mricwd,arg) >= sizeof(dstbuf)) + if (slbt_snprintf(dstbuf,sizeof(dstbuf), + "%s/%s",mricwd,arg) < 0) return 0; target = dstbuf; } - for (i=0,lnk=0; i<1024 && !lnk; i++) { - if (!(tmpnam(buf))) + lnk = 0; + + { + struct stat st; + + if (fstatat(fdat,target,&st,0) < 0) return 0; + sprintf(buf, + ".mri.tmplnk" + ".dev."PPRIX64 + ".inode."PPRIX64 + ".size."PPRIX64 + ".tmp", + st.st_dev, + st.st_ino, + st.st_size); + + unlinkat(fdat,buf,0); + if (!(symlinkat(target,fdat,buf))) lnk = buf; } @@ -59,7 +82,7 @@ static char * slbt_mri_argument( return lnk; } -static void slbt_archive_import_child( +static void slbt_util_import_archive_child( char * program, int fd[2]) { @@ -77,11 +100,10 @@ static void slbt_archive_import_child( _exit(EXIT_FAILURE); } -int slbt_archive_import( - const struct slbt_driver_ctx * dctx, - struct slbt_exec_ctx * ectx, - char * dstarchive, - char * srcarchive) +int slbt_util_import_archive_mri( + struct slbt_exec_ctx * ectx, + char * dstarchive, + char * srcarchive) { int fdcwd; pid_t pid; @@ -90,10 +112,15 @@ int slbt_archive_import( char * dst; char * src; char * fmt; - char mridst [L_tmpnam]; - char mrisrc [L_tmpnam]; + char mridst [96]; + char mrisrc [96]; char program[PATH_MAX]; + const struct slbt_driver_ctx * dctx; + + /* driver context */ + dctx = (slbt_get_exec_ictx(ectx))->dctx; + /* fdcwd */ fdcwd = slbt_driver_fdcwd(dctx); @@ -102,17 +129,15 @@ int slbt_archive_import( return 0; /* program */ - if ((size_t)snprintf(program,sizeof(program), - "%s", - dctx->cctx->host.ar) - >= sizeof(program)) + if (slbt_snprintf(program,sizeof(program), + "%s",dctx->cctx->host.ar) < 0) return SLBT_BUFFER_ERROR(dctx); /* fork */ if (pipe(fd)) return SLBT_SYSTEM_ERROR(dctx,0); - if ((pid = fork()) < 0) { + if ((pid = slbt_fork()) < 0) { close(fd[0]); close(fd[1]); return SLBT_SYSTEM_ERROR(dctx,0); @@ -120,7 +145,7 @@ int slbt_archive_import( /* child */ if (pid == 0) - slbt_archive_import_child( + slbt_util_import_archive_child( program, fd); @@ -132,8 +157,10 @@ int slbt_archive_import( dst = slbt_mri_argument(fdcwd,dstarchive,mridst); src = slbt_mri_argument(fdcwd,srcarchive,mrisrc); - if (!dst || !src) + if (!dst || !src) { + close(fd[1]); return SLBT_SYSTEM_ERROR(dctx,0); + } fmt = "OPEN %s\n" "ADDLIB %s\n" diff --git a/src/host/slbt_host_flavor.c b/src/host/slbt_host_flavor.c new file mode 100644 index 0000000..ab7040e --- /dev/null +++ b/src/host/slbt_host_flavor.c @@ -0,0 +1,203 @@ +/*******************************************************************/ +/* 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_driver_impl.h" + +/* 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,maps, \ + ldenv) \ + static const struct slbt_flavor_settings flavor = { \ + bfmt,arp,ars,dsop,dsos,osds,osdf, \ + exep,exes,impp,imps,maps, \ + ldenv,pic} + +SLBT_FLAVOR_SETTINGS(host_flavor_default, \ + "elf","-fPIC", \ + "lib",".a","lib",".so",".so","", \ + "","","","",".expsyms.ver", \ + "LD_LIBRARY_PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_midipix, \ + "pe","-fPIC", \ + "lib",".a","lib",".so",".so","", \ + "","","lib",".lib.a",".expsyms.def", \ + "LD_LIBRARY_PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_mingw, \ + "pe",0, \ + "lib",".a","lib",".dll","",".dll", \ + "",".exe","lib",".dll.a",".expsyms.def",\ + "PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_cygwin, \ + "pe",0, \ + "lib",".a","lib",".dll","",".dll", \ + "",".exe","lib",".dll.a",".expsyms.def",\ + "PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_msys, \ + "pe",0, \ + "lib",".a","lib",".dll","",".dll", \ + "",".exe","lib",".dll.a",".expsyms.def",\ + "PATH"); + +SLBT_FLAVOR_SETTINGS(host_flavor_darwin, \ + "macho","-fPIC", \ + "lib",".a","lib",".dylib","",".dylib", \ + "","","","",".expsyms.exp", \ + "DYLD_LIBRARY_PATH"); + + +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; +} + + +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,"msys")) + settings = &host_flavor_msys; + 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)); +} + + +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,"msys")) + *settings = &host_flavor_msys; + 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; +} + + +int slbt_host_objfmt_is_coff(const struct slbt_driver_ctx * dctx) +{ + const char * flavor = dctx->cctx->host.flavor; + + return !strcmp(flavor,"midipix") + || !strcmp(flavor,"mingw") + || !strcmp(flavor,"cygwin") + || !strcmp(flavor,"msys"); +} + + +int slbt_host_objfmt_is_macho(const struct slbt_driver_ctx * dctx) +{ + const char * flavor = dctx->cctx->host.flavor; + + return !strcmp(flavor,"darwin"); +} + + +int slbt_host_group_is_winnt(const struct slbt_driver_ctx * dctx) +{ + return slbt_host_objfmt_is_coff(dctx); +} + + +int slbt_host_group_is_darwin(const struct slbt_driver_ctx * dctx) +{ + return slbt_host_objfmt_is_macho(dctx); +} diff --git a/src/host/slbt_host_params.c b/src/host/slbt_host_params.c new file mode 100644 index 0000000..cd9ad87 --- /dev/null +++ b/src/host/slbt_host_params.c @@ -0,0 +1,584 @@ +/*******************************************************************/ +/* 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 <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_spawn_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"; + +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 = slbt_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_nm, + 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 (!strcmp(base,"slibtool-ar")) { + host->host = drvhost->machine; + cfgmeta->host = cfgnmachine; + fnative = 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,"-msys")) || strstr(machine,"-msys-")) + host->flavor = "msys"; + 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; + } + + /* nm */ + if (host->nm) + cfgmeta->nm = cfgmeta_nm ? cfgmeta_nm : cfgexplicit; + else { + if (!(drvhost->nm = calloc(1,toollen))) + return -1; + + if (fnative) { + strcpy(drvhost->nm,"nm"); + cfgmeta->nm = cfgnative; + } else { + sprintf(drvhost->nm,"%s-nm",host->host); + cfgmeta->nm = cfghost; + } + + host->nm = drvhost->nm; + } + + /* 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,"msys") + && 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,"msys") + && 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,"msys") + && 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->nm) + free(host->nm); + + 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->nm_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)); +} + + +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,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; +} diff --git a/src/internal/argv/argv.h b/src/internal/argv/argv.h index 2324c8f..d17865b 100644 --- a/src/internal/argv/argv.h +++ b/src/internal/argv/argv.h @@ -1,6 +1,6 @@ /****************************************************************************/ /* argv.h: a thread-safe argument vector parser and usage screen generator */ -/* Copyright (C) 2015--2021 SysDeer Technologies, LLC */ +/* Copyright (C) 2015--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /****************************************************************************/ @@ -83,6 +83,7 @@ enum argv_error { ARGV_ERROR_INTERNAL, ARGV_ERROR_SHORT_OPTION, ARGV_ERROR_LONG_OPTION, + ARGV_ERROR_VENDOR_OPTION, ARGV_ERROR_OPTARG_NONE, ARGV_ERROR_OPTARG_REQUIRED, ARGV_ERROR_OPTARG_PARADIGM, @@ -398,7 +399,11 @@ static void argv_scan( fval = ch; } } else { - ferr = ARGV_ERROR_SHORT_OPTION; + if ((ch == &parg[0][1]) && (ch[0] == 'W') && ch[1]) { + ferr = ARGV_ERROR_VENDOR_OPTION; + } else { + ferr = ARGV_ERROR_SHORT_OPTION; + } } } else if (!fnoscan && (fhybrid || is_long_option(ch))) { @@ -413,49 +418,72 @@ static void argv_scan( ch = *parg; } - if (fhybrid && !(option->flags & ARGV_OPTION_HYBRID_SWITCH)) + /* now verify the proper setting of option values */ + if (fhybrid && !(option->flags & ARGV_OPTION_HYBRID_SWITCH)) { ferr = ARGV_ERROR_HYBRID_NONE; - else if (!fhybrid && (option->flags & ARGV_OPTION_HYBRID_ONLY)) + + } else if (!fhybrid && (option->flags & ARGV_OPTION_HYBRID_ONLY)) { ferr = ARGV_ERROR_HYBRID_ONLY; - else if (option->optarg == ARGV_OPTARG_NONE) { + + } else if (option->optarg == ARGV_OPTARG_NONE) { if (val[0]) { ferr = ARGV_ERROR_OPTARG_NONE; ctx->errch = val + 1; - } else + } else { fval = false; + } + } else if (val[0] && (option->flags & ARGV_OPTION_HYBRID_JOINED)) { fval = true; ch = val; - } else if (fhybrid && !val[0] && !(option->flags & ARGV_OPTION_HYBRID_SPACE)) - ferr = ARGV_ERROR_HYBRID_SPACE; - else if (fhybrid && (val[0]=='=') && !(option->flags & ARGV_OPTION_HYBRID_EQUAL)) + + } else if (fhybrid && !val[0] && !(option->flags & ARGV_OPTION_HYBRID_SPACE)) { + if (option->optarg == ARGV_OPTARG_OPTIONAL) { + fval = false; + + } else { + ferr = ARGV_ERROR_HYBRID_SPACE; + } + + } else if (fhybrid && (val[0]=='=') && !(option->flags & ARGV_OPTION_HYBRID_EQUAL)) { ferr = ARGV_ERROR_HYBRID_EQUAL; - else if (fhybrid && (val[0]==',') && !(option->flags & ARGV_OPTION_HYBRID_COMMA)) + + } else if (fhybrid && (val[0]==',') && !(option->flags & ARGV_OPTION_HYBRID_COMMA)) { ferr = ARGV_ERROR_HYBRID_COMMA; - else if (!fhybrid && (val[0]==',')) + + } else if (!fhybrid && (val[0]==',')) { ferr = ARGV_ERROR_HYBRID_COMMA; - else if (val[0] && !val[1]) + + } else if (val[0] && !val[1]) { ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (val[0] && val[1]) { + + } else if (val[0] && val[1]) { fval = true; ch = ++val; + } else if (option->optarg == ARGV_OPTARG_REQUIRED) { - if (!val[0] && !*parg) + if (!val[0] && !*parg) { ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (*parg && is_short_option(*parg)) + + } else if (*parg && is_short_option(*parg)) { ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (*parg && is_long_option(*parg)) + + } else if (*parg && is_long_option(*parg)) { ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (*parg && is_last_option(*parg)) + + } else if (*parg && is_last_option(*parg)) { ferr = ARGV_ERROR_OPTARG_REQUIRED; - else + + } else { fval = true; + } } else { /* ARGV_OPTARG_OPTIONAL */ fval = val[0]; } - } else + } else { ferr = ARGV_ERROR_LONG_OPTION; + } } if (ferr == ARGV_ERROR_OK) @@ -531,7 +559,11 @@ static const char * argv_program_name(const char * program_path) static void argv_show_error(int fd, struct argv_ctx * ctx) { - char opt_short_name[2] = {0,0}; + const char * src; + char * dst; + char * cap; + char opt_vendor_buf[256]; + char opt_short_name[2] = {0,0}; if (ctx->erropt && ctx->erropt->short_name) opt_short_name[0] = ctx->erropt->short_name; @@ -547,6 +579,27 @@ static void argv_show_error(int fd, struct argv_ctx * ctx) argv_dprintf(fd,"'--%s' is not a valid long option\n",ctx->errch); break; + case ARGV_ERROR_VENDOR_OPTION: + src = ctx->errch; + dst = opt_vendor_buf; + cap = &opt_vendor_buf[sizeof(opt_vendor_buf)]; + + for (; src && *src && dst<cap; ) { + if ((*src == '=') || (*src == ',') || (*src == ':')) { + src = 0; + } else { + *dst++ = *src++; + } + } + + if (dst == cap) + dst--; + + *dst = '\0'; + + argv_dprintf(fd,"'-%s' is not a valid vendor option\n",opt_vendor_buf); + break; + case ARGV_ERROR_OPTARG_NONE: argv_dprintf(fd,"'%s' is not a valid option value for [%s%s%s%s%s] " "(option values may not be specified)\n", @@ -563,7 +616,9 @@ static void argv_show_error(int fd, struct argv_ctx * ctx) opt_short_name[0] ? "-" : "", opt_short_name, opt_short_name[0] ? "," : "", - ctx->erropt->long_name ? "--" : "", + ctx->erropt->long_name + ? (ctx->erropt->flags & ARGV_OPTION_HYBRID_ONLY) ? "-" : "--" + : "", ctx->erropt->long_name, ctx->erropt->paradigm ? "one of the following values:" : "a value", ctx->erropt->paradigm ? "{" : "", diff --git a/src/internal/slibtool_ar_impl.h b/src/internal/slibtool_ar_impl.h new file mode 100644 index 0000000..57ff1cc --- /dev/null +++ b/src/internal/slibtool_ar_impl.h @@ -0,0 +1,100 @@ +/*******************************************************************/ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#ifndef SLIBTOOL_AR_IMPL_H +#define SLIBTOOL_AR_IMPL_H + +#include "argv/argv.h" +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_arbits.h> + +/* decimal values in archive header are right padded with ascii spaces */ +#define AR_DEC_PADDING (0x20) + +/* archive file members are right padded as needed with ascii newline */ +#define AR_OBJ_PADDING (0x0A) + +/* initial number of elements in the transient, on-stack vector */ +# define AR_STACK_VECTOR_ELEMENTS (0x200) + +extern const struct argv_option slbt_ar_options[]; + +struct ar_armaps_impl { + struct ar_meta_armap_ref_32 * armap_symrefs_32; + struct ar_meta_armap_ref_64 * armap_symrefs_64; + struct ar_raw_armap_bsd_32 armap_bsd_32; + struct ar_raw_armap_bsd_64 armap_bsd_64; + struct ar_raw_armap_sysv_32 armap_sysv_32; + struct ar_raw_armap_sysv_64 armap_sysv_64; + struct ar_meta_armap_common_32 armap_common_32; + struct ar_meta_armap_common_64 armap_common_64; + uint64_t armap_nsyms; +}; + +struct slbt_archive_meta_impl { + const struct slbt_driver_ctx * dctx; + struct slbt_archive_ctx * actx; + size_t ofmtattr; + size_t nentries; + void * hdrinfov; + char * namestrs; + const char * symstrs; + const char ** symstrv; + const char ** mapstrv; + off_t * offsetv; + struct ar_meta_symbol_info * syminfo; + struct ar_meta_symbol_info ** syminfv; + struct ar_meta_member_info ** memberv; + struct ar_meta_member_info * members; + struct ar_armaps_impl armaps; + struct slbt_txtfile_ctx * nminfo; + struct slbt_archive_meta armeta; +}; + +struct ar_meta_member_info * slbt_archive_member_from_offset( + struct slbt_archive_meta_impl * meta, + off_t offset); + +int slbt_ar_parse_primary_armap_bsd_32( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m); + +int slbt_ar_parse_primary_armap_bsd_64( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m); + +int slbt_ar_parse_primary_armap_sysv_32( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m); + +int slbt_ar_parse_primary_armap_sysv_64( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m); + +int slbt_update_mapstrv( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m); + +int slbt_ar_update_syminfo( + struct slbt_archive_ctx * actx); + +int slbt_ar_update_syminfo_ex( + struct slbt_archive_ctx * actx, + int fdout); + +static inline struct slbt_archive_meta_impl * slbt_archive_meta_ictx(const struct slbt_archive_meta * meta) +{ + uintptr_t addr; + + if (meta) { + addr = (uintptr_t)meta - offsetof(struct slbt_archive_meta_impl,armeta); + return (struct slbt_archive_meta_impl *)addr; + } + + return 0; +} + +#endif diff --git a/src/internal/slibtool_coff_impl.c b/src/internal/slibtool_coff_impl.c new file mode 100644 index 0000000..ac6a2fd --- /dev/null +++ b/src/internal/slibtool_coff_impl.c @@ -0,0 +1,46 @@ +/*******************************************************************/ +/* 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 <string.h> +#include "slibtool_visibility_impl.h" + +slbt_hidden int slbt_coff_qsort_strcmp(const void * a, const void * b) +{ + const char * dot; + const char * mark; + const char * stra; + const char * strb; + const char ** pstra; + const char ** pstrb; + char strbufa[4096]; + char strbufb[4096]; + + pstra = (const char **)a; + pstrb = (const char **)b; + + stra = *pstra; + strb = *pstrb; + + if (!strncmp(*pstra,".weak.",6)) { + stra = strbufa; + mark = &(*pstra)[6]; + dot = strchr(mark,'.'); + + strncpy(strbufa,mark,dot-mark); + strbufa[dot-mark] = '\0'; + } + + if (!strncmp(*pstrb,".weak.",6)) { + strb = strbufb; + mark = &(*pstrb)[6]; + dot = strchr(mark,'.'); + + strncpy(strbufb,mark,dot-mark); + strbufb[dot-mark] = '\0'; + } + + return strcmp(stra,strb); +} diff --git a/src/internal/slibtool_coff_impl.h b/src/internal/slibtool_coff_impl.h new file mode 100644 index 0000000..b08c858 --- /dev/null +++ b/src/internal/slibtool_coff_impl.h @@ -0,0 +1,6 @@ +#ifndef SLIBTOOL_COFF_IMPL_H +#define SLIBTOOL_COFF_IMPL_H + +int slbt_coff_qsort_strcmp(const void * a, const void * b); + +#endif diff --git a/src/internal/slibtool_dprintf_impl.c b/src/internal/slibtool_dprintf_impl.c index 5bc7e8a..58c7eed 100644 --- a/src/internal/slibtool_dprintf_impl.c +++ b/src/internal/slibtool_dprintf_impl.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,8 +11,9 @@ #include <errno.h> #include "slibtool_dprintf_impl.h" +#include "slibtool_visibility_impl.h" -int slbt_dprintf(int fd, const char * fmt, ...) +slbt_hidden int slbt_dprintf(int fd, const char * fmt, ...) { int ret; int cnt; diff --git a/src/internal/slibtool_driver_impl.h b/src/internal/slibtool_driver_impl.h index 0971fd9..65e5f96 100644 --- a/src/internal/slibtool_driver_impl.h +++ b/src/internal/slibtool_driver_impl.h @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ @@ -9,10 +9,13 @@ #include <stdint.h> #include <stdio.h> +#include <sys/stat.h> #include <sys/types.h> #include <slibtool/slibtool.h> #include "slibtool_dprintf_impl.h" +#include "slibtool_mapfile_impl.h" +#include "slibtool_visibility_impl.h" #include "argv/argv.h" #define SLBT_OPTV_ELEMENTS 128 @@ -23,6 +26,7 @@ enum app_tags { TAG_HELP, TAG_HELP_ALL, TAG_VERSION, + TAG_INFO, TAG_CONFIG, TAG_DUMPMACHINE, TAG_DEBUG, @@ -42,6 +46,8 @@ enum app_tags { TAG_HOST, TAG_FLAVOR, TAG_AR, + TAG_AS, + TAG_NM, TAG_RANLIB, TAG_WINDRES, TAG_DLLTOOL, @@ -54,11 +60,12 @@ enum app_tags { TAG_RPATH, TAG_SYSROOT, TAG_RELEASE, + TAG_OBJECTLIST, TAG_DLOPEN, TAG_DLPREOPEN, TAG_EXPORT_DYNAMIC, - TAG_EXPSYM_FILE, - TAG_EXPSYM_REGEX, + TAG_EXPSYMS_FILE, + TAG_EXPSYMS_REGEX, TAG_VERSION_INFO, TAG_VERSION_NUMBER, TAG_NO_SUPPRESS, @@ -79,6 +86,34 @@ enum app_tags { TAG_VERBATIM_FLAG, TAG_THREAD_SAFE, TAG_WEAK, + /* ar mode */ + TAG_AR_HELP, + TAG_AR_VERSION, + TAG_AR_CHECK, + TAG_AR_PRINT, + TAG_AR_MAPFILE, + TAG_AR_DLUNIT, + TAG_AR_DLSYMS, + TAG_AR_NOSORT, + TAG_AR_REGEX, + TAG_AR_PRETTY, + TAG_AR_POSIX, + TAG_AR_YAML, + TAG_AR_MERGE, + TAG_AR_OUTPUT, + TAG_AR_VERBOSE, + /* slibtoolize (stoolie) mode */ + TAG_STLE_VERSION, + TAG_STLE_HELP, + TAG_STLE_COPY, + TAG_STLE_FORCE, + TAG_STLE_INSTALL, + TAG_STLE_DEBUG, + TAG_STLE_DRY_RUN, + TAG_STLE_SILENT, + TAG_STLE_VERBOSE, + TAG_STLE_WARNINGS, + TAG_STLE_NO_WARNINGS, }; struct slbt_split_vector { @@ -93,43 +128,250 @@ struct slbt_host_strs { char * host; char * flavor; char * ar; + char * as; + char * nm; char * ranlib; char * windres; char * dlltool; char * mdso; + char ** ar_argv; + char ** as_argv; + char ** nm_argv; + char ** ranlib_argv; + char ** windres_argv; + char ** dlltool_argv; + char ** mdso_argv; +}; + +struct slbt_obj_list { + const char * name; + void * addr; + size_t size; + int objc; + char ** objv; }; struct slbt_driver_ctx_impl { - struct slbt_common_ctx cctx; - struct slbt_driver_ctx ctx; - struct slbt_host_strs host; - struct slbt_host_strs ahost; - struct slbt_fd_ctx fdctx; - char * libname; - char * dargs; - char ** dargv; - char ** targv; - char ** cargv; - char ** envp; - struct slbt_error_info**errinfp; - struct slbt_error_info**erricap; - struct slbt_error_info *erriptr[64]; - struct slbt_error_info erribuf[64]; + struct argv_meta * meta; + struct slbt_common_ctx cctx; + struct slbt_driver_ctx ctx; + struct slbt_host_strs host; + struct slbt_host_strs ahost; + struct slbt_fd_ctx fdctx; + struct slbt_map_info lconf; + struct slbt_txtfile_ctx * lconfctx; + struct slbt_obj_list * objlistv; + + struct argv_entry ** dlopenv; + size_t ndlopen; + + const struct slbt_archive_ctx * arctx; + const char * arpath; + + char * libname; + char * dargs; + char ** dargv; + char ** targv; + char ** cargv; + char ** envp; + + struct slbt_error_info** errinfp; + struct slbt_error_info** erricap; + struct slbt_error_info * erriptr[64]; + struct slbt_error_info erribuf[64]; +}; + +struct slbt_driver_ctx_alloc { + struct slbt_driver_ctx_impl ctx; + uint64_t guard; }; struct slbt_exec_ctx_impl { - int argc; - char * args; - char * shadow; - char * dsoprefix; - size_t size; - struct slbt_exec_ctx ctx; - int fdwrapper; - char ** lout[2]; - char ** mout[2]; - char * vbuffer[]; + const struct slbt_driver_ctx * dctx; + struct slbt_symlist_ctx * sctx; + struct slbt_exec_ctx ctx; + struct slbt_archive_ctx ** dlactxv; + struct slbt_archive_ctx * dlpreopen; + char ** dlargv; + int argc; + char * args; + char * shadow; + char * dsoprefix; + size_t size; + size_t exts; + int fdwrapper; + char sbuf[PATH_MAX]; + char ** lout[2]; + char ** mout[2]; + char ** vbuffer; }; +struct slbt_archive_ctx_impl { + const struct slbt_driver_ctx * dctx; + const char * path; + char * pathbuf; + struct slbt_raw_archive map; + struct slbt_archive_meta * meta; + struct slbt_archive_ctx actx; +}; + +struct slbt_symlist_ctx_impl { + const struct slbt_driver_ctx * dctx; + const char * path; + char * pathbuf; + char * symstrs; + const char ** symstrv; + struct slbt_symlist_ctx sctx; +}; + + +struct slbt_txtfile_ctx_impl { + const struct slbt_driver_ctx * dctx; + const char * path; + char * pathbuf; + char * txtlines; + const char ** txtlinev; + struct slbt_txtfile_ctx tctx; +}; + +struct slbt_stoolie_ctx_impl { + const struct slbt_driver_ctx * dctx; + const char * path; + char * pathbuf; + int fdtgt; + int fdaux; + int fdm4; + const char * auxarg; + char * auxbuf; + const char * m4arg; + char * m4buf; + char ** m4argv; + struct slbt_txtfile_ctx * acinc; + struct slbt_txtfile_ctx * cfgac; + struct slbt_txtfile_ctx * makam; + struct slbt_stoolie_ctx zctx; +}; + +const char * slbt_program_name(const char *); + + +int slbt_optv_init( + const struct argv_option[], + const struct argv_option **); + + +uint64_t slbt_argv_flags(uint64_t flags); + + +void slbt_argv_scan( + char ** argv, + const struct argv_option ** optv, + struct argv_ctx * ctx, + struct argv_meta * meta); + + +struct argv_meta * slbt_argv_get( + char **, + const struct argv_option **, + int flags, + int fd); + +void slbt_argv_free(struct argv_meta *); + + +void slbt_argv_usage( + int fd, + const char * header, + const struct argv_option **, + const char * mode); + + +void slbt_argv_usage_plain( + int fd, + const char * header, + const struct argv_option **, + const char * mode); + + +int slbt_driver_usage( + int fdout, + const char * program, + const char * arg, + const struct argv_option ** optv, + struct argv_meta * meta, + struct slbt_split_vector * sargv, + struct slbt_obj_list * objlistv, + int noclr); + + +int slbt_split_argv( + char ** argv, + uint64_t flags, + struct slbt_split_vector * sargv, + struct slbt_obj_list ** aobjlistv, + int fderr, + int fdcwd); + + +int slbt_init_version_info( + struct slbt_driver_ctx_impl * ictx, + struct slbt_version_info * verinfo); + + +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_nm, + const char * cfgmeta_ranlib, + const char * cfgmeta_dlltool); + + +void slbt_free_host_params(struct slbt_host_strs * host); + + +int slbt_init_link_params(struct slbt_driver_ctx_impl * ctx); + + +void slbt_init_flavor_settings( + struct slbt_common_ctx * cctx, + const struct slbt_host_params * ahost, + struct slbt_flavor_settings * psettings); + + +int slbt_init_ldrpath( + struct slbt_common_ctx * cctx, + struct slbt_host_params * host); + + +void slbt_reset_placeholders (struct slbt_exec_ctx *); + +void slbt_disable_placeholders (struct slbt_exec_ctx *); + +int slbt_impl_get_txtfile_ctx( + const struct slbt_driver_ctx * dctx, + const char * path, + int fdsrc, + struct slbt_txtfile_ctx ** pctx); + + +static inline struct slbt_archive_ctx_impl * slbt_get_archive_ictx(const struct slbt_archive_ctx * actx) +{ + uintptr_t addr; + + if (actx) { + addr = (uintptr_t)actx - offsetof(struct slbt_archive_ctx_impl,actx); + return (struct slbt_archive_ctx_impl *)addr; + } + + return 0; +} + static inline struct slbt_driver_ctx_impl * slbt_get_driver_ictx(const struct slbt_driver_ctx * dctx) { uintptr_t addr; @@ -142,6 +384,43 @@ static inline struct slbt_driver_ctx_impl * slbt_get_driver_ictx(const struct sl return 0; } +static inline struct slbt_symlist_ctx_impl * slbt_get_symlist_ictx(const struct slbt_symlist_ctx * sctx) +{ + uintptr_t addr; + + if (sctx) { + addr = (uintptr_t)sctx - offsetof(struct slbt_symlist_ctx_impl,sctx); + return (struct slbt_symlist_ctx_impl *)addr; + } + + return 0; +} + +static inline struct slbt_stoolie_ctx_impl * slbt_get_stoolie_ictx(const struct slbt_stoolie_ctx * stctx) +{ + uintptr_t addr; + + if (stctx) { + addr = (uintptr_t)stctx - offsetof(struct slbt_stoolie_ctx_impl,zctx); + return (struct slbt_stoolie_ctx_impl *)addr; + } + + return 0; +} + +static inline void slbt_driver_set_arctx( + const struct slbt_driver_ctx * dctx, + const struct slbt_archive_ctx * arctx, + const char * arpath) +{ + struct slbt_driver_ctx_impl * ictx; + + + ictx = slbt_get_driver_ictx(dctx); + ictx->arctx = arctx; + ictx->arpath = arpath; +} + static inline char ** slbt_driver_envp(const struct slbt_driver_ctx * dctx) { struct slbt_driver_ctx_impl * ictx; @@ -152,42 +431,42 @@ static inline char ** slbt_driver_envp(const struct slbt_driver_ctx * dctx) static inline int slbt_driver_fdin(const struct slbt_driver_ctx * dctx) { struct slbt_fd_ctx fdctx; - slbt_get_driver_fdctx(dctx,&fdctx); + slbt_lib_get_driver_fdctx(dctx,&fdctx); return fdctx.fdin; } static inline int slbt_driver_fdout(const struct slbt_driver_ctx * dctx) { struct slbt_fd_ctx fdctx; - slbt_get_driver_fdctx(dctx,&fdctx); + slbt_lib_get_driver_fdctx(dctx,&fdctx); return fdctx.fdout; } static inline int slbt_driver_fderr(const struct slbt_driver_ctx * dctx) { struct slbt_fd_ctx fdctx; - slbt_get_driver_fdctx(dctx,&fdctx); + slbt_lib_get_driver_fdctx(dctx,&fdctx); return fdctx.fderr; } static inline int slbt_driver_fdlog(const struct slbt_driver_ctx * dctx) { struct slbt_fd_ctx fdctx; - slbt_get_driver_fdctx(dctx,&fdctx); + slbt_lib_get_driver_fdctx(dctx,&fdctx); return fdctx.fdlog; } static inline int slbt_driver_fdcwd(const struct slbt_driver_ctx * dctx) { struct slbt_fd_ctx fdctx; - slbt_get_driver_fdctx(dctx,&fdctx); + slbt_lib_get_driver_fdctx(dctx,&fdctx); return fdctx.fdcwd; } static inline int slbt_driver_fddst(const struct slbt_driver_ctx * dctx) { struct slbt_fd_ctx fdctx; - slbt_get_driver_fdctx(dctx,&fdctx); + slbt_lib_get_driver_fdctx(dctx,&fdctx); return fdctx.fddst; } diff --git a/src/internal/slibtool_errinfo_impl.c b/src/internal/slibtool_errinfo_impl.c index 5b91d9b..6501d84 100644 --- a/src/internal/slibtool_errinfo_impl.c +++ b/src/internal/slibtool_errinfo_impl.c @@ -1,14 +1,15 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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_driver_impl.h" #include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" -int slbt_record_error( +slbt_hidden int slbt_record_error( const struct slbt_driver_ctx * dctx, int esyscode, int elibcode, diff --git a/src/internal/slibtool_errinfo_impl.h b/src/internal/slibtool_errinfo_impl.h index aa82089..fa185c8 100644 --- a/src/internal/slibtool_errinfo_impl.h +++ b/src/internal/slibtool_errinfo_impl.h @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ diff --git a/src/internal/slibtool_lconf_impl.c b/src/internal/slibtool_lconf_impl.c index fee39e5..33dfb23 100644 --- a/src/internal/slibtool_lconf_impl.c +++ b/src/internal/slibtool_lconf_impl.c @@ -1,10 +1,10 @@ - /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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 <ctype.h> #include <fcntl.h> #include <stdio.h> #include <stdint.h> @@ -18,6 +18,8 @@ #include "slibtool_errinfo_impl.h" #include "slibtool_symlink_impl.h" #include "slibtool_readlink_impl.h" +#include "slibtool_realpath_impl.h" +#include "slibtool_visibility_impl.h" enum slbt_lconf_opt { SLBT_LCONF_OPT_UNKNOWN, @@ -364,13 +366,21 @@ static int slbt_lconf_trace_result_silent( int fd, int fdat, const char * lconf, - int err) + int err, + char (*pathbuf)[PATH_MAX]) { (void)dctx; (void)fd; (void)fdat; (void)lconf; - return err ? (-1) : fd; + + if (err) + return -1; + + if (slbt_realpath(fdat,lconf,0,*pathbuf,sizeof(*pathbuf)) <0) + return -1; + + return fd; } static int slbt_lconf_trace_result_plain( @@ -378,16 +388,16 @@ static int slbt_lconf_trace_result_plain( int fd, int fdat, const char * lconf, - int err) + int err, + char (*pathbuf)[PATH_MAX]) { int fderr; const char * cpath; - char path[PATH_MAX]; fderr = slbt_driver_fderr(dctx); - cpath = !(slbt_realpath(fdat,lconf,0,path,sizeof(path))) - ? path : lconf; + cpath = !(slbt_realpath(fdat,lconf,0,*pathbuf,sizeof(*pathbuf))) + ? *pathbuf : lconf; switch (err) { case 0: @@ -426,16 +436,16 @@ static int slbt_lconf_trace_result_annotated( int fd, int fdat, const char * lconf, - int err) + int err, + char (*pathbuf)[PATH_MAX]) { int fderr; const char * cpath; - char path[PATH_MAX]; fderr = slbt_driver_fderr(dctx); - cpath = !(slbt_realpath(fdat,lconf,0,path,sizeof(path))) - ? path : lconf; + cpath = !(slbt_realpath(fdat,lconf,0,*pathbuf,sizeof(*pathbuf))) + ? *pathbuf : lconf; switch (err) { case 0: @@ -504,7 +514,8 @@ static int slbt_lconf_trace_result_annotated( static int slbt_lconf_open( struct slbt_driver_ctx * dctx, - const char * lconf) + const char * lconf, + char (*lconfpath)[PATH_MAX]) { int fderr; int fdcwd; @@ -525,7 +536,8 @@ static int slbt_lconf_open( int,const char *,int,int); int (*trace_result)(struct slbt_driver_ctx *, - int,int,const char *,int); + int,int,const char *,int, + char (*)[PATH_MAX]); lconf = lconf ? lconf : "libtool"; fderr = slbt_driver_fderr(dctx); @@ -563,6 +575,11 @@ static int slbt_lconf_open( trace_result = slbt_lconf_trace_result_plain; } + if (!(dctx->cctx->drvflags & SLBT_DRIVER_DEBUG)) { + trace_fstat = slbt_lconf_trace_fstat_silent; + trace_openat = slbt_lconf_trace_openat_silent; + } + if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) { trace_lconf(dctx,lconf); slbt_output_fdcwd(dctx); @@ -571,7 +588,7 @@ static int slbt_lconf_open( if (lconf && strchr(lconf,'/')) return ((fdlconf = trace_openat(dctx,fdcwd,lconf,O_RDONLY,0)) < 0) ? SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LCONF_OPEN) - : trace_result(dctx,fdlconf,fdcwd,lconf,0); + : trace_result(dctx,fdlconf,fdcwd,lconf,0,lconfpath); if (trace_fstat(dctx,fdlconfdir,".",&stcwd) < 0) return SLBT_SYSTEM_ERROR(dctx,0); @@ -592,14 +609,14 @@ static int slbt_lconf_open( } if (stparent.st_dev != stcwd.st_dev) { - trace_result(dctx,fdparent,fdparent,".",EXDEV); + trace_result(dctx,fdparent,fdparent,".",EXDEV,lconfpath); close(fdparent); return SLBT_CUSTOM_ERROR( dctx,SLBT_ERR_LCONF_OPEN); } if (stparent.st_ino == stinode) { - trace_result(dctx,fdparent,fdparent,".",ELOOP); + trace_result(dctx,fdparent,fdparent,".",ELOOP,lconfpath); close(fdparent); return SLBT_CUSTOM_ERROR( dctx,SLBT_ERR_LCONF_OPEN); @@ -610,34 +627,126 @@ static int slbt_lconf_open( stinode = stparent.st_ino; } - trace_result(dctx,fdlconf,fdlconfdir,lconf,0); + trace_result(dctx,fdlconf,fdlconfdir,lconf,0,lconfpath); slbt_lconf_close(fdcwd,fdlconfdir); return fdlconf; } -int slbt_get_lconf_flags( +static int slbt_get_lconf_var( + const struct slbt_txtfile_ctx * tctx, + const char * var, + const char space, + char (*val)[PATH_MAX]) +{ + const char ** pline; + const char * mark; + const char * match; + const char * cap; + ssize_t len; + int cint; + + /* init */ + match = 0; + pline = tctx->txtlinev; + len = strlen(var); + + /* search for ^var= */ + for (; *pline && !match; ) { + if (!strncmp(*pline,var,len)) { + match = *pline; + } else { + pline++; + } + } + + /* not found? */ + if (!match) + return 0; + + /* support a single pair of double quotes */ + match = &match[len]; + mark = match; + + if (match[0] == '"') { + match++; + mark++; + + for (; *mark && (*mark != '"'); ) + mark++; + + /* unpaired quote? */ + if (*mark != '"') + return -1; + } else { + for (; *mark && !isspace((cint=*mark)); ) + mark++; + } + + cap = mark; + + /* validate */ + for (mark=match; mark<cap; mark++) { + if ((*mark >= 'a') && (*mark <= 'z')) + (void)0; + + else if ((*mark >= 'A') && (*mark <= 'Z')) + (void)0; + + else if ((*mark >= '0') && (*mark <= '9')) + (void)0; + + else if ((*mark == '+') || (*mark == '-')) + (void)0; + + else if ((*mark == '/') || (*mark == '@')) + (void)0; + + else if ((*mark == '.') || (*mark == '_')) + (void)0; + + else if ((*mark == ':') || (*mark == space)) + (void)0; + + else + return -1; + } + + /* all done */ + memcpy(*val,match,cap-match); + (*val)[cap-match] = '\0'; + + return 0; +} + +slbt_hidden int slbt_get_lconf_flags( struct slbt_driver_ctx * dctx, const char * lconf, uint64_t * flags) { + struct slbt_driver_ctx_impl * ctx; + struct slbt_txtfile_ctx * confctx; int fdlconf; struct stat st; void * addr; - const char * mark; - const char * cap; uint64_t optshared; uint64_t optstatic; - int optsharedlen; - int optstaticlen; - const char * optsharedstr; - const char * optstaticstr; + char val[PATH_MAX]; + + /* driver context (ar, ranlib, cc) */ + ctx = slbt_get_driver_ictx(dctx); /* open relative libtool script */ - if ((fdlconf = slbt_lconf_open(dctx,lconf)) < 0) + if ((fdlconf = slbt_lconf_open(dctx,lconf,&val)) < 0) return SLBT_NESTED_ERROR(dctx); + /* cache the configuration in library friendly form) */ + if (slbt_lib_get_txtfile_ctx(dctx,val,&ctx->lconfctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + confctx = ctx->lconfctx; + /* map relative libtool script */ if (fstat(fdlconf,&st) < 0) return SLBT_SYSTEM_ERROR(dctx,0); @@ -653,78 +762,34 @@ int slbt_get_lconf_flags( return SLBT_CUSTOM_ERROR( dctx,SLBT_ERR_LCONF_MAP); - mark = addr; - cap = &mark[st.st_size]; - /* scan */ optshared = 0; optstatic = 0; - optsharedstr = "build_libtool_libs="; - optstaticstr = "build_old_libs="; - - optsharedlen = strlen(optsharedstr); - optstaticlen = strlen(optstaticstr); - - for (; mark && mark<cap; ) { - if (!optshared && (cap - mark < optsharedlen)) { - mark = 0; - - } else if (!optstatic && (cap - mark < optstaticlen)) { - mark = 0; - - } else if (!optshared && !strncmp(mark,optsharedstr,optsharedlen)) { - mark += optsharedlen; - - if ((cap - mark >= 3) - && (mark[0]=='n') - && (mark[1]=='o') - && (mark[2]=='\n') - && (mark = &mark[3])) - optshared = SLBT_DRIVER_DISABLE_SHARED; - - else if ((cap - mark >= 4) - && (mark[0]=='y') - && (mark[1]=='e') - && (mark[2]=='s') - && (mark[3]=='\n') - && (mark = &mark[4])) - optshared = SLBT_DRIVER_SHARED; - - if (!optshared) - mark--; - - } else if (!optstatic && !strncmp(mark,optstaticstr,optstaticlen)) { - mark += optstaticlen; - - if ((cap - mark >= 3) - && (mark[0]=='n') - && (mark[1]=='o') - && (mark[2]=='\n') - && (mark = &mark[3])) - optstatic = SLBT_DRIVER_DISABLE_STATIC; - - else if ((cap - mark >= 4) - && (mark[0]=='y') - && (mark[1]=='e') - && (mark[2]=='s') - && (mark[3]=='\n') - && (mark = &mark[4])) - optstatic = SLBT_DRIVER_STATIC; - - if (!optstatic) - mark--; - } else { - for (; (mark<cap) && (*mark!='\n'); ) - mark++; - mark++; - } + /* shared libraries option */ + if (slbt_get_lconf_var(confctx,"build_libtool_libs=",0,&val) < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); - if (optshared && optstatic) - mark = 0; + if (!strcmp(val,"yes")) { + optshared = SLBT_DRIVER_SHARED; + + } else if (!strcmp(val,"no")) { + optshared = SLBT_DRIVER_DISABLE_SHARED; } - munmap(addr,st.st_size); + + /* static libraries option */ + if (slbt_get_lconf_var(confctx,"build_old_libs=",0,&val) < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); + + if (!strcmp(val,"yes")) { + optstatic = SLBT_DRIVER_STATIC; + + } else if (!strcmp(val,"no")) { + optstatic = SLBT_DRIVER_DISABLE_STATIC; + } if (!optshared || !optstatic) return SLBT_CUSTOM_ERROR( @@ -732,5 +797,89 @@ int slbt_get_lconf_flags( *flags = optshared | optstatic; + + /* host */ + if (!ctx->cctx.host.host) { + if (slbt_get_lconf_var(confctx,"host=",0,&val) < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); + + if (val[0] && !(ctx->host.host = strdup(val))) + return SLBT_SYSTEM_ERROR(dctx,0); + + ctx->cctx.host.host = ctx->host.host; + } + + + /* ar tool */ + if (!ctx->cctx.host.ar) { + if (slbt_get_lconf_var(confctx,"AR=",0x20,&val) < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); + + if (val[0] && !(ctx->host.ar = strdup(val))) + return SLBT_SYSTEM_ERROR(dctx,0); + + ctx->cctx.host.ar = ctx->host.ar; + } + + + /* nm tool */ + if (!ctx->cctx.host.nm) { + if (slbt_get_lconf_var(confctx,"NM=",0x20,&val) < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); + + if (val[0] && !(ctx->host.nm = strdup(val))) + return SLBT_SYSTEM_ERROR(dctx,0); + + ctx->cctx.host.nm = ctx->host.nm; + } + + + /* ranlib tool */ + if (!ctx->cctx.host.ranlib) { + if (slbt_get_lconf_var(confctx,"RANLIB=",0x20,&val) < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); + + if (val[0] && !(ctx->host.ranlib = strdup(val))) + return SLBT_SYSTEM_ERROR(dctx,0); + + ctx->cctx.host.ranlib = ctx->host.ranlib; + } + + + /* as tool (optional) */ + if (!ctx->cctx.host.as) { + if (slbt_get_lconf_var(confctx,"AS=",0x20,&val) < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); + + if (val[0] && !(ctx->host.as = strdup(val))) + return SLBT_SYSTEM_ERROR(dctx,0); + + + ctx->cctx.host.as = ctx->host.as; + } + + + /* dlltool tool (optional) */ + if (!ctx->cctx.host.dlltool) { + if (slbt_get_lconf_var(confctx,"DLLTOOL=",0x20,&val) < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); + + if (val[0] && !(ctx->host.dlltool = strdup(val))) + return SLBT_SYSTEM_ERROR(dctx,0); + + ctx->cctx.host.dlltool = ctx->host.dlltool; + } + + + /* all done */ + ctx->lconf.addr = addr; + ctx->lconf.size = st.st_size; + return 0; } diff --git a/src/internal/slibtool_libmeta_impl.c b/src/internal/slibtool_libmeta_impl.c index 3fc9645..17e090c 100644 --- a/src/internal/slibtool_libmeta_impl.c +++ b/src/internal/slibtool_libmeta_impl.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,14 +13,15 @@ #include "slibtool_dprintf_impl.h" #include "slibtool_errinfo_impl.h" #include "slibtool_metafile_impl.h" +#include "slibtool_visibility_impl.h" static int slbt_create_default_library_wrapper( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx, - char * arname, - char * soname, - char * soxyz, - char * solnk) + const char * arname, + const char * soname, + const char * soxyz, + const char * solnk) { int ret; int fdout; @@ -28,6 +29,7 @@ static int slbt_create_default_library_wrapper( const char * base; bool fnover; bool fvernum; + bool fspace; int current; int revision; int age; @@ -54,7 +56,8 @@ static int slbt_create_default_library_wrapper( fnover = !!(dctx->cctx->drvflags & SLBT_DRIVER_AVOID_VERSION); fvernum = !!(dctx->cctx->verinfo.vernumber); - verinfo = slbt_source_version(); + fspace = !!soname[0]; + verinfo = slbt_api_source_version(); /* wrapper header */ header = "libtool compatible library wrapper\n"; @@ -67,7 +70,7 @@ static int slbt_create_default_library_wrapper( "# [commit reference: %s]\n\n" "dlname='%s'\n" - "library_names='%s %s %s'\n" + "library_names='%s%s%s%s%s'\n" "old_library='%s'\n\n" "inherited_linker_flags='%s'\n" @@ -99,7 +102,9 @@ static int slbt_create_default_library_wrapper( /* library_names */ fnover ? solnk : soxyz, + fspace ? " " : "", fnover ? solnk : soname, + fspace ? " " : "", solnk, /* old_library */ @@ -130,16 +135,17 @@ static int slbt_create_default_library_wrapper( static int slbt_create_compatible_library_wrapper( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx, - char * arname, - char * soname, - char * soxyz, - char * solnk) + const char * arname, + const char * soname, + const char * soxyz, + const char * solnk) { int ret; int fdout; const char * base; bool fnover; bool fvernum; + bool fspace; int current; int revision; int age; @@ -173,7 +179,8 @@ static int slbt_create_compatible_library_wrapper( fnover = !!(dctx->cctx->drvflags & SLBT_DRIVER_AVOID_VERSION); fvernum = !!(dctx->cctx->verinfo.vernumber); - verinfo = slbt_source_version(); + fspace = !!soname[0]; + verinfo = slbt_api_source_version(); /* wrapper content */ ret = slbt_dprintf(fdout, @@ -188,7 +195,7 @@ static int slbt_create_compatible_library_wrapper( "dlname='%s'\n\n" "# Names of this library.\n" - "library_names='%s %s %s'\n\n" + "library_names='%s%s%s%s%s'\n\n" "# The name of the static archive.\n" "old_library='%s'\n\n" @@ -233,7 +240,9 @@ static int slbt_create_compatible_library_wrapper( /* library_names */ fnover ? solnk : soxyz, + fspace ? " " : "", fnover ? solnk : soname, + fspace ? " " : "", solnk, /* old_library */ @@ -266,14 +275,24 @@ static int slbt_create_compatible_library_wrapper( return (ret < 0) ? SLBT_SYSTEM_ERROR(dctx,0) : 0; } -int slbt_create_library_wrapper( +slbt_hidden int slbt_create_library_wrapper( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx, - char * arname, - char * soname, - char * soxyz, - char * solnk) + const char * arname, + const char * soname, + const char * soxyz, + const char * solnk) { + if (!arname) { + arname = ""; + } + + if (!soname) { + soname = ""; + soxyz = ""; + solnk = ""; + } + if (dctx->cctx->drvflags & SLBT_DRIVER_LEGABITS) return slbt_create_compatible_library_wrapper( dctx,ectx,arname,soxyz,soname,solnk); diff --git a/src/internal/slibtool_linkcmd_impl.h b/src/internal/slibtool_linkcmd_impl.h new file mode 100644 index 0000000..e1b384e --- /dev/null +++ b/src/internal/slibtool_linkcmd_impl.h @@ -0,0 +1,89 @@ +#ifndef SLIBTOOL_LINKCMD_IMPL_H +#define SLIBTOOL_LINKCMD_IMPL_H + +struct slbt_deps_meta { + char ** altv; + char * args; + int depscnt; + int infolen; +}; + +int slbt_get_deps_meta( + const struct slbt_driver_ctx * dctx, + char * libfilename, + int fexternal, + struct slbt_deps_meta * depsmeta); + +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); + +bool slbt_adjust_object_argument( + char * arg, + bool fpic, + bool fany, + int fdcwd); + +bool slbt_adjust_wrapper_argument( + char * arg, + bool fpic, + const char * suffix); + +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 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 slbt_exec_link_finalize_argument_vector( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx); + +int slbt_exec_link_create_host_tag( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + char * deffilename); + +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 slbt_exec_link_create_archive( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + const char * arfilename, + bool fpic, + bool fdep); + +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 slbt_exec_link_create_executable( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + const char * exefilename); + +#endif diff --git a/src/internal/slibtool_m4fake_impl.c b/src/internal/slibtool_m4fake_impl.c new file mode 100644 index 0000000..3bab8c8 --- /dev/null +++ b/src/internal/slibtool_m4fake_impl.c @@ -0,0 +1,142 @@ +/*******************************************************************/ +/* 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 <string.h> +#include <limits.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_snprintf_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_visibility_impl.h" +#include "slibtool_m4fake_impl.h" + +slbt_hidden int slbt_m4fake_expand_cmdarg( + const struct slbt_driver_ctx * dctx, + struct slbt_txtfile_ctx * sctx, + const char * cmdname, + char (*argbuf)[PATH_MAX]) +{ + const char ** pline; + size_t slen; + const char * mark; + const char * match; + const char * cap; + int fquote; + char varbuf[PATH_MAX]; + char strbuf[PATH_MAX]; + + memset(*argbuf,0,sizeof(*argbuf)); + + slen = strlen(cmdname); + pline = sctx->txtlinev; + match = 0; + + for (; !match && *pline; ) { + if (!strncmp(*pline,cmdname,slen)) { + if ((*pline)[slen] == '(') { + mark = &(*pline)[slen]; + cap = ++mark; + + for (fquote=0; !match && *cap; ) { + if (*cap == '[') + fquote++; + + else if ((*cap == ']') && fquote) + fquote--; + + else if ((*cap == ')') && !fquote) + match = cap; + + if (!match) + cap++; + } + + if (!match) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + } + } + + if (!match) + pline++; + } + + if (!match) + return 0; + + strncpy(strbuf,mark,cap-mark); + strbuf[cap-mark] = '\0'; + + mark = strbuf; + slen = strlen(mark); + + if ((mark[0] == '[') && (mark[--slen] == ']')) { + strcpy(*argbuf,++mark); + (*argbuf)[--slen] = '\0'; + return 0; + } + + if (slbt_snprintf( + varbuf,sizeof(varbuf), + "AC_DEFUN([%s],", + strbuf) < 0) + return SLBT_BUFFER_ERROR(dctx); + + slen = strlen(varbuf); + + for (--pline; pline >= sctx->txtlinev; pline--) { + if (!strncmp(*pline,varbuf,slen)) { + mark = &(*pline)[slen]; + cap = mark; + match = 0; + + for (fquote=0; !match && *cap; ) { + if (*cap == '[') + fquote++; + + else if ((*cap == ']') && fquote) + fquote--; + + else if ((*cap == ')') && !fquote) + match = cap; + + if (!match) + cap++; + } + + if (!match) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + strncpy(strbuf,mark,cap-mark); + strbuf[cap-mark] = '\0'; + + mark = strbuf; + slen = strlen(mark); + + if ((mark[0] == '[') && (mark[--slen] == ']')) { + strcpy(*argbuf,++mark); + (*argbuf)[--slen] = '\0'; + return 0; + } + + if (slbt_snprintf( + varbuf,sizeof(varbuf), + "AC_DEFUN([%s],", + strbuf) < 0) + return SLBT_BUFFER_ERROR(dctx); + + slen = strlen(varbuf); + } + } + + strcpy(*argbuf,strbuf); + + return 0; +} diff --git a/src/internal/slibtool_m4fake_impl.h b/src/internal/slibtool_m4fake_impl.h new file mode 100644 index 0000000..8bb2b5f --- /dev/null +++ b/src/internal/slibtool_m4fake_impl.h @@ -0,0 +1,12 @@ +#ifndef SLIBTOOL_M4FAKE_IMPL_H +#define SLIBTOOL_M4FAKE_IMPL_H + +#include <slibtool/slibtool.h> + +int slbt_m4fake_expand_cmdarg( + const struct slbt_driver_ctx * dctx, + struct slbt_txtfile_ctx * sctx, + const char * cmdname, + char (*argbuf)[PATH_MAX]); + +#endif diff --git a/src/internal/slibtool_mapfile_impl.c b/src/internal/slibtool_mapfile_impl.c index 1241f17..5a4fcff 100644 --- a/src/internal/slibtool_mapfile_impl.c +++ b/src/internal/slibtool_mapfile_impl.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ @@ -15,6 +15,7 @@ #include "slibtool_errinfo_impl.h" #include "slibtool_mapfile_impl.h" +#include "slibtool_visibility_impl.h" static void slbt_munmap(void * addr, size_t size) { @@ -23,7 +24,7 @@ static void slbt_munmap(void * addr, size_t size) } } -struct slbt_map_info * slbt_map_file( +slbt_hidden struct slbt_map_info * slbt_map_file( int fdat, const char * path, uint32_t flags) @@ -82,13 +83,13 @@ struct slbt_map_info * slbt_map_file( return mapinfo; } -void slbt_unmap_file(struct slbt_map_info * mapinfo) +slbt_hidden void slbt_unmap_file(struct slbt_map_info * mapinfo) { slbt_munmap(mapinfo->addr,mapinfo->size); free(mapinfo); } -int slbt_mapped_readline( +slbt_hidden int slbt_mapped_readline( const struct slbt_driver_ctx * dctx, struct slbt_map_info * mapinfo, char * buf, diff --git a/src/internal/slibtool_metafile_impl.h b/src/internal/slibtool_metafile_impl.h index bd78b09..b415c05 100644 --- a/src/internal/slibtool_metafile_impl.h +++ b/src/internal/slibtool_metafile_impl.h @@ -10,9 +10,9 @@ int slbt_create_object_wrapper( int slbt_create_library_wrapper( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx, - char * arname, - char * soname, - char * soxyz, - char * solnk); + const char * arname, + const char * soname, + const char * soxyz, + const char * solnk); #endif diff --git a/src/internal/slibtool_mkdir_impl.h b/src/internal/slibtool_mkdir_impl.h index f291383..41943f1 100644 --- a/src/internal/slibtool_mkdir_impl.h +++ b/src/internal/slibtool_mkdir_impl.h @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ diff --git a/src/internal/slibtool_objlist_impl.c b/src/internal/slibtool_objlist_impl.c new file mode 100644 index 0000000..9f25529 --- /dev/null +++ b/src/internal/slibtool_objlist_impl.c @@ -0,0 +1,83 @@ +/*******************************************************************/ +/* 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 <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_mapfile_impl.h" +#include "slibtool_objlist_impl.h" +#include "slibtool_visibility_impl.h" + +slbt_hidden int slbt_objlist_read( + int fdcwd, + struct slbt_obj_list * objlist) +{ + struct slbt_map_info * mapinfo; + int objc; + char ** objv; + char * src; + char * dst; + char * mark; + int skip; + + /* temporarily map the object list */ + if (!(mapinfo = slbt_map_file(fdcwd,objlist->name,SLBT_MAP_INPUT))) + return -1; + + /* object list, cautionary null termination, vector null termination */ + objlist->size = mapinfo->size; + objlist->size++; + objlist->size++; + + if (!(objlist->addr = calloc(1,objlist->size))) { + slbt_unmap_file(mapinfo); + return -1; + } + + /* object list file to normalized object strings */ + objc = 0; + skip = true; + + for (src=mapinfo->addr,dst=objlist->addr; src<mapinfo->cap; src++) { + if (!*src || (*src==' ') || (*src=='\n') || (*src=='\r')) { + if (!skip) + *dst++ = 0; + + skip = true; + } else { + *dst++ = *src; + + objc += !!skip; + skip = false; + } + } + + /* object vector */ + objlist->objc = objc; + + if (!(objlist->objv = calloc(++objc,sizeof(char *)))) { + free(objlist->addr); + slbt_unmap_file(mapinfo); + return -1; + } + + for (objv=objlist->objv,mark=objlist->addr; *mark; objv++) { + *objv = mark; + mark += strlen(mark) + 1; + } + + slbt_unmap_file(mapinfo); + + return 0; +} diff --git a/src/internal/slibtool_objlist_impl.h b/src/internal/slibtool_objlist_impl.h new file mode 100644 index 0000000..cb11d07 --- /dev/null +++ b/src/internal/slibtool_objlist_impl.h @@ -0,0 +1,10 @@ +#ifndef SLIBTOOL_OBJLIST_IMPL_H +#define SLIBTOOL_OBJLIST_IMPL_H + +#include "slibtool_driver_impl.h" + +int slbt_objlist_read( + int fdcwd, + struct slbt_obj_list * objlist); + +#endif diff --git a/src/internal/slibtool_objmeta_impl.c b/src/internal/slibtool_objmeta_impl.c index 9fe2dad..768cc96 100644 --- a/src/internal/slibtool_objmeta_impl.c +++ b/src/internal/slibtool_objmeta_impl.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,6 +11,7 @@ #include "slibtool_dprintf_impl.h" #include "slibtool_errinfo_impl.h" #include "slibtool_metafile_impl.h" +#include "slibtool_visibility_impl.h" static int slbt_create_default_object_wrapper( const struct slbt_driver_ctx * dctx, @@ -27,7 +28,7 @@ static int slbt_create_default_object_wrapper( 0644)) < 0) return SLBT_SYSTEM_ERROR(dctx,ectx->ltobjname); - verinfo = slbt_source_version(); + verinfo = slbt_api_source_version(); ret = slbt_dprintf(fdout, "# libtool compatible object wrapper\n" @@ -68,7 +69,7 @@ static int slbt_create_compatible_object_wrapper( 0644)) < 0) return SLBT_SYSTEM_ERROR(dctx, ectx->ltobjname); - verinfo = slbt_source_version(); + verinfo = slbt_api_source_version(); ret = slbt_dprintf(fdout, "# %s - a libtool object file\n" @@ -101,7 +102,7 @@ static int slbt_create_compatible_object_wrapper( return (ret < 0) ? SLBT_SYSTEM_ERROR(dctx,0) : 0; } -int slbt_create_object_wrapper( +slbt_hidden int slbt_create_object_wrapper( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx) { diff --git a/src/internal/slibtool_pecoff_impl.c b/src/internal/slibtool_pecoff_impl.c new file mode 100644 index 0000000..590fafc --- /dev/null +++ b/src/internal/slibtool_pecoff_impl.c @@ -0,0 +1,16 @@ +/*******************************************************************/ +/* 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 <string.h> + +#include "slibtool_visibility_impl.h" + +slbt_hidden int slbt_is_strong_coff_symbol(const char * sym) +{ + return strncmp(sym,"__imp_",6) + && strncmp(sym,".weak.",6) + && strncmp(sym,".refptr.",8); +} diff --git a/src/internal/slibtool_pecoff_impl.h b/src/internal/slibtool_pecoff_impl.h new file mode 100644 index 0000000..e18b5af --- /dev/null +++ b/src/internal/slibtool_pecoff_impl.h @@ -0,0 +1,6 @@ +#ifndef SLIBTOOL_PECOFF_IMPL_H +#define SLIBTOOL_PECOFF_IMPL_H + +int slbt_is_strong_coff_symbol(const char *); + +#endif diff --git a/src/internal/slibtool_readlink_impl.h b/src/internal/slibtool_readlink_impl.h index 00a9b28..378ed5c 100644 --- a/src/internal/slibtool_readlink_impl.h +++ b/src/internal/slibtool_readlink_impl.h @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ diff --git a/src/helper/slbt_realpath.c b/src/internal/slibtool_realpath_impl.c index 9c41c87..63fc3c4 100644 --- a/src/helper/slbt_realpath.c +++ b/src/internal/slibtool_realpath_impl.c @@ -1,7 +1,6 @@ - /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ @@ -14,9 +13,12 @@ #include "slibtool_driver_impl.h" #include "slibtool_readlink_impl.h" +#include "slibtool_realpath_impl.h" +#include "slibtool_visibility_impl.h" -#ifdef __unix__ +#ifdef HAVE_SYS_SYSCALL_H #include <sys/syscall.h> +#include <unistd.h> #endif #ifdef _MIDIPIX_ABI @@ -27,11 +29,7 @@ #define ENOTSUP EOPNOTSUPP #endif -#ifdef SYS___realpathat -extern long syscall(int, ...); -#endif - -int slbt_realpath( +slbt_hidden int slbt_realpath( int fdat, const char * path, int options, diff --git a/src/internal/slibtool_realpath_impl.h b/src/internal/slibtool_realpath_impl.h new file mode 100644 index 0000000..01df1c1 --- /dev/null +++ b/src/internal/slibtool_realpath_impl.h @@ -0,0 +1,13 @@ +#ifndef SLIBTOOL_REALPATH_IMPL_H +#define SLIBTOOL_REALPATH_IMPL_H + +#include <stdlib.h> + +int slbt_realpath( + int fdat, + const char * path, + int options, + char * buf, + size_t buflen); + +#endif diff --git a/src/internal/slibtool_snprintf_impl.c b/src/internal/slibtool_snprintf_impl.c new file mode 100644 index 0000000..84e01f0 --- /dev/null +++ b/src/internal/slibtool_snprintf_impl.c @@ -0,0 +1,40 @@ +/*******************************************************************/ +/* 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 <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include "slibtool_snprintf_impl.h" +#include "slibtool_visibility_impl.h" + + +/*****************************************************************/ +/* snprintf() wrapper that simplifies usage via the following: */ +/* */ +/* (1) fail (return a negative result) in case the buffer is */ +/* not sufficiently large for the formatted string plus */ +/* the terminating null character. */ +/* */ +/**********************************************************/ + + +slbt_hidden int slbt_snprintf(char * buf, size_t buflen, const char * fmt, ...) +{ + va_list ap; + size_t nbytes; + + va_start(ap,fmt); + nbytes = vsnprintf(buf,buflen,fmt,ap); + va_end(ap); + + if (nbytes >= buflen) + return -1; + + return nbytes; +} diff --git a/src/internal/slibtool_snprintf_impl.h b/src/internal/slibtool_snprintf_impl.h new file mode 100644 index 0000000..87fa65a --- /dev/null +++ b/src/internal/slibtool_snprintf_impl.h @@ -0,0 +1,6 @@ +#ifndef SLIBTOOL_SNPRINTF_IMPL_H +#define SLIBTOOL_SNPRINTF_IMPL_H + +int slbt_snprintf(char * buf, size_t buflen, const char * fmt, ...); + +#endif diff --git a/src/internal/slibtool_spawn_impl.h b/src/internal/slibtool_spawn_impl.h index 188af5d..aa4ea35 100644 --- a/src/internal/slibtool_spawn_impl.h +++ b/src/internal/slibtool_spawn_impl.h @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ @@ -30,6 +30,12 @@ #include <spawn.h> #endif +#ifdef __midipix__ +static pid_t slbt_fork(void) {return vfork();} +#else +static pid_t slbt_fork(void) {return fork();} +#endif + static inline int slbt_spawn( struct slbt_exec_ctx * ectx, bool fwait) @@ -56,6 +62,8 @@ static inline int slbt_spawn( #endif + (void)slbt_fork; + if (pid < 0) { ectx->pid = pid; ectx->exitcode = errno; diff --git a/src/internal/slibtool_stoolie_impl.h b/src/internal/slibtool_stoolie_impl.h new file mode 100644 index 0000000..43d70a5 --- /dev/null +++ b/src/internal/slibtool_stoolie_impl.h @@ -0,0 +1,15 @@ +/*******************************************************************/ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#ifndef SLIBTOOL_STOOLIE_IMPL_H +#define SLIBTOOL_STOOLIE_IMPL_H + +#include "argv/argv.h" +#include <slibtool/slibtool.h> + +extern const struct argv_option slbt_stoolie_options[]; + +#endif diff --git a/src/internal/slibtool_symlink_impl.c b/src/internal/slibtool_symlink_impl.c index 27f8171..bb117e2 100644 --- a/src/internal/slibtool_symlink_impl.c +++ b/src/internal/slibtool_symlink_impl.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,26 +13,32 @@ #include "slibtool_errinfo_impl.h" #include "slibtool_symlink_impl.h" #include "slibtool_readlink_impl.h" +#include "slibtool_realpath_impl.h" +#include "slibtool_snprintf_impl.h" +#include "slibtool_visibility_impl.h" #define SLBT_DEV_NULL_FLAGS (SLBT_DRIVER_ALL_STATIC \ | SLBT_DRIVER_DISABLE_SHARED \ | SLBT_DRIVER_DISABLE_STATIC) -int slbt_create_symlink( +slbt_hidden int slbt_create_symlink_ex( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx, + int fddst, const char * target, const char * lnkname, uint32_t options) { - int fdcwd; int fliteral; int fwrapper; int fdevnull; + size_t slen; char ** oargv; const char * slash; char * ln[5]; + char * dot; char * dotdot; + char * mark; char tmplnk [PATH_MAX]; char lnkarg [PATH_MAX]; char alnkarg[PATH_MAX]; @@ -45,18 +51,14 @@ int slbt_create_symlink( fdevnull = (options & SLBT_SYMLINK_DEVNULL); /* symlink is a placeholder? */ - if (fliteral && fdevnull) { + if (fliteral) { slash = target; - } else if ((dctx->cctx->drvflags & SLBT_DEV_NULL_FLAGS) - && !strcmp(target,"/dev/null")) { + /* .disabled .so or .a file */ + } else if (fdevnull) { slash = target; suffix = ".disabled"; - /* target is an absolute path? */ - } else if (fliteral) { - slash = target; - /* symlink target contains a dirname? */ } else if ((slash = strrchr(target,'/'))) { slash++; @@ -70,23 +72,52 @@ int slbt_create_symlink( dotdot = fwrapper ? "../" : ""; /* atarget */ - if ((size_t)snprintf(atarget,sizeof(atarget),"%s%s", - dotdot,slash) >= sizeof(atarget)) + if (slbt_snprintf(atarget,sizeof(atarget), + "%s%s",dotdot,slash) < 0) return SLBT_BUFFER_ERROR(dctx); /* tmplnk */ - if ((size_t)snprintf(tmplnk,sizeof(tmplnk),"%s.symlink.tmp", - lnkname) >= sizeof(tmplnk)) + if (slbt_snprintf(tmplnk,sizeof(tmplnk), + "%s.symlink.tmp", + lnkname) <0) return SLBT_BUFFER_ERROR(dctx); /* placeholder? */ + if (fdevnull) { + if (unlinkat(fddst,lnkname,0) && (errno != ENOENT)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if ((dot = strrchr(lnkname,'.'))) { + if (!strcmp(dot,dctx->cctx->settings.dsosuffix)) { + strcpy(dot,".expsyms.a"); + + if (unlinkat(fddst,lnkname,0) && (errno != ENOENT)) + return SLBT_SYSTEM_ERROR(dctx,0); + + strcpy(dot,dctx->cctx->settings.dsosuffix); + } + } + } + if (suffix) { sprintf(alnkarg,"%s%s",lnkname,suffix); lnkname = alnkarg; } /* lnkarg */ - strcpy(lnkarg,lnkname); + if (fddst == slbt_driver_fdcwd(dctx)) { + strcpy(lnkarg,lnkname); + } else { + if (slbt_realpath(fddst,".",0,lnkarg,sizeof(lnkarg)) < 0) + return SLBT_BUFFER_ERROR(dctx); + + if ((slen = strlen(lnkarg)) + strlen(lnkname) + 1 >= PATH_MAX) + return SLBT_BUFFER_ERROR(dctx); + + mark = &lnkarg[slen]; + mark[0] = '/'; + strcpy(++mark,lnkname); + } /* ln argv (fake) */ ln[0] = "ln"; @@ -101,12 +132,12 @@ int slbt_create_symlink( /* step output */ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) { if (dctx->cctx->mode == SLBT_MODE_LINK) { - if (slbt_output_link(dctx,ectx)) { + if (slbt_output_link(ectx)) { ectx->argv = oargv; return SLBT_NESTED_ERROR(dctx); } } else { - if (slbt_output_install(dctx,ectx)) { + if (slbt_output_install(ectx)) { ectx->argv = oargv; return SLBT_NESTED_ERROR(dctx); } @@ -116,19 +147,29 @@ int slbt_create_symlink( /* restore execution context */ ectx->argv = oargv; - /* fdcwd */ - fdcwd = slbt_driver_fdcwd(dctx); - /* create symlink */ - if (symlinkat(atarget,fdcwd,tmplnk)) + if (symlinkat(atarget,fddst,tmplnk)) return SLBT_SYSTEM_ERROR(dctx,tmplnk); - return renameat(fdcwd,tmplnk,fdcwd,lnkname) + return renameat(fddst,tmplnk,fddst,lnkname) ? SLBT_SYSTEM_ERROR(dctx,lnkname) : 0; } -int slbt_symlink_is_a_placeholder(int fdcwd, char * lnkpath) +slbt_hidden int slbt_create_symlink( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + const char * target, + const char * lnkname, + uint32_t options) +{ + return slbt_create_symlink_ex( + dctx,ectx, + slbt_driver_fdcwd(dctx), + target,lnkname,options); +} + +slbt_hidden int slbt_symlink_is_a_placeholder(int fdcwd, const char * lnkpath) { size_t len; char slink [PATH_MAX]; diff --git a/src/internal/slibtool_symlink_impl.h b/src/internal/slibtool_symlink_impl.h index fc4c708..9f968de 100644 --- a/src/internal/slibtool_symlink_impl.h +++ b/src/internal/slibtool_symlink_impl.h @@ -16,6 +16,14 @@ int slbt_create_symlink( const char * lnkname, uint32_t options); -int slbt_symlink_is_a_placeholder(int fdcwd, char * lnkpath); +int slbt_create_symlink_ex( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + int fddst, + const char * target, + const char * lnkname, + uint32_t options); + +int slbt_symlink_is_a_placeholder(int fdcwd, const char * lnkpath); #endif diff --git a/src/internal/slibtool_tmpfile_impl.c b/src/internal/slibtool_tmpfile_impl.c new file mode 100644 index 0000000..52c7317 --- /dev/null +++ b/src/internal/slibtool_tmpfile_impl.c @@ -0,0 +1,89 @@ +/*******************************************************************/ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#define _GNU_SOURCE +#include <time.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <inttypes.h> + +#include "slibtool_visibility_impl.h" + +#define PPRIX64 "%"PRIx64 + +/* mkostemp might be guarded by non-standard macros */ +/* unless HAVE_NO_MKOSTEMP, assume it is available */ +extern int mkstemp(char *); +extern int mkostemp(char *, int); + +/* __fs_tmpfile() atomically provides a private tmpfile */ +static int slbt_tmpfile_by_framework(void) +{ +#ifdef _MIDIPIX_ABI + extern int __fs_tmpfile(int); + return __fs_tmpfile(O_CLOEXEC); +#else + return (-1); +#endif +} + +/* O_TMPFILE atomically provides a private tmpfile */ +static int slbt_tmpfile_by_kernel(void) +{ +#ifdef O_TMPFILE + return openat(AT_FDCWD,"/tmp",O_RDWR|O_TMPFILE|O_CLOEXEC,0); +#else + return (-1); +#endif +} + +/* mk{o}stemp() provides a non-private tmpfile */ +static int slbt_mkostemp(char * tmplate) +{ + int fd; +#ifdef HAVE_NO_MKOSTEMP + if ((fd = mkstemp(tmplate)) >= 0) + fcntl(fd,F_SETFD,FD_CLOEXEC); +#else + fd = mkostemp(tmplate,O_CLOEXEC); +#endif + return fd; +} + +slbt_hidden int slbt_tmpfile(void) +{ + int fd; + void * addr; + char tmplate[128]; + + /* try with __fs_tmpfile() */ + if ((fd = slbt_tmpfile_by_framework()) >= 0) + return fd; + + /* try with O_TMPFILE */ + if ((fd = slbt_tmpfile_by_kernel()) >= 0) + return fd; + + /* fallback to mk{o}stemp */ + addr = tmplate; + memset(tmplate,0,sizeof(tmplate)); + snprintf(tmplate,sizeof(tmplate), + "/tmp/" + ".slibtool.tmpfile" + ".time."PPRIX64 + ".salt.%p" + ".pid.%d" + ".XXXXXXXXXXXX", + time(0), + addr, + getpid()); + + return slbt_mkostemp(tmplate); +} diff --git a/src/internal/slibtool_tmpfile_impl.h b/src/internal/slibtool_tmpfile_impl.h new file mode 100644 index 0000000..cd6a02b --- /dev/null +++ b/src/internal/slibtool_tmpfile_impl.h @@ -0,0 +1,6 @@ +#ifndef SLIBTOOL_TMPFILE_IMPL_H +#define SLIBTOOL_TMPFILE_IMPL_H + +int slbt_tmpfile(void); + +#endif diff --git a/src/internal/slibtool_txtline_impl.c b/src/internal/slibtool_txtline_impl.c new file mode 100644 index 0000000..4c8f2ad --- /dev/null +++ b/src/internal/slibtool_txtline_impl.c @@ -0,0 +1,67 @@ +/*******************************************************************/ +/* 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 <string.h> +#include <stdlib.h> + +#include <slibtool/slibtool.h> +#include "slibtool_visibility_impl.h" + +slbt_hidden int slbt_txtline_to_string_vector(const char * txtline, char *** pargv) +{ + int argc; + char ** argv; + const char * ch; + const char * mark; + + if (!(ch = txtline)) + return 0; + + argc = 1; + + for (; *ch == ' '; ) + ch++; + + for (; *ch; ) { + if (*ch++ == ' ') { + argc++; + + for (; (*ch == ' '); ) + ch++; + } + } + + if (argc == 1) + return 0; + + if (!(*pargv = calloc(++argc,sizeof(char *)))) + return -1; + + for (ch=txtline; (*ch == ' '); ch++) + (void)0; + + argv = *pargv; + mark = ch; + + for (; *ch; ) { + if (*ch == ' ') { + if (!(*argv++ = strndup(mark,ch-mark))) + return -1; + + for (; (*ch == ' '); ) + ch++; + + mark = ch; + } else { + ch++; + } + } + + if (!(*argv++ = strndup(mark,ch-mark))) + return -1; + + return 0; +} diff --git a/src/internal/slibtool_txtline_impl.h b/src/internal/slibtool_txtline_impl.h new file mode 100644 index 0000000..2a647b1 --- /dev/null +++ b/src/internal/slibtool_txtline_impl.h @@ -0,0 +1,8 @@ +#ifndef SLIBTOOL_TXTLINE_IMPL_H +#define SLIBTOOL_TXTLINE_IMPL_H + +#include <slibtool/slibtool.h> + +int slbt_txtline_to_string_vector(const char *, char ***); + +#endif diff --git a/src/internal/slibtool_visibility_impl.h b/src/internal/slibtool_visibility_impl.h new file mode 100644 index 0000000..2bdded0 --- /dev/null +++ b/src/internal/slibtool_visibility_impl.h @@ -0,0 +1,26 @@ +#ifndef SLIBTOOL_VISIBILITY_IMPL_H +#define SLIBTOOL_VISIBILITY_IMPL_H + +/**********************************************************************/ +/* PE targets: __dllexport suffices for the purpose of exporting only */ +/* the desired subset of global symbols; this makes the visibility */ +/* attribute not only redundant, but also tricky if not properly */ +/* supported by the toolchain. */ +/* */ +/* When targeting Midipix, __PE__, __dllexport and __dllimport are */ +/* always defined by the toolchain. Otherwise, the absnece of these */ +/* macros has been detected by sofort's ccenv.sh during ./configure, */ +/* and they have accordingly been added to CFLAGS_OS. */ +/**********************************************************************/ + +#ifdef __PE__ +#define slbt_hidden +#else +#ifdef _ATTR_VISIBILITY_HIDDEN +#define slbt_hidden _ATTR_VISIBILITY_HIDDEN +#else +#define slbt_hidden +#endif +#endif + +#endif 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 f9cd1d2..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 SysDeer Technologies, LLC */ +/* 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 294641e..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 SysDeer Technologies, LLC */ +/* 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 971ff3c..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 SysDeer Technologies, LLC */ +/* 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 d643cae..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 SysDeer Technologies, LLC */ +/* 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 b2cad03..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 SysDeer Technologies, LLC */ +/* 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 5c59d3f..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 SysDeer Technologies, LLC */ +/* 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; } diff --git a/src/output/slbt_output_config.c b/src/output/slbt_output_config.c index 181aa84..5d52e44 100644 --- a/src/output/slbt_output_config.c +++ b/src/output/slbt_output_config.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,102 +13,88 @@ #include "slibtool_dprintf_impl.h" #include "slibtool_errinfo_impl.h" -#ifndef SLBT_TAB_WIDTH -#define SLBT_TAB_WIDTH 8 -#endif +static const char lconf_begin[] = "# ### BEGIN LIBTOOL CONFIG\n"; +static const char lconf_end [] = "# ### END LIBTOOL CONFIG\n"; -#ifndef SLBT_KEY_WIDTH -#define SLBT_KEY_WIDTH 16 -#endif - -static bool slbt_output_config_line( - int fd, - const char * key, - const char * value, - const char * annotation, - int midwidth) +static int slbt_output_config_lconf( + const struct slbt_driver_ctx * dctx, + const struct slbt_map_info * lconf) { - return (slbt_dprintf(fd,"%-*s%-*s%s\n", - SLBT_KEY_WIDTH, key, - midwidth, value ? value : "", - annotation ? annotation : "") < 0) - ? true : false; + const char * ch; + const char * cfg_begin; + const char * cfg_end; + const char * map_cap; + size_t cmp_len; + size_t end_len; + size_t min_len; + size_t nbytes; + ssize_t written; + int fdout; + + cmp_len = strlen(lconf_begin); + end_len = strlen(lconf_end); + min_len = cmp_len + end_len; + + if (lconf->size < min_len) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + map_cap = lconf->addr; + map_cap += lconf->size; + map_cap -= strlen(lconf_end); + map_cap -= strlen(lconf_begin); + + cfg_begin = cfg_end = 0; + + for (ch=lconf->addr; !cfg_begin && (ch < map_cap); ch++) + if (!strncmp(ch,lconf_begin,cmp_len)) + cfg_begin = ch; + + if (!cfg_begin) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + for (++ch; !cfg_end && (ch < map_cap); ch++) + if (!strncmp(ch,lconf_end,end_len)) + cfg_end = ch; + + if (!cfg_end) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + fdout = slbt_driver_fdout(dctx); + nbytes = cfg_end - cfg_begin - cmp_len; + + for (ch=&cfg_begin[cmp_len]; nbytes; ) { + written = write(fdout,ch,nbytes); + + while ((written < 0) && (errno == EINTR)) + written = write(fdout,ch,nbytes); + + if (written < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + nbytes -= written; + ch += written; + } + + return 0; } int slbt_output_config(const struct slbt_driver_ctx * dctx) { - const struct slbt_common_ctx * cctx; - const char * compiler; - const char * target; - int len; - int midwidth; - int fdout; - - cctx = dctx->cctx; - compiler = cctx->cargv[0] ? cctx->cargv[0] : ""; - target = cctx->target ? cctx->target : ""; - midwidth = strlen(compiler); - fdout = slbt_driver_fdout(dctx); - - if ((len = strlen(target)) > midwidth) - midwidth = len; - - if ((len = strlen(cctx->host.host)) > midwidth) - midwidth = len; - - if ((len = strlen(cctx->host.flavor)) > midwidth) - midwidth = len; - - if ((len = strlen(cctx->host.ar)) > midwidth) - midwidth = len; - - if ((len = strlen(cctx->host.ranlib)) > midwidth) - midwidth = len; - - if ((len = strlen(cctx->host.windres)) > midwidth) - midwidth = len; - - if ((len = strlen(cctx->host.dlltool)) > midwidth) - midwidth = len; - - if ((len = strlen(cctx->host.mdso)) > midwidth) - midwidth = len; - - midwidth += SLBT_TAB_WIDTH; - midwidth &= (~(SLBT_TAB_WIDTH-1)); - - if (slbt_output_config_line(fdout,"key","value","annotation",midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); - - if (slbt_output_config_line(fdout,"---","-----","----------",midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); - - if (slbt_output_config_line(fdout,"compiler",cctx->cargv[0],"",midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); - - if (slbt_output_config_line(fdout,"target",cctx->target,"",midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); - - if (slbt_output_config_line(fdout,"host",cctx->host.host,cctx->cfgmeta.host,midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); - - if (slbt_output_config_line(fdout,"flavor",cctx->host.flavor,cctx->cfgmeta.flavor,midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); - - if (slbt_output_config_line(fdout,"ar",cctx->host.ar,cctx->cfgmeta.ar,midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); - - if (slbt_output_config_line(fdout,"ranlib",cctx->host.ranlib,cctx->cfgmeta.ranlib,midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); - - if (slbt_output_config_line(fdout,"windres",cctx->host.windres,cctx->cfgmeta.windres,midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); + struct slbt_driver_ctx_impl * ictx; + const struct slbt_map_info * lconf; - if (slbt_output_config_line(fdout,"dlltool",cctx->host.dlltool,cctx->cfgmeta.dlltool,midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); + ictx = slbt_get_driver_ictx(dctx); + lconf = &ictx->lconf; - if (slbt_output_config_line(fdout,"mdso",cctx->host.mdso,cctx->cfgmeta.mdso,midwidth)) - return SLBT_SYSTEM_ERROR(dctx,0); + if (lconf->addr) + return slbt_output_config_lconf( + dctx,lconf); return 0; } diff --git a/src/output/slbt_output_error.c b/src/output/slbt_output_error.c index a2de253..4077497 100644 --- a/src/output/slbt_output_error.c +++ b/src/output/slbt_output_error.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ diff --git a/src/output/slbt_output_exec.c b/src/output/slbt_output_exec.c index 187c3ac..9c88bac 100644 --- a/src/output/slbt_output_exec.c +++ b/src/output/slbt_output_exec.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ @@ -17,8 +17,8 @@ static const char aclr_reset[] = "\x1b[0m"; static const char aclr_bold[] = "\x1b[1m"; static const char aclr_green[] = "\x1b[32m"; -static const char aclr_blue[] = "\x1b[34m"; static const char aclr_magenta[] = "\x1b[35m"; +static const char aclr_white[] = "\x1b[37m"; static int slbt_output_exec_annotated( const struct slbt_driver_ctx * dctx, @@ -31,7 +31,9 @@ static int slbt_output_exec_annotated( const char * aclr_color; const char * aclr_unset; - fdout = slbt_driver_fdout(dctx); + fdout = (strcmp(step,"execute")) + ? slbt_driver_fdout(dctx) + : slbt_driver_fderr(dctx); if (slbt_dprintf( fdout,"%s%s%s: %s%s%s%s:%s", @@ -43,7 +45,7 @@ static int slbt_output_exec_annotated( for (parg=ectx->argv; *parg; parg++) { if ((parg == ectx->lout[0]) || (parg == ectx->mout[0])) { aclr_set = aclr_bold; - aclr_color = aclr_blue; + aclr_color = aclr_white; aclr_unset = aclr_null; } else { aclr_set = aclr_null; @@ -74,7 +76,9 @@ static int slbt_output_exec_plain( int fdout; char ** parg; - fdout = slbt_driver_fdout(dctx); + fdout = (strcmp(step,"execute")) + ? slbt_driver_fdout(dctx) + : slbt_driver_fderr(dctx); if (slbt_dprintf(fdout,"%s: %s:",dctx->program,step) < 0) return SLBT_SYSTEM_ERROR(dctx,0); @@ -90,11 +94,17 @@ static int slbt_output_exec_plain( } int slbt_output_exec( - const struct slbt_driver_ctx * dctx, const struct slbt_exec_ctx * ectx, const char * step) { - int fdout = slbt_driver_fdout(dctx); + const struct slbt_driver_ctx * dctx; + int fdout; + + dctx = (slbt_get_exec_ictx(ectx))->dctx; + + fdout = (strcmp(step,"execute")) + ? slbt_driver_fdout(dctx) + : slbt_driver_fderr(dctx); if (dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER) return slbt_output_exec_plain(dctx,ectx,step); @@ -109,37 +119,27 @@ int slbt_output_exec( return slbt_output_exec_plain(dctx,ectx,step); } -int slbt_output_compile( - const struct slbt_driver_ctx * dctx, - const struct slbt_exec_ctx * ectx) +int slbt_output_compile(const struct slbt_exec_ctx * ectx) { - return slbt_output_exec(dctx,ectx,"compile"); + return slbt_output_exec(ectx,"compile"); } -int slbt_output_execute( - const struct slbt_driver_ctx * dctx, - const struct slbt_exec_ctx * ectx) +int slbt_output_execute(const struct slbt_exec_ctx * ectx) { - return slbt_output_exec(dctx,ectx,"execute"); + return slbt_output_exec(ectx,"execute"); } -int slbt_output_install( - const struct slbt_driver_ctx * dctx, - const struct slbt_exec_ctx * ectx) +int slbt_output_install(const struct slbt_exec_ctx * ectx) { - return slbt_output_exec(dctx,ectx,"install"); + return slbt_output_exec(ectx,"install"); } -int slbt_output_link( - const struct slbt_driver_ctx * dctx, - const struct slbt_exec_ctx * ectx) +int slbt_output_link(const struct slbt_exec_ctx * ectx) { - return slbt_output_exec(dctx,ectx,"link"); + return slbt_output_exec(ectx,"link"); } -int slbt_output_uninstall( - const struct slbt_driver_ctx * dctx, - const struct slbt_exec_ctx * ectx) +int slbt_output_uninstall(const struct slbt_exec_ctx * ectx) { - return slbt_output_exec(dctx,ectx,"uninstall"); + return slbt_output_exec(ectx,"uninstall"); } diff --git a/src/output/slbt_output_fdcwd.c b/src/output/slbt_output_fdcwd.c index 650f288..4b5c54d 100644 --- a/src/output/slbt_output_fdcwd.c +++ b/src/output/slbt_output_fdcwd.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,6 +13,7 @@ #include "slibtool_driver_impl.h" #include "slibtool_dprintf_impl.h" +#include "slibtool_realpath_impl.h" static const char aclr_reset[] = "\x1b[0m"; static const char aclr_bold[] = "\x1b[1m"; diff --git a/src/output/slbt_output_features.c b/src/output/slbt_output_features.c index bd4ba1f..a6a5a20 100644 --- a/src/output/slbt_output_features.c +++ b/src/output/slbt_output_features.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ diff --git a/src/output/slbt_output_info.c b/src/output/slbt_output_info.c new file mode 100644 index 0000000..583906f --- /dev/null +++ b/src/output/slbt_output_info.c @@ -0,0 +1,126 @@ +/*******************************************************************/ +/* 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 <stdio.h> +#include <string.h> +#include <stdbool.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_dprintf_impl.h" +#include "slibtool_errinfo_impl.h" + +#ifndef SLBT_TAB_WIDTH +#define SLBT_TAB_WIDTH 8 +#endif + +#ifndef SLBT_KEY_WIDTH +#define SLBT_KEY_WIDTH 16 +#endif + +static bool slbt_output_info_line( + int fd, + const char * key, + const char * value, + const char * annotation, + int midwidth) +{ + return (slbt_dprintf(fd,"%-*s%-*s%s\n", + SLBT_KEY_WIDTH, key, + midwidth, value ? value : "", + annotation ? annotation : "") < 0) + ? true : false; +} + +int slbt_output_info(const struct slbt_driver_ctx * dctx) +{ + const struct slbt_common_ctx * cctx; + const char * compiler; + const char * target; + int len; + int midwidth; + int fdout; + + cctx = dctx->cctx; + compiler = cctx->cargv[0] ? cctx->cargv[0] : ""; + target = cctx->target ? cctx->target : ""; + midwidth = strlen(compiler); + fdout = slbt_driver_fdout(dctx); + + if ((len = strlen(target)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.host)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.flavor)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.ar)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.as)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.nm)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.ranlib)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.windres)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.dlltool)) > midwidth) + midwidth = len; + + if ((len = strlen(cctx->host.mdso)) > midwidth) + midwidth = len; + + midwidth += SLBT_TAB_WIDTH; + midwidth &= (~(SLBT_TAB_WIDTH-1)); + + if (slbt_output_info_line(fdout,"key","value","annotation",midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"---","-----","----------",midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"compiler",cctx->cargv[0],"",midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"target",cctx->target,"",midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"host",cctx->host.host,cctx->cfgmeta.host,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"flavor",cctx->host.flavor,cctx->cfgmeta.flavor,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"ar",cctx->host.ar,cctx->cfgmeta.ar,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"as",cctx->host.as,cctx->cfgmeta.as,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"nm",cctx->host.nm,cctx->cfgmeta.nm,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"ranlib",cctx->host.ranlib,cctx->cfgmeta.ranlib,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"windres",cctx->host.windres,cctx->cfgmeta.windres,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"dlltool",cctx->host.dlltool,cctx->cfgmeta.dlltool,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (slbt_output_info_line(fdout,"mdso",cctx->host.mdso,cctx->cfgmeta.mdso,midwidth)) + return SLBT_SYSTEM_ERROR(dctx,0); + + return 0; +} diff --git a/src/output/slbt_output_machine.c b/src/output/slbt_output_machine.c index ab95837..ad98066 100644 --- a/src/output/slbt_output_machine.c +++ b/src/output/slbt_output_machine.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ diff --git a/src/output/slbt_output_mapfile.c b/src/output/slbt_output_mapfile.c new file mode 100644 index 0000000..166b1f4 --- /dev/null +++ b/src/output/slbt_output_mapfile.c @@ -0,0 +1,12 @@ +/*******************************************************************/ +/* 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> + +int slbt_output_mapfile(const struct slbt_symlist_ctx * sctx) +{ + return slbt_util_create_mapfile(sctx,0,0); +} diff --git a/src/skin/slbt_skin_ar.c b/src/skin/slbt_skin_ar.c new file mode 100644 index 0000000..52d9380 --- /dev/null +++ b/src/skin/slbt_skin_ar.c @@ -0,0 +1,97 @@ +#include "slibtool_driver_impl.h" +#include "slibtool_visibility_impl.h" +#include "argv/argv.h" + +const slbt_hidden struct argv_option slbt_ar_options[] = { + {"version", 0,TAG_AR_VERSION,ARGV_OPTARG_NONE,0,0,0, + "show version information"}, + + {"help", 'h',TAG_AR_HELP,ARGV_OPTARG_NONE,0,0,0, + "display ar mode help"}, + + {"Wcheck", 0,TAG_AR_CHECK,ARGV_OPTARG_NONE, + ARGV_OPTION_HYBRID_ONLY, + "[ARCHIVE-FILE]",0, + "verify that each %s is a valid archive; " + "supported variants are BSD, SysV, and PE/COFF"}, + + {"Wmerge", 0,TAG_AR_MERGE,ARGV_OPTARG_NONE, + ARGV_OPTION_HYBRID_ONLY, + "[ARCHIVE-FILE]",0, + "merge one or more archive files; " + "the name of the new archive, which may be the same " + "as one of the input archives, shall be specified " + "via the -Woutput switch; order of archive members " + "shall be retained, and symbol maps shall be " + "merged as well as normalized."}, + + {"Woutput", 0,TAG_AR_OUTPUT,ARGV_OPTARG_REQUIRED, + ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, + 0,0, + "specify the name of the archive to be created " + "(or replaced) as a result of a -Wmerge operation."}, + + {"Wprint", 0,TAG_AR_PRINT,ARGV_OPTARG_OPTIONAL, + ARGV_OPTION_HYBRID_EQUAL|ARGV_OPTION_HYBRID_COMMA, + "members|symbols",0, + "print out information pertaining to each archive file " + "and its various internal elements"}, + + {"Wmapfile", 0,TAG_AR_MAPFILE,ARGV_OPTARG_NONE, + ARGV_OPTION_HYBRID_ONLY, + 0,0, + "print out a (sorted) map file " + "(aka symbol file, aka version script), " + "including either all armap symbols (if no regex filter was " + "specified), or otherwise only the symbols that match the " + "specified regex filter."}, + + {"Wregex", 0,TAG_AR_REGEX,ARGV_OPTARG_REQUIRED, + ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, + 0,"<regexp>", + "filter armap symbols using the specified %s."}, + + {"Wdlunit", 0,TAG_AR_DLUNIT,ARGV_OPTARG_REQUIRED, + ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, + 0,"<dlunit>", + "consider %s to be the name of " + "the dynamic library (libfoo), the program (foo), " + "or the loaded module (foo) for which " + "a compatible dlsym vtable should be created."}, + + {"Wdlsyms", 0,TAG_AR_DLSYMS,ARGV_OPTARG_NONE, + ARGV_OPTION_HYBRID_ONLY, + 0,0, + "print out a compatible dlsyms vtable."}, + + {"Wnosort", 0,TAG_AR_NOSORT,ARGV_OPTARG_NONE, + ARGV_OPTION_HYBRID_ONLY, + 0,0, + "do not sort the symbol list; " + "affected switches are -Wprint=symbols and -Wmapfile."}, + + {"Wpretty", 0,TAG_AR_PRETTY,ARGV_OPTARG_REQUIRED, + ARGV_OPTION_HYBRID_EQUAL, + "posix|yaml|hexdata",0, + "select the pretty printer to be used: " + "'posix' for ar(1) compatible output; " + "'yaml' for yaml-formatted data; and " + "'hexdata' for yaml-formatted data with additional " + "hexdump output"}, + + {"Wposix", 0,TAG_AR_POSIX,ARGV_OPTARG_NONE, + ARGV_OPTION_HYBRID_ONLY,0,0, + "a shorthand for -Wpretty=posix"}, + + {"Wyaml", 0,TAG_AR_YAML,ARGV_OPTARG_NONE, + ARGV_OPTION_HYBRID_ONLY,0,0, + "a shorthand for -Wpretty=yaml"}, + + {"Wverbose", 0,TAG_AR_VERBOSE,ARGV_OPTARG_NONE, + ARGV_OPTION_HYBRID_ONLY,0,0, + "produce verbose output; " + "in combination with -Wpretty=posix, this will result " + "in `ar(1) -tv` compatible output."}, + + {0,0,0,0,0,0,0,0} +}; diff --git a/src/skin/slbt_skin_default.c b/src/skin/slbt_skin_default.c index 3be3b74..7c54f76 100644 --- a/src/skin/slbt_skin_default.c +++ b/src/skin/slbt_skin_default.c @@ -1,15 +1,16 @@ #include "slibtool_driver_impl.h" +#include "slibtool_visibility_impl.h" #include "argv/argv.h" -const struct argv_option slbt_default_options[] = { +const slbt_hidden struct argv_option slbt_default_options[] = { {"version", 0,TAG_VERSION,ARGV_OPTARG_NONE,0,0,0, - "show version information"}, + "show version information."}, {"help", 'h',TAG_HELP,ARGV_OPTARG_OPTIONAL,0,0,0, - "show usage information"}, + "show usage information."}, {"help-all", 'h',TAG_HELP_ALL,ARGV_OPTARG_NONE,0,0,0, - "show comprehensive help information"}, + "show comprehensive help information."}, {"heuristics", 0,TAG_HEURISTICS,ARGV_OPTARG_OPTIONAL,0,0,"<path>", "enable/disable creation of shared/static libraries " @@ -19,34 +20,44 @@ const struct argv_option slbt_default_options[] = { {"mode", 0,TAG_MODE,ARGV_OPTARG_REQUIRED,0, "clean|compile|execute|finish" - "|install|link|uninstall",0, + "|install|link|uninstall|ar" + "|stoolie|slibtoolize",0, "set the execution mode, where <mode> " "is one of {%s}. of the above modes, " "'finish' is not needed and is therefore " "a no-op; 'clean' is currently not implemented, " "however its addition is expected before the " - "next major release"}, + "next major release."}, {"finish", 0,TAG_FINISH,ARGV_OPTARG_NONE,0,0,0, "same as --mode=finish"}, {"dry-run", 'n',TAG_DRY_RUN,ARGV_OPTARG_NONE,0,0,0, "do not spawn any processes, " - "do not make any changes to the file system"}, + "do not make any changes to the file system."}, {"tag", 0,TAG_TAG,ARGV_OPTARG_REQUIRED,0, - "CC|CXX|FC|F77|NASM|RC|disable-static|disable-shared",0, + "CC|CXX|FC|F77|ASM|NASM|RC|disable-static|disable-shared",0, "a universal playground game; " - "currently accepted tags are {%s}"}, + "currently accepted tags are {%s}."}, {"config", 0,TAG_CONFIG,ARGV_OPTARG_NONE,0,0,0, - "display configuration information"}, + "print a compatible --config output"}, + + {"info", 0,TAG_INFO,ARGV_OPTARG_NONE,0,0,0, + "display detected (or cached) environment information."}, + + {"rosylee", 0,TAG_INFO,ARGV_OPTARG_NONE,0,0,0, + "synonym for --info"}, + + {"valerius", 0,TAG_INFO,ARGV_OPTARG_NONE,0,0,0, + "alternative for --rosylee"}, {"debug", 0,TAG_DEBUG,ARGV_OPTARG_NONE,0,0,0, - "display internal debug information"}, + "display internal debug information."}, {"features", 0,TAG_FEATURES,ARGV_OPTARG_NONE,0,0,0, - "show feature information"}, + "show feature information."}, {"dumpmachine", 0,TAG_DUMPMACHINE,ARGV_OPTARG_NONE,0,0,0, "print the cached result of the native compiler's " @@ -73,7 +84,7 @@ const struct argv_option slbt_default_options[] = { {"no-warnings", 0,TAG_WARNINGS,ARGV_OPTARG_NONE,0,0,0,""}, {"preserve-dup-deps", 0,TAG_DEPS,ARGV_OPTARG_NONE,0,0,0, - "leave the dependency list alone"}, + "leave the dependency list alone."}, {"annotate", 0,TAG_ANNOTATE,ARGV_OPTARG_REQUIRED,0, "always|never|minimal|full",0, @@ -81,67 +92,74 @@ const struct argv_option slbt_default_options[] = { "the defautls are full annotation when " "stdout is a tty, and no annotation " "at all otherwise; accepted modes " - "are {%s}"}, + "are {%s}."}, {"quiet", 0,TAG_SILENT,ARGV_OPTARG_NONE,0,0,0, - "do not say anything"}, + "do not say anything."}, {"silent", 0,TAG_SILENT,ARGV_OPTARG_NONE,0,0,0, - "say absolutely nothing"}, + "say absolutely nothing."}, {"verbose", 0,TAG_VERBOSE,ARGV_OPTARG_NONE,0,0,0, "generate lots of informational messages " - "that nobody can understand"}, + "that nobody can understand."}, {"host", 0,TAG_HOST,ARGV_OPTARG_REQUIRED,0,0,"<host>", - "set an explicit (cross-)host"}, + "set an explicit (cross-)host."}, {"flavor", 0,TAG_FLAVOR,ARGV_OPTARG_REQUIRED,0, "bsd|cygwin|darwin|linux|midipix|mingw", 0,"explicitly specify the host's flavor; " - "currently accepted flavors are {%s}"}, + "currently accepted flavors are {%s}."}, {"ar", 0,TAG_AR,ARGV_OPTARG_REQUIRED,0,0,"<ar>", - "explicitly specify the archiver to be used"}, + "explicitly specify the archiver to be used."}, + + {"as", 0,TAG_AS,ARGV_OPTARG_REQUIRED,0,0,"<as>", + "explicitly specify the assembler to be used (with dlltool)."}, + + {"nm", 0,TAG_NM,ARGV_OPTARG_REQUIRED,0,0,"<nm>", + "explicitly specify the name mangler to be used."}, {"ranlib", 0,TAG_RANLIB,ARGV_OPTARG_REQUIRED,0,0,"<ranlib>", - "explicitly specify the librarian to be used"}, + "explicitly specify the librarian to be used."}, {"dlltool", 0,TAG_DLLTOOL,ARGV_OPTARG_REQUIRED,0,0,"<dlltool>", "explicitly specify the PE import library generator " - "to be used"}, + "to be used."}, {"mdso", 0,TAG_MDSO,ARGV_OPTARG_REQUIRED,0,0,"<mdso>", "explicitly specify the PE custom import library " - "generator to be used"}, + "generator to be used."}, {"windres", 0,TAG_WINDRES,ARGV_OPTARG_REQUIRED,0,0,"<windres>", "explicitly specify the PE resource compiler " - "to be used"}, + "to be used."}, {"implib", 0,TAG_IMPLIB,ARGV_OPTARG_REQUIRED,0, "idata|dsometa",0, "PE import libraries should either use the legacy " "format (.idata section) and be generated by dlltool, " "or the custom format (.dsometa section) and be " - "generated by mdso"}, + "generated by mdso."}, {"warnings", 0,TAG_WARNINGS,ARGV_OPTARG_REQUIRED,0, "all|none|error",0, "set the warning reporting level; " - "accepted levels are {%s}"}, + "accepted levels are {%s}."}, {"W", 0,TAG_WARNINGS,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_JOINED, "all|none|error","", - "convenient shorthands for the above"}, + "convenient shorthands for the above."}, {"output", 'o',TAG_OUTPUT,ARGV_OPTARG_REQUIRED,0,0,"<file>", - "write output to %s"}, + "write output to %s."}, - {"target", 0,TAG_TARGET,ARGV_OPTARG_REQUIRED,0,0,"<target>", + {"target", 0,TAG_TARGET,ARGV_OPTARG_REQUIRED, + ARGV_OPTION_HYBRID_SPACE,0,"<target>", "set an explicit (cross-)target, then pass it to " - "the compiler"}, + "the compiler."}, {"R", 0,TAG_LDRPATH,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_CIRCUS,0,0, @@ -152,7 +170,7 @@ const struct argv_option slbt_default_options[] = { ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE,0,0, "override destination directory when installing " "PE shared libraries. Not needed, ignored for " - "compatibility"}, + "compatibility."}, {"shrext", 0,TAG_SHREXT,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE,0,0, @@ -168,103 +186,112 @@ const struct argv_option slbt_default_options[] = { {"sysroot", 0,TAG_SYSROOT,ARGV_OPTARG_REQUIRED,0,0,"<sysroot>", "an absolute sysroot path to pass to the compiler " - "or linker driver"}, + "or linker driver."}, {"release", 0,TAG_RELEASE,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE,0,0, "specify release information; this will result " "in the generation of libfoo-x.y.z.so, " "followed by the creation of libfoo.so " - "as a symlink thereto"}, + "as a symlink thereto."}, + + {"objectlist", 0,TAG_OBJECTLIST,ARGV_OPTARG_REQUIRED, + ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, + 0,"<file>", + "add the object listed in %s to the object vector}."}, {"dlopen", 0,TAG_DLOPEN,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, 0,"<module>", - "add the directory containing %s to the library path " - "[currently a no-op]"}, + "create and link into the dynamic library, dynamic module, " + "or executable program a minimal, backward-compatible dlsyms " + "vtable. On modern systems, this has the same effect as " + "``-dlpreopen force``."}, {"dlpreopen", 0,TAG_DLPREOPEN,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, 0,"<FILE>", "Link the specified %s into the generated library " - "or executable"}, + "or executable, and make it available to the compiled " + "shared library, dynamic module, or executable program " + "via a backward-compatible dlsymas vtable. The special " + "arguments 'self' and 'force' can be used to request " + "that symbols from the executable program be added " + "to the vtable, and that a vtable always be created, " + "respectively."}, {"export-dynamic", 0,TAG_EXPORT_DYNAMIC,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, - "allow symbols in the output file to be resolved via dlsym() " - "[currently a no-op]"}, + "allow symbols in the output file to be resolved via dlsym()."}, - {"export-symbols", 0,TAG_EXPSYM_FILE,ARGV_OPTARG_REQUIRED, + {"export-symbols", 0,TAG_EXPSYMS_FILE,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, 0,"<symfile>", - "only export the symbols that are listed in %s " - "[currently a no-op]"}, + "only export the symbols that are listed in %s."}, - {"export-symbols-regex",0,TAG_EXPSYM_REGEX,ARGV_OPTARG_REQUIRED, + {"export-symbols-regex",0,TAG_EXPSYMS_REGEX,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, 0,"<regex>", - "only export symbols mathing the regex expression %s " - "[currently a no-op]"}, + "only export symbols mathing the regex expression %s."}, {"module", 0,TAG_MODULE,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, "create a shared object that will only be " "loaded at runtime via dlopen(3). the shared " "object name need not follow the platform's " - "library naming conventions"}, + "library naming conventions."}, {"all-static", 0,TAG_ALL_STATIC,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, "for programs, create a zero-dependency, " "statically linked binary; for libraries, " - "only create an archive of non-pic objects"}, + "only create an archive of non-pic objects."}, {"disable-static", 0,TAG_DISABLE_STATIC,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, "for libraries, only create a shared library, " "and accordingly do not create an archive " - "containing the individual object files. " - "[currently a no-op]"}, + "containing the individual object files."}, {"disable-shared", 0,TAG_DISABLE_SHARED,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, "for libraries, only create an archive " "containing the individual object files, and " - "accordingly do not create a shared library"}, + "accordingly do not create a shared library."}, {"avoid-version", 0,TAG_AVOID_VERSION,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, "do not store version information, " - "do not create version-specific symlinks"}, + "do not create version-specific symlinks."}, {"version-info", 0,TAG_VERSION_INFO,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE,0, "<current>[:<revision>[:<age>]]", - "specify version information using a %s syntax"}, + "specify version information using a %s syntax."}, {"version-number", 0,TAG_VERSION_NUMBER,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE,0, "<major>[:<minor>[:<revision>]]", - "specify version information using a %s syntax"}, + "specify version information using a %s syntax."}, {"no-suppress", 0,TAG_NO_SUPPRESS,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, "transparently forward all " - "compiler-generated output"}, + "compiler-generated output."}, {"no-install", 0,TAG_NO_INSTALL,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, "consider the executable image wrapper " "to be optional " - "[currently a no-op]"}, + "[currently a no-op]."}, {"prefer-pic", 0,TAG_PREFER_PIC,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, - "pick on non-PIC objects"}, + "pick on non-PIC objects."}, {"prefer-non-pic", 0,TAG_PREFER_NON_PIC,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, - "pick on PIC objects"}, + "pick on PIC objects."}, {"shared", 0,TAG_SHARED,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, @@ -288,30 +315,30 @@ const struct argv_option slbt_default_options[] = { {"Xcompiler", 0,TAG_VERBATIM_FLAG,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, 0,"<flag>", - "pass a raw flag to the compiler"}, + "pass a raw flag to the compiler."}, {"Xlinker", 0,TAG_VERBATIM_FLAG,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, 0,"<flag>", - "pass a raw flag to the compiler linker-driver"}, + "pass a raw flag to the compiler linker-driver."}, {"XCClinker", 0,TAG_VERBATIM_FLAG,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, 0,"<flag>", - "pass a raw flag to the compiler linker-driver"}, + "pass a raw flag to the compiler linker-driver."}, {"weak", 0,TAG_WEAK,ARGV_OPTARG_REQUIRED, ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_SPACE, 0,"<LIBNAME>", - "hint only, currently a no-op"}, + "hint only, currently a no-op."}, {"no-undefined", 0,TAG_NO_UNDEFINED,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, - "disallow unresolved references"}, + "disallow unresolved references."}, {"thread-safe", 0,TAG_THREAD_SAFE,ARGV_OPTARG_NONE, ARGV_OPTION_HYBRID_ONLY,0,0, - "sleep tight, your threads are now safe"}, + "sleep tight, your threads are now safe."}, {0,0,0,0,0,0,0,0} }; diff --git a/src/skin/slbt_skin_install.c b/src/skin/slbt_skin_install.c index e8feb59..a6e6b15 100644 --- a/src/skin/slbt_skin_install.c +++ b/src/skin/slbt_skin_install.c @@ -1,7 +1,8 @@ #include "slibtool_install_impl.h" +#include "slibtool_visibility_impl.h" #include "argv/argv.h" -const struct argv_option slbt_install_options[] = { +const slbt_hidden struct argv_option slbt_install_options[] = { {"help", 'h',TAG_INSTALL_HELP,ARGV_OPTARG_NONE,0,0,0, "display install mode help"}, diff --git a/src/skin/slbt_skin_stoolie.c b/src/skin/slbt_skin_stoolie.c new file mode 100644 index 0000000..598a410 --- /dev/null +++ b/src/skin/slbt_skin_stoolie.c @@ -0,0 +1,52 @@ +#include "slibtool_driver_impl.h" +#include "slibtool_visibility_impl.h" +#include "argv/argv.h" + +const slbt_hidden struct argv_option slbt_stoolie_options[] = { + {"version", 0,TAG_STLE_VERSION,ARGV_OPTARG_NONE,0,0,0, + "show version information"}, + + {"help", 'h',TAG_STLE_HELP,ARGV_OPTARG_NONE,0,0,0, + "display slibtoolize (stoolie) mode help"}, + + {"copy", 'c',TAG_STLE_COPY,ARGV_OPTARG_NONE,0,0,0, + "copy build-auxiliary m4 files " + "(create symbolic links otherwise."}, + + {"force", 'f',TAG_STLE_FORCE,ARGV_OPTARG_NONE,0,0,0, + "replace existing build-auxiliary and m4 " + "files and/or symbolic links."}, + + {"install", 'i',TAG_STLE_INSTALL,ARGV_OPTARG_NONE,0,0,0, + "create symbolic links to, or otherwise copy " + "missing build-auxiliary and m4 files."}, + + {"debug", 'd',TAG_STLE_DEBUG,ARGV_OPTARG_NONE,0,0,0, + "display internal debug information."}, + + {"dry-run", 'n',TAG_STLE_DRY_RUN,ARGV_OPTARG_NONE,0,0,0, + "do not spawn any processes, " + "do not make any changes to the file system."}, + + {"automake", 0,TAG_STLE_SILENT,ARGV_OPTARG_NONE,0,0,0, + "backward-compatible alias for --quiet."}, + + {"quiet", 'q',TAG_STLE_SILENT,ARGV_OPTARG_NONE,0,0,0, + "do not say anything."}, + + {"silent", 's',TAG_STLE_SILENT,ARGV_OPTARG_NONE,0,0,0, + "say absolutely nothing."}, + + {"verbose", 'v',TAG_STLE_VERBOSE,ARGV_OPTARG_NONE,0,0,0, + "generate lots of informational messages " + "that nobody can understand."}, + + {"warnings", 'W',TAG_STLE_WARNINGS,ARGV_OPTARG_REQUIRED,0, + "all|none|error|doubt|concern|environment|file",0, + "specify category of warnings to display (or not)."}, + + {"no-warnings", 0,TAG_STLE_NO_WARNINGS,ARGV_OPTARG_NONE,0,0,0, + "suppress all warning messages (or not)."}, + + {0,0,0,0,0,0,0,0} +}; diff --git a/src/skin/slbt_skin_uninstall.c b/src/skin/slbt_skin_uninstall.c index 02b3599..e197373 100644 --- a/src/skin/slbt_skin_uninstall.c +++ b/src/skin/slbt_skin_uninstall.c @@ -1,7 +1,8 @@ #include "slibtool_uninstall_impl.h" +#include "slibtool_visibility_impl.h" #include "argv/argv.h" -const struct argv_option slbt_uninstall_options[] = { +const slbt_hidden struct argv_option slbt_uninstall_options[] = { {"help", 'h',TAG_UNINSTALL_HELP,ARGV_OPTARG_NONE,0,0,0, "display uninstall mode help"}, diff --git a/src/slibtool.c b/src/slibtool.c index 702f2a2..33904d1 100644 --- a/src/slibtool.c +++ b/src/slibtool.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ diff --git a/src/stoolie/slbt_stoolie_ctx.c b/src/stoolie/slbt_stoolie_ctx.c new file mode 100644 index 0000000..b74edd3 --- /dev/null +++ b/src/stoolie/slbt_stoolie_ctx.c @@ -0,0 +1,303 @@ +/*******************************************************************/ +/* 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 <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_realpath_impl.h" +#include "slibtool_stoolie_impl.h" +#include "slibtool_txtline_impl.h" +#include "slibtool_m4fake_impl.h" + +static const char slbt_this_dir[2] = {'.',0}; + +static int slbt_st_free_stoolie_ctx_impl( + struct slbt_stoolie_ctx_impl * ctx, + int fdsrc, + int ret) +{ + char ** parg; + + if (ctx) { + if (fdsrc >= 0) + close(fdsrc); + + if (ctx->fdtgt >= 0) + close(ctx->fdtgt); + + if (ctx->fdaux >= 0) + close(ctx->fdaux); + + if (ctx->fdm4 >= 0) + close(ctx->fdm4); + + for (parg=ctx->m4argv; parg && *parg; parg++) + free(*parg); + + free(ctx->m4buf); + free(ctx->m4argv); + free(ctx->auxbuf); + free(ctx->pathbuf); + + slbt_lib_free_txtfile_ctx(ctx->acinc); + slbt_lib_free_txtfile_ctx(ctx->cfgac); + slbt_lib_free_txtfile_ctx(ctx->makam); + + free(ctx); + } + + return ret; +} + +int slbt_st_get_stoolie_ctx( + const struct slbt_driver_ctx * dctx, + const char * path, + struct slbt_stoolie_ctx ** pctx) +{ + struct slbt_stoolie_ctx_impl * ctx; + int cint; + int fdcwd; + int fdtgt; + int fdsrc; + const char ** pline; + char ** margv; + const char * mark; + const char * dpath; + char pathbuf[PATH_MAX]; + + /* target directory: fd and real path*/ + fdcwd = slbt_driver_fdcwd(dctx); + + if ((fdtgt = openat(fdcwd,path,O_DIRECTORY|O_CLOEXEC,0)) < 0) + return SLBT_SYSTEM_ERROR(dctx,path); + + if (slbt_realpath(fdtgt,".",0,pathbuf,sizeof(pathbuf)) < 0) { + close(fdtgt); + return SLBT_SYSTEM_ERROR(dctx,path); + } + + /* context alloc and init */ + if (!(ctx = calloc(1,sizeof(*ctx)))) { + close(fdtgt); + return SLBT_BUFFER_ERROR(dctx); + } + + ctx->fdtgt = fdtgt; + ctx->fdaux = (-1); + ctx->fdm4 = (-1); + + /* target directory real path */ + if (!(ctx->pathbuf = strdup(pathbuf))) + return slbt_st_free_stoolie_ctx_impl(ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + + /* acinclude.m4, configure.ac, Makefile.am */ + if ((fdsrc = openat(fdtgt,"acinlcude.m4",O_RDONLY,0)) < 0) { + if (errno != ENOENT) + return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc, + SLBT_SYSTEM_ERROR(dctx,"acinlcude.m4")); + } else { + if (slbt_impl_get_txtfile_ctx(dctx,"acinclude.m4",fdsrc,&ctx->acinc) < 0) + return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc, + SLBT_NESTED_ERROR(dctx)); + + close(fdsrc); + } + + if ((fdsrc = openat(fdtgt,"configure.ac",O_RDONLY,0)) < 0) { + if (errno != ENOENT) + return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc, + SLBT_SYSTEM_ERROR(dctx,"configure.ac")); + } else { + if (slbt_impl_get_txtfile_ctx(dctx,"configure.ac",fdsrc,&ctx->cfgac) < 0) + return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc, + SLBT_NESTED_ERROR(dctx)); + + close(fdsrc); + } + + if ((fdsrc = openat(fdtgt,"Makefile.am",O_RDONLY,0)) < 0) { + if (errno != ENOENT) + return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc, + SLBT_SYSTEM_ERROR(dctx,"Makefile.am")); + } else { + if (slbt_impl_get_txtfile_ctx(dctx,"Makefile.am",fdsrc,&ctx->makam) < 0) + return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc, + SLBT_NESTED_ERROR(dctx)); + + close(fdsrc); + } + + /* aux dir */ + if (ctx->acinc) { + if (slbt_m4fake_expand_cmdarg( + dctx,ctx->acinc, + "AC_CONFIG_AUX_DIR", + &pathbuf) < 0) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + + if (pathbuf[0]) + if (!(ctx->auxbuf = strdup(pathbuf))) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + } + + if (!ctx->auxbuf && ctx->cfgac) { + if (slbt_m4fake_expand_cmdarg( + dctx,ctx->cfgac, + "AC_CONFIG_AUX_DIR", + &pathbuf) < 0) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + + if (pathbuf[0]) + if (!(ctx->auxbuf = strdup(pathbuf))) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + } + + /* m4 dir */ + if (ctx->acinc) { + if (slbt_m4fake_expand_cmdarg( + dctx,ctx->acinc, + "AC_CONFIG_MACRO_DIR", + &pathbuf) < 0) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + + if (pathbuf[0]) + if (!(ctx->m4buf = strdup(pathbuf))) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + } + + if (!ctx->m4buf && ctx->cfgac) { + if (slbt_m4fake_expand_cmdarg( + dctx,ctx->cfgac, + "AC_CONFIG_MACRO_DIR", + &pathbuf) < 0) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + + if (pathbuf[0]) + if (!(ctx->m4buf = strdup(pathbuf))) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_NESTED_ERROR(dctx)); + } + if (!ctx->m4buf && ctx->makam) { + for (pline=ctx->makam->txtlinev; !ctx->m4argv && *pline; pline++) { + if (!strncmp(*pline,"ACLOCAL_AMFLAGS",15)) { + if (isspace((*pline)[15]) || ((*pline)[15] == '=')) { + mark = &(*pline)[15]; + + for (; isspace(cint = *mark); ) + mark++; + + if (mark[0] != '=') + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR)); + + if (slbt_txtline_to_string_vector(++mark,&margv) < 0) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR)); + + ctx->m4argv = margv; + + if (!strcmp((mark = margv[0]),"-I")) { + ctx->m4buf = strdup(margv[1]); + + } else if (!strncmp(mark,"-I",2)) { + ctx->m4buf = strdup(&mark[2]); + } + + if (!ctx->m4buf) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR)); + } + } + } + } + + /* build-aux directory */ + if (!(dpath = ctx->auxbuf)) + dpath = slbt_this_dir; + + if ((ctx->fdaux = openat(fdtgt,dpath,O_DIRECTORY,0)) < 0) + if (errno == ENOENT) + if (!mkdirat(fdtgt,dpath,0755)) + ctx->fdaux = openat(fdtgt,dpath,O_DIRECTORY,0); + + if (ctx->fdaux < 0) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_SYSTEM_ERROR(dctx,dpath)); + + /* m4 directory */ + if ((dpath = ctx->m4buf)) + if ((ctx->fdm4 = openat(fdtgt,dpath,O_DIRECTORY,0)) < 0) + if (errno == ENOENT) + if (!mkdirat(fdtgt,dpath,0755)) + ctx->fdm4 = openat(fdtgt,dpath,O_DIRECTORY,0); + + if (dpath && (ctx->fdm4 < 0)) + return slbt_st_free_stoolie_ctx_impl( + ctx,(-1), + SLBT_SYSTEM_ERROR(dctx,dpath)); + + /* all done */ + ctx->path = ctx->pathbuf; + ctx->auxarg = ctx->auxbuf; + ctx->m4arg = ctx->m4buf; + + ctx->zctx.path = &ctx->path; + ctx->zctx.acinc = ctx->acinc; + ctx->zctx.cfgac = ctx->cfgac; + ctx->zctx.makam = ctx->makam; + ctx->zctx.auxarg = &ctx->auxarg; + ctx->zctx.m4arg = &ctx->m4arg; + + *pctx = &ctx->zctx; + return 0; +} + +void slbt_st_free_stoolie_ctx(struct slbt_stoolie_ctx * ctx) +{ + struct slbt_stoolie_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct slbt_stoolie_ctx_impl,zctx); + ictx = (struct slbt_stoolie_ctx_impl *)addr; + slbt_st_free_stoolie_ctx_impl(ictx,(-1),0); + } +} diff --git a/src/util/slbt_archive_import.c b/src/util/slbt_archive_import.c new file mode 100644 index 0000000..11b68de --- /dev/null +++ b/src/util/slbt_archive_import.c @@ -0,0 +1,71 @@ +/*******************************************************************/ +/* 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_driver_impl.h" +#include "slibtool_symlink_impl.h" +#include "slibtool_errinfo_impl.h" + +/* legacy fallback, no longer in use */ +extern int slbt_util_import_archive_mri( + struct slbt_exec_ctx * ectx, + char * dstarchive, + char * srcarchive); + +/* use slibtool's in-memory archive merging facility */ +static int slbt_util_import_archive_impl( + const struct slbt_driver_ctx * dctx, + const struct slbt_exec_ctx * ectx, + char * dstarchive, + char * srcarchive) +{ + int ret; + struct slbt_archive_ctx * arctxv[3] = {0,0,0}; + struct slbt_archive_ctx * arctx; + + (void)ectx; + + if (slbt_ar_get_archive_ctx(dctx,dstarchive,&arctxv[0]) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (slbt_ar_get_archive_ctx(dctx,srcarchive,&arctxv[1]) < 0) { + slbt_ar_free_archive_ctx(arctxv[0]); + return SLBT_NESTED_ERROR(dctx); + } + + ret = slbt_ar_merge_archives(arctxv,&arctx); + + slbt_ar_free_archive_ctx(arctxv[0]); + slbt_ar_free_archive_ctx(arctxv[1]); + + if (ret == 0) { + ret = slbt_ar_store_archive(arctx,dstarchive,0644); + slbt_ar_free_archive_ctx(arctx); + } + + return (ret < 0) ? SLBT_NESTED_ERROR(dctx) : 0; +} + + +int slbt_util_import_archive( + const struct slbt_exec_ctx * ectx, + char * dstarchive, + char * srcarchive) +{ + const struct slbt_driver_ctx * dctx; + + dctx = (slbt_get_exec_ictx(ectx))->dctx; + + if (slbt_symlink_is_a_placeholder( + slbt_driver_fdcwd(dctx), + srcarchive)) + return 0; + + return slbt_util_import_archive_impl( + dctx,ectx, + dstarchive, + srcarchive); +} diff --git a/src/helper/slbt_copy_file.c b/src/util/slbt_copy_file.c index 2adbd32..23d8cc3 100644 --- a/src/helper/slbt_copy_file.c +++ b/src/util/slbt_copy_file.c @@ -1,7 +1,6 @@ - /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* 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,25 +10,40 @@ #include "slibtool_symlink_impl.h" #include "slibtool_errinfo_impl.h" -int slbt_copy_file( - const struct slbt_driver_ctx * dctx, - struct slbt_exec_ctx * ectx, - char * src, - char * dst) +int slbt_util_copy_file( + struct slbt_exec_ctx * ectx, + const char * from, + const char * to) { + int ret; int fdcwd; char ** oargv; char * oprogram; + char * src; + char * dst; char * cp[4]; - int ret; + + const struct slbt_driver_ctx * dctx; + + /* driver context */ + dctx = (slbt_get_exec_ictx(ectx))->dctx; /* fdcwd */ fdcwd = slbt_driver_fdcwd(dctx); /* placeholder? */ - if (slbt_symlink_is_a_placeholder(fdcwd,src)) + if (slbt_symlink_is_a_placeholder(fdcwd,from)) return 0; + /* until we perform an in-memory copy ... */ + if (!(src = strdup(from))) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (!(dst = strdup(to))) { + free(src); + return SLBT_SYSTEM_ERROR(dctx,0); + } + /* cp argv */ cp[0] = "cp"; cp[1] = src; @@ -45,23 +59,36 @@ int slbt_copy_file( /* step output */ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) { if (dctx->cctx->mode == SLBT_MODE_LINK) { - if (slbt_output_link(dctx,ectx)) { + if (slbt_output_link(ectx)) { ectx->argv = oargv; ectx->program = oprogram; + free(src); free(dst); return SLBT_NESTED_ERROR(dctx); } } else { - if (slbt_output_install(dctx,ectx)) { + if (slbt_output_install(ectx)) { ectx->argv = oargv; ectx->program = oprogram; + free(src); free(dst); return SLBT_NESTED_ERROR(dctx); } } } - /* dlltool spawn */ - ret = ((slbt_spawn(ectx,true) < 0) || ectx->exitcode) - ? SLBT_SYSTEM_ERROR(dctx,0) : 0; + /* cp spawn */ + if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) { + ret = SLBT_SPAWN_ERROR(dctx); + + } else if (ectx->exitcode) { + ret = SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_COPY_ERROR); + } else { + ret = 0; + } + + free(src); + free(dst); ectx->argv = oargv; ectx->program = oprogram; diff --git a/src/util/slbt_create_mapfile.c b/src/util/slbt_create_mapfile.c new file mode 100644 index 0000000..8c03920 --- /dev/null +++ b/src/util/slbt_create_mapfile.c @@ -0,0 +1,132 @@ +/*******************************************************************/ +/* 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 <time.h> +#include <locale.h> +#include <regex.h> +#include <inttypes.h> +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_output.h> +#include "slibtool_driver_impl.h" +#include "slibtool_dprintf_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_pecoff_impl.h" +#include "slibtool_ar_impl.h" + +/****************************************************/ +/* Generate a linker version script (aka mapfile) */ +/* that could be passed to the host linker. */ +/* */ +/* Since the provided symbol list is host-neautral, */ +/* prepend symbol names with an underscore whenever */ +/* necessary. */ +/****************************************************/ + +static int slbt_util_output_mapfile_impl( + const struct slbt_driver_ctx * dctx, + const struct slbt_symlist_ctx * sctx, + int fdout) +{ + bool fcoff; + bool fmach; + const char * dot; + const char * mark; + const char ** symv; + const char ** symstrv; + char strbuf[4096]; + + fcoff = slbt_host_objfmt_is_coff(dctx); + fmach = slbt_host_objfmt_is_macho(dctx); + + if (fcoff) { + if (slbt_dprintf(fdout,"EXPORTS\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else if (fmach) { + if (slbt_dprintf(fdout,"# export_list, underscores prepended\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else { + if (slbt_dprintf(fdout,"{\n" "\t" "global:\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + + symstrv = sctx->symstrv; + + for (symv=symstrv; *symv; symv++) { + if (fcoff && slbt_is_strong_coff_symbol(*symv)) { + if (slbt_dprintf(fdout,"%s\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + } else if (fcoff && !strncmp(*symv,".weak.",6)) { + mark = &(*symv)[6]; + dot = strchr(mark,'.'); + + strncpy(strbuf,mark,dot-mark); + strbuf[dot-mark] = '\0'; + + if (slbt_dprintf(fdout," %s = %s\n",strbuf,++dot) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + } else if (fmach) { + if (slbt_dprintf(fdout,"_%s\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + } else { + if (slbt_dprintf(fdout,"\t\t%s;\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + + if (!fcoff && !fmach) + if (slbt_dprintf(fdout,"\n\t" "local:\n" "\t\t*;\n" "};\n") < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + return 0; +} + + +static int slbt_util_create_mapfile_impl( + const struct slbt_symlist_ctx * sctx, + const char * path, + mode_t mode) +{ + int ret; + const struct slbt_driver_ctx * dctx; + struct slbt_fd_ctx fdctx; + int fdout; + + dctx = (slbt_get_symlist_ictx(sctx))->dctx; + + if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (path) { + if ((fdout = openat( + fdctx.fdcwd,path, + O_WRONLY|O_CREAT|O_TRUNC, + mode)) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else { + fdout = fdctx.fdout; + } + + ret = slbt_util_output_mapfile_impl( + dctx,sctx,fdout); + + if (path) { + close(fdout); + } + + return ret; +} + + +int slbt_util_create_mapfile( + const struct slbt_symlist_ctx * sctx, + const char * path, + mode_t mode) +{ + return slbt_util_create_mapfile_impl(sctx,path,mode); +} diff --git a/src/util/slbt_create_symfile.c b/src/util/slbt_create_symfile.c new file mode 100644 index 0000000..8c9b4be --- /dev/null +++ b/src/util/slbt_create_symfile.c @@ -0,0 +1,84 @@ +/*******************************************************************/ +/* 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 <time.h> +#include <locale.h> +#include <regex.h> +#include <inttypes.h> +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_output.h> +#include "slibtool_driver_impl.h" +#include "slibtool_dprintf_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_pecoff_impl.h" +#include "slibtool_ar_impl.h" + +/********************************************************/ +/* Clone a symbol list that could be used by a build */ +/* system for code generation or any other purpose. */ +/********************************************************/ + +static int slbt_util_output_symfile_impl( + const struct slbt_driver_ctx * dctx, + const struct slbt_symlist_ctx * sctx, + int fdout) +{ + const char ** symv; + const char ** symstrv; + + symstrv = sctx->symstrv; + + for (symv=symstrv; *symv; symv++) + if (slbt_dprintf(fdout,"%s\n",*symv) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + + return 0; +} + + +static int slbt_util_create_symfile_impl( + const struct slbt_symlist_ctx * sctx, + const char * path, + mode_t mode) +{ + int ret; + const struct slbt_driver_ctx * dctx; + struct slbt_fd_ctx fdctx; + int fdout; + + dctx = (slbt_get_symlist_ictx(sctx))->dctx; + + if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (path) { + if ((fdout = openat( + fdctx.fdcwd,path, + O_WRONLY|O_CREAT|O_TRUNC, + mode)) < 0) + return SLBT_SYSTEM_ERROR(dctx,0); + } else { + fdout = fdctx.fdout; + } + + ret = slbt_util_output_symfile_impl( + dctx,sctx,fdout); + + if (path) { + close(fdout); + } + + return ret; +} + + +int slbt_util_create_symfile( + const struct slbt_symlist_ctx * sctx, + const char * path, + mode_t mode) +{ + return slbt_util_create_symfile_impl(sctx,path,mode); +} diff --git a/src/helper/slbt_dump_machine.c b/src/util/slbt_dump_machine.c index 3d3a454..1b42211 100644 --- a/src/helper/slbt_dump_machine.c +++ b/src/util/slbt_dump_machine.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ @@ -15,8 +15,9 @@ #include <slibtool/slibtool.h> #include "slibtool_spawn_impl.h" +#include "slibtool_snprintf_impl.h" -static void slbt_dump_machine_child( +static void slbt_util_dump_machine_child( char * program, int fd[2]) { @@ -42,7 +43,7 @@ static void slbt_dump_machine_child( _exit(EXIT_FAILURE); } -int slbt_dump_machine( +int slbt_util_dump_machine( const char * compiler, char * machine, size_t buflen) @@ -61,15 +62,15 @@ int slbt_dump_machine( return -1; } - if ((size_t)snprintf(program,sizeof(program),"%s", - compiler) >= sizeof(program)) + if (slbt_snprintf(program,sizeof(program), + "%s",compiler) < 0) return -1; /* fork */ if (pipe(fd)) return -1; - if ((pid = fork()) < 0) { + if ((pid = slbt_fork()) < 0) { close(fd[0]); close(fd[1]); return -1; @@ -77,7 +78,7 @@ int slbt_dump_machine( /* child */ if (pid == 0) - slbt_dump_machine_child( + slbt_util_dump_machine_child( program, fd); diff --git a/src/util/slbt_map_input.c b/src/util/slbt_map_input.c new file mode 100644 index 0000000..d99b4ba --- /dev/null +++ b/src/util/slbt_map_input.c @@ -0,0 +1,67 @@ +/*******************************************************************/ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2015--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include <stdint.h> +#include <stdbool.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" + +int slbt_fs_map_input( + const struct slbt_driver_ctx * dctx, + int fd, + const char * path, + int prot, + struct slbt_input * map) +{ + int ret; + struct stat st; + bool fnew; + int fdcwd; + + fdcwd = slbt_driver_fdcwd(dctx); + + if ((fnew = (fd < 0))) + fd = openat(fdcwd,path,O_RDONLY | O_CLOEXEC); + + if (fd < 0) + return SLBT_SYSTEM_ERROR(dctx,path); + + if ((ret = fstat(fd,&st) < 0) && fnew) + close(fd); + + else if ((st.st_size == 0) && fnew) + close(fd); + + if (ret < 0) + return SLBT_SYSTEM_ERROR(dctx,path); + + if (st.st_size == 0) { + map->size = 0; + map->addr = 0; + } else { + map->size = st.st_size; + map->addr = mmap(0,map->size,prot,MAP_PRIVATE,fd,0); + } + + if (fnew) + close(fd); + + return (map->addr == MAP_FAILED) + ? SLBT_SYSTEM_ERROR(dctx,path) + : 0; +} + +int slbt_fs_unmap_input(struct slbt_input * map) +{ + return map->size ? munmap(map->addr,map->size) : 0; +} diff --git a/src/util/slbt_realpath.c b/src/util/slbt_realpath.c new file mode 100644 index 0000000..823f3a0 --- /dev/null +++ b/src/util/slbt_realpath.c @@ -0,0 +1,18 @@ +/*******************************************************************/ +/* 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_realpath_impl.h" + +int slbt_util_real_path( + int fdat, + const char * path, + int options, + char * buf, + size_t buflen) +{ + return slbt_realpath(fdat,path,options,buf,buflen); +} |