diff --git a/cmake/platforms/OSX.cmake b/cmake/platforms/OSX.cmake index 6506b4210..9fa94da5a 100644 --- a/cmake/platforms/OSX.cmake +++ b/cmake/platforms/OSX.cmake @@ -1,57 +1,57 @@ # Copyright (c) 2017 The Bitcoin developers set(CMAKE_SYSTEM_NAME Darwin) set(CMAKE_SYSTEM_PROCESSOR x86_64) set(TOOLCHAIN_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-apple-darwin) # Set Corrosion Rust target set(Rust_CARGO_TARGET "x86_64-apple-darwin") # On OSX, we use clang by default. set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN_PREFIX}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN_PREFIX}) set(OSX_MIN_VERSION 10.15) -# OSX_SDK_VERSION 10.15.6 +# OSX_SDK_VERSION 11.0 # Note: don't use XCODE_VERSION, it's a cmake built-in variable ! -set(SDK_XCODE_VERSION 12.1) -set(SDK_XCODE_BUILD_ID 12A7403) +set(SDK_XCODE_VERSION 12.2) +set(SDK_XCODE_BUILD_ID 12B45b) set(LD64_VERSION 609) # On OSX we use various stuff from Apple's SDK. set(OSX_SDK_PATH "${CMAKE_CURRENT_SOURCE_DIR}/depends/SDKs/Xcode-${SDK_XCODE_VERSION}-${SDK_XCODE_BUILD_ID}-extracted-SDK-with-libcxx-headers") set(CMAKE_OSX_SYSROOT "${OSX_SDK_PATH}") set(CMAKE_OSX_DEPLOYMENT_TARGET ${OSX_MIN_VERSION}) set(CMAKE_OSX_ARCHITECTURES x86_64) # target environment on the build host system # set 1st to dir with the cross compiler's C/C++ headers/libs set(CMAKE_FIND_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/depends/${TOOLCHAIN_PREFIX};${OSX_SDK_PATH}") # We also may have built dependencies for the native plateform. set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/depends/${TOOLCHAIN_PREFIX}/native") # modify default behavior of FIND_XXX() commands to # search for headers/libs in the target environment and # search for programs in the build host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # When cross-compiling for Darwin using Clang, -mlinker-version must be passed # to ensure that modern linker features are enabled. string(APPEND CMAKE_CXX_FLAGS_INIT " -stdlib=libc++ -mlinker-version=${LD64_VERSION}") # Ensure we use an OSX specific version the binary manipulation tools. find_program(CMAKE_AR ${TOOLCHAIN_PREFIX}-ar) find_program(CMAKE_INSTALL_NAME_TOOL ${TOOLCHAIN_PREFIX}-install_name_tool) find_program(CMAKE_LINKER ${TOOLCHAIN_PREFIX}-ld) find_program(CMAKE_NM ${TOOLCHAIN_PREFIX}-nm) find_program(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}-objcopy) find_program(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}-objdump) find_program(CMAKE_OTOOL ${TOOLCHAIN_PREFIX}-otool) find_program(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}-ranlib) find_program(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip) diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index 0abcad587..14783a5bb 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -1,323 +1,323 @@ #!/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 "librt.so.1", # real-time (clock) "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 # 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 == [10, 15, 6] + 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/gitian-build.py b/contrib/gitian-build.py index 4327e769b..86075144b 100755 --- a/contrib/gitian-build.py +++ b/contrib/gitian-build.py @@ -1,616 +1,616 @@ #!/usr/bin/env python3 # Copyright (c) 2019-2020 The Bitcoin developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. import argparse import multiprocessing import os import subprocess import sys def setup(): global args, workdir programs = ["ruby", "git", "apt-cacher-ng", "make", "wget"] if args.kvm: programs += ["python-vm-builder", "qemu-kvm", "qemu-utils"] elif args.docker: dockers = ["docker.io", "docker-ce"] for i in dockers: return_code = subprocess.call(["sudo", "apt-get", "install", "-qq", i]) if return_code == 0: break if return_code != 0: print("Cannot find any way to install docker", file=sys.stderr) exit(1) else: programs += ["lxc", "debootstrap"] subprocess.check_call(["sudo", "apt-get", "install", "-qq"] + programs) if not os.path.isdir("gitian-builder"): subprocess.check_call( ["git", "clone", "https://github.com/devrandom/gitian-builder.git"] ) if not os.path.isdir("bitcoin-abc"): subprocess.check_call( ["git", "clone", "https://github.com/Bitcoin-ABC/bitcoin-abc.git"] ) os.chdir("gitian-builder") make_image_prog = [ "bin/make-base-vm", "--distro", "debian", "--suite", "buster", "--arch", "amd64", ] if args.docker: make_image_prog += ["--docker"] elif not args.kvm: make_image_prog += ["--lxc"] subprocess.check_call(make_image_prog) os.chdir(workdir) if args.is_bionic and not args.kvm and not args.docker: subprocess.check_call( ["sudo", "sed", "-i", "s/lxcbr0/br0/", "/etc/default/lxc-net"] ) print("Reboot is required") exit(0) def build(): global args, workdir base_output_dir = "bitcoin-binaries/" + args.version os.makedirs(base_output_dir + "/src", exist_ok=True) print("\nBuilding Dependencies\n") os.chdir("gitian-builder") os.makedirs("inputs", exist_ok=True) subprocess.check_call( [ "make", "-C", "../bitcoin-abc/depends", "download", "SOURCES_PATH=" + os.getcwd() + "/cache/common", ] ) output_dir_src = "../" + base_output_dir + "/src" if args.linux: print("\nCompiling " + args.version + " Linux") subprocess.check_call( [ "bin/gbuild", "-j", args.jobs, "-m", args.memory, "--commit", "bitcoin=" + args.commit, "--url", "bitcoin=" + args.url, "../bitcoin-abc/contrib/gitian-descriptors/gitian-linux.yml", ] ) subprocess.check_call( [ "bin/gsign", "-p", args.sign_prog, "--signer", args.signer, "--release", args.version + "-linux", "--destination", "../gitian.sigs/", "../bitcoin-abc/contrib/gitian-descriptors/gitian-linux.yml", ] ) output_dir_linux = "../" + base_output_dir + "/linux" os.makedirs(output_dir_linux, exist_ok=True) subprocess.check_call( "mv build/out/bitcoin-*.tar.gz " + output_dir_linux, shell=True ) subprocess.check_call( "mv build/out/src/bitcoin-*.tar.gz " + output_dir_src, shell=True ) subprocess.check_call( "mv result/bitcoin-*-linux-res.yml " + output_dir_linux, shell=True ) if args.windows: print("\nCompiling " + args.version + " Windows") subprocess.check_call( [ "bin/gbuild", "-j", args.jobs, "-m", args.memory, "--commit", "bitcoin=" + args.commit, "--url", "bitcoin=" + args.url, "../bitcoin-abc/contrib/gitian-descriptors/gitian-win.yml", ] ) subprocess.check_call( [ "bin/gsign", "-p", args.sign_prog, "--signer", args.signer, "--release", args.version + "-win-unsigned", "--destination", "../gitian.sigs/", "../bitcoin-abc/contrib/gitian-descriptors/gitian-win.yml", ] ) output_dir_win = "../" + base_output_dir + "/win" os.makedirs(output_dir_win, exist_ok=True) subprocess.check_call( "mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/", shell=True ) subprocess.check_call( "mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe " + output_dir_win, shell=True, ) subprocess.check_call( "mv build/out/src/bitcoin-*.tar.gz " + output_dir_src, shell=True ) subprocess.check_call( "mv result/bitcoin-*-win-res.yml " + output_dir_win, shell=True ) if args.macos: print("\nCompiling " + args.version + " MacOS") subprocess.check_call( [ "bin/gbuild", "-j", args.jobs, "-m", args.memory, "--commit", "bitcoin=" + args.commit, "--url", "bitcoin=" + args.url, "../bitcoin-abc/contrib/gitian-descriptors/gitian-osx.yml", ] ) subprocess.check_call( [ "bin/gsign", "-p", args.sign_prog, "--signer", args.signer, "--release", args.version + "-osx-unsigned", "--destination", "../gitian.sigs/", "../bitcoin-abc/contrib/gitian-descriptors/gitian-osx.yml", ] ) output_dir_osx = "../" + base_output_dir + "/osx" os.makedirs(output_dir_osx, exist_ok=True) subprocess.check_call( "mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/", shell=True ) subprocess.check_call( "mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg " + output_dir_osx, shell=True, ) subprocess.check_call( "mv build/out/src/bitcoin-*.tar.gz " + output_dir_src, shell=True ) subprocess.check_call( "mv result/bitcoin-*-osx-res.yml " + output_dir_osx, shell=True ) os.chdir(workdir) if args.commit_files: print("\nCommitting " + args.version + " Unsigned Sigs\n") os.chdir("gitian.sigs") subprocess.check_call(["git", "add", args.version + "-linux/" + args.signer]) subprocess.check_call( ["git", "add", args.version + "-win-unsigned/" + args.signer] ) subprocess.check_call( ["git", "add", args.version + "-osx-unsigned/" + args.signer] ) subprocess.check_call( [ "git", "commit", "-m", "Add " + args.version + " unsigned sigs for " + args.signer, ] ) os.chdir(workdir) def sign(): global args, workdir os.chdir("gitian-builder") if args.windows: print("\nSigning " + args.version + " Windows") subprocess.check_call( "cp inputs/bitcoin-" + args.version + "-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz", shell=True, ) subprocess.check_call( [ "bin/gbuild", "-i", "--commit", "signature=" + args.commit, "../bitcoin-abc/contrib/gitian-descriptors/gitian-win-signer.yml", ] ) subprocess.check_call( [ "bin/gsign", "-p", args.sign_prog, "--signer", args.signer, "--release", args.version + "-win-signed", "--destination", "../gitian.sigs/", "../bitcoin-abc/contrib/gitian-descriptors/gitian-win-signer.yml", ] ) subprocess.check_call( "mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/" + args.version, shell=True, ) if args.macos: print("\nSigning " + args.version + " MacOS") subprocess.check_call( "cp inputs/bitcoin-" + args.version + "-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz", shell=True, ) subprocess.check_call( [ "bin/gbuild", "-i", "--commit", "signature=" + args.commit, "../bitcoin-abc/contrib/gitian-descriptors/gitian-osx-signer.yml", ] ) subprocess.check_call( [ "bin/gsign", "-p", args.sign_prog, "--signer", args.signer, "--release", args.version + "-osx-signed", "--destination", "../gitian.sigs/", "../bitcoin-abc/contrib/gitian-descriptors/gitian-osx-signer.yml", ] ) subprocess.check_call( "mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/" + args.version + "/bitcoin-" + args.version + "-osx.dmg", shell=True, ) os.chdir(workdir) if args.commit_files: print("\nCommitting " + args.version + " Signed Sigs\n") os.chdir("gitian.sigs") subprocess.check_call( ["git", "add", args.version + "-win-signed/" + args.signer] ) subprocess.check_call( ["git", "add", args.version + "-osx-signed/" + args.signer] ) subprocess.check_call( [ "git", "commit", "-a", "-m", "Add " + args.version + " signed binary sigs for " + args.signer, ] ) os.chdir(workdir) def verify(): global args, workdir os.chdir("gitian-builder") print("\nVerifying v" + args.version + " Linux\n") subprocess.check_call( [ "bin/gverify", "-v", "-d", "../gitian.sigs/", "-r", args.version + "-linux", "../bitcoin-abc/contrib/gitian-descriptors/gitian-linux.yml", ] ) print("\nVerifying v" + args.version + " Windows\n") subprocess.check_call( [ "bin/gverify", "-v", "-d", "../gitian.sigs/", "-r", args.version + "-win-unsigned", "../bitcoin-abc/contrib/gitian-descriptors/gitian-win.yml", ] ) print("\nVerifying v" + args.version + " MacOS\n") subprocess.check_call( [ "bin/gverify", "-v", "-d", "../gitian.sigs/", "-r", args.version + "-osx-unsigned", "../bitcoin-abc/contrib/gitian-descriptors/gitian-osx.yml", ] ) print("\nVerifying v" + args.version + " Signed Windows\n") subprocess.check_call( [ "bin/gverify", "-v", "-d", "../gitian.sigs/", "-r", args.version + "-win-signed", "../bitcoin-abc/contrib/gitian-descriptors/gitian-win-signer.yml", ] ) print("\nVerifying v" + args.version + " Signed MacOS\n") subprocess.check_call( [ "bin/gverify", "-v", "-d", "../gitian.sigs/", "-r", args.version + "-osx-signed", "../bitcoin-abc/contrib/gitian-descriptors/gitian-osx-signer.yml", ] ) os.chdir(workdir) def main(): global args, workdir num_cpus = multiprocessing.cpu_count() parser = argparse.ArgumentParser(usage="%(prog)s [options] signer version") parser.add_argument( "-c", "--commit", action="store_true", dest="commit", help="Indicate that the version argument is for a commit or branch", ) parser.add_argument( "-p", "--pull", action="store_true", dest="pull", help=( "Indicate that the version argument is the number of a github repository" " pull request" ), ) parser.add_argument( "-u", "--url", dest="url", default="https://github.com/Bitcoin-ABC/bitcoin-abc.git", help="Specify the URL of the repository. Default is %(default)s", ) parser.add_argument( "-v", "--verify", action="store_true", dest="verify", help="Verify the Gitian build", ) parser.add_argument( "-b", "--build", action="store_true", dest="build", help="Do a Gitian build" ) parser.add_argument( "-s", "--sign", action="store_true", dest="sign", help="Make signed binaries for Windows and MacOS", ) parser.add_argument( "-B", "--buildsign", action="store_true", dest="buildsign", help="Build both signed and unsigned binaries", ) parser.add_argument( "-o", "--os", dest="os", default="lwm", help=( "Specify which Operating Systems the build is for. Default is %(default)s." " l for Linux, w for Windows, m for MacOS" ), ) parser.add_argument( "-j", "--jobs", dest="jobs", default=str(num_cpus), help="Number of processes to use. Default %(default)s", ) parser.add_argument( "-m", "--memory", dest="memory", default="3500", help="Memory to allocate in MiB. Default %(default)s", ) parser.add_argument( "-k", "--kvm", action="store_true", dest="kvm", help="Use KVM instead of LXC" ) parser.add_argument( "-d", "--docker", action="store_true", dest="docker", help="Use Docker instead of LXC", ) parser.add_argument( "-S", "--setup", action="store_true", dest="setup", help=( "Set up the Gitian building environment. Uses LXC. If you want to use KVM," " use the --kvm option. Only works on Debian-based systems (Ubuntu, Debian)" ), ) parser.add_argument( "-D", "--detach-sign", action="store_true", dest="detach_sign", help="Create the assert file for detached signing. Will not commit anything.", ) parser.add_argument( "-n", "--no-commit", action="store_false", dest="commit_files", help="Do not commit anything to git", ) parser.add_argument("signer", help="GPG signer to sign each build assert file") parser.add_argument( "version", help=( "Version number, commit, or branch to build. If building a commit or" " branch, the -c option must be specified" ), ) args = parser.parse_args() workdir = os.getcwd() args.linux = "l" in args.os args.windows = "w" in args.os args.macos = "m" in args.os args.is_bionic = b"bionic" in subprocess.check_output(["lsb_release", "-cs"]) if args.buildsign: args.build = True args.sign = True if args.kvm and args.docker: raise Exception("Error: cannot have both kvm and docker") args.sign_prog = "true" if args.detach_sign else "gpg --detach-sign" # Set environment variable USE_LXC or USE_DOCKER, let gitian-builder know # that we use lxc or docker if args.docker: os.environ["USE_DOCKER"] = "1" elif not args.kvm: os.environ["USE_LXC"] = "1" if "GITIAN_HOST_IP" not in os.environ.keys(): os.environ["GITIAN_HOST_IP"] = "10.0.3.1" if "LXC_GUEST_IP" not in os.environ.keys(): os.environ["LXC_GUEST_IP"] = "10.0.3.5" # Disable for MacOS if no SDK found if args.macos and not os.path.isfile( - "gitian-builder/inputs/Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz" + "gitian-builder/inputs/Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz" ): print("Cannot build for MacOS, SDK does not exist. Will build for other OSes") args.macos = False script_name = os.path.basename(sys.argv[0]) # Signer and version shouldn't be empty if args.signer == "": print(script_name + ": Missing signer.") print("Try " + script_name + " --help for more information") exit(1) if args.version == "": print(script_name + ": Missing version.") print("Try " + script_name + " --help for more information") exit(1) # Add leading 'v' for tags if args.commit and args.pull: raise Exception("Cannot have both commit and pull") args.commit = ("" if args.commit else "v") + args.version if args.setup: setup() os.chdir("bitcoin-abc") if args.pull: subprocess.check_call( ["git", "fetch", args.url, "refs/pull/" + args.version + "/merge"] ) os.chdir("../gitian-builder/inputs/bitcoin") subprocess.check_call( ["git", "fetch", args.url, "refs/pull/" + args.version + "/merge"] ) args.commit = subprocess.check_output( ["git", "show", "-s", "--format=%H", "FETCH_HEAD"], universal_newlines=True, encoding="utf8", ).strip() args.version = "pull-" + args.version print(args.commit) subprocess.check_call(["git", "fetch"]) subprocess.check_call(["git", "checkout", args.commit]) os.chdir(workdir) if args.build: build() if args.sign: sign() if args.verify: verify() if __name__ == "__main__": main() diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 793663b50..84bf75d04 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,180 +1,180 @@ --- name: "bitcoin-abc-osx" enable_cache: true distro: "debian" suites: - "bullseye" architectures: - "amd64" packages: - "autoconf" - "automake" - "bsdmainutils" - "ca-certificates" - "cmake" - "curl" - "faketime" - "fonts-tuffy" - "g++" - "git" - "libbz2-dev" - "libcap-dev" - "libtinfo5" - "libtool" - "libz-dev" - "ninja-build" - "pkg-config" - "python3" - "python3-dev" - "python3-pip" - "python3-setuptools" - "xorriso" remotes: - "url": "https://github.com/Bitcoin-ABC/bitcoin-abc.git" "dir": "bitcoin" files: -- "Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz" +- "Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz" script: | WRAP_DIR=$HOME/wrapped HOSTS=( x86_64-apple-darwin ) # CMake toolchain file name differ from host name declare -A CMAKE_TOOLCHAIN_FILE CMAKE_TOOLCHAIN_FILE[x86_64-apple-darwin]=OSX.cmake FAKETIME_HOST_PROGS="" FAKETIME_PROGS="ar ranlib date xorrisofs" export TZ="UTC" export BUILD_DIR=`pwd` mkdir -p ${WRAP_DIR} if test -n "$GBUILD_CACHE_ENABLED"; then export SOURCES_PATH=${GBUILD_COMMON_CACHE} export BASE_CACHE=${GBUILD_PACKAGE_CACHE} mkdir -p ${BASE_CACHE} ${SOURCES_PATH} fi export ZERO_AR_DATE=1 function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done } function create_per-host_faketime_wrappers { for i in ${HOSTS[@]}; do for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done } pip3 install lief==0.11.5 # Faketime for depends so intermediate results are comparable export PATH_orig=${PATH} create_global_faketime_wrappers "2000-01-01 12:00:00" create_per-host_faketime_wrappers "2000-01-01 12:00:00" export PATH=${WRAP_DIR}:${PATH} cd bitcoin SOURCEDIR=`pwd` BASEPREFIX=`pwd`/depends mkdir -p ${BASEPREFIX}/SDKs - tar -C ${BASEPREFIX}/SDKs -xf ${BUILD_DIR}/Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz + tar -C ${BASEPREFIX}/SDKs -xf ${BUILD_DIR}/Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz # Build dependencies for each host for i in ${HOSTS[@]}; do make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done # Faketime for binaries export PATH=${PATH_orig} create_global_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" export PATH=${WRAP_DIR}:${PATH} mkdir -p source_package pushd source_package # Any toolchain file will work for building the source package, just pick the # first one cmake -GNinja .. \ -DCMAKE_TOOLCHAIN_FILE=${SOURCEDIR}/cmake/platforms/${CMAKE_TOOLCHAIN_FILE[${HOSTS[0]}]} ninja package_source SOURCEDIST=`echo bitcoin-abc-*.tar.gz` mv ${SOURCEDIST} .. popd DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` # Correct tar file order mkdir -p temp pushd temp tar -xf ../$SOURCEDIST find bitcoin-abc-* | sort | tar --mtime="${REFERENCE_DATETIME}" --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS[@]}; do export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} mkdir -p distsrc-${i} cd distsrc-${i} INSTALLPATH=`pwd`/installed/${DISTNAME} mkdir -p ${INSTALLPATH} cmake -GNinja .. \ -DCMAKE_TOOLCHAIN_FILE=${SOURCEDIR}/cmake/platforms/${CMAKE_TOOLCHAIN_FILE[${i}]} \ -DCLIENT_VERSION_IS_RELEASE=ON \ -DENABLE_CLANG_TIDY=OFF \ -DENABLE_REDUCE_EXPORTS=ON \ -DCMAKE_INSTALL_PREFIX=${INSTALLPATH} \ -DCCACHE=OFF \ -DXORRISOFS_EXECUTABLE="${WRAP_DIR}/xorrisofs" ninja ninja security-check ninja symbol-check ninja install/strip export PYTHONPATH="${BASEPREFIX}/${i}/native/lib/python3/dist-packages:${PYTHONPATH}" ninja osx-deploydir OSX_VOLNAME="$(cat osx_volname)" mkdir -p unsigned-app-${i} cp osx_volname unsigned-app-${i}/ cp ../contrib/macdeploy/detached-sig-apply.sh unsigned-app-${i} cp ../contrib/macdeploy/detached-sig-create.sh unsigned-app-${i} cp ${BASEPREFIX}/${i}/native/bin/${i}-codesign_allocate unsigned-app-${i}/codesign_allocate cp ${BASEPREFIX}/${i}/native/bin/${i}-pagestuff unsigned-app-${i}/pagestuff mv dist unsigned-app-${i} pushd unsigned-app-${i} find . | sort | tar --mtime="${REFERENCE_DATETIME}" --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz popd ninja osx-dmg mv "${OSX_VOLNAME}.dmg" ${OUTDIR}/${DISTNAME}-osx-unsigned.dmg cd installed find -path "*.app*" -type f -executable -exec mv {} ${DISTNAME}/bin/bitcoin-qt \; find ${DISTNAME} -not -path "*.app*" | sort | tar --mtime="${REFERENCE_DATETIME}" --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz cd ../../ done mkdir -p $OUTDIR/src mv $SOURCEDIST $OUTDIR/src mv ${OUTDIR}/${DISTNAME}-x86_64-*.tar.gz ${OUTDIR}/${DISTNAME}-osx64.tar.gz diff --git a/contrib/guix/README.md b/contrib/guix/README.md index 7e31fcddb..c9e22e5df 100644 --- a/contrib/guix/README.md +++ b/contrib/guix/README.md @@ -1,382 +1,382 @@ # Bootstrappable Bitcoin ABC Builds This directory contains the files necessary to perform bootstrappable Bitcoin ABC builds. [Bootstrappability][b17e] furthers our binary security guarantees by allowing us to _audit and reproduce_ our toolchain instead of blindly _trusting_ binary downloads. We achieve bootstrappability by using Guix as a functional package manager. # Requirements Conservatively, you will need an x86_64 machine with: - 16GB of free disk space on the partition that /gnu/store will reside in - 8GB of free disk space **per platform triple** you're planning on building (see the `HOSTS` [environment variable description][env-vars-list]) # Installation and Setup If you don't have Guix installed and set up, please follow the instructions in [INSTALL.md](./INSTALL.md) # Usage If you haven't considered your security model yet, please read [the relevant section](#choosing-your-security-model) before proceeding to perform a build. ## Making the Xcode SDK available for macOS cross-compilation In order to perform a build for macOS (which is included in the default set of platform triples to build), you'll need to extract the macOS SDK tarball using tools found in the [`macdeploy` directory](../macdeploy/README.md). You can then either point to the SDK using the `SDK_PATH` environment variable: ```sh # Extract the SDK tarball to /path/to/parent/dir/of/extracted/SDK/Xcode---extracted-SDK-with-libcxx-headers tar -C /path/to/parent/dir/of/extracted/SDK -xaf /path/to/Xcode---extracted-SDK-with-libcxx-headers.tar.gz # Indicate where to locate the SDK tarball export SDK_PATH=/path/to/parent/dir/of/extracted/SDK ``` or extract it into `depends/SDKs`: ```sh mkdir -p depends/SDKs tar -C depends/SDKs -xaf /path/to/SDK/tarball ``` ## Building *The author highly recommends at least reading over the [common usage patterns and examples](#common-guix-build-invocation-patterns-and-examples) section below before starting a build. For a full list of customization options, see the [recognized environment variables][env-vars-list] section.* To build Bitcoin ABC reproducibly with all default options, invoke the following from the top of a clean repository: ```sh ./contrib/guix/guix-build ``` ## Cleaning intermediate work directories By default, `guix-build` leaves all intermediate files or "work directories" (e.g. `depends/work`, `guix-build-*/distsrc-*`) intact at the end of a build so that they are available to the user (to aid in debugging, etc.). However, these directories usually take up a large amount of disk space. Therefore, a `guix-clean` convenience script is provided which cleans the current `git` worktree to save disk space: ``` ./contrib/guix/guix-clean ``` ## Common `guix-build` invocation patterns and examples ### Keeping caches and SDKs outside of the worktree If you perform a lot of builds and have a bunch of worktrees, you may find it more efficient to keep the depends tree's download cache, build cache, and SDKs outside of the worktrees to avoid duplicate downloads and unnecessary builds. To help with this situation, the `guix-build` script honours the `SOURCES_PATH`, `BASE_CACHE`, and `SDK_PATH` environment variables and will pass them on to the depends tree so that you can do something like: ```sh env SOURCES_PATH="$HOME/depends-SOURCES_PATH" BASE_CACHE="$HOME/depends-BASE_CACHE" SDK_PATH="$HOME/macOS-SDKs" ./contrib/guix/guix-build ``` Note that the paths that these environment variables point to **must be directories**, and **NOT symlinks to directories**. See the [recognized environment variables][env-vars-list] section for more details. ### Building a subset of platform triples Sometimes you only want to build a subset of the supported platform triples, in which case you can override the default list by setting the space-separated `HOSTS` environment variable: ```sh env HOSTS='x86_64-w64-mingw32 x86_64-apple-darwin' ./contrib/guix/guix-build ``` See the [recognized environment variables][env-vars-list] section for more details. ### Controlling the number of threads used by `guix` build commands Depending on your system's RAM capacity, you may want to decrease the number of threads used to decrease RAM usage or vice versa. By default, the scripts under `./contrib/guix` will invoke all `guix` build commands with `--cores="$JOBS"`. Note that `$JOBS` defaults to `$(nproc)` if not specified. However, astute manual readers will also notice that `guix` build commands also accept a `--max-jobs=` flag (which defaults to 1 if unspecified). Here is the difference between `--cores=` and `--max-jobs=`: > Note: When I say "derivation," think "package" `--cores=` - controls the number of CPU cores to build each derivation. This is the value passed to `make`'s `--jobs=` flag. `--max-jobs=` - controls how many derivations can be built in parallel - defaults to 1 Therefore, the default is for `guix` build commands to build one derivation at a time, utilizing `$JOBS` threads. Specifying the `$JOBS` environment variable will only modify `--cores=`, but you can also modify the value for `--max-jobs=` by specifying `$ADDITIONAL_GUIX_COMMON_FLAGS`. For example, if you have a LOT of memory, you may want to set: ```sh export ADDITIONAL_GUIX_COMMON_FLAGS='--max-jobs=8' ``` Which allows for a maximum of 8 derivations to be built at the same time, each utilizing `$JOBS` threads. Or, if you'd like to avoid spurious build failures caused by issues with parallelism within a single package, but would still like to build multiple packages when the dependency graph allows for it, you may want to try: ```sh export JOBS=1 ADDITIONAL_GUIX_COMMON_FLAGS='--max-jobs=8' ``` See the [recognized environment variables][env-vars-list] section for more details. ## Recognized environment variables * _**HOSTS**_ Override the space-separated list of platform triples for which to perform a bootstrappable build. _(defaults to "x86\_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu x86\_64-w64-mingw32 x86\_64-apple-darwin")_ * _**SOURCES_PATH**_ Set the depends tree download cache for sources. This is passed through to the depends tree. Setting this to the same directory across multiple builds of the depends tree can eliminate unnecessary redownloading of package sources. The path that this environment variable points to **must be a directory**, and **NOT a symlink to a directory**. * _**BASE_CACHE**_ Set the depends tree cache for built packages. This is passed through to the depends tree. Setting this to the same directory across multiple builds of the depends tree can eliminate unnecessary building of packages. The path that this environment variable points to **must be a directory**, and **NOT a symlink to a directory**. * _**SDK_PATH**_ Set the path where _extracted_ SDKs can be found. This is passed through to the depends tree. Note that this is should be set to the _parent_ directory of the actual SDK (e.g. `SDK_PATH=$HOME/Downloads/macOS-SDKs` instead of - `$HOME/Downloads/macOS-SDKs/Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers`). + `$HOME/Downloads/macOS-SDKs/Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers`). The path that this environment variable points to **must be a directory**, and **NOT a symlink to a directory**. * _**JOBS**_ Override the number of jobs to run simultaneously, you might want to do so on a memory-limited machine. This may be passed to: - `guix` build commands as in `guix environment --cores="$JOBS"` - `make` as in `make --jobs="$JOBS"` - `xargs` as in `xargs -P"$JOBS"` See [here](#controlling-the-number-of-threads-used-by-guix-build-commands) for more details. _(defaults to the value of `nproc` outside the container)_ * _**SOURCE_DATE_EPOCH**_ Override the reference UNIX timestamp used for bit-for-bit reproducibility, the variable name conforms to [standard][r12e/source-date-epoch]. _(defaults to the output of `$(git log --format=%at -1)`)_ * _**V**_ If non-empty, will pass `V=1` to all `make` invocations, making `make` output verbose. Note that any given value is ignored. The variable is only checked for emptiness. More concretely, this means that `V=` (setting `V` to the empty string) is interpreted the same way as not setting `V` at all, and that `V=0` has the same effect as `V=1`. * _**SUBSTITUTE_URLS**_ A whitespace-delimited list of URLs from which to download pre-built packages. A URL is only used if its signing key is authorized (refer to the [substitute servers section](#option-1-building-with-substitutes) for more details). * _**ADDITIONAL_GUIX_COMMON_FLAGS**_ Additional flags to be passed to all `guix` commands. * _**ADDITIONAL_GUIX_TIMEMACHINE_FLAGS**_ Additional flags to be passed to `guix time-machine`. * _**ADDITIONAL_GUIX_ENVIRONMENT_FLAGS**_ Additional flags to be passed to the invocation of `guix environment` inside `guix time-machine`. # Choosing your security model No matter how you installed Guix, you need to decide on your security model for building packages with Guix. Guix allows us to achieve better binary security by using our CPU time to build everything from scratch. However, it doesn't sacrifice user choice in pursuit of this: users can decide whether or not to use **substitutes** (pre-built packages). ## Option 1: Building with substitutes ### Step 1: Authorize the signing keys Depending on the installation procedure you followed, you may have already authorized the Guix build farm key. In particular, the official shell installer script asks you if you want the key installed, and the debian distribution package authorized the key during installation. You can check the current list of authorized keys at `/etc/guix/acl`. At the time of writing, a `/etc/guix/acl` with just the Guix build farm key authorized looks something like: ```lisp (acl (entry (public-key (ecc (curve Ed25519) (q #8D156F295D24B0D9A86FA5741A840FF2D24F60F7B6C4134814AD55625971B394#) ) ) (tag (guix import) ) ) ) ``` If you've determined that the official Guix build farm key hasn't been authorized, and you would like to authorize it, run the following as root: ``` guix archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub ``` If `/var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub` doesn't exist, try: ```sh guix archive --authorize < /share/guix/ci.guix.gnu.org.pub ``` Where `` is likely: - `/usr` if you installed from a distribution package - `/usr/local` if you installed Guix from source and didn't supply any prefix-modifying flags to Guix's `./configure` For dongcarl's substitute server at https://guix.carldong.io, run as root: ```sh wget -qO- 'https://guix.carldong.io/signing-key.pub' | guix archive --authorize ``` #### Removing authorized keys To remove previously authorized keys, simply edit `/etc/guix/acl` and remove the `(entry (public-key ...))` entry. ### Step 2: Specify the substitute servers Once its key is authorized, the official Guix build farm at https://ci.guix.gnu.org is automatically used unless the `--no-substitutes` flag is supplied. This default list of substitute servers is overridable both on a `guix-daemon` level and when you invoke `guix` commands. See examples below for the various ways of adding dongcarl's substitute server after having [authorized his signing key](#step-1-authorize-the-signing-keys). Change the **default list** of substitute servers by starting `guix-daemon` with the `--substitute-urls` option (you will likely need to edit your init script): ```sh guix-daemon --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org' ``` Override the default list of substitute servers by passing the `--substitute-urls` option for invocations of `guix` commands: ```sh guix --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org' ``` For scripts under `./contrib/guix`, set the `SUBSTITUTE_URLS` environment variable: ```sh export SUBSTITUTE_URLS='https://guix.carldong.io https://ci.guix.gnu.org' ``` ## Option 2: Disabling substitutes on an ad-hoc basis If you prefer not to use any substitutes, make sure to supply `--no-substitutes` like in the following snippet. The first build will take a while, but the resulting packages will be cached for future builds. For direct invocations of `guix`: ```sh guix --no-substitutes ``` For the scripts under `./contrib/guix/`: ```sh export ADDITIONAL_GUIX_COMMON_FLAGS='--no-substitutes' ``` ## Option 3: Disabling substitutes by default `guix-daemon` accepts a `--no-substitutes` flag, which will make sure that, unless otherwise overridden by a command line invocation, no substitutes will be used. If you start `guix-daemon` using an init script, you can edit said script to supply this flag. [b17e]: https://bootstrappable.org/ [r12e/source-date-epoch]: https://reproducible-builds.org/docs/source-date-epoch/ [env-vars-list]: #recognized-environment-variables diff --git a/contrib/macdeploy/README.md b/contrib/macdeploy/README.md index 8dc045991..30fd59024 100644 --- a/contrib/macdeploy/README.md +++ b/contrib/macdeploy/README.md @@ -1,110 +1,105 @@ # MacOS Deployment The `macdeployqtplus.py` script should not be run manually. Instead, after building as usual: ```bash ninja osx-dmg ``` When complete, it will have produced `Bitcoin-ABC.dmg`. ## SDK Extraction ### Step 1: Obtaining `Xcode.app` +A free Apple Developer Account is required to proceed. + Our current macOS SDK -(`Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz`) can be +(`Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz`) can be extracted from -[Xcode_12.1.xip](https://download.developer.apple.com/Developer_Tools/Xcode_12.1/Xcode_12.1.xip). -An Apple ID is needed to download this. +[Xcode_12.2.xip](https://download.developer.apple.com/Developer_Tools/Xcode_12.2/Xcode_12.2.xip). +Alternatively, after logging in to your account go to 'Downloads', then 'More' +and search for [`Xcode_12.2`](https://developer.apple.com/download/all/?q=Xcode%2012.2). +An Apple ID and cookies enabled for the hostname are needed to download this. +The `sha256sum` of the archive should be `28d352f8c14a43d9b8a082ac6338dc173cb153f964c6e8fb6ba389e5be528bd0`. After Xcode version 7.x, Apple started shipping the `Xcode.app` in a `.xip` archive. This makes the SDK less-trivial to extract on non-macOS machines. One approach (tested on Debian Buster) is outlined below: ```bash # Install/clone tools needed for extracting Xcode.app apt install cpio -# Unpack Xcode_12.1.xip and place the resulting Xcode.app in your current +# Unpack Xcode_12.2.xip and place the resulting Xcode.app in your current # working directory -python3 contrib/apple-sdk-tools/extract_xcode.py -f Xcode_12.1.xip | cpio -d -i +python3 contrib/apple-sdk-tools/extract_xcode.py -f Xcode_12.2.xip | cpio -d -i ``` On macOS the process is more straightforward: ```bash -xip -x Xcode_12.1.xip +xip -x Xcode_12.2.xip ``` -### Step 2: Generating `Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz` from `Xcode.app` +### Step 2: Generating `Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz` from `Xcode.app` -To generate `Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz`, run +To generate `Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz`, run the script [`gen-sdk`](./gen-sdk) with the path to `Xcode.app` (extracted in the previous stage) as the first argument. ```bash -# Generate a Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz from +# Generate a Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz from # the supplied Xcode.app ./contrib/macdeploy/gen-sdk '/path/to/Xcode.app' ``` ## Deterministic macOS DMG Notes Working macOS DMGs are created in Linux by combining a recent `clang`, the Apple `binutils` (`ld`, `ar`, etc) and DMG authoring tools. Apple uses `clang` extensively for development and has upstreamed the necessary functionality so that a vanilla clang can take advantage. It supports the use of `-F`, `-target`, `-mmacosx-version-min`, and `-isysroot`, which are all necessary when building for macOS. Apple's version of `binutils` (called `cctools`) contains lots of functionality missing in the FSF's `binutils`. In addition to extra linker options for frameworks and sysroots, several other tools are needed as well such as `install_name_tool`, `lipo`, and `nmedit`. These do not build under Linux, so they have been patched to do so. The work here was used as a starting point: [mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4). In order to build a working toolchain, the following source packages are needed from Apple: `cctools`, `dyld`, and `ld64`. These tools inject timestamps by default, which produce non-deterministic binaries. The `ZERO_AR_DATE` environment variable is used to disable that. This version of `cctools` has been patched to use the current version of `clang`'s headers and its `libLTO.so` rather than those from `llvmgcc`, as it was originally done in `toolchain4`. To complicate things further, all builds must target an Apple SDK. These SDKs are free to -download, but not redistributable. To obtain it, register for an Apple Developer Account, -then download [Xcode_11.3.1](https://download.developer.apple.com/Developer_Tools/Xcode_11.3.1/Xcode_11.3.1.xip). - -This file is many gigabytes in size, but most (but not all) of what we need is -contained only in a single directory: - -```bash -Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -``` - -See the SDK Extraction notes above for how to obtain it. +download, but not redistributable. See the SDK Extraction notes above for how to obtain it. The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries which are created using these tools. The build process has been designed to avoid including the SDK's files in Gitian's outputs. All interim tarballs are fully deterministic and may be freely redistributed. [`xorrisofs`](https://www.gnu.org/software/xorriso/) is used to create the DMG. A background image is added to DMG files by inserting a `.DS_Store` during creation. As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a requirement in order to satisfy the new Gatekeeper requirements. Because this private key cannot be shared, we'll have to be a bit creative in order for the build process to remain somewhat deterministic. Here's how it works: - Builders use Gitian to create an unsigned release. This outputs an unsigned DMG which users may choose to bless and run. It also outputs an unsigned app structure in the form of a tarball, which also contains all of the tools that have been previously (deterministically) built in order to create a final DMG. - The Apple keyholder uses this unsigned app to create a detached signature, using the script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs). - Builders feed the unsigned app + detached signature back into Gitian. It uses the pre-built tools to recombine the pieces into a deterministic DMG. diff --git a/contrib/teamcity/download-apple-sdk.sh b/contrib/teamcity/download-apple-sdk.sh index c2a28b088..314f9c0cb 100755 --- a/contrib/teamcity/download-apple-sdk.sh +++ b/contrib/teamcity/download-apple-sdk.sh @@ -1,35 +1,35 @@ #!/usr/bin/env bash export LC_ALL=C set -euxo pipefail : "${SDK_DL_REMOTE:=}" usage() { echo "Usage: download-apple-sdk.sh dest_dir" echo "The SDK_DL_REMOTE environment variable should be set to a URL pointing to the folder containing the SDK archive, with no trailing /." echo "Output: prints the SDK file name" } if [ -z "${SDK_DL_REMOTE}" ] || [ $# -ne 1 ]; then usage exit 1 fi DEST_DIR="$1" : "${TOPLEVEL:=$(git rev-parse --show-toplevel)}" -OSX_SDK="Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz" -OSX_SDK_SHA256="12bd3827817f0c6b305e77140f440864eab29077e0b77b6627030e241dce76a4" +OSX_SDK="Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz" +OSX_SDK_SHA256="5b7e65304bb9abcc2cffc8bc4dd68b8f7e318dce85c195bea77c59600e777bd3" pushd "${DEST_DIR}" > /dev/null if ! echo "${OSX_SDK_SHA256} ${OSX_SDK}" | sha256sum --quiet -c > /dev/null 2>&1; then rm -f "${OSX_SDK}" wget -q "${SDK_DL_REMOTE}/${OSX_SDK}" echo "${OSX_SDK_SHA256} ${OSX_SDK}" | sha256sum --quiet -c fi popd > /dev/null echo "${OSX_SDK}" diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index ea92bb779..6bf30b499 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,121 +1,121 @@ OSX_MIN_VERSION=10.15 -OSX_SDK_VERSION=10.15.6 -XCODE_VERSION=12.1 -XCODE_BUILD_ID=12A7403 +OSX_SDK_VERSION=11.0 +XCODE_VERSION=12.2 +XCODE_BUILD_ID=12B45b LD64_VERSION=609 OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-libcxx-headers darwin_native_binutils=native_cctools ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),) # FORCE_USE_SYSTEM_CLANG is empty, so we use our depends-managed, pinned clang # from llvm.org # Clang is a dependency of native_cctools when FORCE_USE_SYSTEM_CLANG is empty darwin_native_toolchain=native_cctools clang_prog=$(build_prefix)/bin/clang clangxx_prog=$(clang_prog)++ clang_resource_dir=$(build_prefix)/lib/clang/$(native_clang_version) else # FORCE_USE_SYSTEM_CLANG is non-empty, so we use the clang from the user's # system darwin_native_toolchain= # We can't just use $(shell command -v clang) because GNU Make handles builtins # in a special way and doesn't know that `command` is a POSIX-standard builtin # prior to 1af314465e5dfe3e8baa839a32a72e83c04f26ef, first released in v4.2.90. # At the time of writing, GNU Make v4.2.1 is still being used in supported # distro releases. # # Source: https://lists.gnu.org/archive/html/bug-make/2017-11/msg00017.html clang_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang") clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++") clang_resource_dir=$(shell clang -print-resource-dir) endif cctools_TOOLS=AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL # Make-only lowercase function lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1)))))))))))))))))))))))))) # For well-known tools provided by cctools, make sure that their well-known # variable is set to the full path of the tool, just like how AC_PATH_{TOO,PROG} # would. $(foreach TOOL,$(cctools_TOOLS),$(eval darwin_$(TOOL) = $$(build_prefix)/bin/$$(host)-$(call lc,$(TOOL)))) # Flag explanations: # # -mlinker-version # # Ensures that modern linker features are enabled. See here for more # details: https://github.com/bitcoin/bitcoin/pull/19407. # # -B$(build_prefix)/bin # # Explicitly point to our binaries (e.g. cctools) so that they are # ensured to be found and preferred over other possibilities. # # -stdlib=libc++ -stdlib++-isystem$(OSX_SDK)/usr/include/c++/v1 # # Forces clang to use the libc++ headers from our SDK and completely # forget about the libc++ headers from the standard directories # # -Xclang -*system \ # -Xclang -*system \ # -Xclang -*system ... # # Adds path_a, path_b, and path_c to the bottom of clang's list of # include search paths. This is used to explicitly specify the list of # system include search paths and its ordering, rather than rely on # clang's autodetection routine. This routine has been shown to: # 1. Fail to pickup libc++ headers in $SYSROOT/usr/include/c++/v1 # when clang was built manually (see: https://github.com/bitcoin/bitcoin/pull/17919#issuecomment-656785034) # 2. Fail to pickup C headers in $SYSROOT/usr/include when # C_INCLUDE_DIRS was specified at configure time (see: https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9) # # Talking directly to cc1 with -Xclang here grants us access to specify # more granular categories for these system include search paths, and we # can use the correct categories that these search paths would have been # placed in if the autodetection routine had worked correctly. (see: # https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9#the-treatment) # # Furthermore, it places these search paths after any "non-Xclang" # specified search paths. This prevents any additional clang options or # environment variables from coming after or in between these system # include search paths, as that would be wrong in general but would also # break #include_next's. # darwin_CC=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \ -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \ -u LIBRARY_PATH \ $(clang_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \ -B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \ -isysroot$(OSX_SDK) \ -Xclang -internal-externc-isystem$(clang_resource_dir)/include \ -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include darwin_CXX=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \ -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \ -u LIBRARY_PATH \ $(clangxx_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \ -B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \ -isysroot$(OSX_SDK) \ -stdlib=libc++ \ -stdlib++-isystem$(OSX_SDK)/usr/include/c++/v1 \ -Xclang -internal-externc-isystem$(clang_resource_dir)/include \ -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include darwin_CFLAGS=-pipe darwin_CXXFLAGS=$(darwin_CFLAGS) darwin_release_CFLAGS=-O2 darwin_release_CXXFLAGS=$(darwin_release_CFLAGS) darwin_debug_CFLAGS=-O1 darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS) darwin_cmake_system=Darwin diff --git a/doc/gitian-building/gitian-building-mac-os-sdk.md b/doc/gitian-building/gitian-building-mac-os-sdk.md index be4ad3fbb..877670007 100644 --- a/doc/gitian-building/gitian-building-mac-os-sdk.md +++ b/doc/gitian-building/gitian-building-mac-os-sdk.md @@ -1,29 +1,29 @@ Gitian building Mac OS SDK ========================== On the host machine, register for a free Apple [developer account](https://developer.apple.com/register/), then download the SDK [here](https://download.developer.apple.com/Developer_Tools/Xcode_12.1/Xcode_12.1.xip). Extract the SDK --------------- Follow [these instructions](../../contrib/macdeploy/README.md#SDK-Extraction) to extract the SDK archive from the download. Copy SDK to Gitian VM: ---------------------- Copy it to the Gitian VM and clean up, e.g.: ```bash -scp Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz gitian: -rm Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz +scp Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz gitian: +rm Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz ``` Login to the VM and: ```bash mkdir -p gitian-builder/inputs -mv Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers.tar.gz gitian-builder/inputs +mv Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz gitian-builder/inputs ``` Troubleshooting --------------- See [README_osx.md](https://github.com/Bitcoin-ABC/bitcoin-abc/blob/master/doc/README_osx.md) for troubleshooting tips.