Skip to content

Commit

Permalink
cmake: rework -Wl,--no-undefined/-Wl,-undefined,error handling
Browse files Browse the repository at this point in the history
Issue tbeu#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 tbeu#233
  • Loading branch information
Christian Seiler committed Feb 9, 2024
1 parent 18082eb commit 58e52d6
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 20 deletions.
61 changes: 42 additions & 19 deletions cmake/compilerOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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 <stdlib.h>
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()
6 changes: 5 additions & 1 deletion cmake/src.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 ";"
Expand Down

0 comments on commit 58e52d6

Please sign in to comment.