diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f6135bc..39c76406 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ include(CheckSymbolExists) include(CheckStructHasMember) include(CheckCSourceCompiles) include(cmake/tuklib_integer.cmake) +include(cmake/tuklib_gnu_c_attributes.cmake) include(cmake/tuklib_cpucores.cmake) include(cmake/tuklib_physmem.cmake) include(cmake/tuklib_progname.cmake) @@ -750,17 +751,7 @@ if(NOT TUKLIB_CPUCORES_FOUND OR NOT TUKLIB_PHYSMEM_FOUND) endif() # Check for __attribute__((__constructor__)) support. -# This needs -Werror because some compilers just warn -# about this being unsupported. -cmake_push_check_state() -set(CMAKE_REQUIRED_FLAGS "-Werror") -check_c_source_compiles(" - __attribute__((__constructor__)) - static void my_constructor_func(void) { return; } - int main(void) { return 0; } - " - HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR) -cmake_pop_check_state() +tuklib_check_func_attribute_constructor(HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR) tuklib_add_definition_if(liblzma HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR) # The Win95 threading lacks a thread-safe one-time initialization function. @@ -782,25 +773,7 @@ option(ALLOW_ATTR_IFUNC "Allow use of __attribute__((__ifunc__())) if \ supported by the system" ON) if(ALLOW_ATTR_IFUNC) - cmake_push_check_state() - set(CMAKE_REQUIRED_FLAGS "-Werror") - check_c_source_compiles(" - static void func(void) { return; } - static void (*resolve_func(void)) (void) { return func; } - void func_ifunc(void) - __attribute__((__ifunc__(\"resolve_func\"))); - int main(void) { return 0; } - /* - * 'clang -Wall' incorrectly warns that resolve_func is - * unused (-Wunused-function). Correct assembly output is - * still produced. This problem exists at least in Clang - * versions 4 to 17. The following silences the bogus warning: - */ - void make_clang_quiet(void); - void make_clang_quiet(void) { resolve_func()(); } - " - HAVE_FUNC_ATTRIBUTE_IFUNC) - cmake_pop_check_state() + tuklib_check_func_attribute_ifunc(HAVE_FUNC_ATTRIBUTE_IFUNC) tuklib_add_definition_if(liblzma HAVE_FUNC_ATTRIBUTE_IFUNC) endif() diff --git a/cmake/tuklib_gnu_c_attributes.cmake b/cmake/tuklib_gnu_c_attributes.cmake new file mode 100644 index 00000000..2cfcddeb --- /dev/null +++ b/cmake/tuklib_gnu_c_attributes.cmake @@ -0,0 +1,56 @@ +# +# tuklib_gnu_c_attributes.cmake - Checks for GNU C attributes +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# + +include("${CMAKE_CURRENT_LIST_DIR}/tuklib_common.cmake") +include(CheckCSourceCompiles) + +# This is a helper function for the actual attribute tests. +function(tuklib_check_attribute CODE RESULT) + # GCC, Clang, ICC, Solaris Studio, and XLC don't exit with + # a non-zero exit status if an unknown attribute is provided. + # They only print a warning. Accept the attribute only if no + # attribute-related warnings were issued. + # + # - XLC doesn't use the lower-case string "warning". + # It might use "WARNING" on z/OS or "(W)" on AIX. + # So "warning" isn't checked. + # + # - A few XLC messages use "Attribute" instead of "attribute". + # + # - ICC doesn't use the word "ignored". + # + # The problem with this method is that the regex might become + # outdated with newer compiler versions. Using -Werror would be + # an alternative but it fails if warnings occur for reasons other + # than unsupported attribute. + # + # The first pattern is for GCC, Solaris Studio, and XLC. + # The second one is for ICC. Both patterns work with Clang. + # Matching the leading space or colon reduces chances of + # matching any unrelated messages. + check_c_source_compiles("${CODE} int main(void) { return 0; }" "${RESULT}" + FAIL_REGEX " [Aa]ttribute .* ignored" + ": unknown attribute") +endfunction() + +function(tuklib_check_func_attribute_constructor RESULT) + tuklib_check_attribute(" + __attribute__((__constructor__)) + void my_constructor_func(void) { return; } + " "${RESULT}") +endfunction() + +function(tuklib_check_func_attribute_ifunc RESULT) + tuklib_check_attribute(" + static void func(void) { return; } + static void (*resolve_func(void))(void) { return &func; } + void func_ifunc(void) + __attribute__((__ifunc__(\"resolve_func\"))); + " "${RESULT}") +endfunction()