project( 'ahfail', ['c', 'rust'], version: '0.10.2', meson_version: '>=1.3.0', default_options: ['warning_level=3', 'c_std=c11'] ) ahfail_inc = include_directories('include') cc = meson.get_compiler('c') is_linux = host_machine.system() == 'linux' # All Rust artefacts come from ONE cargo invocation with one target directory. # Four separate builds with four target directories compiled the whole GTK and # GStreamer binding stack four times over (about an hour for a package build). # # -Dupdate_check=false (distro packages) builds without the ahfail-ui feature # `update-check`, so the binaries never ask Gitea for new releases and the HTTP # client is not compiled in at all. cargo_features = get_option('update_check') ? '' : '--no-default-features' # Linux builds everything: the ahfail locker, the gtklock module (Wayland), the # PAM hook and its display binary. macOS only has the PAM hook + display binary: # gtklock and the locker are Linux-only, and the module's GNU-ld link flags do # not exist on macOS. # Cargo names a cdylib .dylib on macOS. The installed name stays # libahfail_pam.so: PAM loads the module by path, whatever the extension. pam_built = host_machine.system() == 'darwin' ? 'libahfail_pam.dylib' : 'libahfail_pam.so' if is_linux cargo_pkgs = '-p ahfail-gtklock -p ahfail-pam -p ahfail-display -p ahfail' cargo_outputs = ['libahfail_module.a', 'libahfail_pam.so', 'ahfail-display', 'ahfail'] # module archive: linked below, not installed; PAM hook + display: libdir/ahfail; locker: bindir. cargo_install_dirs = [false, get_option('libdir') / 'ahfail', get_option('libdir') / 'ahfail', get_option('bindir')] cargo_copy = (' && cp "@OUTDIR@/target/release/libahfail_module.a" "@OUTPUT0@"' + ' && cp "@OUTDIR@/target/release/libahfail_pam.so" "@OUTPUT1@"' + ' && cp "@OUTDIR@/target/release/ahfail-display" "@OUTPUT2@"' + ' && cp "@OUTDIR@/target/release/ahfail" "@OUTPUT3@"') else cargo_pkgs = '-p ahfail-pam -p ahfail-display' cargo_outputs = ['libahfail_pam.so', 'ahfail-display'] cargo_install_dirs = [get_option('libdir') / 'ahfail', get_option('libdir') / 'ahfail'] cargo_copy = (' && cp "@OUTDIR@/target/release/' + pam_built + '" "@OUTPUT0@"' + ' && cp "@OUTDIR@/target/release/ahfail-display" "@OUTPUT1@"') endif cargo_all = custom_target( 'ahfail-cargo-build', input: ['Cargo.toml', 'Cargo.lock'], output: cargo_outputs, command: [ 'sh', '-c', # The PAM module's build.rs needs the absolute libdir to know where # ahfail-display is installed; get_option('libdir') alone is relative. 'AHFAIL_LIBDIR=' + get_option('prefix') / get_option('libdir') + ' cargo build --release --locked' + ' ' + cargo_pkgs + ' ' + cargo_features + ' --target-dir "@OUTDIR@/target"' + cargo_copy ], build_by_default: true, build_always_stale: true, # cargo decides what is out of date, not meson install: true, install_dir: cargo_install_dirs, install_mode: 'rwxr-xr-x' ) pam_cargo = is_linux ? cargo_all[1] : cargo_all[0] # The locker's own PAM service. Shipped as its own file, like swaylock and # gtklock do, so no other package's PAM configuration is ever touched. if is_linux install_data('data/pam.d/ahfail', install_dir: get_option('sysconfdir') / 'pam.d', install_mode: 'rw-r--r--' ) endif if is_linux m_dep = cc.find_library('m', required : false) gtk_dep = dependency('gtk+-3.0') gstplayer_dep = dependency('gstreamer-player-1.0') resources = import('gnome').compile_resources( 'ahfail-resources', 'assets/ahfail.gresource.xml', source_dir: 'assets', c_name: 'ahfail' ) # The gtklock module (Wayland): the Rust staticlib linked whole into a .so. libahfail = shared_library( 'ahfail-module', resources, link_args: ['-Wl,--whole-archive', meson.current_build_dir() / 'libahfail_module.a', '-Wl,--no-whole-archive'], link_depends: cargo_all[0], include_directories: ahfail_inc, dependencies: [gtk_dep, gstplayer_dep, m_dep], install: true, install_dir: get_option('libdir') / 'gtklock', name_prefix: '' ) smoke = executable( 'module_smoke_test', 'tests/module_test.c', include_directories: ahfail_inc, link_with: libahfail, dependencies: [gtk_dep, gstplayer_dep] ) test('module symbols', smoke) endif # PAM module smoke test: dlopen libahfail_pam.so and verify pam_sm_authenticate is exported. pam_smoke = executable( 'pam_smoke_test', 'tests/pam_smoke_test.c', dependencies: [cc.find_library('dl', required: false)] # part of libSystem on macOS ) test('pam symbols', pam_smoke, args: [meson.current_build_dir() / 'libahfail_pam.so'], depends: pam_cargo)