diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index 911f0d72c..b232d9939 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -1,322 +1,325 @@ #!/usr/bin/env python3 # Copyright (c) 2014 Wladimir J. van der Laan # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """ A script to check that release executables only contain certain symbols and are only linked against allowed libraries. Example usage: find ../path/to/binaries -type f -executable | xargs python3 contrib/devtools/symbol-check.py """ import sys import lief # Debian 10 (Buster) EOL: 2024. https://wiki.debian.org/LTS # # - libgcc version 8.3.0 (https://packages.debian.org/search?suite=buster&arch=any&searchon=names&keywords=libgcc1) # - libc version 2.28 (https://packages.debian.org/search?suite=buster&arch=any&searchon=names&keywords=libc6) # # CentOS Stream 8 EOL: 2024. https://wiki.centos.org/About/Product # # - libgcc version 8.5.0 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/) # - libc version 2.28 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/) # # See https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html for more info. MAX_VERSIONS = { "GCC": (8, 3, 0), "GLIBC": { lief.ELF.ARCH.i386: (2, 28), lief.ELF.ARCH.x86_64: (2, 28), lief.ELF.ARCH.ARM: (2, 28), lief.ELF.ARCH.AARCH64: (2, 28), }, "LIBATOMIC": (1, 0), "V": (0, 5, 0), # xkb (bitcoin-qt only) } # See here for a description of _IO_stdin_used: # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109 # Ignore symbols that are exported as part of every executable IGNORE_EXPORTS = { "_edata", "_end", "__end__", "_init", "__bss_start", "__bss_start__", "_bss_end__", "__bss_end__", "_fini", "_IO_stdin_used", "stdin", "stdout", "stderr", # Jemalloc exported symbols "__malloc_hook", "malloc", "calloc", "malloc_usable_size", "__free_hook", "free", "__realloc_hook", "realloc", "__memalign_hook", "memalign", "posix_memalign", "aligned_alloc", "valloc", # Figure out why we get these symbols exported on xenial. "_ZNKSt5ctypeIcE8do_widenEc", "in6addr_any", "optarg", "_ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE10_M_destroyEv", } # Expected linker-loader names can be found here: # https://sourceware.org/glibc/wiki/ABIList?action=recall&rev=16 ELF_INTERPRETER_NAMES = { lief.ELF.ARCH.i386: { lief.ENDIANNESS.LITTLE: "/lib/ld-linux.so.2", }, lief.ELF.ARCH.x86_64: { lief.ENDIANNESS.LITTLE: "/lib64/ld-linux-x86-64.so.2", }, lief.ELF.ARCH.ARM: { lief.ENDIANNESS.LITTLE: "/lib/ld-linux-armhf.so.3", }, lief.ELF.ARCH.AARCH64: { lief.ENDIANNESS.LITTLE: "/lib/ld-linux-aarch64.so.1", }, } # Allowed NEEDED libraries ELF_ALLOWED_LIBRARIES = { # bitcoind and bitcoin-qt "libgcc_s.so.1", # GCC base support "libc.so.6", # C library "libpthread.so.0", # threading "libanl.so.1", # DNS resolve "libm.so.6", # math library "libatomic.so.1", "ld-linux-x86-64.so.2", # 64-bit dynamic linker "ld-linux.so.2", # 32-bit dynamic linker "ld-linux-aarch64.so.1", # 64-bit ARM dynamic linker "ld-linux-armhf.so.3", # 32-bit ARM dynamic linker # bitcoin-qt only "libxcb.so.1", # part of X11 "libxkbcommon.so.0", # keyboard keymapping "libxkbcommon-x11.so.0", # keyboard keymapping "libfontconfig.so.1", # font support "libfreetype.so.6", # font parsing "libdl.so.2", # programming interface to dynamic linker "libdl.so.2", # programming interface to dynamic linker "libxcb-icccm.so.4", "libxcb-image.so.0", "libxcb-shm.so.0", "libxcb-keysyms.so.1", "libxcb-randr.so.0", "libxcb-render-util.so.0", "libxcb-render.so.0", "libxcb-shape.so.0", "libxcb-sync.so.1", "libxcb-xfixes.so.0", "libxcb-xinerama.so.0", "libxcb-xkb.so.1", } MACHO_ALLOWED_LIBRARIES = { # bitcoind and bitcoin-qt "libc++.1.dylib", # C++ Standard Library "libSystem.B.dylib", # libc, libm, libpthread, libinfo # bitcoin-qt only "AppKit", # user interface "ApplicationServices", # common application tasks. "Carbon", # deprecated c back-compat API "ColorSync", "CFNetwork", # network services and changes in network configurations "CoreFoundation", # low level func, data types "CoreGraphics", # 2D rendering "CoreServices", # operating system services "CoreText", # interface for laying out text and handling fonts. "CoreVideo", # video processing "Foundation", # base layer functionality for apps/frameworks "ImageIO", # read and write image file formats. "IOKit", # user-space access to hardware devices and drivers. "IOSurface", # cross process image/drawing buffers "libobjc.A.dylib", # Objective-C runtime library "Metal", # 3D graphics "Security", # access control and authentication "QuartzCore", # animation "SystemConfiguration", # access network configuration settings "GSS", } PE_ALLOWED_LIBRARIES = { "ADVAPI32.dll", # security & registry "IPHLPAPI.DLL", # IP helper API "KERNEL32.dll", # win32 base APIs "msvcrt.dll", # C standard library for MSVC "SHELL32.dll", # shell API "USER32.dll", # user interface "WS2_32.dll", # sockets + "bcrypt.dll", # password hashing + "ntdll.dll", # user-mode face of the Windows kernel + "RPCRT4.dll", # RPC API # bitcoin-qt only "dwmapi.dll", # desktop window manager "CRYPT32.dll", # openssl "GDI32.dll", # graphics device interface "IMM32.dll", # input method editor "NETAPI32.dll", "ole32.dll", # component object model "OLEAUT32.dll", # OLE Automation API "SHLWAPI.dll", # light weight shell API "USERENV.dll", "UxTheme.dll", "VERSION.dll", # version checking "WINMM.dll", # WinMM audio API "WTSAPI32.dll", } def check_version(max_versions, version, arch) -> bool: (lib, _, ver) = version.rpartition("_") ver = tuple([int(x) for x in ver.split(".")]) if lib not in max_versions: return False if isinstance(max_versions[lib], tuple): return ver <= max_versions[lib] else: return ver <= max_versions[lib][arch] def check_imported_symbols(binary) -> bool: ok = True for symbol in binary.imported_symbols: if not symbol.imported: continue version = symbol.symbol_version if symbol.has_version else None if version: aux_version = ( version.symbol_version_auxiliary.name if version.has_auxiliary_version else None ) if aux_version and not check_version( MAX_VERSIONS, aux_version, binary.header.machine_type ): print( f"{filename}: symbol {symbol.name} from unsupported version" f" {version}" ) ok = False return ok def check_exported_symbols(binary) -> bool: ok = True for symbol in binary.dynamic_symbols: if not symbol.exported: continue name = symbol.name if name in IGNORE_EXPORTS: continue print(f"{binary.name}: export of symbol {name} not allowed!") ok = False return ok def check_ELF_libraries(binary) -> bool: ok = True for library in binary.libraries: if library not in ELF_ALLOWED_LIBRARIES: print(f"{filename}: {library} is not in ALLOWED_LIBRARIES!") ok = False return ok def check_MACHO_libraries(binary) -> bool: ok = True for dylib in binary.libraries: split = dylib.name.split("/") if split[-1] not in MACHO_ALLOWED_LIBRARIES: print(f"{split[-1]} is not in ALLOWED_LIBRARIES!") ok = False return ok def check_MACHO_min_os(binary) -> bool: return binary.build_version.minos == [10, 15, 0] def check_MACHO_sdk(binary) -> bool: return binary.build_version.sdk == [11, 0, 0] def check_PE_libraries(binary) -> bool: ok: bool = True for dylib in binary.libraries: if dylib not in PE_ALLOWED_LIBRARIES: print(f"{dylib} is not in ALLOWED_LIBRARIES!") ok = False return ok def check_PE_subsystem_version(binary) -> bool: binary = lief.parse(filename) major: int = binary.optional_header.major_subsystem_version minor: int = binary.optional_header.minor_subsystem_version return major == 6 and minor == 1 def check_ELF_interpreter(binary) -> bool: expected_interpreter = ELF_INTERPRETER_NAMES[binary.header.machine_type][ binary.abstract.header.endianness ] return binary.concrete.interpreter == expected_interpreter CHECKS = { lief.EXE_FORMATS.ELF: [ ("IMPORTED_SYMBOLS", check_imported_symbols), ("EXPORTED_SYMBOLS", check_exported_symbols), ("LIBRARY_DEPENDENCIES", check_ELF_libraries), ("INTERPRETER_NAME", check_ELF_interpreter), ], lief.EXE_FORMATS.MACHO: [ ("DYNAMIC_LIBRARIES", check_MACHO_libraries), ("MIN_OS", check_MACHO_min_os), ("SDK", check_MACHO_sdk), ], lief.EXE_FORMATS.PE: [ ("DYNAMIC_LIBRARIES", check_PE_libraries), ("SUBSYSTEM_VERSION", check_PE_subsystem_version), ], } if __name__ == "__main__": retval = 0 for filename in sys.argv[1:]: try: binary = lief.parse(filename) etype = binary.format if etype == lief.EXE_FORMATS.UNKNOWN: print(f"{filename}: unknown executable format") failed = [] for name, func in CHECKS[etype]: if not func(binary): failed.append(name) if failed: print(f'{filename}: failed {" ".join(failed)}') retval = 1 except IOError: print(f"{filename}: cannot open") retval = 1 sys.exit(retval) diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 9f1aab156..b412145d5 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -1,363 +1,363 @@ #!/usr/bin/env bash # Copyright (c) 2019-2023 The Bitcoin developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. export LC_ALL=C set -e -o pipefail export TZ=UTC # Although Guix _does_ set umask when building its own packages (in our case, # this is all packages in manifest.scm), it does not set it for `guix # shell`. It does make sense for at least `guix shell --container` # to set umask, so if that change gets merged upstream and we bump the # time-machine to a commit which includes the aforementioned change, we can # remove this line. # # This line should be placed before any commands which creates files. umask 0022 if [ -n "$V" ]; then # Print both unexpanded (-v) and expanded (-x) forms of commands as they are # read from this file. set -vx # Set VERBOSE for CMake-based builds export VERBOSE="$V" fi # Check that required environment variables are set cat << EOF Required environment variables as seen inside the container: DIST_ARCHIVE_BASE: ${DIST_ARCHIVE_BASE:?not set} DISTNAME: ${DISTNAME:?not set} HOST: ${HOST:?not set} SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH:?not set} JOBS: ${JOBS:?not set} DISTSRC: ${DISTSRC:?not set} OUTDIR: ${OUTDIR:?not set} EOF ACTUAL_OUTDIR="${OUTDIR}" OUTDIR="${DISTSRC}/output" ##################### # Environment Setup # ##################### # The depends folder also serves as a base-prefix for depends packages for # $HOSTs after successfully building. BASEPREFIX="${PWD}/depends" # Given a package name and an output name, return the path of that output in our # current guix environment store_path() { grep --extended-regexp "/[^-]{32}-${1}-[^-]+${2:+-${2}}" "${GUIX_ENVIRONMENT}/manifest" \ | head --lines=1 \ | sed --expression='s|\x29*$||' \ --expression='s|^[[:space:]]*"||' \ --expression='s|"[[:space:]]*$||' } # Set environment variables to point the NATIVE toolchain to the right # includes/libs NATIVE_GCC="$(store_path gcc-toolchain)" NATIVE_GCC_STATIC="$(store_path gcc-toolchain static)" NATIVE_GCC_LIBS="$(store_path gcc lib)" unset LIBRARY_PATH unset CPATH unset C_INCLUDE_PATH unset CPLUS_INCLUDE_PATH unset OBJC_INCLUDE_PATH unset OBJCPLUS_INCLUDE_PATH export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC_STATIC}/lib:${NATIVE_GCC_LIBS}/lib" export C_INCLUDE_PATH="${NATIVE_GCC}/include" export CPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include" export OBJC_INCLUDE_PATH="${NATIVE_GCC}/include" export OBJCPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include" # Set environment variables to point the CROSS toolchain to the right # includes/libs for $HOST case "$HOST" in *mingw*) # Determine output paths to use in CROSS_* environment variables CROSS_GLIBC="$(store_path "mingw-w64-x86_64-winpthreads")" CROSS_GCC_ROOT="$(store_path "gcc-cross-${HOST}")" CROSS_GCC_LIB_STORE="$(store_path "gcc-cross-${HOST}" lib)" CROSS_GCC_LIBS=( "${CROSS_GCC_LIB_STORE}/lib/gcc/${HOST}"/* ) # This expands to an array of directories... CROSS_GCC_LIB="${CROSS_GCC_LIBS[0]}" # ...we just want the first one (there should only be one) # The search path ordering is generally: # 1. gcc-related search paths # 2. libc-related search paths # 2. kernel-header-related search paths (not applicable to mingw-w64 hosts) export CROSS_C_INCLUDE_PATH="${CROSS_GCC_LIB}/include:${CROSS_GCC_LIB}/include-fixed:${CROSS_GLIBC}/include" export CROSS_CPLUS_INCLUDE_PATH="${CROSS_GCC_ROOT}/include/c++:${CROSS_GCC_ROOT}/include/c++/${HOST}:${CROSS_GCC_ROOT}/include/c++/backward:${CROSS_C_INCLUDE_PATH}" export CROSS_LIBRARY_PATH="${CROSS_GCC_LIB_STORE}/lib:${CROSS_GCC_LIB}:${CROSS_GLIBC}/lib" ;; *darwin*) # The CROSS toolchain for darwin uses the SDK and ignores environment variables. # See depends/hosts/darwin.mk for more details. ;; *linux*) CROSS_GLIBC="$(store_path "glibc-cross-${HOST}")" CROSS_GLIBC_STATIC="$(store_path "glibc-cross-${HOST}" static)" CROSS_KERNEL="$(store_path "linux-libre-headers-cross-${HOST}")" CROSS_GCC_ROOT="$(store_path "gcc-cross-${HOST}")" CROSS_GCC_LIB_STORE="$(store_path "gcc-cross-${HOST}" lib)" CROSS_GCC_LIBS=( "${CROSS_GCC_LIB_STORE}/lib/gcc/${HOST}"/* ) # This expands to an array of directories... CROSS_GCC_LIB="${CROSS_GCC_LIBS[0]}" # ...we just want the first one (there should only be one) export CROSS_CC="${CROSS_GCC_ROOT}/bin/${HOST}-gcc" export CROSS_CXX="${CROSS_GCC_ROOT}/bin/${HOST}-g++" export CROSS_C_INCLUDE_PATH="${CROSS_GCC_LIB}/include:${CROSS_GCC_LIB}/include-fixed:${CROSS_GLIBC}/include:${CROSS_KERNEL}/include" export CROSS_CPLUS_INCLUDE_PATH="${CROSS_GCC_ROOT}/include/c++:${CROSS_GCC_ROOT}/include/c++/${HOST}:${CROSS_GCC_ROOT}/include/c++/backward:${CROSS_C_INCLUDE_PATH}" export CROSS_LIBRARY_PATH="${CROSS_GCC_LIB_STORE}/lib:${CROSS_GCC_LIB}:${CROSS_GLIBC}/lib:${CROSS_GLIBC_STATIC}/lib" ;; *) exit 1 ;; esac # Sanity check CROSS_(CC|CXX) for compiler in "${CROSS_CC}" "${CROSS_CXX}"; do if [ -n "${compiler}" ] && [ ! -f "${compiler}" ]; then echo "'${compiler}' doesn't exist... Aborting..." exit 1 fi done # Sanity check CROSS_*_PATH directories IFS=':' read -ra PATHS <<< "${CROSS_C_INCLUDE_PATH}:${CROSS_CPLUS_INCLUDE_PATH}:${CROSS_LIBRARY_PATH}" for p in "${PATHS[@]}"; do if [ -n "$p" ] && [ ! -d "$p" ]; then echo "'$p' doesn't exist or isn't a directory... Aborting..." exit 1 fi done # Disable Guix ld auto-rpath behavior case "$HOST" in *darwin*) # The auto-rpath behavior is necessary for darwin builds as some native # tools built by depends refer to and depend on Guix-built native # libraries # # After the native packages in depends are built, the ld wrapper should # no longer affect our build, as clang would instead reach for # x86_64-apple-darwin-ld from cctools ;; *) export GUIX_LD_WRAPPER_DISABLE_RPATH=yes ;; esac # Make /usr/bin if it doesn't exist [ -e /usr/bin ] || mkdir -p /usr/bin # Symlink file and env to a conventional path [ -e /usr/bin/file ] || ln -s --no-dereference "$(command -v file)" /usr/bin/file [ -e /usr/bin/env ] || ln -s --no-dereference "$(command -v env)" /usr/bin/env # Determine the correct value for -Wl,--dynamic-linker for the current $HOST case "$HOST" in *linux*) glibc_dynamic_linker=$( case "$HOST" in x86_64-linux-gnu) echo /lib64/ld-linux-x86-64.so.2 ;; arm-linux-gnueabihf) echo /lib/ld-linux-armhf.so.3 ;; aarch64-linux-gnu) echo /lib/ld-linux-aarch64.so.1 ;; *) exit 1 ;; esac ) ;; esac # Environment variables for determinism export TAR_OPTIONS="--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name" export TZ="UTC" case "$HOST" in *darwin*) # cctools AR, unlike GNU binutils AR, does not have a deterministic mode # or a configure flag to enable determinism by default, it only # understands if this env-var is set or not. See: # # https://github.com/tpoechtrager/cctools-port/blob/55562e4073dea0fbfd0b20e0bf69ffe6390c7f97/cctools/ar/archive.c#L334 export ZERO_AR_DATE=yes ;; esac #################### # Depends Building # #################### # Build the depends tree, overriding variables that assume multilib gcc make -C depends --jobs="$JOBS" HOST="$HOST" \ ${V:+V=1} \ ${SOURCES_PATH+SOURCES_PATH="$SOURCES_PATH"} \ ${BASE_CACHE+BASE_CACHE="$BASE_CACHE"} \ ${SDK_PATH+SDK_PATH="$SDK_PATH"} \ x86_64_linux_CC=x86_64-linux-gnu-gcc \ x86_64_linux_CXX=x86_64-linux-gnu-g++ \ x86_64_linux_AR=x86_64-linux-gnu-gcc-ar \ x86_64_linux_RANLIB=x86_64-linux-gnu-gcc-ranlib \ x86_64_linux_NM=x86_64-linux-gnu-gcc-nm \ x86_64_linux_STRIP=x86_64-linux-gnu-strip \ FORCE_USE_SYSTEM_CLANG=1 ########################### # Source Tarball Building # ########################### # Toolchain case "$HOST" in *mingw*) CMAKE_TOOLCHAIN_FILE="/bitcoin/cmake/platforms/Win64.cmake" RUST_TARGET="x86_64-pc-windows-gnu" ;; aarch64-linux-gnu) CMAKE_TOOLCHAIN_FILE="/bitcoin/cmake/platforms/LinuxAArch64.cmake" RUST_TARGET="aarch64-unknown-linux-gnu" ;; arm-linux-gnueabihf) CMAKE_TOOLCHAIN_FILE="/bitcoin/cmake/platforms/LinuxARM.cmake" RUST_TARGET="arm-unknown-linux-gnueabihf" ;; x86_64-linux-gnu) CMAKE_TOOLCHAIN_FILE="/bitcoin/cmake/platforms/Linux64.cmake" RUST_TARGET="x86_64-unknown-linux-gnu" ;; *darwin*) CMAKE_TOOLCHAIN_FILE="/bitcoin/cmake/platforms/OSX.cmake" RUST_TARGET="x86_64-apple-darwin" ;; esac curl -sSf https://static.rust-lang.org/rustup/archive/1.26.0/x86_64-unknown-linux-gnu/rustup-init -o rustup-init echo "0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db rustup-init" | sha256sum -c chmod +x rustup-init ./rustup-init -y --default-toolchain=1.76.0 # shellcheck disable=SC1091 source "$HOME/.cargo/env" rustup target add "${RUST_TARGET}" mkdir -p source_package pushd source_package rm -f CMakeCache.txt cmake -GNinja .. \ -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} \ -DBUILD_BITCOIN_WALLET=OFF \ -DBUILD_BITCOIN_CHRONIK=OFF \ -DBUILD_BITCOIN_QT=OFF \ -DBUILD_BITCOIN_ZMQ=OFF \ -DENABLE_QRCODE=OFF \ -DENABLE_NATPMP=OFF \ -DENABLE_UPNP=OFF \ -DUSE_JEMALLOC=OFF \ -DENABLE_CLANG_TIDY=OFF \ -DENABLE_BIP70=OFF \ -DUSE_LINKER= ninja package_source SOURCEDIST=$(echo bitcoin-abc-*.tar.gz) mv ${SOURCEDIST} .. popd rm -rf source_package DISTNAME=${SOURCEDIST//.tar.*/} mkdir -p "$OUTDIR" OUTDIR=$(realpath "${OUTDIR}") ########################### # Binary Tarball Building # ########################### # CFLAGS HOST_CFLAGS=$(find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;) case "$HOST" in *linux*) HOST_CFLAGS+=" -ffile-prefix-map=${PWD}=." ;; *mingw*) HOST_CFLAGS+=" -fno-ident" ;; *darwin*) unset HOST_CFLAGS ;; esac # CXXFLAGS HOST_CXXFLAGS="$HOST_CFLAGS" case "$HOST" in arm-linux-gnueabihf) HOST_CXXFLAGS="${HOST_CXXFLAGS} -Wno-psabi" ;; esac # LDFLAGS case "$HOST" in *linux*) HOST_LDFLAGS="-Wl,--as-needed -Wl,--dynamic-linker=$glibc_dynamic_linker" ;; *mingw*) HOST_LDFLAGS="-Wl,--no-insert-timestamp" ;; esac # CMake flags case "$HOST" in *mingw*) - CMAKE_EXTRA_OPTIONS=(-DBUILD_BITCOIN_SEEDER=OFF -DCPACK_PACKAGE_FILE_NAME="${DISTNAME}-win64-setup-unsigned") + CMAKE_EXTRA_OPTIONS=(-DBUILD_BITCOIN_SEEDER=OFF -DBUILD_BITCOIN_CHRONIK=ON -DCPACK_PACKAGE_FILE_NAME="${DISTNAME}-win64-setup-unsigned") ;; *linux*) CMAKE_EXTRA_OPTIONS=(-DENABLE_STATIC_LIBSTDCXX=ON -DENABLE_GLIBC_BACK_COMPAT=ON -DBUILD_BITCOIN_CHRONIK=ON -DUSE_LINKER=) ;; *darwin*) CMAKE_EXTRA_OPTIONS=(-DGENISOIMAGE_EXECUTABLE="${WRAP_DIR}/genisoimage") ;; esac # Make $HOST-specific native binaries from depends available in $PATH export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}" mkdir -p "$DISTSRC" ( cd "$DISTSRC" # Setup the directory where our Bitcoin ABC build for HOST will be # installed. This directory will also later serve as the input for our # binary tarballs. INSTALLPATH=$(pwd)/installed/${DISTNAME} mkdir -p "${INSTALLPATH}" # Needed for rustup, cargo and rustc export LD_LIBRARY_PATH="${LIBRARY_PATH}" # rocksdb-sys uses libclang to parse the headers but it doesn't know what # the host arch is. As a consequence it fails to parse gnu/stubs.h if the # multilib headers are not installed because it falls back to the 32 bits # variant gnu/stubs-32.h that guix don't provide. # Instead we can instruct clang to use the correct arch. export BINDGEN_EXTRA_CLANG_ARGS="-D__x86_64__ -D__LP64__ -U__ILP32__" cmake -GNinja .. \ -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} \ -DCLIENT_VERSION_IS_RELEASE=ON \ -DENABLE_CLANG_TIDY=OFF \ -DENABLE_REDUCE_EXPORTS=ON \ -DCMAKE_INSTALL_PREFIX="${INSTALLPATH}" \ -DCCACHE=OFF \ -DCMAKE_C_FLAGS="${HOST_CFLAGS}" \ -DCMAKE_CXX_FLAGS="${HOST_CXXFLAGS}" \ -DCMAKE_EXE_LINKER_FLAGS="${HOST_LDFLAGS}" \ "${CMAKE_EXTRA_OPTIONS[@]}" # Build Bitcoin ABC ninja ninja security-check ninja symbol-check ninja install-debug cd installed find ${DISTNAME} -not -name "*.dbg" | sort | tar --mtime=@${SOURCE_DATE_EPOCH} --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${HOST}.tar.gz find ${DISTNAME} -name "*.dbg" | sort | tar --mtime=@${SOURCE_DATE_EPOCH} --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz ) # $DISTSRC rm -rf "$ACTUAL_OUTDIR" mv --no-target-directory "$OUTDIR" "$ACTUAL_OUTDIR" \ || ( rm -rf "$ACTUAL_OUTDIR" && exit 1 ) mv ${SOURCEDIST} "$ACTUAL_OUTDIR" ( cd /outdir-base find "$ACTUAL_OUTDIR" -type f -print0 \ | xargs -0 realpath --relative-base="$PWD" \ | xargs sha256sum \ | sort -k2 \ | sponge "$ACTUAL_OUTDIR"/SHA256SUMS.part ) diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 4737d54b4..293e9045a 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -1,621 +1,622 @@ (use-modules (gnu packages) (gnu packages autotools) ((gnu packages bash) #:select (bash-minimal)) (gnu packages bison) ((gnu packages certs) #:select (nss-certs)) ((gnu packages cdrom) #:select (xorriso)) ((gnu packages cmake) #:select (cmake-minimal)) (gnu packages commencement) (gnu packages compression) (gnu packages cross-base) (gnu packages curl) (gnu packages file) (gnu packages gawk) (gnu packages gcc) (gnu packages gperf) ((gnu packages installers) #:select (nsis-x86_64)) ((gnu packages linux) #:select (linux-libre-headers-5.15 util-linux)) (gnu packages llvm) (gnu packages mingw) (gnu packages moreutils) (gnu packages ninja) (gnu packages perl) (gnu packages pkg-config) ((gnu packages python) #:select (python-minimal)) ((gnu packages python-build) #:select (python-tomli)) ((gnu packages python-crypto) #:select (python-asn1crypto)) ((gnu packages python-web) #:select (python-requests)) ((gnu packages tls) #:select (openssl)) ((gnu packages version-control) #:select (git-minimal)) (guix build-system cmake) (guix build-system gnu) (guix build-system python) (guix build-system trivial) (guix gexp) (guix git-download) ((guix licenses) #:prefix license:) (guix packages) ((guix utils) #:select (substitute-keyword-arguments))) (define-syntax-rule (search-our-patches file-name ...) "Return the list of absolute file names corresponding to each FILE-NAME found in ./patches relative to the current file." (parameterize ((%patch-path (list (string-append (dirname (current-filename)) "/patches")))) (list (search-patch file-name) ...))) (define building-on (string-append "--build=" (list-ref (string-split (%current-system) #\-) 0) "-guix-linux-gnu")) (define (make-cross-toolchain target base-gcc-for-libc base-kernel-headers base-libc base-gcc) "Create a cross-compilation toolchain package for TARGET" (let* ((xbinutils (cross-binutils target)) ;; 1. Build a cross-compiling gcc without targeting any libc, derived ;; from BASE-GCC-FOR-LIBC (xgcc-sans-libc (cross-gcc target #:xgcc base-gcc-for-libc #:xbinutils xbinutils)) ;; 2. Build cross-compiled kernel headers with XGCC-SANS-LIBC, derived ;; from BASE-KERNEL-HEADERS (xkernel (cross-kernel-headers target #:linux-headers base-kernel-headers #:xgcc xgcc-sans-libc #:xbinutils xbinutils)) ;; 3. Build a cross-compiled libc with XGCC-SANS-LIBC and XKERNEL, ;; derived from BASE-LIBC (xlibc (cross-libc target #:libc base-libc #:xgcc xgcc-sans-libc #:xbinutils xbinutils #:xheaders xkernel)) ;; 4. Build a cross-compiling gcc targeting XLIBC, derived from ;; BASE-GCC (xgcc (cross-gcc target #:xgcc base-gcc #:xbinutils xbinutils #:libc xlibc))) ;; Define a meta-package that propagates the resulting XBINUTILS, XLIBC, and ;; XGCC (package (name (string-append target "-toolchain")) (version (package-version xgcc)) (source #f) (build-system trivial-build-system) (arguments '(#:builder (begin (mkdir %output) #t))) (propagated-inputs `(("binutils" ,xbinutils) ("libc" ,xlibc) ("libc:static" ,xlibc "static") ("gcc" ,xgcc) ("gcc-lib" ,xgcc "lib"))) (synopsis (string-append "Complete GCC tool chain for " target)) (description (string-append "This package provides a complete GCC tool chain for " target " development.")) (home-page (package-home-page xgcc)) (license (package-license xgcc))))) (define base-gcc gcc-10) (define base-linux-kernel-headers linux-libre-headers-5.15) (define* (make-bitcoin-cross-toolchain target #:key (base-gcc-for-libc linux-base-gcc) (base-kernel-headers base-linux-kernel-headers) (base-libc glibc-2.28) (base-gcc linux-base-gcc)) "Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values desirable for building Bitcoin ABC release binaries." (make-cross-toolchain target base-gcc-for-libc base-kernel-headers base-libc base-gcc)) (define (gcc-mingw-patches gcc) (package-with-extra-patches gcc (search-our-patches "gcc-remap-guix-store.patch" "vmov-alignment.patch"))) (define (make-mingw-pthreads-cross-toolchain target) "Create a cross-compilation toolchain package for TARGET" (let* ((xbinutils (cross-binutils target)) (pthreads-xlibc mingw-w64-x86_64-winpthreads) (pthreads-xgcc (cross-gcc target #:xgcc (gcc-mingw-patches mingw-w64-base-gcc) #:xbinutils xbinutils #:libc pthreads-xlibc))) ;; Define a meta-package that propagates the resulting XBINUTILS, XLIBC, and ;; XGCC (package (name (string-append target "-posix-toolchain")) (version (package-version pthreads-xgcc)) (source #f) (build-system trivial-build-system) (arguments '(#:builder (begin (mkdir %output) #t))) (propagated-inputs `(("binutils" ,xbinutils) ("libc" ,pthreads-xlibc) ("gcc" ,pthreads-xgcc) ("gcc-lib" ,pthreads-xgcc "lib"))) (synopsis (string-append "Complete GCC tool chain for " target)) (description (string-append "This package provides a complete GCC tool chain for " target " development.")) (home-page (package-home-page pthreads-xgcc)) (license (package-license pthreads-xgcc))))) ;; While LIEF is packaged in Guix, we maintain our own package, ;; to simplify building, and more easily apply updates. ;; Moreover, the Guix's package uses cmake, which caused build ;; failure; see https://github.com/bitcoin/bitcoin/pull/27296. (define-public python-lief (package (name "python-lief") (version "0.13.2") (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/lief-project/LIEF") (commit version))) (file-name (git-file-name name version)) (modules '((guix build utils))) (snippet '(begin ;; Configure build for Python bindings. (substitute* "api/python/config-default.toml" (("(ninja = )true" all m) (string-append m "false")) (("(parallel-jobs = )0" all m) (string-append m (number->string (parallel-job-count))))))) (sha256 (base32 "0y48x358ppig5xp97ahcphfipx7cg9chldj2q5zrmn610fmi4zll")))) (build-system python-build-system) (native-inputs (list cmake-minimal python-tomli)) (arguments (list #:tests? #f ;needs network #:phases #~(modify-phases %standard-phases (add-before 'build 'change-directory (lambda _ (chdir "api/python"))) (replace 'build (lambda _ (invoke "python" "setup.py" "build")))))) (home-page "https://github.com/lief-project/LIEF") (synopsis "Library to instrument executable formats") (description "@code{python-lief} is a cross platform library which can parse, modify and abstract ELF, PE and MachO formats.") (license license:asl2.0))) (define osslsigncode (package (name "osslsigncode") (version "2.5") (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/mtrojnar/osslsigncode") (commit version))) (sha256 (base32 "1j47vwq4caxfv0xw68kw5yh00qcpbd56d7rq6c483ma3y7s96yyz")))) (build-system cmake-build-system) (inputs `(("openssl", openssl))) (home-page "https://github.com/mtrojnar/osslsigncode") (synopsis "Authenticode signing and timestamping tool") (description "osslsigncode is a small tool that implements part of the functionality of the Microsoft tool signtool.exe - more exactly the Authenticode signing and timestamping. But osslsigncode is based on OpenSSL and cURL, and thus should be able to compile on most platforms where these exist.") (license license:gpl3+))) ; license is with openssl exception (define-public python-elfesteem (let ((commit "2eb1e5384ff7a220fd1afacd4a0170acff54fe56")) (package (name "python-elfesteem") (version (git-version "0.1" "1" commit)) (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/LRGH/elfesteem") (commit commit))) (file-name (git-file-name name commit)) (sha256 (base32 "07x6p8clh11z8s1n2kdxrqwqm2almgc5qpkcr9ckb6y5ivjdr5r6")))) (build-system python-build-system) ;; There are no tests, but attempting to run python setup.py test leads to ;; PYTHONPATH problems, just disable the test (arguments '(#:tests? #f)) (home-page "https://github.com/LRGH/elfesteem") (synopsis "ELF/PE/Mach-O parsing library") (description "elfesteem parses ELF, PE and Mach-O files.") (license license:lgpl2.1)))) (define-public python-oscrypto (package (name "python-oscrypto") (version "1.3.0") (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/wbond/oscrypto") (commit version))) (file-name (git-file-name name version)) (sha256 (base32 "1v5wkmzcyiqy39db8j2dvkdrv2nlsc48556h73x4dzjwd6kg4q0a")) (patches (search-our-patches "oscrypto-hard-code-openssl.patch")))) (build-system python-build-system) (native-search-paths (list (search-path-specification (variable "SSL_CERT_FILE") (file-type 'regular) (separator #f) ;single entry (files '("etc/ssl/certs/ca-certificates.crt"))))) (propagated-inputs `(("python-asn1crypto" ,python-asn1crypto) ("openssl" ,openssl))) (arguments `(#:phases (modify-phases %standard-phases (add-after 'unpack 'hard-code-path-to-libscrypt (lambda* (#:key inputs #:allow-other-keys) (let ((openssl (assoc-ref inputs "openssl"))) (substitute* "oscrypto/__init__.py" (("@GUIX_OSCRYPTO_USE_OPENSSL@") (string-append openssl "/lib/libcrypto.so" "," openssl "/lib/libssl.so"))) #t))) (add-after 'unpack 'disable-broken-tests (lambda _ ;; This test is broken as there is no keyboard interrupt. (substitute* "tests/test_trust_list.py" (("^(.*)class TrustListTests" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) (substitute* "tests/test_tls.py" (("^(.*)class TLSTests" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) #t)) (replace 'check (lambda _ (invoke "python" "run.py" "tests") #t))))) (home-page "https://github.com/wbond/oscrypto") (synopsis "Compiler-free Python crypto library backed by the OS") (description "oscrypto is a compilation-free, always up-to-date encryption library for Python.") (license license:expat))) (define-public python-oscryptotests (package (inherit python-oscrypto) (name "python-oscryptotests") (propagated-inputs `(("python-oscrypto" ,python-oscrypto))) (arguments `(#:tests? #f #:phases (modify-phases %standard-phases (add-after 'unpack 'hard-code-path-to-libscrypt (lambda* (#:key inputs #:allow-other-keys) (chdir "tests") #t))))))) (define-public python-certvalidator (let ((commit "a145bf25eb75a9f014b3e7678826132efbba6213")) (package (name "python-certvalidator") (version (git-version "0.1" "1" commit)) (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/achow101/certvalidator") (commit commit))) (file-name (git-file-name name commit)) (sha256 (base32 "1qw2k7xis53179lpqdqyylbcmp76lj7sagp883wmxg5i7chhc96k")))) (build-system python-build-system) (propagated-inputs `(("python-asn1crypto" ,python-asn1crypto) ("python-oscrypto" ,python-oscrypto) ("python-oscryptotests", python-oscryptotests))) ;; certvalidator tests import oscryptotests (arguments `(#:phases (modify-phases %standard-phases (add-after 'unpack 'disable-broken-tests (lambda _ (substitute* "tests/test_certificate_validator.py" (("^(.*)class CertificateValidatorTests" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) (substitute* "tests/test_crl_client.py" (("^(.*)def test_fetch_crl" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) (substitute* "tests/test_ocsp_client.py" (("^(.*)def test_fetch_ocsp" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) (substitute* "tests/test_registry.py" (("^(.*)def test_build_paths" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) (substitute* "tests/test_validate.py" (("^(.*)def test_revocation_mode_hard" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) (substitute* "tests/test_validate.py" (("^(.*)def test_revocation_mode_soft" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) #t)) (replace 'check (lambda _ (invoke "python" "run.py" "tests") #t))))) (home-page "https://github.com/wbond/certvalidator") (synopsis "Python library for validating X.509 certificates and paths") (description "certvalidator is a Python library for validating X.509 certificates or paths. Supports various options, including: validation at a specific moment in time, whitelisting and revocation checks.") (license license:expat)))) (define-public python-altgraph (package (name "python-altgraph") (version "0.17") (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/ronaldoussoren/altgraph") (commit (string-append "v" version)))) (file-name (git-file-name name version)) (sha256 (base32 "09sm4srvvkw458pn48ga9q7ykr4xlz7q8gh1h9w7nxpf001qgpwb")))) (build-system python-build-system) (home-page "https://github.com/ronaldoussoren/altgraph") (synopsis "Python graph (network) package") (description "altgraph is a fork of graphlib: a graph (network) package for constructing graphs, BFS and DFS traversals, topological sort, shortest paths, etc. with graphviz output.") (license license:expat))) (define-public python-macholib (package (name "python-macholib") (version "1.14") (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/ronaldoussoren/macholib") (commit (string-append "v" version)))) (file-name (git-file-name name version)) (sha256 (base32 "0aislnnfsza9wl4f0vp45ivzlc0pzhp9d4r08700slrypn5flg42")))) (build-system python-build-system) (propagated-inputs `(("python-altgraph" ,python-altgraph))) (arguments '(#:phases (modify-phases %standard-phases (add-after 'unpack 'disable-broken-tests (lambda _ ;; This test is broken as there is no keyboard interrupt. (substitute* "macholib_tests/test_command_line.py" (("^(.*)class TestCmdLine" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line))) (substitute* "macholib_tests/test_dyld.py" (("^(.*)def test_\\S+_find" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line)) (("^(.*)def testBasic" line indent) (string-append indent "@unittest.skip(\"Disabled by Guix\")\n" line)) ) #t))))) (home-page "https://github.com/ronaldoussoren/macholib") (synopsis "Python library for analyzing and editing Mach-O headers") (description "macholib is a Macho-O header analyzer and editor. It's typically used as a dependency analysis tool, and also to rewrite dylib references in Mach-O headers to be @executable_path relative. Though this tool targets a platform specific file format, it is pure python code that is platform and endian independent.") (license license:expat))) (define-public python-signapple (let ((commit "8a945a2e7583be2665cf3a6a89d665b70ecd1ab6")) (package (name "python-signapple") (version (git-version "0.1" "1" commit)) (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/achow101/signapple") (commit commit))) (file-name (git-file-name name commit)) (sha256 (base32 "0fr1hangvfyiwflca6jg5g8zvg3jc9qr7vd2c12ff89pznf38dlg")))) (build-system python-build-system) (propagated-inputs `(("python-asn1crypto" ,python-asn1crypto) ("python-oscrypto" ,python-oscrypto) ("python-certvalidator" ,python-certvalidator) ("python-elfesteem" ,python-elfesteem) ("python-requests" ,python-requests) ("python-macholib" ,python-macholib))) ;; There are no tests, but attempting to run python setup.py test leads to ;; problems, just disable the test (arguments '(#:tests? #f)) (home-page "https://github.com/achow101/signapple") (synopsis "Mach-O binary signature tool") (description "signapple is a Python tool for creating, verifying, and inspecting signatures in Mach-O binaries.") (license license:expat)))) (define-public mingw-w64-base-gcc (package (inherit base-gcc) (arguments (substitute-keyword-arguments (package-arguments base-gcc) ((#:configure-flags flags) `(append ,flags ;; https://gcc.gnu.org/install/configure.html (list "--enable-threads=posix", building-on))) ((#:make-flags flags) ;; Uses the SSP functions from glibc instead of from libssp.so. ;; Our 'symbol-check' script will complain if we link against libssp.so, ;; and thus will ensure that this works properly. `(cons "gcc_cv_libc_provides_ssp=yes" ,flags)))))) (define-public linux-base-gcc (package (inherit base-gcc) (arguments (substitute-keyword-arguments (package-arguments base-gcc) ((#:configure-flags flags) `(append ,flags ;; https://gcc.gnu.org/install/configure.html (list "--enable-initfini-array=yes", "--enable-default-ssp=yes", "--enable-default-pie=yes", building-on))) ((#:phases phases) `(modify-phases ,phases ;; Given a XGCC package, return a modified package that replace each instance of ;; -rpath in the default system spec that's inserted by Guix with -rpath-link (add-after 'pre-configure 'replace-rpath-with-rpath-link (lambda _ (substitute* (cons "gcc/config/rs6000/sysv4.h" (find-files "gcc/config" "^gnu-user.*\\.h$")) (("-rpath=") "-rpath-link=")) #t)))))))) (define-public glibc-2.28 (package (inherit glibc-2.31) (version "2.28") (source (origin (method git-fetch) (uri (git-reference (url "https://sourceware.org/git/glibc.git") (commit "c9e58ae23402eb82877de90fd8a18519c086ed87"))) (file-name (git-file-name "glibc" "c9e58ae23402eb82877de90fd8a18519c086ed87")) (sha256 (base32 "0wm0if2n4z48kpn85va6yb4iac34crds2f55ddpz1hykx6jp1pb6")) (patches (search-our-patches "glibc-2.28-fcommon.patch" "glibc-2.28-guix-prefix.patch" "glibc-2.28-no-librt.patch")))) (arguments (substitute-keyword-arguments (package-arguments glibc) ((#:configure-flags flags) `(append ,flags ;; https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html (list "--enable-stack-protector=all", "--enable-bind-now", "--disable-werror", building-on))) ((#:phases phases) `(modify-phases ,phases (add-before 'configure 'set-etc-rpc-installation-directory (lambda* (#:key outputs #:allow-other-keys) ;; Install the rpc data base file under `$out/etc/rpc'. ;; Otherwise build will fail with "Permission denied." (let ((out (assoc-ref outputs "out"))) (substitute* "sunrpc/Makefile" (("^\\$\\(inst_sysconfdir\\)/rpc(.*)$" _ suffix) (string-append out "/etc/rpc" suffix "\n")) (("^install-others =.*$") (string-append "install-others = " out "/etc/rpc\n")))))))))))) (packages->manifest (append (list ;; The Basics bash-minimal which coreutils-minimal util-linux gperf ;; File(system) inspection file grep diffutils findutils ;; File transformation patch gawk sed moreutils ;; Compression and archiving tar bzip2 gzip xz zlib ;; Build tools cmake-minimal ninja gnu-make libtool autoconf-2.71 automake pkg-config bison ;; Native GCC 10 toolchain gcc-toolchain-10 (list gcc-toolchain-10 "static") (list gcc "lib") ;; Scripting python-minimal ;; (3.10) perl ;; Git git-minimal ;; Tests python-lief ;; Web curl nss-certs) (let ((target (getenv "HOST"))) (cond ((string-suffix? "-mingw32" target) ;; Windows (list zip + clang-10 (make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32") nsis-x86_64 nss-certs osslsigncode)) ((string-contains target "-linux-") (list clang-10 (make-bitcoin-cross-toolchain target))) ((string-contains target "darwin") (list clang-toolchain-10 binutils xorriso python-signapple)) (else '())))))