442 строки
15 KiB
Python
442 строки
15 KiB
Python
# -*- 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):
|
|
|
|
@depends(build_environment, configure_cache, c_compiler)
|
|
@imports(_from="textwrap", _import="dedent")
|
|
@imports(_from="os.path", _import="join")
|
|
def rnp_version_string(build_env, configure_cache, compiler):
|
|
log.info("Determining librnp version from version.h.")
|
|
include_path = join(build_env.topsrcdir, "comm", "third_party", "rnp", "src", "lib")
|
|
check = dedent(
|
|
"""\
|
|
#include "version.h"
|
|
RNP_VERSION_STRING_FULL
|
|
"""
|
|
)
|
|
result = try_preprocess(
|
|
configure_cache,
|
|
compiler.wrapper + [compiler.compiler] + compiler.flags + ["-I", include_path],
|
|
"C",
|
|
check,
|
|
)
|
|
if result:
|
|
rnp_version = result.splitlines()[-1]
|
|
rnp_version = rnp_version.replace('"', "")
|
|
else:
|
|
raise FatalCheckError("Unable to determine RNP version string.")
|
|
return rnp_version
|
|
|
|
set_config("MZLA_LIBRNP_FULL_VERSION", rnp_version_string)
|
|
|
|
# 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")
|
|
|
|
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))
|
|
|
|
|
|
@depends(c_compiler, target, when=compile_environment)
|
|
@checking("for clang_rt.builtins path", lambda x: x if x is None else x.clang_rt_lib)
|
|
@imports(_from="os", _import="pathsep")
|
|
@imports(_from="os.path", _import="isdir")
|
|
@imports(_from="os.path", _import="exists")
|
|
@imports(_from="os.path", _import="join")
|
|
def clang_rt_builtins(compiler_info, target):
|
|
if compiler_info.type == "clang-cl":
|
|
if target.raw_cpu in ["i686"]:
|
|
rt_arch = "i386"
|
|
else:
|
|
rt_arch = target.raw_cpu
|
|
|
|
clang_rt_builtins = "clang_rt.builtins-{}".format(rt_arch)
|
|
clang_cl = compiler_info.compiler
|
|
flags = []
|
|
flags.extend(compiler_info.flags)
|
|
flags.append("-clang:-print-search-dirs")
|
|
clang_search_dirs = check_cmd_output(clang_cl, *flags)
|
|
for line in clang_search_dirs.splitlines():
|
|
name, _, value = line.partition(": =")
|
|
if name == "libraries":
|
|
for dir in value.split(pathsep):
|
|
if dir.endswith(compiler_info.version.vstring):
|
|
clang_rt_dir = join(dir, "lib/windows")
|
|
clang_rt_lib = join(clang_rt_dir, clang_rt_builtins)
|
|
if isdir(clang_rt_dir):
|
|
if exists("{}.lib".format(clang_rt_lib)):
|
|
return namespace(
|
|
clang_rt_path=clang_rt_dir,
|
|
clang_rt_lib=clang_rt_lib,
|
|
)
|
|
die("Cannot find clang_rt.builtins path.")
|
|
|
|
|
|
set_config("COMPILER_RT_BUILTIN_PATH", clang_rt_builtins.clang_rt_path, when=is_windows)
|
|
set_config("COMPILER_RT_BUILTIN_LIB", clang_rt_builtins.clang_rt_lib, when=is_windows)
|