I wrote this little code to ensure that my software links to libatomic if necessary. Usually linking to libatomic is only necessary on Raspberry Pi. Currently, I'm using a Raspberry Pi 4, with Raspbian Bullseye 64-bit.
Here's the cmake code:
set(ATOMIC32_TEST_CODE "
#include <atomic>
#include <stdint.h>
int main() {
std::atomic<int32_t> x;
x.store(1);
x--;
return x.load();
}")
set(ATOMIC64_TEST_CODE "
#include <atomic>
#include <stdint.h>
int main() {
std::atomic<int64_t> x;
x.store(1);
x--;
return x.load();
}")
macro(ATOMIC_CHECK)
# test whether atomic works
check_cxx_source_compiles("${ATOMIC32_TEST_CODE}" atomic32_test)
check_cxx_source_compiles("${ATOMIC64_TEST_CODE}" atomic64_test)
# if doesn't work, attempt to find the atomic library, link with it and try again
if(NOT atomic32_test OR NOT atomic64_test)
find_library(ATOMIC NAMES libatomic.so.1
HINTS
$ENV{HOME}/local/lib64
$ENV{HOME}/local/lib
/usr/local/lib64
/usr/local/lib
/opt/local/lib64
/opt/local/lib
/usr/lib64
/usr/lib
/lib64
/lib
/usr/lib/arm-linux-gnueabihf
)
if(ATOMIC)
set(LIBATOMIC ${ATOMIC})
message(STATUS "Found libatomic: ${LIBATOMIC}")
message(STATUS "Attempting to test atomic with atomic library linked")
get_filename_component(atomic_lib_dir ${LIBATOMIC} DIRECTORY)
# Before setting CMAKE_REQUIRED_FLAGS, we preserve the current state
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES "-L${atomic_lib_dir} -latomic")
check_cxx_source_compiles("${ATOMIC32_TEST_CODE}" atomic32_test_with_atomic_linking)
check_cxx_source_compiles("${ATOMIC64_TEST_CODE}" atomic64_test_with_atomic_linking)
cmake_pop_check_state()
if(NOT atomic32_test_with_atomic_linking)
message(FATAL_ERROR "Even after linking with the atomic library, atomic 32-bit compilation failed.")
endif()
if(NOT atomic64_test_with_atomic_linking)
message(FATAL_ERROR "Even after linking with the atomic library, atomic 64-bit compilation failed.")
endif()
set(ATOMIC_LINKER_LIBS "-L${atomic_lib_dir} -latomic")
else()
message(FATAL_ERROR "Failed to find libatomic even though it seems to be required")
endif()
endif()
endmacro()
ATOMIC_CHECK()
What this code does, is the following:
- Attempt to compile both the 32-bit and 64-bit versions of the code and ensure that they return 0 on exit.
- If any of them doesn't compile, find libatomic, if not found, error.
- If found, attempt to link to it and compile the same small sources again
- If they succeed, great, we use the new found libraries as base for compiling everything else. If not, cmake configuration stops.
Recently I started to get linking errors on my Pi out of the blue. So I investigated, and that lead me to this problem. In CMakeError.log
, I see this linking error:
/usr/bin/c++ -Wall -Wextra -Wno-unused-variable -Wno-unused-function -Wno-unused-private-field -Wno-class-memacces>
/usr/bin/ld: CMakeFiles/cmTC_7285b.dir/src.cxx.o: in function `main':
src.cxx:(.text+0x40): undefined reference to `__atomic_store_8'
/usr/bin/ld: src.cxx:(.text+0x80): undefined reference to `__atomic_load_8'
/usr/bin/ld: CMakeFiles/cmTC_7285b.dir/src.cxx.o: in function `std::__atomic_base<long long>::operator--(int)':
src.cxx:(.text._ZNSt13__atomic_baseIxEmmEi[_ZNSt13__atomic_baseIxEmmEi]+0x40): undefined reference to `__atomic_fetch_s>
collect2: error: ld returned 1 exit status
Eventually, I figured that the only issue is the linking order. All cmake has to do to get this to work, is to put -latomic
after the source file it's trying to compile.
How can I tell cmake to put the linking commands after the source file, and not before it?
Aucun commentaire:
Enregistrer un commentaire