summaryrefslogtreecommitdiffstats
path: root/src/prelude.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/prelude.h')
-rw-r--r--src/prelude.h391
1 files changed, 80 insertions, 311 deletions
diff --git a/src/prelude.h b/src/prelude.h
index 3521fe8..a0cc2a1 100644
--- a/src/prelude.h
+++ b/src/prelude.h
@@ -2,355 +2,124 @@
// SPDX-License-Identifier: 0BSD
/**
- * Configuration and feature/platform detection.
+ * Praeludium.
+ *
+ * This header is automatically included in every translation unit, before any
+ * other headers, so it can set feature test macros[1][2]. This sets up our own
+ * mini-dialect of C, which includes
+ *
+ * - Standard C17 and POSIX.1 2024 features
+ * - Portable and platform-specific extensions
+ * - Convenience macros like `bool`, `alignof`, etc.
+ * - Common compiler extensions like __has_include()
+ *
+ * Further bfs-specific utilities are defined in "bfs.h".
+ *
+ * [1]: https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
+ * [2]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html
*/
#ifndef BFS_PRELUDE_H
#define BFS_PRELUDE_H
-// Possible __STDC_VERSION__ values
+// Feature test macros
-#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 <assert.h>
-
-#if __STDC_VERSION__ < C23
-# include <stdalign.h>
-# include <stdbool.h>
-# include <stdnoreturn.h>
-#endif
+/**
+ * Linux and BSD handle _POSIX_C_SOURCE differently: on Linux, it enables POSIX
+ * interfaces that are not visible by default. On BSD, it also *disables* most
+ * extensions, giving a strict POSIX environment. Since we want the extensions,
+ * we don't set _POSIX_C_SOURCE.
+ */
+// #define _POSIX_C_SOURCE 202405L
-// bfs packaging configuration
+/** openat() etc. */
+#define _ATFILE_SOURCE 1
-#include "config.h"
+/** BSD-derived extensions. */
+#define _BSD_SOURCE 1
-#ifndef BFS_COMMAND
-# define BFS_COMMAND "bfs"
-#endif
-#ifndef BFS_HOMEPAGE
-# define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html"
-#endif
+/** glibc successor to _BSD_SOURCE. */
+#define _DEFAULT_SOURCE 1
-// 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[];
+/** GNU extensions. */
+#define _GNU_SOURCE 1
-// Check for system headers
+/** Use 64-bit off_t. */
+#define _FILE_OFFSET_BITS 64
-#ifdef __has_include
+/** Use 64-bit time_t. */
+#define _TIME_BITS 64
-#if __has_include(<mntent.h>)
-# define BFS_HAS_MNTENT_H true
-#endif
-#if __has_include(<paths.h>)
-# define BFS_HAS_PATHS_H true
-#endif
-#if __has_include(<sys/extattr.h>)
-# define BFS_HAS_SYS_EXTATTR_H true
-#endif
-#if __has_include(<sys/mkdev.h>)
-# define BFS_HAS_SYS_MKDEV_H true
+/** macOS extensions. */
+#if __APPLE__
+# define _DARWIN_C_SOURCE 1
#endif
-#if __has_include(<sys/param.h>)
-# define BFS_HAS_SYS_PARAM_H true
-#endif
-#if __has_include(<sys/sysmacros.h>)
-# define BFS_HAS_SYS_SYSMACROS_H true
-#endif
-#if __has_include(<sys/xattr.h>)
-# define BFS_HAS_SYS_XATTR_H true
-#endif
-#if __has_include(<threads.h>)
-# define BFS_HAS_THREADS_H true
-#endif
-#if __has_include(<util.h>)
-# 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_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
+/** Solaris extensions. */
+#if __sun
+# define __EXTENSIONS__ 1
+// https://illumos.org/man/3C/getpwnam#standard-conforming
+# define _POSIX_PTHREAD_SEMANTICS 1
#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
-
-// Fundamental utilities
-/**
- * Get the length of an array.
- */
-#define countof(array) (sizeof(array) / sizeof(0[array]))
+// Get the convenience macros that became standard spellings in C23
+#if __STDC_VERSION__ < 202311L
-/**
- * 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
+/** _Static_assert() => static_assert() */
+#include <assert.h>
+/** _Alignas(), _Alignof() => alignas(), alignof() */
+#include <stdalign.h>
+/** _Bool => bool, true, false */
+#include <stdbool.h>
/**
- * True sharing/constructive interference/smallest cache line size.
+ * C23 deprecates `noreturn void` in favour of `[[noreturn]] void`, so we expose
+ * _noreturn instead with the other attributes in "bfs.h".
*/
-#ifdef __GCC_CONSTRUCTIVE_SIZE
-# define TRUE_SHARING_SIZE __GCC_CONSTRUCTIVE_SIZE
-#else
-# define TRUE_SHARING_SIZE 64
-#endif
+// #include <stdnoreturn.h>
-/**
- * Alignment specifier that avoids false sharing.
- */
-#define cache_align alignas(FALSE_SHARING_SIZE)
+/** Part of <threads.h>, but we don't use anything else from it. */
+#define thread_local _Thread_local
-// Wrappers for attributes
+#endif // !C23
-/**
- * Silence warnings about switch/case fall-throughs.
- */
-#if __has_attribute(fallthrough)
-# define fallthru __attribute__((fallthrough))
-#else
-# define fallthru ((void)0)
-#endif
+// Feature detection
-/**
- * Silence warnings about unused declarations.
- */
-#if __has_attribute(unused)
-# define attr_maybe_unused __attribute__((unused))
-#else
-# define attr_maybe_unused
-#endif
-
-/**
- * Warn if a value is unused.
- */
-#if __has_attribute(warn_unused_result)
-# define attr_nodiscard __attribute__((warn_unused_result))
-#else
-# define attr_nodiscard
-#endif
-
-/**
- * Hint to avoid inlining a function.
- */
-#if __has_attribute(noinline)
-# define attr_noinline __attribute__((noinline))
-#else
-# define attr_noinline
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
+#ifndef __has_attribute
+# define __has_attribute(attr) false
#endif
-/**
- * Hint that a function is unlikely to be called.
- */
-#if __has_attribute(cold)
-# define attr_cold attr_noinline __attribute__((cold))
-#else
-# define attr_cold attr_noinline
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-builtin
+#ifndef __has_builtin
+# define __has_builtin(builtin) false
#endif
-/**
- * Adds compiler warnings for bad printf()-style function calls, if supported.
- */
-#if __has_attribute(format)
-# define attr_printf(fmt, args) __attribute__((format(printf, fmt, args)))
-#else
-# define attr_printf(fmt, args)
+// https://en.cppreference.com/w/c/language/attributes#Attribute_testing
+#ifndef __has_c_attribute
+# define __has_c_attribute(attr) false
#endif
-/**
- * Annotates functions that potentially modify and return format strings.
- */
-#if __has_attribute(format_arg)
-# define attr_format_arg(arg) __attribute__((format_arg(arg)))
-#else
-# define attr_format_arg(args)
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
+#ifndef __has_feature
+# define __has_feature(feat) false
#endif
-/**
- * Annotates allocator-like functions.
- */
-#if __has_attribute(malloc)
-# if __GNUC__ >= 11 && !__OPTIMIZE__ // malloc(deallocator) disables inlining on GCC
-# define attr_malloc(...) attr_nodiscard __attribute__((malloc(__VA_ARGS__)))
-# else
-# define attr_malloc(...) attr_nodiscard __attribute__((malloc))
-# endif
-#else
-# define attr_malloc(...) attr_nodiscard
+// https://en.cppreference.com/w/c/preprocessor/include
+#ifndef __has_include
+# define __has_include(header) false
#endif
-/**
- * Specifies that a function returns allocations with a given alignment.
- */
-#if __has_attribute(alloc_align)
-# define attr_alloc_align(param) __attribute__((alloc_align(param)))
-#else
-# define attr_alloc_align(param)
-#endif
+// Sanitizer macros (GCC defines these but Clang does not)
-/**
- * Specifies that a function returns allocations with a given size.
- */
-#if __has_attribute(alloc_size)
-# define attr_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__)))
-#else
-# define attr_alloc_size(...)
+#if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
+# define __SANITIZE_ADDRESS__ true
#endif
-
-/**
- * Shorthand for attr_alloc_align() and attr_alloc_size().
- */
-#define attr_aligned_alloc(align, ...) \
- attr_alloc_align(align) \
- attr_alloc_size(__VA_ARGS__)
-
-/**
- * Check if function multiversioning via GNU indirect functions (ifunc) is supported.
- */
-#ifndef BFS_USE_TARGET_CLONES
-# if __has_attribute(target_clones) && (__GLIBC__ || __FreeBSD__)
-# define BFS_USE_TARGET_CLONES true
-# endif
+#if __has_feature(memory_sanitizer) && !defined(__SANITIZE_MEMORY__)
+# define __SANITIZE_MEMORY__ true
#endif
-
-/**
- * Apply the target_clones attribute, if available.
- */
-#if BFS_USE_TARGET_CLONES
-# define attr_target_clones(...) __attribute__((target_clones(__VA_ARGS__)))
-#else
-# define attr_target_clones(...)
+#if __has_feature(thread_sanitizer) && !defined(__SANITIZE_THREAD__)
+# define __SANITIZE_THREAD__ true
#endif
-/**
- * Shorthand for multiple attributes at once. attr(a, b(c), d) is equivalent to
- *
- * attr_a
- * attr_b(c)
- * attr_d
- */
-#define attr(...) \
- attr__(attr_##__VA_ARGS__, none, none, none, none, none, none, none, none, none, )
-
-/**
- * attr() helper. For exposition, pretend we support only 2 args, instead of 9.
- * There are a few cases:
- *
- * attr()
- * => attr__(attr_, none, none)
- * => attr_ =>
- * attr_none =>
- * attr_too_many_none() =>
- *
- * attr(a)
- * => attr__(attr_a, none, none)
- * => attr_a => __attribute__((a))
- * attr_none =>
- * attr_too_many_none() =>
- *
- * attr(a, b(c))
- * => attr__(attr_a, b(c), none, none)
- * => attr_a => __attribute__((a))
- * attr_b(c) => __attribute__((b(c)))
- * attr_too_many_none(none) =>
- *
- * attr(a, b(c), d)
- * => attr__(attr_a, b(c), d, none, none)
- * => attr_a => __attribute__((a))
- * attr_b(c) => __attribute__((b(c)))
- * attr_too_many_d(none, none) => error
- *
- * Some attribute names are the same as standard library functions, e.g. printf.
- * Standard libraries are permitted to define these functions as macros, like
- *
- * #define printf(...) __builtin_printf(__VA_ARGS__)
- *
- * The token paste in
- *
- * #define attr(...) attr__(attr_##__VA_ARGS__, none, none)
- *
- * is necessary to prevent macro expansion before evaluating attr__().
- * Otherwise, we could get
- *
- * attr(printf(1, 2))
- * => attr__(__builtin_printf(1, 2), none, none)
- * => attr____builtin_printf(1, 2)
- * => error
- */
-#define attr__(a1, a2, a3, a4, a5, a6, a7, a8, a9, none, ...) \
- a1 \
- attr_##a2 \
- attr_##a3 \
- attr_##a4 \
- attr_##a5 \
- attr_##a6 \
- attr_##a7 \
- attr_##a8 \
- attr_##a9 \
- attr_too_many_##none(__VA_ARGS__)
-
-// Ignore `attr_none` from expanding 1-9 argument attr(a1, a2, ...)
-#define attr_none
-// Ignore `attr_` from expanding 0-argument attr()
-#define attr_
-// Only trigger an error on more than 9 arguments
-#define attr_too_many_none(...)
-
#endif // BFS_PRELUDE_H