From b0b3140fdeda9dcf3b17834e74819a5305040d82 Mon Sep 17 00:00:00 2001 From: Christian Seiler Date: Fri, 9 Feb 2024 08:38:35 +0100 Subject: [PATCH] cmake: rework -Wl,--no-undefined/-Wl,-undefined,error handling Issue https://github.com/tbeu/matio/issues/187 appears to indicate that OpenBSD requires an explicit specification of -lc on the linker line if -Wl,--no-undefined is used. Unfortunately, -lc is not available on MinGW (due to the C runtime working different on Windows), so adding it whenever -lm is also linked against does not work. This commit reworks the entire CMake linker flag logic: - Remove dependency on CMake >= 3.17.0 for some checks -- we need to do a manual check_c_source_compiles() anyway (due to check_linker_flag() not triggering the potential error when -lc is not supplied), so we can drop that dependency. - Check for -Wl,--no-undefined both without and with an explicit -lc on the command line. If either version works, assume we can pass GNU-style linker options. If only the explicit version works, also pass -lc explicitly. (If both work don't, because even if -lc works, such as on a standard Linux, one would typically not pass it explicitly while compiling software.) Fixes https://github.com/tbeu/matio/issues/233 --- cmake/compilerOptions.cmake | 61 +++++++++++++++++++++++++------------ cmake/src.cmake | 6 +++- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/cmake/compilerOptions.cmake b/cmake/compilerOptions.cmake index 1bab664e..760832ea 100644 --- a/cmake/compilerOptions.cmake +++ b/cmake/compilerOptions.cmake @@ -88,26 +88,49 @@ check_c_source_compiles("${TEST_CODE_THOUSANDS_SEP}" HAVE_STRUCT_LCONV_THOUSANDS set(USE_GNU_LINK_FLAGS 0) set(USE_LLVM_MACOS_LINK_FLAGS 0) +set(REQUIRE_EXPLICIT_LIBC_LINK 0) if(NOT MSVC) - if(${CMAKE_VERSION} VERSION_GREATER "3.17") - include(CheckLinkerFlag) - check_linker_flag(C "-Wl,--no-undefined" HAVE_LINK_NO_UNDEFINED) - check_linker_flag( - C "-Wl,--retain-symbols-file,${PROJECT_SOURCE_DIR}/src/matio.sym" - HAVE_LINK_RETAIN_SYMBOLS_FILE - ) - check_linker_flag(C "-Wl,-undefined,error" HAVE_LINK_UNDEFINED_ERROR) + # OpenBSD apparently requires an explicit -lc if -Wl,--no-undefined + # is used, but that is NOT required on other platforms, and on even + # other platforms (e.g. MinGW) -lc might not even exist at all. + # Therefore detect if -lc works and if it is required, and omit it + # if it doesn't. + # Just running check_linker_flag() doesn't help here, because we + # actually need to reference a symbol from libc to cause an error. + # Use -shared in CMAKE_REQUIRED_LINK_OPTIONS because how symbols + # (esp. undefined ones) are resolved during linking can differ + # between shared libraries and executables. + set(TEST_SRC_LINK_NO_UNDEFINED " +#include +int main() { int* foo = (int*) malloc(sizeof(int)); free(foo); return 0; } +") - if(HAVE_LINK_NO_UNDEFINED AND HAVE_LINK_RETAIN_SYMBOLS_FILE) - set(USE_GNU_LINK_FLAGS 1) - elseif(APPLE AND HAVE_LINK_UNDEFINED_ERROR) - set(USE_LLVM_MACOS_LINK_FLAGS 1) - endif() - else() - if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(USE_LLVM_MACOS_LINK_FLAGS 1) - else() - set(USE_GNU_LINK_FLAGS 1) - endif() + set(CMAKE_REQUIRED_FLAGS "-fPIC") + set(CMAKE_REQUIRED_LINK_OPTIONS "-shared;-Wl,--no-undefined") + check_c_source_compiles("${TEST_SRC_LINK_NO_UNDEFINED}" HAVE_LINK_NO_UNDEFINED_IMPLICIT_LIBC) + set(CMAKE_REQUIRED_LINK_OPTIONS "-shared;-Wl,--no-undefined;-lc") + check_c_source_compiles("${TEST_SRC_LINK_NO_UNDEFINED}" HAVE_LINK_NO_UNDEFINED_EXPLICIT_LIBC) + # Reuse the same source code for other linker flag tests (This was + # previously guarded by CMake version >= 3.17 using + # check_linker_flag, but this variant should work for even older + # CMake versions.) + set(CMAKE_REQUIRED_LINK_OPTIONS "-shared;-Wl,--retain-symbols-file,${PROJECT_SOURCE_DIR}/src/matio.sym") + check_c_source_compiles("${TEST_SRC_LINK_NO_UNDEFINED}" HAVE_LINK_RETAIN_SYMBOLS_FILE) + set(CMAKE_REQUIRED_LINK_OPTIONS "-shared;-Wl,-undefined,error") + check_c_source_compiles("${TEST_SRC_LINK_NO_UNDEFINED}" HAVE_LINK_UNDEFINED_ERROR) + set(CMAKE_REQUIRED_FLAGS "") + set(CMAKE_REQUIRED_LINK_OPTIONS "") + + if((HAVE_LINK_NO_UNDEFINED_IMPLICIT_LIBC OR HAVE_LINK_NO_UNDEFINED_EXPLICIT_LIBC) AND HAVE_LINK_RETAIN_SYMBOLS_FILE) + message(VERBOSE "Using GNU-style linker flags") + set(USE_GNU_LINK_FLAGS 1) + elseif(APPLE AND HAVE_LINK_UNDEFINED_ERROR) + message(VERBOSE "Using Apple-clang-style linker flags") + set(USE_LLVM_MACOS_LINK_FLAGS 1) + endif() + + if(NOT HAVE_LINK_NO_UNDEFINED_IMPLICIT_LIBC AND HAVE_LINK_NO_UNDEFINED_EXPLICIT_LIBC) + message(VERBOSE "The usage of -Wl,--no-undefined requires the explicit usage of -lc on this platform.") + set(REQUIRE_EXPLICIT_LIBC_LINK 1) endif() endif() diff --git a/cmake/src.cmake b/cmake/src.cmake index 348d9877..929f9eed 100644 --- a/cmake/src.cmake +++ b/cmake/src.cmake @@ -68,7 +68,7 @@ if(STDINT_MSVC) endif() if(HAVE_LIBM) - target_link_libraries(${PROJECT_NAME} PUBLIC m c) + target_link_libraries(${PROJECT_NAME} PUBLIC m) endif() if(MSVC) @@ -84,6 +84,10 @@ if(ZLIB_FOUND) target_link_libraries(${PROJECT_NAME} PUBLIC MATIO::ZLIB) endif() +if(REQUIRE_EXPLICIT_LIBC_LINK) + target_link_libraries(${PROJECT_NAME} PUBLIC c) +endif() + set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ${MATIO_PIC}) # Convert matio_LIB_VERSIONINFO libtool version format into SOVERSION # Convert from ":" separated into CMake list format using ";"