/* See license.txt in the root of this project. */ # ifndef LMT_COMPILER_H # define LMT_COMPILER_H /*tex Let's see if C 23 works out ok. We have to make sure that some assumed to be present functions like \type {readlink} and a few math ones are defined. The extensions flag below ensures that we're okay. CMake will fall back to older versions if needed, which is fine, until of course we start using more recent language features. \starttyping set(CMAKE_C_STANDARD 23) set(CMAKE_C_STANDARD_REQUIRED OFF) # OFF is default ###(CMAKE_C_EXTENSIONS ON) # ON is default \stoptyping This doesn't work: \starttyping // # define _POSIX_C_SOURCE 200809L // Exposes POSIX.1-2008 APIs including readlink // # define _GNU_SOURCE // or _DEFAULT_SOURCE // # include \stoptyping Let's assume that CMake handles all of this. */ /*tex Because \LUA\ (and mimalloc) uses it, why not also use it. The main gain is that the \quote {cold} brache code is move out of the way so that the cache is less stressed. The performance gains can probably be neglected. We mostly put these directives on catching errors. In \CPP\ we actually have a cleaner way \type {[[unlikely]]} that we can put after a condition, \type {else}, \type {label:} in a switch etc. But it didn't make it into C (yet), so we're stick with singular, unchained conditionals usage; I'm not going to cripple the code for more of this. So, for now, consider it an experiment, which is why we (can) report it being enabled. */ # if defined(__GNUC__) || defined(__clang__) # define lmt_likely(x) (__builtin_expect(!!(x),1)) # define lmt_unlikely(x) (__builtin_expect(!!(x),0)) # define LMT_LIKELY_USED 1 # elif (defined(__cplusplus) && (__cplusplus >= 202002L)) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) # define lmt_likely(x) (x) [[likely]] # define lmt_unlikely(x) (x) [[unlikely]] # define LMT_LIKELY_USED 1 # else # define lmt_likely(x) (x) # define lmt_unlikely(x) (x) # define LMT_LIKELY_USED 0 # endif /*tex We keep track of the \CCODE\ version being used, just in case we need to see what a locally compiled version actually uses. It is not relevant at all for the working of the engine. */ # ifndef LMT_COMPILER_USED # define LMT_COMPILER_USED "unknown" # endif #if defined(__STDC_VERSION__) // 202000L catches GCC 14 / Clang experimental C23; 202311L is final C23 # if __STDC_VERSION__ >= 202000L # define LMT_CVERSION_USED 23 # elif __STDC_VERSION__ >= 201710L # define LMT_CVERSION_USED 17 # elif __STDC_VERSION__ >= 201112L # define LMT_CVERSION_USED 11 # elif __STDC_VERSION__ >= 199901L # define LMT_CVERSION_USED 99 # elif __STDC_VERSION__ >= 199409L # define LMT_CVERSION_USED 95 # else # define LMT_CVERSION_USED 89 # endif # else # define LMT_CVERSION_USED 89 # endif /*tex It would be nice if we could test if musl is used. Comments in the web indicate that there never be some macro to check for that (argument: it shouldn't matter code/api wise). Well it does matter if you have to make a choice for a binary (set path to a tree), as needed in a TeX distribution that ships a lot. A bit lack of imagination I guess or maybe it's only for people who compile themselves. So if no one cares, I don't either. Maybe CMAKE can help some day. */ // # ifndef LMT_LIBC_USED // # if defined(__GLIBC__) // # define LMT_LIBC_USED "glibc" // # elif defined(__UCLIBC__) // # define LMT_LIBC_USED "uclibc" // # else // # define LMT_LIBC_USED "unknown" // # endif // # endif /*tex We don't want to see these messages when we compile. With C23 we suddenly got them back in the MS compiler. */ # ifndef __has_c_attribute # define __has_c_attribute(x) 0 # endif /* Ensure __has_c_attribute is safely defined so older preprocessors don't crash */ # ifndef __has_c_attribute # define __has_c_attribute(x) 0 # endif /* Standard C23 attribute */ # if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L # define FALLTHROUGH [[fallthrough]]; /* C23 attribute check for compilers supporting __has_c_attribute */ # elif __has_c_attribute(fallthrough) # define FALLTHROUGH [[fallthrough]]; /* GNU / Clang extension fallback */ # elif defined(__GNUC__) && (__GNUC__ >= 7) # define FALLTHROUGH __attribute__((fallthrough)); /* MSVC fallback */ # elif defined(_MSC_VER) && (_MSC_VER >= 1910) # define FALLTHROUGH __fallthrough; /* No-op fallback for older standard C compilers */ # else # define FALLTHROUGH ((void) 0); # endif # endif