Files
librsvg/meson.build

548 lines
19 KiB
Meson

project('librsvg',
'c',
version: '2.62.1', # Keep this in sync with Cargo.toml, doc/librsvg.toml, rsvg/Cargo.toml
meson_version: '>= 1.3.0',
default_options: [
]
)
librsvg_api_version = '2.0'
api_split = librsvg_api_version.split('.')
librsvg_api_major = api_split[0]
librsvg_api_minor = api_split[1]
librsvg_pc = 'librsvg-@0@'.format(librsvg_api_version)
host_system = host_machine.system()
cc = meson.get_compiler('c')
# MSRV - Minimum Supported Rust Version
# If you change this, please update these:
# - the "rust-version" value in Cargo.toml
# - the "Compilers and build tools" section of devel-docs/_build_dependencies.rst
# - the "RUST_MINIMUM" variable in ci/container_builds.yml
msrv = '1.92.0'
cargo_cbuild_version = '0.10.10'
cargo = find_program('cargo', version:'>= @0@'.format(msrv))
cargo_wrapper = find_program('meson/cargo_wrapper.py', native: true)
cargo_c = find_program('cargo-cbuild', version:'>= @0@'.format(cargo_cbuild_version)) # https://github.com/lu-zero/cargo-c
rustc = find_program('rustc', version:'>= @0@'.format(msrv))
makedef = find_program('meson/makedef.py', native: true)
if host_system in ['darwin', 'ios']
# Validate unconditional presence of getentropy and CCRandomGenerateBytes.
# https://github.com/rust-lang/rust/pull/116319
ret = cc.compiles('''#include <Availability.h>
#include <TargetConditionals.h>
#if !((TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200L) || (TARGET_OS_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000L))
# error "https://gitlab.gnome.org/GNOME/librsvg/-/issues/1097"
#endif''',
name: 'Targets at least macOS 10.12 or iOS 10',
)
if rustc.version().version_compare('>= 1.75.0') and not ret
error('When using rustc >=1.75, you must target at least macOS 10.12 or iOS 10')
endif
endif
py = import('python')
python = py.find_installation()
# Required versions for dependencies - Please update _build_dependencies.rst with version numbers if these change
cairo_required = '>= 1.18.0'
dav1d_required = '>= 1.3.0'
ft2_cmake_required = '>= 2.8.0' # Actual FreeType version required
freetype2_required = '>= 20.0.14' # Corresponds to ft2_cmake_required
glib_required = '>= 2.50.0'
harfbuzz_required = '>= 2.0.0'
libxml_required = '>= 2.9.0'
pango_required = '>= 1.50.0'
# Optional dependencies
gdk_pixbuf_required = '>= 2.20'
gidocgen_required = '>= 2021.1'
introspection_required = '>= 1.39.0'
vapigen_required = '>= 0.17.1.26'
# FIXME: add subprojects for the deps above
cairo_dep = dependency('cairo',
version: cairo_required,
fallback: ['cairo', 'libcairo_dep'])
cairogobj_dep = dependency('cairo-gobject',
version: cairo_required,
fallback: ['cairo', 'libcairogobject_dep'])
cairo_png_dep = dependency('cairo-png',
version: cairo_required,
fallback: ['cairo']) # FIXME: cairo has no _dep for this one
dav1d_dep = dependency('dav1d',
version: dav1d_required,
method: 'pkg-config',
required: get_option('avif'))
freetype2_dep = dependency('freetype2',
version: freetype2_required,
method: 'pkg-config',
required: false)
# Try again using CMake, as Windows builds of FreeType might not
# come with pkg-config files; sadly, pkg-config and CMake use
# different version schemes for FreeType
if not freetype2_dep.found()
freetype2_dep = dependency('FreeType',
version: ft2_cmake_required,
method: 'cmake',
fallback: ['freetype2', 'freetype_dep'])
endif
pixbuf_dep = dependency('gdk-pixbuf-2.0',
version: gdk_pixbuf_required,
required: get_option('pixbuf'),
fallback: ['gdk-pixbuf', 'gdkpixbuf_dep'],
default_options: ['png=enabled', 'jpeg=enabled', 'builtin_loaders=png,jpeg', 'man=false'])
gio_dep = dependency('gio-2.0',
version: glib_required,
fallback: ['glib', 'libgio_dep'])
glib_dep = dependency('glib-2.0',
version: glib_required,
fallback: ['glib', 'libglib_dep'])
harfbuzz_dep = dependency('harfbuzz',
version: harfbuzz_required,
fallback: ['harfbuzz', 'libharfbuzz_dep'])
libxml_dep = dependency(['libxml-2.0', 'LibXml2'],
version: libxml_required)
pango_dep = dependency('pango',
version: pango_required,
fallback: ['pango', 'libpango_dep'])
pangocairo_dep = dependency('pangocairo',
version: pango_required,
fallback: ['pango', 'libpangocairo_dep'])
pangoft2_dep = dependency('pangoft2',
version: pango_required,
required: host_system not in ['windows', 'darwin', 'ios'],
fallback: ['pango', 'libpangoft2_dep'])
gmodule_dep = dependency('gmodule-2.0', version: glib_required,
fallback : ['glib', 'libgmodule_dep'])
rst2man = find_program('rst2man', 'rst2man.py',
required: get_option('docs'),
disabler: true)
gidocgen = find_program('gi-docgen', version: gidocgen_required,
required: false,
disabler: true)
gi_dep = dependency('gobject-introspection-1.0',
version: introspection_required,
required: get_option('introspection'))
vapigen_dep = dependency('vapigen',
version: vapigen_required,
required: get_option('vala'))
# Extra env to pass to cargo
extra_env = environment()
# If FreeType and/or libxml2 is/are found by CMake instead of
# pkg-config, we must tell Cargo the libraries explicitly and
# disable pkg-config for these deps
if freetype2_dep.type_name() == 'cmake' or libxml_dep.type_name() == 'cmake'
fs = import('fs')
endif
if freetype2_dep.type_name() == 'cmake'
ft2_lib = freetype2_dep.get_variable('FREETYPE_LIBRARIES')
extra_env.set('SYSTEM_DEPS_FREETYPE2_NO_PKG_CONFIG', '1')
extra_env.set('SYSTEM_DEPS_FREETYPE2_SEARCH_NATIVE', fs.parent(ft2_lib))
extra_env.set('SYSTEM_DEPS_FREETYPE2_LIB', fs.stem(ft2_lib))
endif
if libxml_dep.type_name() == 'cmake'
libxml_lib = libxml_dep.get_variable('LIBXML2_LIBRARIES')
extra_env.set('SYSTEM_DEPS_LIBXML2_NO_PKG_CONFIG', '1')
extra_env.set('SYSTEM_DEPS_LIBXML2_SEARCH_NATIVE', fs.parent(libxml_lib))
extra_env.set('SYSTEM_DEPS_LIBXML2_LIB', fs.stem(libxml_lib))
endif
if host_system == 'windows'
build_gir = get_option('introspection').require(get_option('default_library') != 'static' and meson.can_run_host_binaries() and gi_dep.found())
else
build_gir = get_option('introspection').require(meson.can_run_host_binaries() and gi_dep.found())
endif
build_vala = get_option('vala').require(meson.can_run_host_binaries() and vapigen_dep.found())
build_rsvg_convert = get_option('rsvg-convert')
build_pixbuf_loader = get_option('pixbuf-loader').require(pixbuf_dep.found())
build_docs = get_option('docs')
build_tests = get_option('tests')
gnome = import('gnome')
foundation_dep = dependency('appleframeworks', modules: 'Foundation',
required: host_system in ['darwin', 'ios'])
m_dep = cc.find_library('m', required: false)
# Solaris and Illumos distros split a lot of networking-related code
# into '-lsocket' and '-lnsl'. Anything that calls socketpair(), getifaddr(),
# etc. probably needs to include network_deps
#
if host_system == 'sunos'
network_deps = [
cc.find_library('socket', required: false),
]
else
network_deps = []
endif
# Use this in place of libxml2/freetype2 for 'Requires:' in the
# pkg-config file in case either or both were found with CMake
empty_pc_dep = dependency('', required: false)
# ignore the system dependencies for GIR
library_dependencies_sole = [
glib_dep,
gio_dep,
pixbuf_dep,
cairo_dep,
]
private_libraries = []
# these dependencies are not exported in the ABI
private_dependencies = [
cairogobj_dep,
cairo_png_dep,
dav1d_dep,
freetype2_dep.type_name() != 'cmake' ? freetype2_dep : empty_pc_dep,
harfbuzz_dep,
libxml_dep.type_name() != 'cmake' ? libxml_dep : empty_pc_dep,
pangocairo_dep,
pangoft2_dep,
gmodule_dep,
]
library_dependencies = library_dependencies_sole
other_library_dependencies = []
foreach d: [libxml_dep, freetype2_dep]
if d.type_name() == 'cmake'
other_library_dependencies += d
endif
endforeach
target = get_option('triplet')
target_arg = []
toolchain_arg = []
toolchain_ver = get_option('rustc-version')
check_version = false
# Check toolchain_ver if supplied, if in the form of a version
# We assume to continue if a stable, nightly or beta or custom toolchain is specified
if toolchain_ver != ''
if host_system == 'windows'
warning('\'rustc-version\' option currently only supported for Windows')
endif
check_version_script = find_program('meson/check-is-version-string.py', native: true)
is_version_string_check = run_command(
[check_version_script, '--string', toolchain_ver],
capture: true,
check: true
)
check_version = is_version_string_check.stdout().split()[0] == 'check'
if check_version
if not toolchain_ver.version_compare('>=@0@'.format(msrv))
error('Specified Rust toolchain version @0@ is less than @1@'.format(toolchain_ver, msrv))
endif
endif
endif
# Ideally, cc.get_argument_syntax() == 'msvc' should
# cover this, but 'clang' can mean GCC or MSVC-style
# depending on the env and/or flags on Windows
is_msvc_style = cc.get_argument_syntax() == 'msvc' or cc.get_define('_MSC_VER') != ''
if target != ''
target_arg += ['--target', target]
endif
query_rustc_harness = find_program('meson/query-rustc.py', native: true, required: get_option('default_library') != 'shared')
rustc_query_args = [
query_rustc_harness,
rustc,
]
if host_system == 'windows'
# First deduce the target that is to be used for the build, based on Meson build settings
host_cpu_family = host_machine.cpu_family()
rustc_toolchain_cpu = host_cpu_family == 'x86' ? 'i686' : host_cpu_family
if is_msvc_style
rustc_toolchain_cc = 'msvc'
elif cc.get_id() == 'clang'
rustc_toolchain_cc = 'gnullvm'
else
rustc_toolchain_cc = 'gnu'
endif
rustc_target = '@0@-pc-windows-@1@'.format(rustc_toolchain_cpu, rustc_toolchain_cc)
if toolchain_ver != ''
build_triplet_arg = []
if target_arg == []
target_arg += ['--target', rustc_target]
endif
# If doing a cross build, with '-Drustc-version=...' we must find the native toolchain on the build
# machine with its arch triplet that is to be used for building against the target, as Cargo will
# require this in its command line
if meson.is_cross_build()
build_cpu_family = build_machine.cpu_family()
rustc_build_toolchain_cpu = build_cpu_family == 'x86' ? 'i686' : build_cpu_family
rustc_build_triplet = '@0@-pc-windows-@1@'.format(rustc_build_toolchain_cpu, rustc_toolchain_cc)
build_triplet_arg += ['--build-triplet', rustc_build_triplet]
endif
# If a version number is used, also check against the actual release that is depicted
# by the currently installed 'stable' toolchain, and use the stable toolchain if the requested
# version matches the installed 'stable' toolchain
if check_version
stable_toolchain_arg = ['--toolchain-version', 'stable']
stable_actual_version = run_command(
rustc_query_args + ['--query=stable-actual-version'] + stable_toolchain_arg + target_arg + build_triplet_arg,
capture: true,
check: true
)
if stable_actual_version.stderr() != ''
error('error occurred when querying stable toolchain: @0@'.format(default_host.stderr().split()[0]))
endif
stable_version = stable_actual_version.stdout().split()[0]
if stable_version == toolchain_ver
toolchain_arg += stable_toolchain_arg
endif
endif
if toolchain_arg == []
toolchain_arg += ['--toolchain-version', toolchain_ver]
endif
toolchain_arg += toolchain_arg + build_triplet_arg
endif
if target_arg == []
default_host = run_command(
rustc_query_args + ['--query=default-host-toolchain'] + toolchain_arg,
capture: true,
check: true
)
if default_host.stderr() != ''
error('error occurred when querying default toolchain: @0@'.format(default_host.stderr().split()[0]))
endif
default_rustc_toolchain = default_host.stdout().split()[0]
# If the default Rust target triplet does not match the triplet that we want to build for
# pass in a --target argument to RustC/Cargo that best matches what we are building for,
# if we didn't use -Dtriplet=... in the Meson setup line. Do the same if a toolchain version
# is requested
if default_rustc_toolchain != rustc_target
target_arg += ['--target', rustc_target]
endif
endif
endif
default_overrides = []
if host_system in ['windows', 'linux']
rustc_query_native_static_libs_args = rustc_query_args
if target_arg != []
rustc_query_native_static_libs_args += target_arg
endif
if toolchain_arg != []
rustc_query_native_static_libs_args += toolchain_arg
endif
rustc_query_native_static_libs_args += ['--query=native-static-libs']
native_libs = run_command(
rustc_query_native_static_libs_args,
capture: true,
check: true
)
if native_libs.stderr() != ''
error(native_libs.stderr())
endif
foreach i: native_libs.stdout().split()
if 'msvcrt' in i
if i.endswith('.lib') # pre Rust 1.83
default_overrides = [
'b_vscrt=md@0@'.format(i.substring(0, -4).split('msvcrt')[1])
]
else # /DEFAULTLIB:<crt goes here, minus the .lib extension>
default_overrides = [
'b_vscrt=md@0@'.format(i.split('msvcrt')[1])
]
endif
else
private_libraries += cc.find_library(i, required: get_option('default_library') != 'shared')
endif
endforeach
endif
private_libraries += [m_dep]
private_dependencies += network_deps
# appleframeworks cannot be exposed to pkg-config
library_dependencies += foundation_dep
library_dependencies += other_library_dependencies
library_dependencies += private_libraries
library_dependencies += private_dependencies
cargo_toml = meson.project_source_root() / 'Cargo.toml'
if get_option('default_library') == 'static'
# Tell the pkg-config crate to think of all libraries as static
extra_env.set('PKG_CONFIG_ALL_STATIC', '1')
# Tell the system-deps crate to process linker flag for static deps
extra_env.set('SYSTEM_DEPS_LINK', 'static')
# Allow cross-compilation
extra_env.set('PKG_CONFIG_ALLOW_CROSS', 'static')
endif
pkg_config = find_program('pkgconfig', 'pkg-config', 'pkgconf', required: true)
extra_env.set('PKG_CONFIG', pkg_config.full_path())
pkg_config_path = get_option('pkg_config_path')
if pkg_config_path.length() > 0
extra_env.set('PKG_CONFIG_PATH', pkg_config_path)
endif
# Make sure dependencies provided by the superproject are propagated
# (or ours, if there are wraps within this tree)
if meson.is_subproject()
extra_env.prepend('PKG_CONFIG_PATH', meson.global_build_root() / 'meson-uninstalled')
endif
# Set up the environment that will be fed to the build
if host_system in ['darwin', 'ios']
var = 'DYLD_LIBRARY_PATH'
elif host_system in ['windows', 'cygwin']
var = 'PATH'
else
var = 'LD_LIBRARY_PATH'
endif
current_library_path = run_command(
[
python,
'-c',
'import os; print(os.environ["@0@"]) if "@0@" in os.environ else ""'.format(var)
],
capture: true,
check: true,
)
extra_env.set(var, current_library_path.stdout().strip())
extra_env.prepend(var, meson.project_build_root() / 'rsvg')
if host_system == 'windows'
foreach i: library_dependencies_sole + private_dependencies
x = i.get_variable(pkgconfig: 'bindir', default_value: '')
if x != ''
extra_env.prepend('PATH', x)
endif
endforeach
endif
# used in librsvg/meson.build. This is so that '#include <librsvg/rsvg.h>` will pick
# up exactly that file from the source tree.
includeinc = include_directories('include')
# Set the suffixes up
if host_system == 'windows'
lib_prefix = is_msvc_style ? '' : 'lib'
ext_dynamic = 'dll'
ext_static = is_msvc_style ? 'lib' : 'a'
ext_exe = '.exe'
elif host_system in ['darwin', 'ios']
lib_prefix = 'lib'
ext_dynamic = 'dylib'
ext_static = 'a'
ext_exe = ''
else
lib_prefix = 'lib'
ext_dynamic = 'so'
ext_static = 'a'
ext_exe = ''
endif
cargo_dylib_prefix = lib_prefix
if cc.has_define('__MINGW32__')
cargo_dylib_prefix = ''
endif
cargo_wrapper_args = [
'--cargo', cargo.full_path(),
'--manifest-path', cargo_toml,
'--project-build-root', meson.project_build_root(),
'--prefix', get_option('prefix'),
'--libdir', get_option('libdir'),
]
if not get_option('debug')
cargo_wrapper_args += ['--release']
endif
optimization = get_option('optimization')
if optimization in ['0', '1', '2', '3', 's']
cargo_wrapper_args += ['--optimization', optimization]
elif optimization != 'plain' # g
cargo_wrapper_args += ['--optimization', '1']
# plain: https://github.com/mesonbuild/meson/issues/7194
endif
if get_option('b_lto')
if get_option('b_lto_mode') == 'default'
cargo_wrapper_args += ['--lto', 'fat']
else
cargo_wrapper_args += ['--lto', 'thin']
endif
endif
if target_arg != []
cargo_wrapper_args += target_arg
endif
if toolchain_arg != []
cargo_wrapper_args += toolchain_arg
endif
# avif support with dav1d
if dav1d_dep.found()
avif_feature_args = ['--avif']
else
avif_feature_args = []
endif
# gdk-pixbuf support
if pixbuf_dep.found()
pixbuf_feature_args = ['--pixbuf']
else
pixbuf_feature_args = []
endif
subdir('include')
subdir('librsvg-c')
subdir('rsvg')
if build_tests
subdir('librsvg-c/tests-c')
endif
if build_rsvg_convert.allowed()
subdir('rsvg_convert')
endif
if build_pixbuf_loader.allowed()
subdir('gdk-pixbuf-loader')
endif
if build_docs.allowed()
subdir('doc')
endif
# The Vala generator must reside in the main folder since Meson isn't yet
# clever enough to take a list of files.
# See https://github.com/mesonbuild/meson/blob/b290a8254122f53d6477b7ba24366d81cfc5e99c/mesonbuild/modules/gnome.py#L2150-L2152
if build_gir.allowed() and build_vala.allowed()
vala = gnome.generate_vapi(
'librsvg-@0@'.format(librsvg_api_version),
packages: vala_includes,
metadata_dirs: [meson.current_source_dir()],
sources: ['Rsvg-@0@-custom.vala'.format(librsvg_api_version), rsvg_gir[0]],
install: true,
)
endif