From d4696bda3615496002392eb4e2227ef0d0f7fa13 Mon Sep 17 00:00:00 2001 From: Mobin Aydinfar Date: Wed, 13 Aug 2025 19:22:27 +0330 Subject: [PATCH 1/6] configure: split compiling/linking functions from argument checkers This makes configure more flexible for other checks such as header checks and more. --- configure | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 199168b1..57be57e3 100755 --- a/configure +++ b/configure @@ -83,6 +83,34 @@ cxx_works() fi } +# Test if the compiler successfully compiles the specified source file. If the optional compilation +# argument is specified ($3) then pass it to the compiler along with the already-established +# arguments (this can be used to test if the compiler accepts the argument). +# $1 - the name of the source file to compile +# $2 - the name of the result object file +# $3 - the argument to test (optional) +# CXX - the name of the compiler +# CXXFLAGS, CXXFLAGS_EXTRA - any predetermined flags +try_compile_source() +{ + eval $CXX $CXXFLAGS ${3:-} $CXXFLAGS_EXTRA '"$configtmpdir"/"$1"' \ + -c -o '"$configtmpdir"/"$2"' > /dev/null 2>&1 +} + +# Test if the specified object file can be linked into an executable. If the optional link argument +# is specified ($3) then pass it to the compiler driver along with the already-established +# arguments (this can be used to test if the linker accepts the argument). +# $1 - the name of the object file to link +# $2 - the name of the result executable file +# $3 - the argument to test (optional) +# CXX - the name of the compiler +# LDFLAGS, LDFLAGS_EXTRA - any predetermined flags +try_link_object() +{ + eval $CXX $LDFLAGS $LDFLAGS_EXTRA ${3:-} '"$configtmpdir"/"$1"' \ + -o '"$configtmpdir"/"$2"' > /dev/null 2>&1 +} + # Test if the compiler accepts an argument (for compilation only); if so add it to named variable. # Note: this function will return failure if the flag is unsupported (use try_optional_cxx_argument # instead, to avoid errorring out). @@ -93,8 +121,7 @@ cxx_works() try_cxx_argument() { info Checking whether "$2" is accepted for compilation... - if eval $CXX $CXXFLAGS $2 $CXXFLAGS_EXTRA $LDFLAGS $LDFLAGS_EXTRA '"$configtmpdir"/testfile.cc' \ - -c -o '"$configtmpdir"/testfile.o' > /dev/null 2>&1; then + if try_compile_source testfile.cc testfile.o "$2"; then rm "$configtmpdir"/testfile.o sub_info Yes. eval "$1=\"\${$1} \$2\"" @@ -127,14 +154,12 @@ try_ld_argument() info Checking whether "$2" is accepted as a link-time option... if [ ! -e "$configtmpdir"/testfile.o ]; then # If the object file doesn't exist yet, need to compile - if ! eval $CXX $CXXFLAGS $CXXFLAGS_EXTRA '"$configtmpdir"/testfile.cc' \ - -c -o '"$configtmpdir"/testfile.o' > /dev/null 2>&1; then + if ! try_compile_source testfile.cc testfile.o; then sub_info "No (compilation failed)." return fi fi - if eval $CXX $LDFLAGS $LDFLAGS_EXTRA $2 '"$configtmpdir"/testfile.o' \ - -o '"$configtmpdir"/testfile' > /dev/null 2>&1; then + if try_link_object testfile.o testfile "$2"; then sub_info Yes. rm "$configtmpdir"/testfile eval "$1=\"\${$1} \$2\"" @@ -153,9 +178,9 @@ try_ld_argument() try_both_argument() { info Checking whether "$3" is accepted for compiling and linking... - if eval $CXX $CXXFLAGS $CXXFLAGS_EXTRA $LDFLAGS $LDFLAGS_EXTRA $3 "$configtmpdir"/testfile.cc \ - -o "$configtmpdir"/testfile > /dev/null 2>&1; then + if try_compile_source testfile.cc testfile.o "$3" && try_link_object testfile.o testfile "$3"; then sub_info Yes. + rm "$configtmpdir"/testfile.o rm "$configtmpdir"/testfile eval "$1=\"\${$1} \$3\"" eval "$1=\${$1# }" From 13bd95ad992cfc02ac3a93ec23bfac1ddca95912 Mon Sep 17 00:00:00 2001 From: Mobin Aydinfar Date: Sat, 16 Aug 2025 18:14:17 +0330 Subject: [PATCH 2/6] try_both_argument: make the out-parameters optional It's common to check a flag against both the compiler and linker, but only add the flag to one of the compiler or link flags variables to avoid duplicate flags. It was done by specifying a "dummy" variable which the caller would then unset. The dash ("-") can now be specified instead of a variable name for this purpose. --- configure | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/configure b/configure index 57be57e3..bcbf3d08 100755 --- a/configure +++ b/configure @@ -170,8 +170,10 @@ try_ld_argument() } # Test if an argument is supported during both compiling and linking. -# $1 - the name of the compiler-flags variable to potentially add the argument to -# $2 - the name of the link-flags variable to potentially add the argument to +# $1 - the name of the compiler-flags variable to potentially add the argument to (or specify the +# dash ("-") to skip adding to the variable) +# $2 - the name of the link-flags variable to potentially add the argument to (or specify the +# dash ("-") to skip adding to the variable) # $3 - the argument to test/add # CXX - the name of the compiler # CXXFLAGS, CXXFLAGS_EXTRA, LDFLAGS, LDFLAGS_EXTRA - any predetermined flags @@ -182,10 +184,14 @@ try_both_argument() sub_info Yes. rm "$configtmpdir"/testfile.o rm "$configtmpdir"/testfile - eval "$1=\"\${$1} \$3\"" - eval "$1=\${$1# }" - eval "$2=\"\${$2} \$3\"" - eval "$2=\${$2# }" + if [ "$1" != "-" ]; then + eval "$1=\"\${$1} \$3\"" + eval "$1=\${$1# }" + fi + if [ "$2" != "-" ]; then + eval "$2=\"\${$2} \$3\"" + eval "$2=\${$2# }" + fi else sub_info No. fi @@ -531,15 +537,13 @@ if [ "$AUTO_CXXFLAGS" = "true" ]; then fi fi if [ "$AUTO_LDFLAGS" = true ] && [ "$AUTO_CXXFLAGS" = true ]; then - DUMMY_LDFLAGS="" # -flto must work for both compiling and linking, but we don't want to add it to LDFLAGS as, # if LTO is used, CXXFLAGS will always be used alongside LDFLAGS. - if try_both_argument CXXFLAGS DUMMY_LDFLAGS -flto; then + if try_both_argument CXXFLAGS - -flto; then HAS_LTO="true" else HAS_LTO="false" fi - unset DUMMY_LDFLAGS fi if [ "$AUTO_LDFLAGS_BASE" = true ] && [ "$PLATFORM" = FreeBSD ]; then try_ld_argument LDFLAGS_BASE -lrt @@ -613,10 +617,9 @@ fi # Check whether sanitizers can be used for tests if [ "$AUTO_TEST_LDFLAGS" = "true" ] && [ "$AUTO_TEST_CXXFLAGS" = "true" ]; then - DUMMY_LDFLAGS="" if [ "$HAS_LTO" = true ]; then # Avoid doubling-up sanitizer options - LDFLAGS_VAR=DUMMY_LDFLAGS + LDFLAGS_VAR=- else LDFLAGS_VAR=TEST_LDFLAGS_MK fi @@ -624,7 +627,6 @@ if [ "$AUTO_TEST_LDFLAGS" = "true" ] && [ "$AUTO_TEST_CXXFLAGS" = "true" ]; then CXXFLAGS="$established_TEST_CXXFLAGS" CXXFLAGS_EXTRA="$TEST_CXXFLAGS_EXTRA" \ LDFLAGS="$established_TEST_LDFLAGS" LDFLAGS_EXTRA="$TEST_LDFLAGS_EXTRA" \ try_both_argument TEST_CXXFLAGS_MK $LDFLAGS_VAR -fsanitize=address,undefined - unset DUMMY_LDFLAGS fi ## Create mconfig From 9e1028c2e875bcb4d9fe0b61add189be8133f6f7 Mon Sep 17 00:00:00 2001 From: Mobin Aydinfar Date: Sat, 16 Aug 2025 18:54:58 +0330 Subject: [PATCH 3/6] configure: check availability of ioprio.h on Linux SUPPORT_IOPRIO was disabled by default on Linux because configure assumes ioprio.h is not available on the system. We now check for ioprio.h via check_header(), a new function for checking header usability. See #478 --- configure | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/configure b/configure index bcbf3d08..5ee72b3a 100755 --- a/configure +++ b/configure @@ -197,6 +197,23 @@ try_both_argument() fi } +# Test if the specified header is usable. +# $1 - the name of the variable to set to 1 or 0 based on header availability +# $2 - the header path +check_header() +{ + info Checking whether "$2" header is available... + echo "#include <$2>" > "$configtmpdir/testheader.cc" + if try_compile_source testheader.cc testheader.o; then + sub_info "Yes." + rm "$configtmpdir"/testheader.o + eval "$1=1" + else + sub_info "No." + eval "$1=0" + fi +} + # Quote a string to preserve its original form after shell evaluation (except that an empty @@ -430,7 +447,7 @@ if [ "$PLATFORM" = "Linux" ]; then : "${BUILD_SHUTDOWN:="yes"}" : "${SUPPORT_CGROUPS:="1"}" : "${SUPPORT_CAPABILITIES:="AUTO"}" - : "${SUPPORT_IOPRIO:="0"}" # the required header may not be available + : "${SUPPORT_IOPRIO:="AUTO"}" : "${SUPPORT_OOM_ADJ:="1"}" : "${SYSCONTROLSOCKET:="/run/dinitctl"}" else @@ -566,6 +583,10 @@ else LDFLAGS_LIBCAP="" fi +if [ "$SUPPORT_IOPRIO" = "AUTO" ]; then + check_header SUPPORT_IOPRIO "linux/ioprio.h" +fi + # "XXX_MK" variables are for values already quoted for use in makefiles. The following will now be # set: TEST_LDFLAGS_BASE_MK, LDFLAGS_MK, TEST_LDFLAGS_MK, TEST_CXXFLAGS_MK. For other build # variables, we'll just do the quoting when we write the value to mconfig. From 1f5442e1373e5e599348b78a1c7511350dce48b1 Mon Sep 17 00:00:00 2001 From: Mobin Aydinfar Date: Sat, 16 Aug 2025 19:55:24 +0330 Subject: [PATCH 4/6] configure: check that -fno-rtti works correctly There is an issue with catching standard library exceptions when using -fno-rtti with some combination of clang and runtime libraries. See #486 --- configure | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 5ee72b3a..b3ed5e6f 100755 --- a/configure +++ b/configure @@ -214,6 +214,27 @@ check_header() fi } +# Write the test code for testing exception handling with -fno-rtti +write_no_rtti_check() +{ + cat << _EOF > "$configtmpdir"/no-rtti-check.cc +#include +#include + +int main() +{ + try { + std::stoull("invalid for stoull"); + } + catch (std::invalid_argument &exc) { + return 0; + } + + return -1; +} +_EOF +} + # Quote a string to preserve its original form after shell evaluation (except that an empty @@ -549,8 +570,27 @@ if [ "$AUTO_CXXFLAGS" = "true" ]; then do try_optional_cxx_argument CXXFLAGS $argument done - if [ "$PLATFORM" != "Darwin" ]; then - try_optional_cxx_argument CXXFLAGS -fno-rtti + + # -fno-rtti is a special case. Clang+libcxxrt is known for generating broken code + # when disabling run-time type information with code which uses exceptions. + info Checking whether -fno-rtti is accepted for compilation... + if [ -n "${CXX_FOR_BUILD:-}" ]; then + # May not be able to execute the check when cross-compiling. + sub_info Cross-compilation detected. Disabling -fno-rtti to make sure exceptions will always work. + else + write_no_rtti_check + if try_compile_source no-rtti-check.cc no-rtti-check.o -fno-rtti; then + sub_info "Yes." + info Checking whether -fno-rtti breaks exceptions... + if try_link_object no-rtti-check.o no-rtti-check && "$configtmpdir"/no-rtti-check; then + sub_info "No." + CXXFLAGS="$CXXFLAGS -fno-rtti" + else + sub_info "Yes. Disabling -fno-rtti" + fi + else + sub_info "No." + fi fi fi if [ "$AUTO_LDFLAGS" = true ] && [ "$AUTO_CXXFLAGS" = true ]; then From 479c772c7d2b9b155441dcb91264c4250c6d384e Mon Sep 17 00:00:00 2001 From: Mobin Aydinfar Date: Wed, 17 Sep 2025 23:04:04 +0330 Subject: [PATCH 5/6] BUILD: refactor documentation about RTTI and -fno-rtti flag It was a little outdated and unclear. For instance, we have a confirmed case of a Dinit crash on FreeBSD with the newest Clang+libcxxrt when using -fno-rtti (#486), but the doc said "(and historically FreeBSD, IIRC)" had the exception handling problem with -fno-rtti. --- BUILD | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/BUILD b/BUILD index 0a492e93..0ad01251 100644 --- a/BUILD +++ b/BUILD @@ -140,9 +140,8 @@ Dinit should generally build fine with no additional options, other than: Recommended options, supported by at least GCC and Clang, are: -Os : optimise for size - -fno-rtti : disable RTTI (run-time type information), it is not required by Dinit. However, on - some platforms such as Mac OS (and historically FreeBSD, IIRC), this prevents - exceptions working correctly. + -fno-rtti : see "Special note for run-time type information", below. May cause Dinit to crash on + errors when compiled with Clang+libcxxrt on some platforms like FreeBSD. -fno-plt : enables better code generation for non-static builds, but may cause unit test failures on some older versions of FreeBSD (eg 11.2-RELEASE-p4 with clang++ 6.0.0). -flto : perform link-time optimisation (option required at compile and link). @@ -292,3 +291,26 @@ upgrading GCC. If you have libstdc++ corresponding to GCC 5.x or 6.x, you *must* old ABI, but Dinit will be broken if you upgrade to GCC 7. If you have libstdc++ from GCC 7, you *must* build with the new ABI. If the wrong ABI is used, Dinit may still run successfully but any attempt to load a non-existing service, for example, will cause Dinit to crash. + + +Special note for run-time type information +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +RTTI, or run-time type information, is a feature of C++ that exposes information about an object's +data type at runtime. This can be used for "dynamic_cast<>" and to manipulate type information at +runtime using the "typeid" operator. Exception handling also uses the same info. + +GCC and Clang provide a compiler flag ("-fno-rtti") which would disable RTTI generation. However +GCC would still generate RTTI for exception handling and therefore "-fno-rtti" is a viable option +for saving output binary size. + +Clang on some platforms (such as FreeBSD) would break handling of certain exceptions when using +"-fno-rtti" and this will result in Dinit crashing when an error occurs (such as when loading a +non-existing service). + +Details regarding the issue with Clang can be found here: + + https://github.com/llvm/llvm-project/issues/66117 + +To avoid Dinit crashes when using Clang+libcxxrt it's recommended to not use the "-fno-rtti" flag. +Clang+libcxxrt is the default compiler+runtime-library on platforms like FreeBSD and macOS. From 60594166e79486f2b56e034dbf58b18f70247ae3 Mon Sep 17 00:00:00 2001 From: Mobin Aydinfar Date: Thu, 18 Sep 2025 00:28:25 +0330 Subject: [PATCH 6/6] BUILD: refactor documentation about configure The reference to configure is now refactored into its own section with more information about it. This is done because of new checks in configure. --- BUILD | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/BUILD b/BUILD index 0ad01251..dfd6e1c6 100644 --- a/BUILD +++ b/BUILD @@ -36,18 +36,34 @@ this file by hand, before proceeding with the build. Note that the the generated a symbolic link to a system-specific default config file. It is not necessary to edit the file; you can override variables on the "make" command line if you prefer. +You can also create and edit the "mconfig" file completely by hand (or start by copying one for a +particular OS from the "configs" directory) to choose appropriate values for the configuration +variables defined within. + + +"configure" script +=-=-=-=-=-=-=-=-=- + An alternative to "make mconfig" is to use the provided "configure" script. It will try to generate a suitable "mconfig" file, based on sensible defaults and options provided on the command -line when the script is run. +line when the script is run. It also has checks for the current system environment to +enable/disable certain features based on the availability of requirements (such as headers). + +The "configure" also checks for usability of the "-fno-rtti" compiler flag. This is achieved by +testing the flag itself and running a test source code to see if it works correctly. However, +because of the nature of cross-compiling, it's not possible to compile and run the test source +code on the building machine, and instead, "configure" disables "-fno-rtti" in this case and prints +out this warning: + + Cross-compilation detected. Disabling -fno-rtti to make sure exceptions will always work. + +See "Special note for run-time type information", below, for more information about the "-fno-rtti" +flag. For more information on available options from the configure script, run: ./configure --help -You can also create and edit the "mconfig" file completely by hand (or start by copying one for a -particular OS from the "configs" directory) to choose appropriate values for the configuration -variables defined within. - Main build variables =-=-=-=-=-=-=-=-=-=-