# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. @template def noset_check_header( header, language="C++", flags=None, includes=None, when=None, onerror=lambda: None ): if when is None: when = always if includes: includes = includes[:] else: includes = [] includes.append(header) return try_compile( includes=includes, language=language, flags=flags, check_msg="for %s" % header, when=when, onerror=onerror, ) @template def check_symbol_exists( symbol, header, language="C", flags=None, includes=None, when=None, onerror=lambda: None, ): if when is None: when = always if includes: includes = includes[:] else: includes = [] includes.append("stdio.h") if isinstance(header, str): header = [header] includes.extend(header) body = """#ifndef %s (void) %s; #endif """ % ( symbol, symbol, ) return try_compile( includes, body, language=language, flags=flags, check_msg="for %s" % symbol, when=when, onerror=onerror, ) with only_when("--enable-compile-environment"): option( "--with-system-librnp", help="Use system RNP (librnp) for OpenPGP support.", ) @depends("--with-system-librnp") def in_tree_librnp(system_librnp): if system_librnp: log.info("System librnp will be used at runtime.") return False return True set_config("MZLA_LIBRNP", depends_if(in_tree_librnp)(lambda _: True)) set_define("MZLA_LIBRNP", depends_if(in_tree_librnp)(lambda _: True)) with only_when(in_tree_librnp): # JSON-C --with-system-json system_lib_option( "--with-system-jsonc", help="Use system JSON-C for librnp (located with pkgconfig)", ) jsonc_pkg = pkg_check_modules("MZLA_JSONC", "json-c >= 0.11", when="--with-system-jsonc") set_config("MZLA_SYSTEM_JSONC", depends_if(jsonc_pkg)(lambda _: True)) @depends("--with-system-jsonc") def in_tree_jsonc(system_jsonc): if not system_jsonc: return True # Bzip2 --with-system-bz2 system_lib_option( "--with-system-bz2", nargs="?", help="Use system Bzip2 for librnp (pkgconfig/given prefix)", ) set_config("MZLA_SYSTEM_BZIP2", True, when="--with-system-bz2") # Bzip2 does not include a pkgconfig file, but some Linux distributions add one bzip2_pkg = pkg_check_modules( "MZLA_BZIP2", "bzip2 >= 1.0.6", when="--with-system-bz2", allow_missing=True, config=False, ) @depends_if("--with-system-bz2", bzip2_pkg) def bzip2_flags(value, bzip2_pkg): if len(value): # A path (eg. /usr/local was given) return namespace( cflags=("-I%s/include" % value[0],), ldflags=("-L%s/lib" % value[0], "-lbz2"), ) if bzip2_pkg: cflags = list(bzip2_pkg.cflags) libs = bzip2_pkg.libs return namespace( cflags=cflags, ldflags=libs, ) # Fallback return namespace( ldflags=["-lbz2"], ) with only_when("--with-system-bz2"): check_symbol( "BZ2_bzread", flags=bzip2_flags.ldflags, onerror=lambda: die("--with-system-bz2 requested but symbol " "BZ2_bzread not found."), ) c_compiler.try_compile( includes=[ "stdio.h", "sys/types.h", "bzlib.h", ], body=""" #ifndef _BZLIB_H #error _BZLIB_H bzlib.h not found #endif """, flags=bzip2_flags.cflags, check_msg="for bzlib.h", onerror=lambda: die("bzlib.h header not found"), ) set_config("MZLA_BZIP2_CFLAGS", bzip2_flags.cflags) set_config("MZLA_BZIP2_LIBS", bzip2_flags.ldflags) # librnp crypto backend selection @depends(target_has_linux_kernel) def librnp_backend_choices(is_linux): if is_linux: return ("botan", "openssl") else: return ("botan",) option( "--with-librnp-backend", help="Build librnp with the selected backend", choices=librnp_backend_choices, nargs=1, default="botan", ) @depends("--with-librnp-backend") def librnp_backend(backend): if backend: return backend[0] set_config("MZLA_LIBRNP_BACKEND", librnp_backend) @depends(librnp_backend) def rnp_botan(backend): return backend == "botan" @depends(librnp_backend) def rnp_openssl(backend): return backend == "openssl" # Botan backend (--with-system-botan) with only_when(rnp_botan): system_lib_option( "--with-system-botan", help="Use system Botan for librnp (located with pkgconfig)", ) botan_pkg = pkg_check_modules("MZLA_BOTAN", "botan-2 >= 2.8.0", when="--with-system-botan") set_config("MZLA_SYSTEM_BOTAN", depends_if(botan_pkg)(lambda _: True)) # OpenSSL backend with only_when(rnp_openssl): option( "--with-openssl", nargs=1, help="OpenSSL library prefix (when not found by pkgconfig)", ) openssl_pkg = pkg_check_modules( "MZLA_LIBRNP_OPENSSL", "openssl >= 1.1.1e", allow_missing=True, config=False ) @depends_if("--with-openssl", openssl_pkg) @imports(_from="os.path", _import="isdir") @imports(_from="os.path", _import="join") def openssl_flags(openssl_prefix, openssl_pkg): if openssl_prefix: openssl_prefix = openssl_prefix[0] include = join(openssl_prefix, "include") lib = join(openssl_prefix, "lib") if not isdir(lib): lib = join(openssl_prefix, "lib64") if isdir(include) and isdir(lib): log.info(f"Using OpenSSL at {openssl_prefix}.") return namespace( cflags=(f"-I{include}",), ldflags=(f"-L{lib}", "-lssl", "-lcrypto"), ) if openssl_pkg: return namespace( cflags=openssl_pkg.cflags, ldflags=openssl_pkg.libs, ) set_config("MZLA_LIBRNP_OPENSSL_CFLAGS", openssl_flags.cflags) set_config("MZLA_LIBRNP_OPENSSL_LIBS", openssl_flags.ldflags) @depends(configure_cache, c_compiler, openssl_flags) @imports(_from="textwrap", _import="dedent") @imports(_from="__builtin__", _import="chr") def openssl_version(configure_cache, compiler, openssl_flags): log.info("Checking for OpenSSL >= 1.1.1e") if openssl_flags is None: die("OpenSSL not found. Must be locatable with pkg-config or use --with-openssl.") def ossl_hexver(hex_str): # See opensshlv.h for description of OPENSSL_VERSION_NUMBER MIN_OSSL_VER = 0x1010105F # Version 1.1.1e ver_as_int = int(hex_str[:-1], 16) ossl_major = (ver_as_int & 0xF0000000) >> 28 ossl_minor = (ver_as_int & 0x0FF00000) >> 20 ossl_fix = (ver_as_int & 0x000FF000) >> 12 # as a letter a-z ossl_patch = chr(96 + ((ver_as_int & 0x00000FF0) >> 4)) ver_as_str = f"{ossl_major}.{ossl_minor}.{ossl_fix}{ossl_patch}" if ver_as_int < MIN_OSSL_VER: die(f"OpenSSL version {ver_as_str} is too old.") return ver_as_str check = dedent( """\ #include #ifdef OPENSSL_VERSION_STR OPENSSL_VERSION_STR #elif defined(OPENSSL_VERSION_NUMBER) OPENSSL_VERSION_NUMBER #else #error Unable to determine OpenSSL version. #endif """ ) result = try_preprocess( configure_cache, compiler.wrapper + [compiler.compiler] + compiler.flags + list(openssl_flags.cflags), "C", check, ) if result: openssl_ver = result.splitlines()[-1] if openssl_ver.startswith("0x"): # OpenSSL 1.x.x - like 0x1010107fL openssl_ver = ossl_hexver(openssl_ver) else: # OpenSSL 3.x.x - quoted version like "3.0.7" openssl_ver = openssl_ver.replace('"', "") major_version = openssl_ver.split(".")[0] if major_version != "3": die( "Unrecognized OpenSSL version {openssl_version} found. Require >= 1.1.1e or 3.x.x" ) log.info(f"Found OpenSSL {openssl_ver}.") return openssl_ver set_config("MZLA_LIBRNP_OPENSSL_VERSION", openssl_version) # Checks for building librnp itself # ================================= have_fcntl_h = check_header("fcntl.h") have_string_h = check_header("string.h") check_headers( "limits.h", "sys/auxv.h", "sys/cdefs.h", "sys/resource.h", "sys/param.h", "sys/stat.h", "sys/wait.h", ) set_define("HAVE_MKDTEMP", check_symbol_exists("mkdtemp", ["stdlib.h", "unistd.h"])) set_define("HAVE_MKSTEMP", check_symbol_exists("mkstemp", ["stdlib.h", "unistd.h"])) set_define("HAVE_REALPATH", check_symbol_exists("realpath", "stdlib.h")) set_define("HAVE_O_BINARY", check_symbol_exists("O_BINARY", "fcntl.h")) set_define("HAVE__O_BINARY", check_symbol_exists("_O_BINARY", "fcntl.h")) # Checks when building JSON-C from tree sources # ============================================= with only_when(in_tree_jsonc): have_stdlib_h = check_header("stdlib.h") have_locale_h = check_header("locale.h") have_strings_h = check_header("strings.h") check_headers("stdarg.h", "dlfcn.h", "endian.h", "memory.h", "xlocale.h") set_define("JSON_C_HAVE_INTTYPES_H", noset_check_header("inttypes.h")) set_define("HAVE_DECL__ISNAN", check_symbol_exists("_isnan", "float.h")) set_define("HAVE_DECL__FINITE", check_symbol_exists("_finite", "float.h")) set_define("HAVE_DECL_INFINITY", check_symbol_exists("INFINITY", "math.h")) set_define("HAVE_DECL_ISINF", check_symbol_exists("isinf", "math.h")) set_define("HAVE_DECL_ISNAN", check_symbol_exists("isnan", "math.h")) set_define("HAVE_DECL_NAN", check_symbol_exists("nan", "math.h")) set_define("HAVE_DOPRNT", check_symbol_exists("_doprnt", "stdio.h")) set_define("HAVE_SNPRINTF", check_symbol_exists("snprintf", "stdio.h")) set_define( "HAVE_VASPRINTF", check_symbol_exists("vasprintf", "stdio.h", flags=["-D_GNU_SOURCE"]), ) set_define("HAVE_VSNPRINTF", check_symbol_exists("vsnprintf", "stdio.h")) set_define("HAVE_VPRINTF", check_symbol_exists("vprintf", "stdio.h")) set_define("HAVE_OPEN", check_symbol_exists("open", "fcntl.h", when=have_fcntl_h)) set_define( "HAVE_REALLOC", check_symbol_exists("realloc", "stdlib.h", when=have_stdlib_h), ) set_define( "HAVE_SETLOCALE", check_symbol_exists("setlocale", "locale.h", when=have_locale_h), ) set_define( "HAVE_USELOCALE", check_symbol_exists("uselocale", "locale.h", when=have_locale_h), ) set_define( "HAVE_STRCASECMP", check_symbol_exists("strcasecmp", "strings.h", when=have_strings_h), ) set_define( "HAVE_STRNCASECMP", check_symbol_exists("strncasecmp", "strings.h", when=have_strings_h), ) set_define("HAVE_STRDUP", check_symbol_exists("strdup", "string.h", when=have_string_h))