From 0162e241b22822c2c42ddb89f06f69d65f88e644 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 3 Oct 2023 18:17:41 +1300 Subject: [PATCH 1/5] abi: expose the library alloc/free interface Third party libraries that make use of wally can use these calls to avoid potential mismatches by end user applications that override the default allocator. --- include/wally_core.h | 47 ++++++++++++++++++++++++++++++++++++++++++++ src/internal.h | 6 ------ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/include/wally_core.h b/include/wally_core.h index e5d6a958e..1f31e3057 100644 --- a/include/wally_core.h +++ b/include/wally_core.h @@ -60,6 +60,53 @@ WALLY_CORE_API int wally_get_build_version( uint32_t *value); #ifndef SWIG +/** + * Allocate memory using the configured library allocator. + * + * :param size: Size of the memory region to allocate in bytes. + * + * The allocated memory must be freed using `wally_free`. + */ +WALLY_CORE_API void *wally_malloc(size_t size); + +/** + * Allocate and zero memory using the configured library allocator. + * + * :param size: Size of the memory region to allocate in bytes. + * + * The allocated memory must be freed using `wally_free`. + */ +WALLY_CORE_API void *wally_calloc(size_t size); + +/** + * Free memory allocated from the configured library allocator. + * + * :param ptr: The memory region to free. + */ +WALLY_CORE_API void wally_free(void *ptr); + +/** + * Duplicate a known-length string using the configured library allocator. + * + * :param str_in: The string to duplicate. + * :param str_len: The length of '`str_in`' in bytes. + * + * This function appends a NUL terminator to the string. + * The allocated string must be freed using `wally_free`. + */ +WALLY_CORE_API char *wally_strdup_n(const char *str, size_t str_len); + +/** + * Duplicate a string using the configured library allocator. + * + * :param str_in: The string to duplicate. + * :param str_len: The length of '`str_in`' in bytes. + * + * This function appends a NUL terminator to the string. + * The allocated string must be freed using `wally_free`. + */ +WALLY_CORE_API char *wally_strdup(const char *str); + /** * Fetch the wally internal secp256k1 context object. * diff --git a/src/internal.h b/src/internal.h index a60307afc..93f3711e6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -70,12 +70,6 @@ bool mem_is_zero(const void *mem, size_t len); /* Fetch our internal operations function pointers */ const struct wally_operations *wally_ops(void); -void *wally_malloc(size_t size); -void *wally_calloc(size_t size); -void wally_free(void *ptr); -char *wally_strdup_n(const char *str, size_t str_len); -char *wally_strdup(const char *str); - #define malloc(size) __use_wally_malloc_internally__ #define calloc(size) __use_wally_calloc_internally__ #define free(ptr) __use_wally_free_internally__ From 90516c5521e952d86600f882ec20e18149d2345c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 29 Oct 2023 17:40:03 +1300 Subject: [PATCH 2/5] build: rename base58/64.c and hex.c to avoid build issues Based on a patch by Marko Bencun . Original commit description/rationale: When configuring libwally core with these flags: ./configure --enable-static --disable-shared and compiling using `make`, libtool outputs this message: copying selected object files to avoid basename conflicts... It copies the base64 and hex object files as they have the same basename as the files built from `src/ccan/ccan/base64/base64.c` `ccan/ccan/str/hex/hex.c`. By using `make V=1` one can see that it is trying to copy it using `ln` (a hardlink). This does not work properly inside a Docker container on macOS, where the hard link is created but cannot be used immediately ("file not found" in the next step where the object files are used in linking). We tested this on two macOS machines, and it only consistently did not work on one of them. We could not figure out the root cause for the error. Giving the files unique names avoids the copying/hardlinking and avoids the error. --- src/Makefile.am | 6 +++--- src/amalgamation/combined.c | 6 +++--- src/{base58.c => base_58.c} | 0 src/{base64.c => base_64.c} | 0 src/{hex.c => hex_.c} | 0 tools/msvc/build.bat | 9 +-------- 6 files changed, 7 insertions(+), 14 deletions(-) rename src/{base58.c => base_58.c} (100%) rename src/{base64.c => base_64.c} (100%) rename src/{hex.c => hex_.c} (100%) diff --git a/src/Makefile.am b/src/Makefile.am index b7baac5e7..18914fb02 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -141,8 +141,8 @@ libwallycore_la_SOURCES = \ address.c \ anti_exfil.c \ aes.c \ - base58.c \ - base64.c \ + base_58.c \ + base_64.c \ bip32.c \ bip38.c \ bip39.c \ @@ -153,7 +153,7 @@ libwallycore_la_SOURCES = \ ecdh.c \ elements.c \ blech32.c \ - hex.c \ + hex_.c \ hmac.c \ internal.c \ map.c \ diff --git a/src/amalgamation/combined.c b/src/amalgamation/combined.c index a5219ac4c..216a6389e 100644 --- a/src/amalgamation/combined.c +++ b/src/amalgamation/combined.c @@ -3,8 +3,8 @@ #include "address.c" #include "aes.c" #include "anti_exfil.c" -#include "base58.c" -#include "base64.c" +#include "base_58.c" +#include "base_64.c" #include "bech32.c" #include "blech32.c" #include "bip32.c" @@ -15,7 +15,7 @@ #include "descriptor.c" #include "ecdh.c" #include "elements.c" -#include "hex.c" +#include "hex_.c" #include "hmac.c" #include "map.c" #include "mnemonic.c" diff --git a/src/base58.c b/src/base_58.c similarity index 100% rename from src/base58.c rename to src/base_58.c diff --git a/src/base64.c b/src/base_64.c similarity index 100% rename from src/base64.c rename to src/base_64.c diff --git a/src/hex.c b/src/hex_.c similarity index 100% rename from src/hex.c rename to src/hex_.c diff --git a/tools/msvc/build.bat b/tools/msvc/build.bat index 561de9c27..4ba735a85 100644 --- a/tools/msvc/build.bat +++ b/tools/msvc/build.bat @@ -5,13 +5,6 @@ REM It seems possible to skip this step and remove the definition REM of USE_ECMULT_STATIC_PRECOMPUTATION from the compiler flags call "%~dp0\gen_ecmult_static_context.bat" -REM There are duplicate file names in both the wally and ccan sources -REM In a sane build system this would not be a problem but because -REM everything is being munged together for Windows as a hack it causes -REM problems. Make renamed copies as a workaround. -copy src\ccan\ccan\str\hex\hex.c src\ccan\ccan\str\hex\hex_.c -copy src\ccan\ccan\base64\base64.c src\ccan\ccan\base64\base64_.c - REM secp now requires its config header in the source directory copy src\amalgamation\windows_config\libsecp256k1-config.h src\secp256k1\src\libsecp256k1-config.h @@ -24,4 +17,4 @@ if "%ELEMENTS_BUILD%" == "elements" ( REM Compile everything (wally, ccan, libsecp256k) in one lump. REM Define USE_ECMULT_STATIC_PRECOMPUTATION to pick up the REM ecmult_static_context.h file generated previously -cl /utf-8 /DUSE_ECMULT_STATIC_PRECOMPUTATION /DECMULT_WINDOW_SIZE=15 /DWALLY_CORE_BUILD %ELEMENTS_OPT% /DHAVE_CONFIG_H /DSECP256K1_BUILD /I%LIBWALLY_DIR%\src\amalgamation\windows_config /I%LIBWALLY_DIR% /I%LIBWALLY_DIR%\src /I%LIBWALLY_DIR%\include /I%LIBWALLY_DIR%\src\ccan /I%LIBWALLY_DIR%\src\ccan\base64 /I%LIBWALLY_DIR%\src\secp256k1 /Zi /LD src/aes.c src/anti_exfil.c src/base58.c src/base64.c src/bech32.c src/bip32.c src/bip38.c src/bip39.c src/bip85.c src/blech32.c src/coins.c src/descriptor.c src/ecdh.c src/elements.c src/hex.c src/hmac.c src/internal.c src/mnemonic.c src/pbkdf2.c src/map.c src/psbt.c src/script.c src/scrypt.c src/sign.c src/symmetric.c src/transaction.c src/wif.c src/wordlist.c src/ccan/ccan/crypto/ripemd160/ripemd160.c src/ccan/ccan/crypto/sha256/sha256.c src/ccan/ccan/crypto/sha512/sha512.c src/ccan/ccan/base64/base64_.c src\ccan\ccan\str\hex\hex_.c src/secp256k1/src/secp256k1.c src/secp256k1/src/precomputed_ecmult_gen.c src/secp256k1/src/precomputed_ecmult.c /Fewally.dll +cl /utf-8 /DUSE_ECMULT_STATIC_PRECOMPUTATION /DECMULT_WINDOW_SIZE=15 /DWALLY_CORE_BUILD %ELEMENTS_OPT% /DHAVE_CONFIG_H /DSECP256K1_BUILD /I%LIBWALLY_DIR%\src\amalgamation\windows_config /I%LIBWALLY_DIR% /I%LIBWALLY_DIR%\src /I%LIBWALLY_DIR%\include /I%LIBWALLY_DIR%\src\ccan /I%LIBWALLY_DIR%\src\ccan\base64 /I%LIBWALLY_DIR%\src\secp256k1 /Zi /LD src/aes.c src/anti_exfil.c src/base_58.c src/base_64.c src/bech32.c src/bip32.c src/bip38.c src/bip39.c src/bip85.c src/blech32.c src/coins.c src/descriptor.c src/ecdh.c src/elements.c src/hex_.c src/hmac.c src/internal.c src/mnemonic.c src/pbkdf2.c src/map.c src/psbt.c src/script.c src/scrypt.c src/sign.c src/symmetric.c src/transaction.c src/wif.c src/wordlist.c src/ccan/ccan/crypto/ripemd160/ripemd160.c src/ccan/ccan/crypto/sha256/sha256.c src/ccan/ccan/crypto/sha512/sha512.c src/ccan/ccan/base64/base64.c src\ccan\ccan\str\hex\hex.c src/secp256k1/src/secp256k1.c src/secp256k1/src/precomputed_ecmult_gen.c src/secp256k1/src/precomputed_ecmult.c /Fewally.dll From dbbf1538aebc31ffd72a5b4b26072eeadde20b27 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Thu, 31 Aug 2023 05:20:30 -0400 Subject: [PATCH 3/5] src/Makefile.am: add -version-info to LDFLAGS in shared library builds version-info is what determines the dotted triplet of numbers trailing the shared library filename. Meticulous maintenance of version-info allows multiple ABI versions of the library to be installed on a system concurrently and also makes obvious when library clients need to be recompiled for a newer ABI (and when no recompilation is necessary). See: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html --- src/Makefile.am | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 18914fb02..9104aba66 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -193,10 +193,17 @@ libwallycore_la_INCLUDES = \ include/wally_transaction.h if SHARED_BUILD_ENABLED +LT_VER_CURRENT = 0 # increment at every ABI change (whether breaking or non-breaking) +LT_VER_REVISION = 0 # increment at every release, but reset to 0 at every ABI change +LT_VER_AGE = 0 # increment at every ABI change, but reset to 0 if breaking +# The library filename will be "libwallycore.so.$((current-age)).$((age)).$((revision))", +# and the soname will be "libwallycore.so.$((current-age))". +# Do NOT try to make the library version-info follow the project release version number! +# Only follow the rules above, explained more fully at: +# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +libwallycore_la_LDFLAGS = -version-info $(LT_VER_CURRENT):$(LT_VER_REVISION):$(LT_VER_AGE) if IS_MINGW -libwallycore_la_LDFLAGS = -no-undefined -else -libwallycore_la_LDFLAGS = +libwallycore_la_LDFLAGS += -no-undefined endif endif # SHARED_BUILD_ENABLED From 014700aaf02f1b964b45cac43c1fb0f824f9e177 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 4 Sep 2023 17:29:46 +1200 Subject: [PATCH 4/5] configure.ac: use AX_SUBDIRS_CONFIGURE; don't alter ac_configure_args Altering ac_configure_args to configure libsecp256k1 with options differing from those of libwally-core causes issues if the wally Makefile is out of date and needs to call autoreconf etc to regenerate itself. The secp arguments are passed back to the top level configure which changes and possibly breaks the original configuration. Instead, import and use AX_SUBDIRS_CONFIGURE from the autoconf-archive which supports sub-confiration with bespoke arguments. Because autoreconf does not recurse into subdirectories named by AX_SUBDIRS_CONFIGURE, we lose the automagic Autotools (re)generation in src/secp256k1, so add an explicit call to src/secp256k1/autogen.sh in tools/autogen.sh. --- configure.ac | 3 +- setup.py | 24 +- tools/autogen.sh | 4 + tools/build-aux/m4/ax_subdirs_configure.m4 | 334 +++++++++++++++++++++ 4 files changed, 351 insertions(+), 14 deletions(-) create mode 100644 tools/build-aux/m4/ax_subdirs_configure.m4 diff --git a/configure.ac b/configure.ac index 4e79cd811..165f1eb49 100644 --- a/configure.ac +++ b/configure.ac @@ -407,8 +407,7 @@ export ARFLAGS export AR_FLAGS export LD export LDFLAGS -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-experimental --enable-module-ecdh --enable-module-recovery --enable-module-ecdsa-s2c --enable-module-rangeproof --enable-module-surjectionproof --enable-module-whitelist --enable-module-generator --enable-module-extrakeys --enable-module-schnorrsig ${secp256k1_test_opt} --enable-exhaustive-tests=no --enable-benchmark=no --disable-dependency-tracking ${secp_asm}" -AC_CONFIG_SUBDIRS([src/secp256k1]) +AX_SUBDIRS_CONFIGURE([src/secp256k1], [[--disable-shared], [--enable-static], [--with-pic], [--enable-experimental], [--enable-module-ecdh], [--enable-module-recovery], [--enable-module-ecdsa-s2c], [--enable-module-rangeproof], [--enable-module-surjectionproof], [--enable-module-whitelist], [--enable-module-generator], [--enable-module-extrakeys], [--enable-module-schnorrsig], [$secp256k1_test_opt], [--enable-exhaustive-tests=no], [--enable-benchmark=no], [--disable-dependency-tracking], [$secp_asm]]) AC_OUTPUT diff --git a/setup.py b/setup.py index 3607aafa9..3f30e1ca2 100644 --- a/setup.py +++ b/setup.py @@ -3,8 +3,9 @@ import copy, os, platform, shutil import distutils.sysconfig -CONFIGURE_ARGS = '--enable-swig-python --enable-python-manylinux' -CONFIGURE_ARGS += ' --disable-swig-java --disable-tests --disable-dependency-tracking' +CONFIGURE_ARGS = ['--disable-shared', '--enable-static', '--with-pic', + '--enable-swig-python', '--enable-python-manylinux', + '--disable-swig-java', '--disable-tests', '--disable-dependency-tracking'] distutils_env = distutils.sysconfig.get_config_vars() configure_env = copy.deepcopy(os.environ) @@ -26,11 +27,11 @@ if is_x86 and not is_native: # We are cross-compiling or compiling a univeral2 binary. # Configure our source code as a cross compile to make the build work - CONFIGURE_ARGS += ' --host x86_64-apple-darwin' + CONFIGURE_ARGS += ['--host', 'x86_64-apple-darwin'] arch = 'universal2' if len(archs) > 1 else archs[0] - CONFIGURE_ARGS += ' --target {}-apple-macos'.format(arch) + CONFIGURE_ARGS += ['--target', '{}-apple-macos'.format(arch)] if len(archs) > 1: - CONFIGURE_ARGS += ' --with-asm=no' + CONFIGURE_ARGS += ['--with-asm=no'] if 'PY_CFLAGS' in distutils_env: configure_env['CFLAGS'] = distutils_env['PY_CFLAGS'] configure_env['LDFLAGS'] = distutils_env['PY_LDFLAGS'] @@ -40,18 +41,17 @@ # then build using the standard Python ext module machinery. # (Windows requires source generation to be done separately). import multiprocessing - import os import subprocess abs_path = os.path.dirname(os.path.abspath(__file__)) + '/' - def call(cmd): - subprocess.check_call(cmd.split(' '), cwd=abs_path, env=configure_env) + def call(args): + subprocess.check_call(args, cwd=abs_path, env=configure_env) - call('./tools/cleanup.sh') - call('./tools/autogen.sh') - call('./configure {}'.format(CONFIGURE_ARGS)) - call('make -j{}'.format(multiprocessing.cpu_count())) + call(['./tools/cleanup.sh']) + call(['./tools/autogen.sh']) + call(['./configure'] + CONFIGURE_ARGS) + call(['make', '-j{}'.format(multiprocessing.cpu_count())]) define_macros=[ ('SWIG_PYTHON_BUILD', None), diff --git a/tools/autogen.sh b/tools/autogen.sh index f572fe1e5..3942bcc64 100755 --- a/tools/autogen.sh +++ b/tools/autogen.sh @@ -8,3 +8,7 @@ if uname | grep "Darwin" >/dev/null 2>&1; then done done fi + +if [ -x src/secp256k1/autogen.sh ] ; then + cd src/secp256k1 && ./autogen.sh +fi diff --git a/tools/build-aux/m4/ax_subdirs_configure.m4 b/tools/build-aux/m4/ax_subdirs_configure.m4 new file mode 100644 index 000000000..01cb074b3 --- /dev/null +++ b/tools/build-aux/m4/ax_subdirs_configure.m4 @@ -0,0 +1,334 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_subdirs_configure.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_SUBDIRS_CONFIGURE( [subdirs], [mandatory arguments], [possibly merged arguments], [replacement arguments], [forbidden arguments]) +# +# DESCRIPTION +# +# AX_SUBDIRS_CONFIGURE attempts to be the equivalent of AC_CONFIG_SUBDIRS +# with customizable options for configure scripts. +# +# Run the configure script for each directory from the comma-separated m4 +# list 'subdirs'. This macro can be used multiple times. All arguments of +# this macro must be comma-separated lists. +# +# All command line arguments from the parent configure script will be +# given to the subdirectory configure script after the following +# modifications (in that order): +# +# 1. The arguments from the 'mandatory arguments' list shall always be +# appended to the argument list. +# +# 2. The arguments from the 'possibly merged arguments' list shall be +# added if not present in the arguments of the parent configure script or +# merged with the existing argument otherwise. +# +# 3. The arguments from the 'replacement arguments' list shall be added if +# not present in the arguments of the parent configure script or replace +# the existing argument otherwise. +# +# 4. The arguments from the 'forbidden arguments' list shall always be +# removed from the argument list. +# +# The lists 'mandatory arguments' and 'forbidden arguments' can hold any +# kind of argument. The 'possibly merged arguments' and 'replacement +# arguments' expect their arguments to be of the form --option-name=value. +# +# This macro aims to remain as close as possible to the AC_CONFIG_SUBDIRS +# macro. It corrects the paths for '--srcdir' and adds +# '--disable-option-checking' and '--silent' if necessary. However, it +# does not change the '--cache-file' argument: typically, configure +# scripts run with different arguments will not be able to share the same +# cache. If you wish to share a single cache, you should give an absolute +# path to '--cache-file'. +# +# This macro also sets the output variable subdirs_extra to the list of +# directories recorded with AX_SUBDIRS_CONFIGURE. This variable can be +# used in Makefile rules or substituted in configured files. +# +# This macro shall do nothing more than managing the arguments of the +# configure script. Just like when using AC_CONFIG_SUBDIRS, it is up to +# the user to check any requirements or define and substitute any required +# variable for the remainder of the project. +# +# Configure scripts recorded with AX_SUBDIRS_CONFIGURE may be executed +# before configure scripts recorded with AC_CONFIG_SUBDIRS. +# +# Without additional arguments, the behaviour of AX_SUBDIRS_CONFIGURE +# should be identical to the behaviour of AC_CONFIG_SUBDIRS, apart from +# the contents of the variables subdirs and subdirs_extra (except that +# AX_SUBDIRS_CONFIGURE expects a comma-separated m4 list): +# +# AC_CONFIG_SUBDIRS([something]) +# AX_SUBDIRS_CONFIGURE([something]) +# +# This macro may be called multiple times. +# +# Usage example: +# +# Let us assume our project has 4 dependencies, namely A, B, C and D. Here +# are some characteristics of our project and its dependencies: +# +# - A does not require any special option. +# +# - we want to build B with an optional feature which can be enabled with +# its configure script's option '--enable-special-feature'. +# +# - B's configure script is strange and has an option '--with-B=build'. +# After close inspection of its documentation, we don't want B to receive +# this option. +# +# - C and D both need B. +# +# - Just like our project, C and D can build B themselves with the option +# '--with-B=build'. +# +# - We want C and D to use the B we build instead of building it +# themselves. +# +# Our top-level configure script will be called as follows: +# +# $ --with-A=build --with-B=build --with-C=build \ +# --with-D=build --some-option +# +# Thus we have to make sure that: +# +# - neither B, C or D receive the option '--with-B=build' +# +# - C and D know where to find the headers and libraries of B. +# +# Under those conditions, we can use the AC_CONFIG_SUBDIRS macro for A, +# but need to use AX_SUBDIRS_CONFIGURE for B, C and D: +# +# - B must receive '--enable-special-feature' but cannot receive +# '--with-B=build' +# +# - C and D cannot receive '--with-B=build' (or else it would be built +# thrice) and need to be told where to find B (since we are building it, +# it would probably not be available in standard paths). +# +# Here is a configure.ac snippet that solves our problem: +# +# AC_CONFIG_SUBDIRS([dependencies/A]) +# AX_SUBDIRS_CONFIGURE( +# [dependencies/B], [--enable-special-feature], [], [], +# [--with-B=build]) +# AX_SUBDIRS_CONFIGURE( +# [[dependencies/C],[dependencies/D]], +# [], +# [[CPPFLAGS=-I${ac_top_srcdir}/dependencies/B -I${ac_top_builddir}/dependencies/B], +# [LDFLAGS=-L${ac_abs_top_builddir}/dependencies/B/.libs]], +# [--with-B=system], +# []) +# +# If using automake, the following can be added to the Makefile.am (we use +# both $(subdirs) and $(subdirs_extra) since our example above used both +# AC_CONFIG_SUBDIRS and AX_SUBDIRS_CONFIGURE): +# +# SUBDIRS = $(subdirs) $(subdirs_extra) +# +# LICENSE +# +# Copyright (c) 2017 Harenome Ranaivoarivony-Razanajato +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# Under Section 7 of GPL version 3, you are granted additional permissions +# described in the Autoconf Configure Script Exception, version 3.0, as +# published by the Free Software Foundation. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . + +#serial 6 + +AC_DEFUN([AX_SUBDIRS_CONFIGURE], +[ + dnl Calls to AC_CONFIG_SUBDIRS perform preliminary steps and build a list + dnl '$subdirs' which is used later by _AC_OUTPUT_SUBDIRS (used by AC_OUTPUT) + dnl to actually run the configure scripts. + dnl This macro performs similar preliminary steps but uses + dnl AC_CONFIG_COMMANDS_PRE to delay the final tasks instead of building an + dnl intermediary list and relying on another macro. + dnl + dnl Since each configure script can get different options, a special variable + dnl named 'ax_sub_configure_args_' is constructed for each + dnl subdirectory. + + # Various preliminary checks. + AC_REQUIRE([AC_DISABLE_OPTION_CHECKING]) + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) + AS_LITERAL_IF([$1], [], + [AC_DIAGNOSE([syntax], [$0: you should use literals])]) + + m4_foreach(subdir_path, [$1], + [ + ax_dir="subdir_path" + + dnl Build the argument list in a similar fashion to AC_CONFIG_SUBDIRS. + dnl A few arguments found in the final call to the configure script are not + dnl added here because they rely on variables that may not yet be available + dnl (see below the part that is similar to _AC_OUTPUT_SUBDIRS). + # Do not complain, so a configure script can configure whichever parts of a + # large source tree are present. + if test -d "$srcdir/$ax_dir"; then + _AC_SRCDIRS(["$ax_dir"]) + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ax_args= + ax_prev= + eval "set x $ac_configure_args" + shift + for ax_arg; do + if test -n "$ax_prev"; then + ax_prev= + continue + fi + case $ax_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi | --cache-f \ + | --cache- | --cache | --cach | --cac | --ca | --c) + ax_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ax_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ax_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* \ + | --p=*) + ;; + --disable-option-checking) + ;; + *) case $ax_arg in + *\'*) ax_arg=$(AS_ECHO(["$ax_arg"]) | sed "s/'/'\\\\\\\\''/g");; + esac + AS_VAR_APPEND([ax_args], [" '$ax_arg'"]) ;; + esac + done + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ax_args="--disable-option-checking $ax_args" + # Options that must be added as they are provided. + m4_ifnblank([$2], [m4_foreach(opt, [$2], [AS_VAR_APPEND(ax_args, " 'opt'") + ])]) + # New options that may need to be merged with existing options. + m4_ifnblank([$3], [m4_foreach(opt, [$3], + [ax_candidate="opt" + ax_candidate_flag="${ax_candidate%%=*}" + ax_candidate_content="${ax_candidate#*=}" + if test "x$ax_candidate" != "x" -a "x$ax_candidate_flag" != "x"; then + if echo "$ax_args" | grep -- "${ax_candidate_flag}=" >/dev/null 2>&1; then + [ax_args=$(echo $ax_args | sed "s,\(${ax_candidate_flag}=[^']*\),\1 ${ax_candidate_content},")] + else + AS_VAR_APPEND(ax_args, " 'opt'") + fi + fi + ])]) + # New options that must replace existing options. + m4_ifnblank([$4], [m4_foreach(opt, [$4], + [ax_candidate="opt" + ax_candidate_flag="${ax_candidate%%=*}" + ax_candidate_content="${ax_candidate#*=}" + if test "x$ax_candidate" != "x" -a "x$ax_candidate_flag" != "x"; then + if echo "$ax_args" | grep -- "${ax_candidate_flag}=" >/dev/null 2>&1; then + [ax_args=$(echo $ax_args | sed "s,${ax_candidate_flag}=[^']*,${ax_candidate},")] + else + AS_VAR_APPEND(ax_args, " 'opt'") + fi + fi + ])]) + # Options that must be removed. + m4_ifnblank([$5], [m4_foreach(opt, [$5], [ax_args=$(echo $ax_args | sed "s,'opt',,") + ])]) + AS_VAR_APPEND([ax_args], [" '--srcdir=$ac_srcdir'"]) + + # Add the subdirectory to the list of target subdirectories. + ax_subconfigures="$ax_subconfigures $ax_dir" + # Save the argument list for this subdirectory. + dnl $1 is a path to some subdirectory: m4_bpatsubsts() is used to convert + dnl $1 into a valid shell variable name. + dnl For instance, "ax_sub_configure_args_path/to/subdir" becomes + dnl "ax_sub_configure_args_path_to_subdir". + ax_var=$(printf "$ax_dir" | tr -c "0-9a-zA-Z_" "_") + eval "ax_sub_configure_args_$ax_var=\"$ax_args\"" + eval "ax_sub_configure_$ax_var=\"yes\"" + else + AC_MSG_WARN([could not find source tree for $ax_dir]) + fi + + dnl Add some more arguments to the argument list and then actually run the + dnl configure script. This is mostly what happens in _AC_OUTPUT_SUBDIRS + dnl except it does not iterate over an intermediary list. + AC_CONFIG_COMMANDS_PRE( + dnl This very line cannot be quoted! m4_foreach has some work here. + ax_dir="subdir_path" + [ + # Convert the path to the subdirectory into a shell variable name. + ax_var=$(printf "$ax_dir" | tr -c "0-9a-zA-Z_" "_") + ax_configure_ax_var=$(eval "echo \"\$ax_sub_configure_$ax_var\"") + if test "$no_recursion" != "yes" -a "x$ax_configure_ax_var" = "xyes"; then + AC_SUBST([subdirs_extra], ["$subdirs_extra $ax_dir"]) + ax_msg="=== configuring in $ax_dir ($(pwd)/$ax_dir)" + _AS_ECHO_LOG([$ax_msg]) + _AS_ECHO([$ax_msg]) + AS_MKDIR_P(["$ax_dir"]) + _AC_SRCDIRS(["$ax_dir"]) + + ax_popdir=$(pwd) + cd "$ax_dir" + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f "$ac_srcdir/configure.gnu"; then + ax_sub_configure=$ac_srcdir/configure.gnu + elif test -f "$ac_srcdir/configure"; then + ax_sub_configure=$ac_srcdir/configure + elif test -f "$ac_srcdir/configure.in"; then + # This should be Cygnus configure. + ax_sub_configure=$ac_aux_dir/configure + else + AC_MSG_WARN([no configuration information is in $ax_dir]) + ax_sub_configure= + fi + + if test -n "$ax_sub_configure"; then + # Get the configure arguments for the current configure. + eval "ax_sub_configure_args=\"\$ax_sub_configure_args_${ax_var}\"" + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ax_arg="--prefix=$prefix" + case $ax_arg in + *\'*) ax_arg=$(AS_ECHO(["$ax_arg"]) | sed "s/'/'\\\\\\\\''/g");; + esac + ax_sub_configure_args="'$ax_arg' $ax_sub_configure_args" + if test "$silent" = yes; then + ax_sub_configure_args="--silent $ax_sub_configure_args" + fi + + AC_MSG_NOTICE([running $SHELL $ax_sub_configure $ax_sub_configure_args --cache-file=$cache_file]) + eval "\$SHELL \"$ax_sub_configure\" $ax_sub_configure_args --cache-file=\"$cache_file\"" \ + || AC_MSG_ERROR([$ax_sub_configure failed for $ax_dir]) + fi + + cd "$ax_popdir" + fi + ]) + ]) +]) From 15bff1e2a62c12c2cd21d60f5cac3385b14acccb Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Thu, 31 Aug 2023 00:32:26 -0400 Subject: [PATCH 5/5] configure.ac: support --with-system-secp256k1 (Modified from the original submission). Libwally-core, in its stock configuration, compiles and statically links against a private copy of libsecp256k1_zkp. However, Gentoo unbundles libsecp256k1_zkp and instead links libwally-core against a system-wide shared libsecp256k1_zkp with headers in /usr/include/secp256k1_zkp and a libsecp256k1_zkp.pc that specifies the relevant CFLAGS and LIBS. Implement a --with-system-secp256k1 configure option to allow compiling and linking against a system-installed libsecp256k1. Pass the user- specified package name (or 'libsecp256k1' or 'libsecp256k1_zkp' by default, depending on --enable-standard-secp) to PKG_CHECK_MODULES to find the CFLAGS and LIBS of a system-installed libsecp256k1. Call AC_CHECK_FUNCS to assert that the required modules are present in the system-installed libsecp256k1. If the user does not specify --with-system-secp256k1 (or specifies --without-system-secp256k1), the build will use the bundled copy of libsecp256k1_zkp as before. Remove the existing libtool hack: When building as a static library, the user will need to link libsecp256k1.a in addition to libwallycore.a. --- configure.ac | 68 ++++++++++++++++++++++++++++++++----------------- src/Makefile.am | 4 ++- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/configure.ac b/configure.ac index 165f1eb49..703f25d5d 100644 --- a/configure.ac +++ b/configure.ac @@ -259,29 +259,49 @@ fi # # libsecp256k1 # -libsecp256k1_CFLAGS='-I$(top_srcdir)/src/secp256k1/include' +AC_ARG_WITH([system-secp256k1], + [AS_HELP_STRING([[--with-system-secp256k1[=PKG]]], + [build using system-installed libsecp256k1 instead of bundled, passing PKG (default: libsecp256k1 or libsecp256k1_zkp, depending on --enable-standard-secp) to pkg-config (default: no)])], + [AS_IF([test "x$withval" = xyes], + [AM_COND_IF([BUILD_STANDARD_SECP], [with_system_secp256k1=libsecp256k1], [with_system_secp256k1=libsecp256k1_zkp])])], + [with_system_secp256k1=no]) + +AM_CONDITIONAL([LINK_SYSTEM_SECP256K1], [test "x$with_system_secp256k1" != xno]) +AM_COND_IF([LINK_SYSTEM_SECP256K1], [ + dnl Use the secp installed system-wide (after checking it for suitability) + saved_LIBS=$LIBS + m4_ifdef([PKG_CHECK_MODULES], + [PKG_CHECK_MODULES([libsecp256k1], [$with_system_secp256k1])], + [AC_MSG_ERROR([You need to install pkg-config to use --with-system-secp256k1.])]) + LIBS="$libsecp256k1_LIBS $LIBS" + missing_modules= + AC_DEFUN([CHECK_MODULE], [ + AC_CHECK_FUNCS([$2], [], [missing_modules="${missing_modules} $1"]) + ]) + CHECK_MODULE([ecdh], [secp256k1_ecdh]) + CHECK_MODULE([extrakeys], [secp256k1_xonly_pubkey_parse]) + CHECK_MODULE([recovery], [secp256k1_ecdsa_recover]) + CHECK_MODULE([schnorrsig], [secp256k1_schnorrsig_verify]) + AM_COND_IF([BUILD_STANDARD_SECP], [], [ + CHECK_MODULE([ecdsa-s2c], [secp256k1_ecdsa_s2c_sign]) + ]) + AM_COND_IF([BUILD_ELEMENTS], [ + CHECK_MODULE([generator], [secp256k1_generator_parse]) + CHECK_MODULE([rangeproof], [secp256k1_rangeproof_verify]) + CHECK_MODULE([surjectionproof], [secp256k1_surjectionproof_initialize]) + CHECK_MODULE([whitelist], [secp256k1_whitelist_sign]) + ]) + AS_IF([test -n "${missing_modules}"], [ + AC_MSG_ERROR([system-installed $with_system_secp256k1 does not support these required modules:${missing_modules}]) + ]) + LIBS=$saved_LIBS +], [ + dnl Use the secp in-tree submodule + libsecp256k1_CFLAGS='-I$(top_srcdir)/src/secp256k1/include' + libsecp256k1_LIBS='$(top_srcdir)/src/secp256k1/libsecp256k1.la' +]) AC_SUBST([libsecp256k1_CFLAGS]) - -# FIXME: This is needed to force libtool to use all object files from secp. -# We can only build secp properly by recursively invoking -# configure/make, and can't include it as a noinst_ library. Libtool -# assumes that such libraries will be installed along with our library -# target and so won't force all object files in the library to be -# included in ours - despite the fact that we are making a shared -# library and linking to a static one. This is broken and we work -# around it by hacking the secp objects directly into the library -# via the _LDADD variable for wallycore. -# We previously achieved this by adding the libsecp256k1.a archive, -# but changes to libtool and apples linkers mean that -# archives-within-archives no longer work. -# Because automake tries to police its users very strictly and fails -# hard when flags are passed in this way, we have to substitute the -# flags here. -# Because libtool both intercepts -Wl and arbitrarily re-orders its -# command line inputs, we have to concoct a single expression to -# enforce linking that cannot be split, hence the below expression. -LIBADD_SECP256K1="-Wl,secp256k1/src/libsecp256k1_la-secp256k1.${OBJEXT},secp256k1/src/libsecp256k1_precomputed_la-precomputed_ecmult_gen.${OBJEXT},secp256k1/src/libsecp256k1_precomputed_la-precomputed_ecmult.${OBJEXT}" -AC_SUBST([LIBADD_SECP256K1]) +AC_SUBST([libsecp256k1_LIBS]) # # Python facilities @@ -408,6 +428,8 @@ export AR_FLAGS export LD export LDFLAGS -AX_SUBDIRS_CONFIGURE([src/secp256k1], [[--disable-shared], [--enable-static], [--with-pic], [--enable-experimental], [--enable-module-ecdh], [--enable-module-recovery], [--enable-module-ecdsa-s2c], [--enable-module-rangeproof], [--enable-module-surjectionproof], [--enable-module-whitelist], [--enable-module-generator], [--enable-module-extrakeys], [--enable-module-schnorrsig], [$secp256k1_test_opt], [--enable-exhaustive-tests=no], [--enable-benchmark=no], [--disable-dependency-tracking], [$secp_asm]]) +AM_COND_IF([LINK_SYSTEM_SECP256K1], [], [ + AX_SUBDIRS_CONFIGURE([src/secp256k1], [[--disable-shared], [--enable-static], [--with-pic], [--enable-experimental], [--enable-module-ecdh], [--enable-module-recovery], [--enable-module-ecdsa-s2c], [--enable-module-rangeproof], [--enable-module-surjectionproof], [--enable-module-whitelist], [--enable-module-generator], [--enable-module-extrakeys], [--enable-module-schnorrsig], [$secp256k1_test_opt], [--enable-exhaustive-tests=no], [--enable-benchmark=no], [--disable-dependency-tracking], [$secp_asm]]) +]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 9104aba66..a20e0c218 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -208,9 +208,11 @@ endif endif # SHARED_BUILD_ENABLED libwallycore_la_CFLAGS = -I$(top_srcdir) -I$(srcdir)/ccan $(libsecp256k1_CFLAGS) -DWALLY_CORE_BUILD=1 $(AM_CFLAGS) -libwallycore_la_LIBADD = $(LIBADD_SECP256K1) $(noinst_LTLIBRARIES) +libwallycore_la_LIBADD = $(libsecp256k1_LIBS) $(noinst_LTLIBRARIES) +if !LINK_SYSTEM_SECP256K1 SUBDIRS = secp256k1 +endif TESTS = noinst_PROGRAMS =