.gitlab-ci.yml | 31 +++++++++++++++++++--- .gitlab-ci/build.sh | 6 ++-- .gitlab-ci/config.yml | 9 ++++++ .gitlab-ci/other.yml | 25 +++++++++++++----- Cargo.lock | 24 +++++++++++++++++ Cargo.toml | 10 +++++++ fc-fontations-bindgen/Cargo.lock | 7 +++++ fc-fontations-bindgen/Cargo.toml | 10 +++++++ fc-fontations-bindgen/build.rs | 34 +++++++++++++++++++++++++ fc-fontations/meson.build | 53 +++++++++++++++++++++++++++++++++++++++ fc-fontations/mod.rs | 41 ++++++++++++++++++++++++++++++ meson.build | 15 +++++++++-- meson_options.txt | 2 + test/meson.build | 6 ++++ 14 files changed, 258 insertions(+), 15 deletions(-) New commits: commit 712c5be5802790dfd20ac809313878e316cb8396 Merge: 00a779b 3b291c2 Author: Akira TAGOH <akira@xxxxxxxxx> Date: Wed Nov 27 11:04:37 2024 +0000 Merge branch 'optionBindGenBuild' into 'main' [Fontations] Build bindgen targets, basic Rust test Closes #435 See merge request fontconfig/fontconfig!349 commit 3b291c2a19e7e51cedd833a2280f699a44b575d7 Author: Dominik Röttsches <drott@xxxxxxxxxxxx> Date: Tue Nov 26 16:50:07 2024 +0200 [Fontations] Build bindgen targets, basic Rust test Define meson bindgen steps that form a bindgen Rust library that allows calling back to typical FontConfig functions for constructing FcPatterns and adding them to an FcFontSet. Add a basic Rust test that demonstrates it's possible to call back to Fontconfig. Enable execution of this test through: meson test -C build as well as through: cargo test Part of #434. diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ed7bbdc..228fc6e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,8 +41,8 @@ variables: # changing these will force rebuilding the associated image # Note: these tags have no meaning and are not tied to a particular # fontconfig version - FEDORA_TAG: '2024-11-13.2-18d71ad2cf03' - FREEBSD_TAG: '2024-11-13.2-c197d92cb6b7' + FEDORA_TAG: '2024-11-13.2-3bd7920ce40a' + FREEBSD_TAG: '2024-11-13.2-f272a7918d7b' FEDORA_EXEC: 'bash .gitlab-ci/fedora-install.sh' FREEBSD_EXEC: 'bash .gitlab-ci/freebsd-install.sh' @@ -96,7 +96,7 @@ fedora:rawhide@container-prep: variables: GIT_STRATEGY: none FDO_DISTRIBUTION_VERSION: 'rawhide' - FDO_DISTRIBUTION_PACKAGES: '@buildsys-build autoconf automake libtool gettext gettext-devel gperf expat-devel libxml2-devel freetype-devel json-c-devel git docbook-utils docbook-utils-pdf bubblewrap ninja-build wget python3-pip mingw64-expat mingw64-gcc mingw64-gettext mingw64-freetype mingw64-libxml2 wine rust cargo' + FDO_DISTRIBUTION_PACKAGES: '@buildsys-build autoconf automake clang-devel libtool gettext gettext-devel gperf expat-devel libxml2-devel freetype-devel json-c-devel git docbook-utils docbook-utils-pdf bubblewrap ninja-build wget python3-pip mingw64-expat mingw64-gcc mingw64-gettext mingw64-freetype mingw64-libxml2 wine rust cargo bindgen-cli' FDO_DISTRIBUTION_TAG: $FEDORA_TAG FDO_DISTRIBUTION_EXEC: $FEDORA_EXEC @@ -106,7 +106,7 @@ fedora:41@container-prep: variables: GIT_STRATEGY: none FDO_DISTRIBUTION_VERSION: '41' - FDO_DISTRIBUTION_PACKAGES: '@buildsys-build autoconf automake libtool gettext gettext-devel gperf expat-devel libxml2-devel freetype-devel json-c-devel git docbook-utils docbook-utils-pdf bubblewrap ninja-build wget python3-pip mingw64-expat mingw64-gcc mingw64-gettext mingw64-freetype mingw64-libxml2 wine rust cargo' + FDO_DISTRIBUTION_PACKAGES: '@buildsys-build autoconf automake clang-devel libtool gettext gettext-devel gperf expat-devel libxml2-devel freetype-devel json-c-devel git docbook-utils docbook-utils-pdf bubblewrap ninja-build wget python3-pip mingw64-expat mingw64-gcc mingw64-gettext mingw64-freetype mingw64-libxml2 wine rust cargo bindgen-cli' FDO_DISTRIBUTION_TAG: $FEDORA_TAG FDO_DISTRIBUTION_EXEC: $FEDORA_EXEC @@ -116,7 +116,7 @@ fedora:40@container-prep: variables: GIT_STRATEGY: none FDO_DISTRIBUTION_VERSION: '40' - FDO_DISTRIBUTION_PACKAGES: '@buildsys-build autoconf automake libtool gettext gettext-devel gperf expat-devel libxml2-devel freetype-devel json-c-devel git docbook-utils docbook-utils-pdf bubblewrap ninja-build wget python3-pip mingw64-expat mingw64-gcc mingw64-gettext mingw64-freetype mingw64-libxml2 wine rust cargo' + FDO_DISTRIBUTION_PACKAGES: '@buildsys-build autoconf automake clang-devel libtool gettext gettext-devel gperf expat-devel libxml2-devel freetype-devel json-c-devel git docbook-utils docbook-utils-pdf bubblewrap ninja-build wget python3-pip mingw64-expat mingw64-gcc mingw64-gettext mingw64-freetype mingw64-libxml2 wine rust cargo bindgen-cli' FDO_DISTRIBUTION_TAG: $FEDORA_TAG FDO_DISTRIBUTION_EXEC: $FEDORA_EXEC @@ -471,6 +471,23 @@ t_fedora:rawhide:mingw meson static expat: - 'fedora:rawhide@container-prep' +t_fedora:rawhide:meson static libxml2 fontations: + extends: + - .build@template + - .fdo.distribution-image@fedora + - .fc_artifacts + variables: + FC_DISTRO_NAME: fedora + FDO_DISTRIBUTION_VERSION: 'rawhide' + FDO_DISTRIBUTION_TAG: $FEDORA_TAG + FC_BUILDSYS: meson + FC_BUILD_TYPE: static + FC_XML_BACKEND: libxml2 + FC_BUILD_ENABLED: fontations + needs: + - 'fedora:rawhide@container-prep' + + t_fedora:41:autotools shared expat: extends: - .build@template @@ -548,6 +565,8 @@ t_fedora:41:meson shared libxml2: + + t_fedora:40:autotools shared expat: extends: - .build@template @@ -641,6 +660,8 @@ t_fedora:40:mingw autotools static libxml2: + + t_freebsd:14.1:autotools shared expat: extends: - .build-in-qemu@template diff --git a/.gitlab-ci/build.sh b/.gitlab-ci/build.sh index d568644..932b042 100755 --- a/.gitlab-ci/build.sh +++ b/.gitlab-ci/build.sh @@ -106,11 +106,13 @@ if [ x"$buildsys" == "xautotools" ]; then fi elif [ x"$buildsys" == "xmeson" ]; then pip install meson +# tomli not required for Python >= 3.11 + pip install tomli for i in "${enable[@]}"; do - buildopt+=(-D$i=true) + buildopt+=(-D$i=enabled) done for i in "${disable[@]}"; do - buildopt+=(-D$i=false) + buildopt+=(-D$i=disabled) done case x"$backend" in 'xexpat') diff --git a/.gitlab-ci/config.yml b/.gitlab-ci/config.yml index 47a0283..426ea6a 100644 --- a/.gitlab-ci/config.yml +++ b/.gitlab-ci/config.yml @@ -72,6 +72,13 @@ distributions: FC_BUILD_PLATFORM: mingw FC_BUILD_ARCH: linux-mingw-w64-64bit FC_BUILD_NO_INSTALL: 1 + - name: "meson static libxml2 fontations" + build_only: "rawhide" + variables: + FC_BUILDSYS: meson + FC_BUILD_TYPE: static + FC_XML_BACKEND: libxml2 + FC_BUILD_ENABLED: "fontations" - name: freebsd tag: *default_tag base_type: freebsd @@ -113,6 +120,7 @@ packages: "@buildsys-build", "autoconf", "automake", + "clang-devel", "libtool", "gettext", "gettext-devel", @@ -136,6 +144,7 @@ packages: "wine", "rust", "cargo", + "bindgen-cli" ] freebsd: needed: diff --git a/.gitlab-ci/other.yml b/.gitlab-ci/other.yml index 074146b..b2aad54 100644 --- a/.gitlab-ci/other.yml +++ b/.gitlab-ci/other.yml @@ -45,17 +45,18 @@ - build-*/meson-logs/*txt - prefix-* -meson vs2019 amd64: - extends: ".build meson windows" - variables: - ARCH: "amd64" meson vs2019 x86: extends: ".build meson windows" variables: ARCH: "x86" + MESON_ARGS: "-Dfontations=disabled" -meson macos: +# A Windows Fontations build would currently require +# libclang and llvm installation which is a several hundred megabyte download. +# Skip that configuration for now. + +.meson macos test: stage: "test" # See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/.gitlab-ci.yml # As of 2024-11-21, this is a Mac OS 15 Sequia image on Apple silicon. @@ -83,12 +84,24 @@ meson macos: - . "$HOME/.cargo/env" # Test Rust availability. - rustup update + - cargo install bindgen-cli - rustc --version + - bindgen --version script: - - CERT_PATH=$(python3 -m certifi) && export SSL_CERT_FILE=${CERT_PATH} && export REQUESTS_CA_BUNDLE=${CERT_PATH} && meson setup -Diconv=enabled build + - CERT_PATH=$(python3 -m certifi) && export SSL_CERT_FILE=${CERT_PATH} && export REQUESTS_CA_BUNDLE=${CERT_PATH} && meson setup -Diconv=enabled $MESON_FONTATIONS_ARG build - meson compile --verbose -C build - meson test -C build +meson macos test: + extends: ".meson macos test" + variables: + MESON_FONTATIONS_ARG: "-Dfontations=disabled" + +meson macos test fontations: + extends: ".meson macos test" + variables: + MESON_FONTATIONS_ARG: "-Dfontations=enabled" + # msys infrastructure is a bit broken, disable for now meson msys2: extends: ".build meson windows" diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..156bffc --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,24 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "fc-fontations" +version = "0.1.0" +dependencies = [ + "fc-fontations-bindgen", + "libc", +] + +[[package]] +name = "fc-fontations-bindgen" +version = "0.1.0" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.165" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6feaf0c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "fc-fontations" +version = "0.1.0" + +[dependencies] +fc-fontations-bindgen = { path = "./fc-fontations-bindgen" } +libc = "0.2" + +[lib] +path = "fc-fontations/mod.rs" diff --git a/fc-fontations-bindgen/Cargo.lock b/fc-fontations-bindgen/Cargo.lock new file mode 100644 index 0000000..98cf25e --- /dev/null +++ b/fc-fontations-bindgen/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "fc-fontations-bindgen" +version = "0.1.0" diff --git a/fc-fontations-bindgen/Cargo.toml b/fc-fontations-bindgen/Cargo.toml new file mode 100644 index 0000000..fafeefc --- /dev/null +++ b/fc-fontations-bindgen/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "fc-fontations-bindgen" +version = "0.1.0" +links = "fontconfig" + +[lib] +path = "../build/fc-fontations/fontconfig.rs" + +[dependencies] +libc = "0.2" diff --git a/fc-fontations-bindgen/build.rs b/fc-fontations-bindgen/build.rs new file mode 100644 index 0000000..50b703d --- /dev/null +++ b/fc-fontations-bindgen/build.rs @@ -0,0 +1,34 @@ +use std::path::PathBuf; +use std::process::Command; + +fn main() { + // Directory for the fontconfig build + let build_dir = PathBuf::from("build"); + + // Configure and build fontconfig using meson + let mut meson = Command::new("meson"); + meson.current_dir("../"); + meson.arg("setup") + .arg(build_dir.to_str().unwrap()) + .arg("-Dfontations=enabled"); + + let status = meson.status().expect("Failed to execute meson"); + if !status.success() { + panic!("Meson setup failed"); + } + + let mut ninja = Command::new("ninja"); + ninja.current_dir("../"); + ninja.arg("-C").arg(build_dir.to_str().unwrap()); + let status = ninja.status().expect("Failed to execute ninja"); + if !status.success() { + panic!("Ninja build failed"); + } + + // Tell cargo to look for fontconfig in the build directory + println!("cargo:rustc-link-search=native={}", build_dir.join("lib").display()); + println!("cargo:rustc-link-lib=dylib=fontconfig"); + + // Rerun this build script if the fontconfig source code changes + println!("cargo:rerun-if-changed=src"); +} diff --git a/fc-fontations/meson.build b/fc-fontations/meson.build new file mode 100644 index 0000000..fd06081 --- /dev/null +++ b/fc-fontations/meson.build @@ -0,0 +1,53 @@ +fontations = get_option('fontations') + +if (fontations.enabled()) + rust = import('rust') + + generated_fontconfig = rust.bindgen( + input : '../fontconfig/fontconfig.h', + output : 'fontconfig.rs', + include_directories : [ '../' ], + args : [ + '--merge-extern-blocks', + '--allowlist-item=(FcCharSet.*|FC_(SLANT|WEIGHT|WIDTH)_.*|FcFontSet(Add|Create|Destroy).*|FcLangSet(Destroy|Copy)|FcWeightFromOpenType.*)', + '--raw-line=#![allow(nonstandard_style,unused)]', + '--raw-line= ', + '--raw-line=pub mod fcint;', + ], + c_args : ['-DBINDGEN_IGNORE_VISIBILITY=1'], + ) + + generated_fcint = rust.bindgen( + input : '../src/fcint.h', + output : 'fcint.rs', + include_directories : [ '../' ], + args : [ + '--merge-extern-blocks', + '--allowlist-item=(FcPattern.*|FcRange.*|FC_.*_OBJECT|FcCharSet.*|FcFreeTypeLangSet)', + '--blocklist-type=(FcCharSet|FcLangSet)', + '--raw-line=#![allow(nonstandard_style,unused)]', + '--raw-line= ', + '--raw-line=pub use FcCharSet; pub use FcLangSet;', + ], + c_args : ['-DBINDGEN_IGNORE_VISIBILITY=1'], + ) + + bindgen_lib = static_library( + 'fc_fontations_bindgen', + sources: [generated_fontconfig, generated_fcint], + rust_abi : 'rust', + ) + + fc_fontations = static_library( + 'fc_fontations', + sources: ['mod.rs'], + link_with: [bindgen_lib, libfontconfig], + rust_abi: 'c', + dependencies: [ + dependency('libc-0.2-rs'), + + ], + + ) + +endif \ No newline at end of file diff --git a/fc-fontations/mod.rs b/fc-fontations/mod.rs new file mode 100644 index 0000000..a39c814 --- /dev/null +++ b/fc-fontations/mod.rs @@ -0,0 +1,41 @@ +extern crate fc_fontations_bindgen; + +use fc_fontations_bindgen::{fcint::FcPatternCreate, FcFontSet, FcFontSetAdd}; + +#[no_mangle] +/// Externally called in fcfontations.c as the file scanner function +/// similar to the job that FreeType performs. +/// +/// # Safety +/// * At this point, the font file path is not dereferenced. +/// * In this initial sanity check mock call, only one empty pattern +/// is added to the FontSet, which is null checked, which is sound. +pub unsafe extern "C" fn add_patterns_to_fontset( + _: *const libc::c_char, + font_set: *mut FcFontSet, +) -> libc::c_int { + let empty_pattern = FcPatternCreate(); + if !font_set.is_null() { + FcFontSetAdd( + font_set, + empty_pattern as *mut fc_fontations_bindgen::FcPattern, + ) + } else { + 0 + } +} + +#[cfg(test)] +mod test { + use crate::add_patterns_to_fontset; + use fc_fontations_bindgen::{FcFontSetCreate, FcFontSetDestroy}; + + #[test] + fn basic_pattern_construction() { + unsafe { + let font_set = FcFontSetCreate(); + assert!(add_patterns_to_fontset(std::ptr::null(), font_set) == 1); + FcFontSetDestroy(font_set); + } + } +} diff --git a/meson.build b/meson.build index 0e9e99a..7d41f84 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('fontconfig', 'c', version: '2.15.0', - meson_version : '>= 1.3.0', - default_options: [ 'buildtype=debugoptimized'], + meson_version : '>= 1.6.0', + default_options: [ 'buildtype=debugoptimized', ] ) fs = import('fs') @@ -73,6 +73,12 @@ if xmltype == '' xmltype = xml_dep.name() endif +fontations = get_option('fontations') +if (fontations.enabled()) + conf.set('ENABLE_FONTATIONS', 1) + add_languages(['rust'], native: false, required : true) +endif + pkgmod = import('pkgconfig') python3 = import('python').find_installation() @@ -484,6 +490,10 @@ subdir('fc-case') subdir('fc-lang') subdir('src') +if get_option('fontations').enabled() + subdir('fc-fontations') +endif + if not get_option('tools').disabled() subdir('fc-cache') subdir('fc-cat') @@ -549,6 +559,7 @@ summary({ 'Tools': not get_option('tools').disabled(), 'iconv': found_iconv == 1, 'XML backend': xmltype, + 'Fontations support' : fontations }, section: 'General', bool_yn: true, list_sep: ', ') summary({ 'Hinting': preferred_hinting, diff --git a/meson_options.txt b/meson_options.txt index 49c6dad..d148621 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -16,6 +16,8 @@ option('cache-build', type : 'feature', value : 'enabled', option('iconv', type: 'feature', value: 'disabled') option('xml-backend', type: 'combo', choices: ['auto', 'expat', 'libxml2'], value: 'auto', description: 'Select xml backend to read config') +option('fontations', type: 'feature', value: 'disabled', + description: 'Use Fontations (https://github.com/googlefonts/fontations) for indexing.') # Defaults option('default-hinting', type: 'combo', choices: ['none', 'slight', 'medium', 'full'], value: 'slight', diff --git a/test/meson.build b/test/meson.build index d547591..eff0b22 100644 --- a/test/meson.build +++ b/test/meson.build @@ -26,6 +26,7 @@ if host_machine.system() != 'windows' endif endif + foreach test_data : tests fname = test_data[0] opts = test_data.length() > 1 ? test_data[1] : {} @@ -43,6 +44,11 @@ foreach test_data : tests test(test_name, exe, timeout: 600) endforeach +if get_option('fontations').enabled() + rust = import('rust') + rust.test('fc_fontations_tests', fc_fontations) +endif + fs = import('fs') if host_machine.system() != 'windows'