diff --git a/CHANGES.md b/CHANGES.md index 738c98d72..534ab0851 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,16 @@ # Changes +## Version 1.0.0 +- The library now follows semantic versioning as per https://semver.org/. +- Elements support is now enabled by default, reflecting the common library + usage. Please see the `configure --help` entries for `--disable-elements` + and `--disable-elements-abi` for details. +- The ABI of the library is now consistent by default regardless of whether + it is built with or without Elements support. +- Some functions in the c++ header wally.hpp have changed interface slightly. + Note that this header is deprecated and will be replaced in an upcoming + release with higher level wrappers in the same manner as Python and JS. + ## Version 0.9.1 - PSET: When adding an Elements transaction output to a PSET, the nonce commitment was incorrectly mapped to the PSET output blinding key field. diff --git a/README.md b/README.md index c1aa4a3e9..cb2621aef 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ for cryptocurrency wallets. Read the API documentation at https://wally.readthedocs.io. -Note that library interfaces may change slightly while the library design matures. Please see the [CHANGES](./CHANGES.md) file to determine if the API has changed when upgrading. +Please see the [CHANGES](./CHANGES.md) for details of ABI changes when upgrading. Please report bugs and submit patches to [Our github repository](https://github.com/ElementsProject/libwally-core). If you wish to report a security issue, please read [Our security reporting guidelines](./SECURITY.md). @@ -117,7 +117,7 @@ installed. For non-development use, you can install wally with `pip` as follows: ``` -pip install wallycore==0.9.2 +pip install wallycore==1.0.0 ``` For python development, you can build and install wally using: diff --git a/_CMakeLists.txt b/_CMakeLists.txt index 23a4b7f63..e575b10c2 100644 --- a/_CMakeLists.txt +++ b/_CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20) project( libwallycore - VERSION 0.9.2 + VERSION 1.0.0 DESCRIPTION "A collection of useful primitives for cryptocurrency wallets" LANGUAGES C ) diff --git a/configure.ac b/configure.ac index 8d46dd3a7..9d8bb0749 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.60]) -AC_INIT([libwallycore],[0.9.2]) +AC_INIT([libwallycore],[1.0.0]) AC_CONFIG_AUX_DIR([tools/build-aux]) AC_CONFIG_MACRO_DIR([tools/build-aux/m4]) AC_CONFIG_SRCDIR([src/mnemonic.h]) @@ -259,26 +259,10 @@ fi # # libsecp256k1 # -# 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]) +libsecp256k1_CFLAGS='-I$(top_srcdir)/src/secp256k1/include' +libsecp256k1_LIBS='$(top_srcdir)/src/secp256k1/libsecp256k1.la' +AC_SUBST([libsecp256k1_CFLAGS]) +AC_SUBST([libsecp256k1_LIBS]) # # Python facilities @@ -404,8 +388,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/docs/source/conf.py b/docs/source/conf.py index 61da01509..e5ca68a98 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -167,7 +167,7 @@ def extract_docs(infile, outfile): # built documents. # # The short X.Y version. -version = u'0.9.2' +version = u'1.0.0' # The full version, including alpha/beta/rc tags. release = version diff --git a/include/wally_core.h b/include/wally_core.h index e5d6a958e..328b2417b 100644 --- a/include/wally_core.h +++ b/include/wally_core.h @@ -29,10 +29,10 @@ extern "C" { #define WALLY_ENOMEM -3 /** malloc() failed */ /** Library version */ -#define WALLY_MAJOR_VER 0 -#define WALLY_MINOR_VER 9 -#define WALLY_PATCH_VER 2 -#define WALLY_BUILD_VER 0x902 +#define WALLY_MAJOR_VER 1 +#define WALLY_MINOR_VER 0 +#define WALLY_PATCH_VER 0 +#define WALLY_BUILD_VER 0x10000 /** * Initialize wally. diff --git a/setup.py b/setup.py index e403ed81a..0d4db4500 100644 --- a/setup.py +++ b/setup.py @@ -3,8 +3,15 @@ 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' +build_shared = os.environ.get('WALLY_ABI_PY_WHEEL_USE_DSO', '').lower() not in ['', '0', 'false', 'no', 'n', 'off'] +if build_shared: + CONFIGURE_ARGS = ['--enable-shared', '--disable-static'] +else: + CONFIGURE_ARGS = ['--disable-shared', '--enable-static', '--with-pic'] + +CONFIGURE_ARGS += [ + '--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 +33,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 +47,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), @@ -67,14 +73,11 @@ def call(cmd): include_dirs=[ './', './src', - './include', - './src/ccan', - './src/secp256k1', - './src/secp256k1/src/' + './src/secp256k1/include', ] if is_windows: shutil.copyfile('./src/amalgamation/windows_config/libsecp256k1-config.h', 'src/secp256k1/src/libsecp256k1-config.h') - include_dirs = ['./src/amalgamation/windows_config'] + include_dirs + include_dirs = ['./src/amalgamation/windows_config'] + include_dirs + ['./src/ccan'] extra_compile_args = ['-flax-vector-conversions'] @@ -82,18 +85,22 @@ def call(cmd): '_wallycore', define_macros=define_macros, include_dirs=include_dirs, + library_dirs=['src/.libs'] + ([] if build_shared else ['src/secp256k1/.libs']), + libraries=['wallycore'] + ([] if build_shared else ['secp256k1']), extra_compile_args=extra_compile_args, sources=[ - 'src/swig_python/swig_wrap.c' if is_windows else 'src/swig_python/swig_python_wrap.c', + 'src/swig_python/swig_wrap.c', 'src/amalgamation/combined.c', 'src/amalgamation/combined_ccan.c', 'src/amalgamation/combined_ccan2.c', + ] if is_windows else [ + 'src/swig_python/swig_python_wrap.c', ], ) kwargs = { 'name': 'wallycore', - 'version': '0.9.2', + 'version': '1.0.0', 'description': 'libwally Bitcoin library', 'long_description': 'Python bindings for the libwally Bitcoin library', 'url': 'https://github.com/ElementsProject/libwally-core', diff --git a/src/Makefile.am b/src/Makefile.am index ed5c23b8f..f42702cb0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,7 +40,7 @@ if USE_SWIG_PYTHON noinst_LTLIBRARIES += libswig_python.la libswig_python_la_SOURCES = swig_python/swig_python_wrap.c -libswig_python_la_CFLAGS = -I$(top_srcdir) $(AM_CFLAGS) $(SWIG_PYTHON_CPPFLAGS) $(SWIG_WARN_CFLAGS) $(NOALIAS_CFLAGS) +libswig_python_la_CFLAGS = -I$(top_srcdir) $(libsecp256k1_CFLAGS) $(AM_CFLAGS) $(SWIG_PYTHON_CPPFLAGS) $(SWIG_WARN_CFLAGS) $(NOALIAS_CFLAGS) if PYTHON_MANYLINUX else libswig_python_la_LIBADD = $(PYTHON_LIBS) @@ -83,7 +83,7 @@ noinst_LTLIBRARIES += libswig_java.la libswig_java_la_SOURCES = \ swig_java/swig_java_wrap.c -libswig_java_la_CFLAGS = -I$(top_srcdir) $(AM_CFLAGS) $(SWIG_JAVA_CPPFLAGS) $(SWIG_WARN_CFLAGS) +libswig_java_la_CFLAGS = -I$(top_srcdir) $(libsecp256k1_CFLAGS) $(AM_CFLAGS) $(SWIG_JAVA_CPPFLAGS) $(SWIG_WARN_CFLAGS) SWIG_JOPT = $(SWIG_JAVA_OPT) -outdir swig_java -noproxy -package com.blockstream.libwally @@ -207,8 +207,8 @@ libwallycore_la_LDFLAGS += -no-undefined endif endif # SHARED_BUILD_ENABLED -libwallycore_la_CFLAGS = -I$(top_srcdir) -I$(srcdir)/ccan -DWALLY_CORE_BUILD=1 $(AM_CFLAGS) -libwallycore_la_LIBADD = $(LIBADD_SECP256K1) $(noinst_LTLIBRARIES) +libwallycore_la_CFLAGS = -I$(top_srcdir) -I$(srcdir)/ccan $(libsecp256k1_CFLAGS) -DWALLY_CORE_BUILD=1 $(AM_CFLAGS) +libwallycore_la_LIBADD = $(libsecp256k1_LIBS) $(noinst_LTLIBRARIES) SUBDIRS = secp256k1 diff --git a/src/ecdh.c b/src/ecdh.c index f81e76c74..0130de427 100644 --- a/src/ecdh.c +++ b/src/ecdh.c @@ -1,7 +1,7 @@ #include "internal.h" #include -#include "secp256k1/include/secp256k1.h" -#include "secp256k1/include/secp256k1_ecdh.h" +#include +#include int wally_ecdh(const unsigned char *pub_key, size_t pub_key_len, const unsigned char *priv_key, size_t priv_key_len, diff --git a/src/elements.c b/src/elements.c index 9edb58ca8..cbe39ba1b 100644 --- a/src/elements.c +++ b/src/elements.c @@ -7,10 +7,10 @@ #include #include #include -#include "secp256k1/include/secp256k1_generator.h" -#include "secp256k1/include/secp256k1_rangeproof.h" -#include "src/secp256k1/include/secp256k1_surjectionproof.h" -#include "src/secp256k1/include/secp256k1_whitelist.h" +#include +#include +#include +#include static const unsigned char LABEL_STR[] = { diff --git a/src/internal.h b/src/internal.h index f99087b31..a60307afc 100644 --- a/src/internal.h +++ b/src/internal.h @@ -13,11 +13,11 @@ #pragma GCC diagnostic ignored "-Wunused-parameter" #endif /* BUILD_ELEMENTS */ #endif /* WALLY_ABI_NO_ELEMENTS */ -#include "secp256k1/include/secp256k1.h" -#include "secp256k1/include/secp256k1_recovery.h" -#include "secp256k1/include/secp256k1_extrakeys.h" +#include +#include +#include #ifndef BUILD_STANDARD_SECP -#include "secp256k1/include/secp256k1_ecdsa_s2c.h" +#include #endif #include #if defined(HAVE_MEMSET_S) diff --git a/src/sign.c b/src/sign.c index c76ab4474..f5b929fee 100644 --- a/src/sign.c +++ b/src/sign.c @@ -1,7 +1,7 @@ #include "internal.h" #include #include "script_int.h" -#include "secp256k1/include/secp256k1_schnorrsig.h" +#include #include "ccan/ccan/build_assert/build_assert.h" #define EC_FLAGS_TYPES (EC_FLAG_ECDSA | EC_FLAG_SCHNORR) diff --git a/src/wasm_package/package-lock.json b/src/wasm_package/package-lock.json index b2352c941..3e0bad7fd 100644 --- a/src/wasm_package/package-lock.json +++ b/src/wasm_package/package-lock.json @@ -1,12 +1,12 @@ { "name": "wallycore", - "version": "0.9.2", + "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wallycore", - "version": "0.9.2", + "version": "1.0.0", "license": "(MIT or BSD)", "devDependencies": { "buffer": "^6.0.3", diff --git a/src/wasm_package/package.json b/src/wasm_package/package.json index afc68984a..604d4a23b 100644 --- a/src/wasm_package/package.json +++ b/src/wasm_package/package.json @@ -1,6 +1,6 @@ { "name": "wallycore", - "version": "0.9.2", + "version": "1.0.0", "description": "JavaScript bindings for libwally", "main": "src/index.js", "type": "module", diff --git a/src/wasm_package/src/const.js b/src/wasm_package/src/const.js index 1d65a81fa..0388fa3f4 100755 --- a/src/wasm_package/src/const.js +++ b/src/wasm_package/src/const.js @@ -109,7 +109,7 @@ export const WALLY_ADDRESS_VERSION_WIF_TESTNET = 0xEF; /** Wallet Import Format export const WALLY_BIP32_CHAIN_CODE_LEN = 32; export const WALLY_BIP32_TWEAK_SUM_LEN = 32; export const WALLY_BTC_MAX = 21000000; -export const WALLY_BUILD_VER = 0x902; +export const WALLY_BUILD_VER = 0x10000; export const WALLY_CA_PREFIX_LIQUID = 0x0c; /** Liquid v1 confidential address prefix */ export const WALLY_CA_PREFIX_LIQUID_REGTEST = 0x04; /** Liquid v1 confidential address prefix for regtest */ export const WALLY_CA_PREFIX_LIQUID_TESTNET = 0x17; /** Liquid v1 confidential address prefix for testnet */ @@ -118,14 +118,14 @@ export const WALLY_EINVAL = -2; /** Invalid argument */ export const WALLY_ENOMEM = -3; /** malloc() failed */ export const WALLY_ERROR = -1; /** General error */ export const WALLY_HOST_COMMITMENT_LEN = 32; -export const WALLY_MAJOR_VER = 0; +export const WALLY_MAJOR_VER = 1; export const WALLY_MAX_OP_RETURN_LEN = 80; /* Maximum length of OP_RETURN data push */ export const WALLY_MINISCRIPT_DEPTH_MASK = 0xffff0000; /** Mask for limiting maximum depth */ export const WALLY_MINISCRIPT_DEPTH_SHIFT = 16; /** Shift to convert maximum depth to flags */ export const WALLY_MINISCRIPT_ONLY = 0x02; /** Only allow miniscript (not descriptor) expressions */ export const WALLY_MINISCRIPT_REQUIRE_CHECKSUM = 0x04; /** Require a checksum to be present */ export const WALLY_MINISCRIPT_TAPSCRIPT = 0x01; /** Tapscript, use x-only pubkeys */ -export const WALLY_MINOR_VER = 9; +export const WALLY_MINOR_VER = 0; export const WALLY_MS_CANONICAL_NO_CHECKSUM = 0x01; /** Do not include a checksum */ export const WALLY_MS_IS_DESCRIPTOR = 0x20; /** Contains only descriptor expressions (no miniscript) */ export const WALLY_MS_IS_MULTIPATH = 0x02; /** Allows multiple paths via ```` */ @@ -142,7 +142,7 @@ export const WALLY_NETWORK_LIQUID_TESTNET = 0x05; /** Liquid v1 testnet */ export const WALLY_NETWORK_NONE = 0x00; /** Used for miniscript parsing only */ export const WALLY_NO_CODESEPARATOR = 0xffffffff; /* No BIP342 code separator position */ export const WALLY_OK = 0; /** Success */ -export const WALLY_PATCH_VER = 2; +export const WALLY_PATCH_VER = 0; export const WALLY_PSBT_EXTRACT_NON_FINAL = 0x1; /* Extract without final scriptsig and witness */ export const WALLY_PSBT_FINALIZE_NO_CLEAR = 0x1; /* Finalize without clearing redeem/witness scripts etc */ export const WALLY_PSBT_FLAG_NON_FINAL = 0x1; 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 + ]) + ]) +])