// Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD /** * Configuration and feature/platform detection. */ #ifndef BFS_PRELUDE_H #define BFS_PRELUDE_H // Possible __STDC_VERSION__ values #define C95 199409L #define C99 199901L #define C11 201112L #define C17 201710L #define C23 202311L // Get the static_assert() definition as well as __GLIBC__ #include // Get the convenience macros that became standard spellings in C23 #if __STDC_VERSION__ < C23 /** _Alignas(), _Alignof() => alignas(), alignof() */ #include /** _Bool => bool, true, false */ #include /** * C23 deprecates `noreturn void` in favour of `[[noreturn]] void`, so we expose * _noreturn instead with the other attributes. */ // #include /** Part of , but we don't use anything else from it. */ #define thread_local _Thread_local #endif // !C23 // bfs packaging configuration #include "config.h" #ifndef BFS_COMMAND # define BFS_COMMAND "bfs" #endif #ifndef BFS_HOMEPAGE # define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html" #endif // This is a symbol instead of a literal so we don't have to rebuild everything // when the version number changes extern const char bfs_version[]; extern const char bfs_confflags[]; extern const char bfs_cc[]; extern const char bfs_cppflags[]; extern const char bfs_cflags[]; extern const char bfs_ldflags[]; extern const char bfs_ldlibs[]; // Check for system headers #ifdef __has_include #if __has_include() # define BFS_HAS_MNTENT_H true #endif #if __has_include() # define BFS_HAS_PATHS_H true #endif #if __has_include() # define BFS_HAS_STDBIT_H true #endif #if __has_include() # define BFS_HAS_SYS_EXTATTR_H true #endif #if __has_include() # define BFS_HAS_SYS_MKDEV_H true #endif #if __has_include() # define BFS_HAS_SYS_PARAM_H true #endif #if __has_include() # define BFS_HAS_SYS_SYSMACROS_H true #endif #if __has_include() # define BFS_HAS_SYS_XATTR_H true #endif #if __has_include() # define BFS_HAS_THREADS_H true #endif #if __has_include() # define BFS_HAS_UTIL_H true #endif #else // !__has_include #define BFS_HAS_MNTENT_H __GLIBC__ #define BFS_HAS_PATHS_H true #define BFS_HAS_STDBIT_H (__STDC_VERSION__ >= C23) #define BFS_HAS_SYS_EXTATTR_H __FreeBSD__ #define BFS_HAS_SYS_MKDEV_H false #define BFS_HAS_SYS_PARAM_H true #define BFS_HAS_SYS_SYSMACROS_H __GLIBC__ #define BFS_HAS_SYS_XATTR_H __linux__ #define BFS_HAS_THREADS_H (!__STDC_NO_THREADS__) #define BFS_HAS_UTIL_H __NetBSD__ #endif // !__has_include #ifndef BFS_USE_MNTENT_H # define BFS_USE_MNTENT_H BFS_HAS_MNTENT_H #endif #ifndef BFS_USE_PATHS_H # define BFS_USE_PATHS_H BFS_HAS_PATHS_H #endif #ifndef BFS_USE_SYS_EXTATTR_H # define BFS_USE_SYS_EXTATTR_H BFS_HAS_SYS_EXTATTR_H #endif #ifndef BFS_USE_SYS_MKDEV_H # define BFS_USE_SYS_MKDEV_H BFS_HAS_SYS_MKDEV_H #endif #ifndef BFS_USE_SYS_PARAM_H # define BFS_USE_SYS_PARAM_H BFS_HAS_SYS_PARAM_H #endif #ifndef BFS_USE_SYS_SYSMACROS_H # define BFS_USE_SYS_SYSMACROS_H BFS_HAS_SYS_SYSMACROS_H #endif #ifndef BFS_USE_SYS_XATTR_H # define BFS_USE_SYS_XATTR_H BFS_HAS_SYS_XATTR_H #endif #ifndef BFS_USE_THREADS_H # define BFS_USE_THREADS_H BFS_HAS_THREADS_H #endif #ifndef BFS_USE_UTIL_H # define BFS_USE_UTIL_H BFS_HAS_UTIL_H #endif // Stub out feature detection on old/incompatible compilers #ifndef __has_feature # define __has_feature(feat) false #endif #ifndef __has_c_attribute # define __has_c_attribute(attr) false #endif #ifndef __has_attribute # define __has_attribute(attr) false #endif #ifndef __has_builtin # define __has_builtin(builtin) false #endif // Sanitizer macros (GCC defines these but Clang does not) #if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) # define __SANITIZE_ADDRESS__ true #endif #if __has_feature(memory_sanitizer) && !defined(__SANITIZE_MEMORY__) # define __SANITIZE_MEMORY__ true #endif #if __has_feature(thread_sanitizer) && !defined(__SANITIZE_THREAD__) # define __SANITIZE_THREAD__ true #endif // Fundamental utilities /** * Get the length of an array. */ #define countof(...) (sizeof(__VA_ARGS__) / sizeof(0[__VA_ARGS__])) /** * False sharing/destructive interference/largest cache line size. */ #ifdef __GCC_DESTRUCTIVE_SIZE # define FALSE_SHARING_SIZE __GCC_DESTRUCTIVE_SIZE #else # define FALSE_SHARING_SIZE 64 #endif /** * True sharing/constructive interference/smallest cache line size. */ #ifdef __GCC_CONSTRUCTIVE_SIZE # define TRUE_SHARING_SIZE __GCC_CONSTRUCTIVE_SIZE #else # define TRUE_SHARING_SIZE 64 #endif /** * Alignment specifier that avoids false sharing. */ #define cache_align alignas(FALSE_SHARING_SIZE) // Wrappers for attributes /** * Silence warnings about switch/case fall-throughs. */ #if __has_attribute(fallthrough) # define _fallthrough __attribute__((fallthrough)) #else # define _fallthrough ((void)0) #endif /** * Silence warnings about unused declarations. */ #if __has_attribute(unused) # define _maybe_unused __attribute__((unused)) #else # define _maybe_unused #endif /** * Warn if a value is unused. */ #if __has_attribute(warn_unused_result) # define _nodiscard __attribute__((warn_unused_result)) #else # define _nodiscard #endif /** * Hint to avoid inlining a function. */ #if __has_attribute(noinline) # define _noinline __attribute__((noinline)) #else # define _noinline #endif /** * Marks a non-returning function. */ #if __STDC_VERSION__ >= C23 # define _noreturn [[noreturn]] #else # define _noreturn _Noreturn #endif /** * Hint that a function is unlikely to be called. */ #if __has_attribute(cold) # define _cold _noinline __attribute__((cold)) #else # define _cold _noinline #endif /** * Adds compiler warnings for bad printf()-style function calls, if supported. */ #if __has_attribute(format) # define _printf(fmt, args) __attribute__((format(printf, fmt, args))) #else # define _printf(fmt, args) #endif /** * Annotates functions that potentially modify and return format strings. */ #if __has_attribute(format_arg) # define _format_arg(arg) __attribute__((format_arg(arg))) #else # define _format_arg(arg) #endif /** * Annotates allocator-like functions. */ #if __has_attribute(malloc) # if __GNUC__ >= 11 && !__OPTIMIZE__ // malloc(deallocator) disables inlining on GCC # define _malloc(...) _nodiscard __attribute__((malloc(__VA_ARGS__))) # else # define _malloc(...) _nodiscard __attribute__((malloc)) # endif #else # define _malloc(...) _nodiscard #endif /** * Specifies that a function returns allocations with a given alignment. */ #if __has_attribute(alloc_align) # define _alloc_align(param) __attribute__((alloc_align(param))) #else # define _alloc_align(param) #endif /** * Specifies that a function returns allocations with a given size. */ #if __has_attribute(alloc_size) # define _alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) #else # define _alloc_size(...) #endif /** * Shorthand for _alloc_align() and _alloc_size(). */ #define _aligned_alloc(align, ...) _alloc_align(align) _alloc_size(__VA_ARGS__) /** * Check if function multiversioning via GNU indirect functions (ifunc) is supported. * * Disabled on TSan due to https://github.com/google/sanitizers/issues/342. */ #ifndef BFS_USE_TARGET_CLONES # if __has_attribute(target_clones) && (__GLIBC__ || __FreeBSD__) && !__SANITIZE_THREAD__ # define BFS_USE_TARGET_CLONES true # endif #endif /** * Apply the target_clones attribute, if available. */ #if BFS_USE_TARGET_CLONES # define _target_clones(...) __attribute__((target_clones(__VA_ARGS__))) #else # define _target_clones(...) #endif #endif // BFS_PRELUDE_H