Revision control

Copy as Markdown

Other Tools

# -*- 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 <openssl/opensslv.h>
#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")
set_config("HAVE_STDINT_H", noset_check_header("stdint.h"))
check_headers("stdarg.h", "dlfcn.h", "endian.h", "memory.h", "xlocale.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))