summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING.SLIBTOOL4
-rw-r--r--COPYING.SOFORT2
-rw-r--r--Makefile.in1
-rw-r--r--NEWS59
-rw-r--r--README2
-rw-r--r--THANKS11
-rwxr-xr-xaux/ltmain.sh2
-rw-r--r--config.project4
-rw-r--r--config.usage2
-rwxr-xr-xconfigure30
-rw-r--r--include/slibtool/slibtool.h281
-rw-r--r--include/slibtool/slibtool_arbits.h187
-rw-r--r--include/slibtool/slibtool_output.h23
-rw-r--r--m4/slibtool.m4214
-rw-r--r--project/common.mk61
-rw-r--r--project/config/cfgdefs.in0
-rw-r--r--project/config/cfgdefs.sh66
-rw-r--r--project/extras.mk29
-rw-r--r--project/headers.mk14
-rw-r--r--project/tagver.mk2
-rw-r--r--project/tree.mk8
-rw-r--r--sofort/ccenv/ccenv.in9
-rw-r--r--sofort/ccenv/ccenv.sh72
-rw-r--r--sofort/ccenv/ccenv.vars6
-rw-r--r--sofort/ccenv/ccswitch.strs1
-rw-r--r--sofort/cfgtest/cfgtest.sh77
-rw-r--r--sofort/config/config.vars1
-rw-r--r--src/arbits/output/slbt_au_output_arname.c86
-rw-r--r--src/arbits/output/slbt_au_output_dlsyms.c12
-rw-r--r--src/arbits/output/slbt_au_output_mapfile.c12
-rw-r--r--src/arbits/output/slbt_au_output_members.c278
-rw-r--r--src/arbits/output/slbt_au_output_symbols.c201
-rw-r--r--src/arbits/slbt_archive_ctx.c117
-rw-r--r--src/arbits/slbt_archive_dlsyms.c458
-rw-r--r--src/arbits/slbt_archive_mapfile.c162
-rw-r--r--src/arbits/slbt_archive_mapstrv.c47
-rw-r--r--src/arbits/slbt_archive_merge.c734
-rw-r--r--src/arbits/slbt_archive_meta.c888
-rw-r--r--src/arbits/slbt_archive_store.c145
-rw-r--r--src/arbits/slbt_archive_symfile.c138
-rw-r--r--src/arbits/slbt_archive_syminfo.c345
-rw-r--r--src/arbits/slbt_armap_bsd_32.c157
-rw-r--r--src/arbits/slbt_armap_bsd_64.c174
-rw-r--r--src/arbits/slbt_armap_sysv_32.c120
-rw-r--r--src/arbits/slbt_armap_sysv_64.c128
-rw-r--r--src/driver/slbt_amain.c60
-rw-r--r--src/driver/slbt_driver_ctx.c1690
-rw-r--r--src/driver/slbt_link_params.c131
-rw-r--r--src/driver/slbt_split_argv.c556
-rw-r--r--src/driver/slbt_symlist_ctx.c150
-rw-r--r--src/driver/slbt_txtfile_ctx.c172
-rw-r--r--src/driver/slbt_version_info.c74
-rw-r--r--src/fallback/slbt_archive_import_mri.c (renamed from src/helper/slbt_archive_import.c)77
-rw-r--r--src/host/slbt_host_flavor.c203
-rw-r--r--src/host/slbt_host_params.c584
-rw-r--r--src/internal/argv/argv.h97
-rw-r--r--src/internal/slibtool_ar_impl.h100
-rw-r--r--src/internal/slibtool_coff_impl.c46
-rw-r--r--src/internal/slibtool_coff_impl.h6
-rw-r--r--src/internal/slibtool_dprintf_impl.c7
-rw-r--r--src/internal/slibtool_driver_impl.h349
-rw-r--r--src/internal/slibtool_errinfo_impl.c7
-rw-r--r--src/internal/slibtool_errinfo_impl.h4
-rw-r--r--src/internal/slibtool_lconf_impl.c333
-rw-r--r--src/internal/slibtool_libmeta_impl.c57
-rw-r--r--src/internal/slibtool_linkcmd_impl.h89
-rw-r--r--src/internal/slibtool_m4fake_impl.c142
-rw-r--r--src/internal/slibtool_m4fake_impl.h12
-rw-r--r--src/internal/slibtool_mapfile_impl.c11
-rw-r--r--src/internal/slibtool_metafile_impl.h8
-rw-r--r--src/internal/slibtool_mkdir_impl.h4
-rw-r--r--src/internal/slibtool_objlist_impl.c83
-rw-r--r--src/internal/slibtool_objlist_impl.h10
-rw-r--r--src/internal/slibtool_objmeta_impl.c11
-rw-r--r--src/internal/slibtool_pecoff_impl.c16
-rw-r--r--src/internal/slibtool_pecoff_impl.h6
-rw-r--r--src/internal/slibtool_readlink_impl.h4
-rw-r--r--src/internal/slibtool_realpath_impl.c (renamed from src/helper/slbt_realpath.c)16
-rw-r--r--src/internal/slibtool_realpath_impl.h13
-rw-r--r--src/internal/slibtool_snprintf_impl.c40
-rw-r--r--src/internal/slibtool_snprintf_impl.h6
-rw-r--r--src/internal/slibtool_spawn_impl.h12
-rw-r--r--src/internal/slibtool_stoolie_impl.h15
-rw-r--r--src/internal/slibtool_symlink_impl.c89
-rw-r--r--src/internal/slibtool_symlink_impl.h10
-rw-r--r--src/internal/slibtool_tmpfile_impl.c89
-rw-r--r--src/internal/slibtool_tmpfile_impl.h6
-rw-r--r--src/internal/slibtool_txtline_impl.c67
-rw-r--r--src/internal/slibtool_txtline_impl.h8
-rw-r--r--src/internal/slibtool_visibility_impl.h26
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_archive.c188
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_argv.c1127
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_deps.c788
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_dsolib.c373
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_executable.c278
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_host.c70
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_implib.c157
-rw-r--r--src/logic/slbt_exec_ar.c431
-rw-r--r--src/logic/slbt_exec_compile.c108
-rw-r--r--src/logic/slbt_exec_ctx.c405
-rw-r--r--src/logic/slbt_exec_execute.c223
-rw-r--r--src/logic/slbt_exec_install.c231
-rw-r--r--src/logic/slbt_exec_link.c1879
-rw-r--r--src/logic/slbt_exec_stoolie.c371
-rw-r--r--src/logic/slbt_exec_uninstall.c55
-rw-r--r--src/output/slbt_output_config.c166
-rw-r--r--src/output/slbt_output_error.c4
-rw-r--r--src/output/slbt_output_exec.c56
-rw-r--r--src/output/slbt_output_fdcwd.c5
-rw-r--r--src/output/slbt_output_features.c4
-rw-r--r--src/output/slbt_output_info.c126
-rw-r--r--src/output/slbt_output_machine.c4
-rw-r--r--src/output/slbt_output_mapfile.c12
-rw-r--r--src/skin/slbt_skin_ar.c97
-rw-r--r--src/skin/slbt_skin_default.c151
-rw-r--r--src/skin/slbt_skin_install.c3
-rw-r--r--src/skin/slbt_skin_stoolie.c52
-rw-r--r--src/skin/slbt_skin_uninstall.c3
-rw-r--r--src/slibtool.c4
-rw-r--r--src/stoolie/slbt_stoolie_ctx.c303
-rw-r--r--src/util/slbt_archive_import.c71
-rw-r--r--src/util/slbt_copy_file.c (renamed from src/helper/slbt_copy_file.c)57
-rw-r--r--src/util/slbt_create_mapfile.c132
-rw-r--r--src/util/slbt_create_symfile.c84
-rw-r--r--src/util/slbt_dump_machine.c (renamed from src/helper/slbt_dump_machine.c)17
-rw-r--r--src/util/slbt_map_input.c67
-rw-r--r--src/util/slbt_realpath.c18
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@
diff --git a/NEWS b/NEWS
index 1375477..1f802d3 100644
--- a/NEWS
+++ b/NEWS
@@ -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,
diff --git a/README b/README
index e86a4f1..aef6300 100644
--- a/README
+++ b/README
@@ -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
diff --git a/THANKS b/THANKS
index e326c30..4b27103 100644
--- a/THANKS
+++ b/THANKS
@@ -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
diff --git a/configure b/configure
index e79d154..839d8b3 100755
--- a/configure
+++ b/configure
@@ -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(&regctx,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(&regctx,*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(&regctx,strbuf,1,pmatch,0))
+ if (slbt_dprintf(fdout,"%s\n",strbuf) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (regex)
+ regfree(&regctx);
+
+ 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(&regctx,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(&regctx,*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(&regctx,strbuf,1,pmatch,0))
+ if (slbt_au_output_one_symbol_yaml(
+ fdout,mctx,strbuf) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (regex)
+ regfree(&regctx);
+
+ 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(&regctx,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(&regctx,*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(&regctx,strbuf,1,pmatch,0))
+ if (slbt_dprintf(fdout," %s = %s\n",strbuf,++dot) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (regex)
+ regfree(&regctx);
+
+ 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(&regctx,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(&regctx,*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(&regctx,strbuf,1,pmatch,0))
+ if (slbt_dprintf(fdout," %s = %s\n",strbuf,++dot) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (regex)
+ regfree(&regctx);
+
+ 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",
- &current,&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",
+ &current,&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);
+}