Files
libfuse/meson.build
T
Benjamin Peterson 57954f4a5f libfuse: remove libnuma dependency
As discussed on https://github.com/libfuse/libfuse/issues/1515, libfuse has
a very light dependency on libnuma, only using very light wrappers over
mmap, mbind, and munmap. Remove the libnuma dependency by calling those
syscalls directly.

Populate memory after mmap to avoid SIGBUS later.

Signed-off-by: Benjamin Peterson <benjamin@python.org>
2026-06-15 23:05:11 +02:00

405 lines
13 KiB
Meson

project('libfuse3', ['c'],
version: '3.19.0-rc0',
meson_version: '>= 0.60.0',
default_options: [
'buildtype=debugoptimized',
'c_std=gnu11',
'cpp_std=c++20',
'warning_level=2',
])
# Would be better to create the version string
# from integers, i.e. concatenating strings instead
# of splitting a string, but 'project' needs to be
# the first meson.build keyword...
# split version into base and rc
version_parts = meson.project_version().split('-')
base_version = version_parts[0]
version_list = base_version.split('.')
FUSE_MAJOR_VERSION = version_list[0]
FUSE_MINOR_VERSION = version_list[1]
FUSE_HOTFIX_VERSION = version_list[2]
FUSE_RC_VERSION = version_parts.length() > 1 ? version_parts[1] : ''
platform = host_machine.system()
if platform == 'darwin'
error('libfuse does not support OS-X.\n' +
'Take a look at http://osxfuse.github.io/ or the more recent\n' +
'https://www.fuse-t.org/ instead')
elif platform == 'cygwin' or platform == 'windows'
error('libfuse does not support Windows.\n' +
'Take a look at http://www.secfs.net/winfsp/ instead')
endif
cc = meson.get_compiler('c')
#
# Feature detection, the resulting config file is installed
# with the package.
# Note: Symbols need to be care fully named, to avoid conflicts
# with applications linking to libfuse and including
# this config.
#
public_cfg = configuration_data()
public_cfg.set('FUSE_MAJOR_VERSION', FUSE_MAJOR_VERSION)
public_cfg.set('FUSE_MINOR_VERSION', FUSE_MINOR_VERSION)
public_cfg.set('FUSE_HOTFIX_VERSION', FUSE_HOTFIX_VERSION)
public_cfg.set('FUSE_RC_VERSION', FUSE_RC_VERSION)
# Default includes when checking for presence of functions and
# struct members
include_default = '''
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h> /* For pthread_setname_np */
'''
args_default = [ '-D_GNU_SOURCE' ]
#
# Feature detection, only available at libfuse compilation time,
# but not for application linking to libfuse.
#
private_cfg = configuration_data()
private_cfg.set_quoted('PACKAGE_VERSION', meson.project_version())
service_socket_dir = get_option('service-socket-dir')
service_socket_perms = get_option('service-socket-perms')
if service_socket_dir == ''
service_socket_dir = '/run/filesystems'
endif
if service_socket_perms == ''
service_socket_perms = '0220'
endif
private_cfg.set('FUSE_SERVICE_SOCKET_DIR_RAW', service_socket_dir)
private_cfg.set_quoted('FUSE_SERVICE_SOCKET_DIR', service_socket_dir)
private_cfg.set('FUSE_SERVICE_SOCKET_PERMS', service_socket_perms)
# Test for presence of some functions
test_funcs = [ 'fork', 'fstatat', 'openat', 'readlinkat', 'pipe2',
'splice', 'vmsplice', 'posix_fallocate', 'fdatasync',
'utimensat', 'copy_file_range', 'fallocate', 'fspacectl',
'faccessat' ]
foreach func : test_funcs
private_cfg.set('HAVE_' + func.to_upper(),
cc.has_function(func, prefix: include_default, args: args_default))
endforeach
# Special case checks that need custom code
special_funcs = {
'pthread_setname_np': '''
#include <pthread.h>
int main(void) {
pthread_t thread = pthread_self();
pthread_setname_np(thread, "test");
return 0;
}
''',
'close_range': '''
#include <unistd.h>
#include <fcntl.h>
#ifdef linux
#include <linux/close_range.h>
#endif
int main(void) {
unsigned int flags = CLOSE_RANGE_UNSHARE;
return close_range(3, ~0U, flags);
}
''',
'listmount': '''
#include <syscall.h>
#include <linux/mount.h>
#include <unistd.h>
#include <stdint.h>
int main(int argc, char *argv[]) {
struct mnt_id_req req = {
.size = sizeof(struct mnt_id_req),
.mnt_id = LSMT_ROOT,
};
uint64_t mnt_ids[1];
int n = syscall(SYS_listmount, &req, &mnt_ids, 1, 0);
if (n == -1) {
return -1;
}
}
''',
'new_mount_api': '''
#define _GNU_SOURCE
#include <sys/mount.h>
#include <linux/mount.h>
#include <unistd.h>
#include <fcntl.h>
int main(void) {
int fsfd = fsopen("fuse", FSOPEN_CLOEXEC);
int res = fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "test", 0);
int mntfd = fsmount(fsfd, FSMOUNT_CLOEXEC, 0);
res = move_mount(mntfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);
return 0;
}
''',
'systemd_headers': '''
#include <systemd/sd-daemon.h>
int main(int argc, char *argv[]) {
return SD_LISTEN_FDS_START;
}
''',
}
foreach name, code : special_funcs
private_cfg.set('HAVE_' + name.to_upper(),
cc.links(code, args: args_default,
name: name + ' check'))
endforeach
# Headers checks
test_headers = [ 'sys/xattr.h', 'linux/limits.h' ]
foreach header : test_headers
private_cfg.set('HAVE_' + header.underscorify().to_upper(),
cc.has_header(header))
endforeach
# Regular function checks
private_cfg.set('HAVE_SETXATTR',
cc.has_function('setxattr', prefix: '#include <sys/xattr.h>'))
private_cfg.set('HAVE_ICONV',
cc.has_function('iconv', prefix: '#include <iconv.h>'))
private_cfg.set('HAVE_BACKTRACE',
cc.has_function('backtrace', prefix: '#include <execinfo.h>'))
private_cfg.set('HAVE_STATX',
cc.has_function('statx', prefix : '#define _GNU_SOURCE\n#include <sys/stat.h>'))
# Struct member checks
private_cfg.set('HAVE_STRUCT_STAT_ST_ATIM',
cc.has_member('struct stat', 'st_atim',
prefix: include_default + '#include <sys/stat.h>',
args: args_default))
private_cfg.set('HAVE_STRUCT_STAT_ST_ATIMESPEC',
cc.has_member('struct stat', 'st_atimespec',
prefix: include_default + '#include <sys/stat.h>',
args: args_default))
private_cfg.set('USDT_ENABLED', get_option('enable-usdt'))
# Check for liburing with SQE128 support
code = '''
#include <liburing.h>
#include <stdio.h>
int main(void) {
struct io_uring ring;
int ret = io_uring_queue_init(1, &ring, 0);
#ifndef IORING_SETUP_SQE128
#error "No SQE128 support"
#endif
return ret;
}'''
liburing = dependency('liburing', required: false)
if get_option('enable-io-uring') and liburing.found()
if cc.links(code,
name: 'liburing linking and SQE128 support',
dependencies: [liburing])
private_cfg.set('HAVE_URING', true)
endif
endif
# Check for systemd support
systemd_system_unit_dir = get_option('systemd-system-unit-dir')
if systemd_system_unit_dir == ''
systemd = dependency('systemd', required: false)
if systemd.found()
systemd_system_unit_dir = systemd.get_variable(pkgconfig: 'systemd_system_unit_dir')
endif
endif
if systemd_system_unit_dir == '' or private_cfg.get('HAVE_SYSTEMD_HEADERS', false) == false
if systemd_system_unit_dir == ''
warning('systemd service support will not be built: systemd unit directory not found')
elif private_cfg.get('HAVE_SYSTEMD_HEADERS', false) == false
warning('systemd service support will not be built: systemd headers (libsystemd-dev) not found')
else
warning('systemd service support will not be built')
endif
else
private_cfg.set_quoted('SYSTEMD_SYSTEM_UNIT_DIR', systemd_system_unit_dir)
private_cfg.set('HAVE_SYSTEMD', true)
private_cfg.set('HAVE_SERVICEMOUNT', true)
endif
#
# Compiler configuration
#
add_project_arguments('-D_REENTRANT', '-DHAVE_LIBFUSE_PRIVATE_CONFIG_H', '-Wno-sign-compare', '-D_FILE_OFFSET_BITS=64',
'-Wstrict-prototypes', '-Wmissing-declarations', '-Wwrite-strings',
'-fno-strict-aliasing', language: 'c')
add_project_arguments('-D_REENTRANT', '-DHAVE_LIBFUSE_PRIVATE_CONFIG_H', '-D_GNU_SOURCE', '-D_FILE_OFFSET_BITS=64',
'-Wno-sign-compare', '-Wmissing-declarations',
'-Wwrite-strings', '-fno-strict-aliasing', language: 'cpp')
# Some (stupid) GCC versions warn about unused return values even when they are
# casted to void. This makes -Wunused-result pretty useless, since there is no
# way to suppress the warning when we really *want* to ignore the value.
code = '''
__attribute__((warn_unused_result)) int get_4() {
return 4;
}
int main(void) {
(void) get_4();
return 0;
}'''
if not cc.compiles(code, args: [ '-O0', '-Werror=unused-result' ])
message('Compiler warns about unused result even when casting to void')
add_project_arguments('-Wno-unused-result', language: 'c')
endif
# It is hard to detect if the libc supports versioned symbols. Only gnu-libc
# seems to provide that, but then glibc is the main target for libfuse, so
# enable it by default
versioned_symbols = 1
# This is an attempt to detect if another libc is used.
code = '''
int main(void) {
#if (defined(__UCLIBC__) || defined(__APPLE__))
#error /* libc does not have versioned symbols */
#endif
return 0;
}'''
if not cc.compiles(code, args: [ '-O0' ])
versioned_symbols = 0
endif
# The detection can be overridden, which is useful for other (above unhandled)
# libcs and also especially useful for testing
if get_option('disable-libc-symbol-version')
versioned_symbols = 0
endif
if versioned_symbols == 1
message('Enabling versioned libc symbols')
public_cfg.set('LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS', 1)
# gcc-10 and newer support the symver attribute which we need to use if we
# want to support LTO
# recent clang and gcc both support __has_attribute (and if they are too old
# to have __has_attribute, then they are too old to support symver)
# other compilers might not have __has_attribute, but in those cases
# it is safe for this check to fail and for us to fallback to the old _asm_
# method for symver. Anyway the attributes not supported by __has_attribute()
# unfortunately return true giving a false positive. So let's try to build
# using __attribute__ ((symver )) and see the result.
code = '''
__attribute__ ((symver ("test@TEST")))
void foo(void) {
}
int main(void) {
return 0;
}'''
if cc.compiles(code, args: [ '-O0', '-c', '-Werror'])
message('Compiler supports symver attribute')
add_project_arguments('-DHAVE_SYMVER_ATTRIBUTE', language: 'c')
else
message('Compiler does not support symver attribute')
endif
else
message('Disabling versioned libc symbols')
endif
# Older versions of musl libc don't unescape entries in /etc/mtab
# Try to detect this behaviour, and work around, if necessary.
detect_getmntent_needs_unescape = '''
#define _GNU_SOURCE
#include <mntent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define dir_space_tab "dir\\040space\\011tab"
int main()
{
const char *fake_mtab = "name " dir_space_tab " type opts 0 0\n";
FILE *f = fmemopen((void *)fake_mtab, strlen(fake_mtab) + 1, "r");
struct mntent *entp = getmntent(f);
fclose(f);
if(NULL == entp)
exit(EXIT_FAILURE);
if (0 == strcmp(entp->mnt_dir, dir_space_tab))
printf("needs escaping\n");
else
printf("no need to escape\n");
}
'''
if not meson.is_cross_build()
result = cc.run(detect_getmntent_needs_unescape)
if result.compiled() and result.returncode() == 0 and result.stdout().strip() == 'needs escaping'
message('getmntent does not unescape')
add_project_arguments('-DGETMNTENT_NEEDS_UNESCAPING', language: 'c')
endif
endif
# Write private test results into fuse_config.h (stored in build directory)
configure_file(output: 'fuse_config.h', configuration : private_cfg)
# Write the test results, installed with the package,
# symbols need to be properly prefixed to avoid
# symbol (define) conflicts
configure_file(output: 'libfuse_config.h',
configuration : public_cfg,
install: true, install_dir: join_paths(get_option('includedir'), 'fuse3'))
# '.' will refer to current build directory, which contains config.h
include_dirs = include_directories('include', 'lib', '.')
# Common dependencies
thread_dep = dependency('threads')
#
# Read build files from sub-directories
#
subdirs = [ 'lib', 'include']
if get_option('utils') and not platform.endswith('bsd') and platform != 'dragonfly'
subdirs += [ 'util', 'doc' ]
endif
if get_option('examples')
subdirs += 'example'
endif
if get_option('tests')
subdirs += 'test'
endif
foreach n : subdirs
subdir(n)
endforeach
#
# Configuration summary
#
summary({
'Examples': get_option('examples'),
'Tests': get_option('tests'),
'Utils': get_option('utils'),
}, section: 'Build Options')
summary({
'io_uring support': private_cfg.get('HAVE_URING', false),
'USDT tracing': private_cfg.get('USDT_ENABLED', false),
'systemd service support': private_cfg.get('HAVE_SYSTEMD', false),
'systemd headers': private_cfg.get('HAVE_SYSTEMD_HEADERS', false),
'systemd unit directory': systemd_system_unit_dir != '' ? systemd_system_unit_dir : '(not found)',
}, section: 'Features')