From b2f33317b712a5bc1c23db1139e3de282791cdcd Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Thu, 31 Aug 2023 00:32:26 -0400 Subject: [PATCH] configure.ac: support --with-system-secp256k1 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), then the pre-existing behavior is preserved: namely, the build will use the bundled copy of libsecp256k1_zkp. setup.py is tweaked to detect if the libwally-core library has already been built and, in that case, elide rebuilding it. This supports a use case of linking libwallycore.so against a system-installed libsecp256k1 and then linking the Python extension against that libwallycore.so. In such a scenario, the Python native extension library contains no code from libwally-core or libsecp256k1 but instead simply specifies a dynamic link with libwallycore.so.1, and libwallycore.so.1 contains no code from libsecp256k1 but instead simply specifies a dynamic link with libsecp256k1_zkp.so.0. This is the "full dynamic link" holy grail. Note that the default case is nearly the opposite: all libsecp256k1 and libwally-core code is embedded into the Python native extension library. --- configure.ac | 42 +++++++++++++++++++++++++++++++++++++++--- setup.py | 18 ++++++++++-------- src/Makefile.am | 2 ++ 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 7a70028cc..92319858d 100644 --- a/configure.ac +++ b/configure.ac @@ -259,8 +259,42 @@ fi # # libsecp256k1 # -libsecp256k1_CFLAGS='-I$(top_srcdir)/src/secp256k1/include' -libsecp256k1_LIBS='$(top_srcdir)/src/secp256k1/libsecp256k1.la' +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], [ + saved_LIBS=$LIBS + PKG_CHECK_MODULES([libsecp256k1], [$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 +], [ + libsecp256k1_CFLAGS='-I$(top_srcdir)/src/secp256k1/include' + libsecp256k1_LIBS='$(top_srcdir)/src/secp256k1/libsecp256k1.la' +]) AC_SUBST([libsecp256k1_CFLAGS]) AC_SUBST([libsecp256k1_LIBS]) @@ -395,6 +429,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/setup.py b/setup.py index b50dc4c19..ddc82bc7d 100644 --- a/setup.py +++ b/setup.py @@ -52,14 +52,16 @@ abs_path = os.path.dirname(os.path.abspath(__file__)) + '/' - def call(args): - subprocess.check_call(args, cwd=abs_path, env=configure_env) - - call(['./tools/cleanup.sh']) - call(['./tools/autogen.sh']) - call(['/bin/sh', '-c', 'cd src/secp256k1 && ./autogen.sh']) - call(['./configure'] + CONFIGURE_ARGS) - call(['make', '-j{}'.format(multiprocessing.cpu_count())]) + if not os.path.isfile(abs_path + 'src/.libs/libwallycore' + ('.so' if build_shared else '.a')): + + def call(args): + subprocess.check_call(args, cwd=abs_path, env=configure_env) + + call(['./tools/cleanup.sh']) + call(['./tools/autogen.sh']) + call(['/bin/sh', '-c', 'cd src/secp256k1 && ./autogen.sh']) + call(['./configure'] + CONFIGURE_ARGS) + call(['make', '-j{}'.format(multiprocessing.cpu_count())]) define_macros=[ ('SWIG_PYTHON_BUILD', None), diff --git a/src/Makefile.am b/src/Makefile.am index 88c5e1cb9..73bb3c8e3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -208,7 +208,9 @@ endif # SHARED_BUILD_ENABLED libwallycore_la_CFLAGS = -I$(top_srcdir) -I$(srcdir)/ccan $(libsecp256k1_CFLAGS) -DWALLY_CORE_BUILD=1 $(AM_CFLAGS) libwallycore_la_LIBADD = $(libsecp256k1_LIBS) $(noinst_LTLIBRARIES) +if !LINK_SYSTEM_SECP256K1 SUBDIRS = secp256k1 +endif TESTS = noinst_PROGRAMS =