CMAKE Linking dynamic library to module, but not showing as link dependency - c++

Point me in the right direction if this has been asked before. I have lib1 and mod2, which must be linked together. This project is spread to a couple of folders and a couple of CMakeLists.txt files. The cmake commands that I am using are as such:
cmake file 1 (base dir):
# Set C/C++ compile and linking flags
set(GCC_COVERAGE_COMPILE_FLAGS "-fpic -Wno-as-needed")
set(GXX_COVERAGE_COMPILE_FLAGS "-std=c++11")
set(GXX_COVERAGE_LINK_FLAGS "-Wl,--no-undefined -Wno-as-needed")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} ${GXX_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER__FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
cmake file 2 (lib1 dir):
pybind11_add_module(elka_comm__common
SHARED
pyelka_common.cpp
elka.cpp
elka_comm.cpp
)
set_target_properties(elka_comm__common PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${ELKA_BINARY_DIR}/python
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} ${GXX_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER__FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
add_dependencies(elka_comm__common msg_gen)
cmake file 3 (mod2 dir):
#FIXME ldd not showing elka_comm__common as a link dependency
# -> CommPort undefined symbol upon module import
target_link_libraries(
elka_comm__gnd_station
PUBLIC
elka_comm__common
)
set_target_properties(elka_comm__gnd_station PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${ELKA_BINARY_DIR}/python
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} ${GXX_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER__FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
add_dependencies(elka_comm__gnd_station
elka_comm__common
msg_gen
)
A few of my steps are redundant as sanity checks (e.g. setting flags w/CMAKE variables).
The following is the partial output of ldd -r <path-to-mod2.so>/mod2.so:
linux-vdso.so.1 => (0x00007fff777fe000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fadfe690000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fadfe479000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fadfe0b0000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fadfddaa000)
/lib64/ld-linux-x86-64.so.2 (0x000055f1e6b2c000)
undefined symbol: _ZTIN4elka8CommPortE (build_elka_data_collection/python/elka_comm__gnd_station.so)
lib1 is called elka_comm__common.so, and so it should show up as a library dependency in ldd, right?
Partial output of cmake/make commands:
[100%] Linking CXX shared module ../../../python/elka_comm__gnd_station.so
cd /home/Programs/elka/elka_data_collection/build_elka_data_collection/src/elka_comm/gnd_station && /opt/cmake-3.4.3-Linux-x86_64/bin/cmake -E cmake_link_script CMakeFiles/elka_comm__gnd_station.dir/link.txt --verbose=1
/usr/bin/c++ -fPIC -fpic -Wno-as-needed -std=c++11 -fpic -Wno-as-needed -std=c++11 -g -shared -o ../../../python/elka_comm__gnd_station.so CMakeFiles/elka_comm__gnd_station.dir/pyelka_gnd_station.cpp.o CMakeFiles/elka_comm__gnd_station.dir/elka_devices.cpp.o `CMakeFiles/elka_comm__gnd_station.dir/inet_comm.cpp.o -L/home/Programs/elka/elka_data_collection/build_elka_data_collection/src/elka_comm/common -L/home/Programs/elka/elka_data_collection/build_elka_data_collection/src/elka_comm/gnd_station -L/home/Programs/elka/elka_data_collection/build_elka_data_collection/python -L/home/Programs/elka/elka_data_collection/python ../../../python/elka_comm__common.so -Wl,-rpath,/home/Programs/elka/elka_data_collection/build_elka_data_collection/src/elka_comm/common:/home/Programs/elka/elka_data_collection/build_elka_data_collection/src/elka_comm/gnd_station:/home/Programs/elka/elka_data_collection/build_elka_data_collection/python:/home/Programs/elka/elka_data_collection/python`
From this, it seems to me that linking is done correctly. My best intuition is that the ordering in the cmake generated link command is incorrect, but I can't justify this other than knowing that link commands are particular about ordering.

Solved by adding -Wl,--no-as-needed to CMAKE_CXX_FLAGS. Be mindful that adding to CMAKE_SHARED_LINKER_FLAGS|CMAKE_MODULE_LINKER_FLAGS doesn't work, and neither does adding -Wno-as-needed to CMAKE_CXX_FLAGS.
Other issues persist, though. If anyone is experienced w/binding c++ code to python pm me.

Related

JNI missing symbol in library built on Linux

My JNI project links against 3 shared libraries: libogg, libvorbis and libtheora.
On Windows everything works fine, and on Linux there are no errors when building my shared library. However, I'm getting a missing symbol: oggpack_readinit.
My CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
project(theoraplayer)
set(CMAKE_CXX_STANDARD 14)
include_directories(include)
include_directories(jnihelpers)
link_directories(lib)
if(ANDROID)
set(CMAKE_C_CFLAGS "${CMAKE_C_FLAGS} -D__GXX_EXPERIMENTAL_CXX0X__")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
else()
find_package(JNI REQUIRED)
endif(ANDROID)
include_directories(${JNI_INCLUDE_DIRS})
if (JNI_FOUND)
message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}")
message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}")
else()
message(STATUS "JNI Not found")
endif()
file(GLOB libJniHelpers_SOURCES jnihelpers/*.cpp)
file(GLOB libJniHelpers_HEADERS jnihelpers/*.h)
add_library(theoraplayer SHARED TheoraPlayer.h TheoraPlayer.cpp theoraplay/theoraplay.c ${libJniHelpers_SOURCES} ${libJniHelpers_HEADERS} NativeLogger.h NativeLogger.cpp VideoFrame.h VideoFrame.cpp TheoraDecoder.h TheoraDecoder.cpp MediaInfo.h MediaInfo.cpp AudioPacket.h AudioPacket.cpp)
set_target_properties(theoraplayer PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
set_target_properties(theoraplayer PROPERTIES INSTALL_RPATH "./")
target_link_libraries(theoraplayer ogg vorbis theora)
if(${UNIX})
set(CMAKE_CXX_FLAGS "-fPIC -O2 -Wl,--no-as-needed")
elseif(${WINDOWS})
set(CMAKE_CXX_FLAGS "/MP /EHsc /O2 /GL")
endif(${UNIX})
When I run ldd on the built library, none of the 3 libraries show up:
ldd libtheoraplayer.so
linux-vdso.so.1 (0x00007fffadd8c000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fdfc9ed0000)
libm.so.6 => /lib64/libm.so.6 (0x00007fdfc9d88000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fdfc9d68000)
libc.so.6 => /lib64/libc.so.6 (0x00007fdfc9b98000)
/lib64/ld-linux-x86-64.so.2 (0x00007fdfca138000)

CLion wont run binary with address sanitizer

I'm using CLion IDE, Cmake with GCC compiler and I'm trying to run binary with address sanitizer. I followed this: What's the proper way to enable AddressSanitizer in CMake that works in Xcode and added
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
to CMakeLists.txt file and then got an error when running the binary in CLion using the run button:
==22084==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
When I run the binary via terminal, it works as it should be. It doesn't work in CLion's run window. https://imgur.com/a/MXOM7BJ
Edit: The solution was adding LD_PRELOAD=libasan.so.5 to environment variables of CLion.
My CMakeLists.txt:
cmake_minimum_required(VERSION 3.17)
project(Playground)
set(CMAKE_CXX_STANDARD 14)
add_executable(Playground main.cpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -g")
What's happening?
Adding these lines from the stackoverflow thread to CMakeLists.txt file didnt work too.
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address -fno-omit-frame-pointer")
and this line from this guide https://www.jetbrains.com/help/clion/google-sanitizers.html#LSanChapter also didnt work
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -O1")
Then I tried adding LD_TRACE_LOADED_OBJECTS=1 to CLion environment variables and nothing changed.
My ldd ./file command output of the binary:
linux-vdso.so.1 (0x00007ffd82d96000)
libgtk3-nocsd.so.0 => /lib/x86_64-linux-gnu/libgtk3-nocsd.so.0 (0x00007f7d532e1000)
libasan.so.5 => /lib/x86_64-linux-gnu/libasan.so.5 (0x00007f7d528af000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7d526bd000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f7d526b7000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f7d52694000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f7d52689000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f7d52538000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f7d5251d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7d5350c000)
First remove all of the set commands you added, and then add these commands before the compile:
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
The problem is caused by the LD_PRELOAD=libgtk3-nocsd.so.0 setting somewhere in your environment. Overwrite it or unset the variable in your CLion run configuration.

Is it possible to force CMake to reorder arguments when calling the linker? [duplicate]

This question already has an answer here:
Flag '-l' in CMAKE_CXX_FLAGS doesn't work
(1 answer)
Closed 4 years ago.
I have a strange behavior where CMake is not able to link any executable if dynamic linking is required. g++ is not able to find any of the symbols defined in the libraries.
I found out it might have to do with the order of the arguments CMake passes to g++ when linking.
Here is the verbose output of the build process (which fails linking):
[ 50%] Building CXX object CMakeFiles/chargen.dir/test.cpp.obj
g++ -std=c++11 -o CMakeFiles/test.dir/test.cpp.obj -c /f/test/test.cpp
[100%] Linking CXX executable mytest
/usr/bin/cmake -E cmake_link_script CMakeFiles/test.dir/link.txt --verbose=1
g++ -std=c++11 -lSDL2 CMakeFiles/test.dir/test.cpp.obj -o mytest
Indeed if I try to link using that command I get undefined references, however if I compile with the library flags at the end:
g++ -std=c++11 CMakeFiles/test.dir/test.cpp.obj -o mytest -lSDL2
it runs just fine. How can I force CMake to use that order of arguments instead?
The contents of the CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(mytest)
set(COMPILER_PATH "/usr/bin/")
set(CMAKE_MAKE_PROGRAM "make")
set(CMAKE_C_COMPILER "gcc")
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lSDL2")
set(SOURCE_FILES test.cpp)
add_executable(mytest ${SOURCE_FILES})
You have probably added -lSDL2 into CMAKE_CXX_FLAGS. In that case it will appear withn compile/link flags, in front of source file name in actual link command, as you showed. Don't do that.
You should use _target_link_libraries_ cmake command in order to define libraries to link against. In brief, the skeleton of your CMakeLists.txt should look like this:
project (project_name)
add_executable (mytest test.cpp)
target_link_libraries( mytest SDL2)
In this case, cmake will put libraries on correct place. Note that you may use target_link_libraries after adding target mytest
[EDIT]
After seeing your CMakeLists it is obvious that your problem is in wrong CMAKE_EXE_LINKER_FLAGS. Simply delete the line where you are setting it, and add target_link_libraries after add_executable.
Regarding your question about handling circular dependencies among static libs, you handle it the sam way as you would if you didn't use cmake: mention it twice:
target_link_libraries(
mytest
circular_dep1
circular_dep2
circular_dep1
circular_dep2
)
regarding your question about specific linker flags, just place them into target_link_libraries command, it accepts linker flags as well. You can find documentation on following link:
https://cmake.org/cmake/help/latest/command/target_link_libraries.html

CMake-based build of CUDA app fails - no files passed to linker

I'm trying to use CMake with a CUDA project of mine, but I'm having trouble getting it to build the executable when compiled on a system that has a CUDA-enabled device.
The CMakeLists.txt in question is below. It supports systems with and without CUDA-enabled devices, and builds just fine on my Macbook which doesn't have CUDA.
cmake_minimum_required (VERSION 2.8)
message(STATUS "CMake version: ${CMAKE_VERSION}")
project(stockModel)
# Grab the CUDA package
find_package(CUDA)
set(GPU_ACCELERATED ${CUDA_FOUND})
# Set directory and compilation flags for both g++ and nvcc
set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")
set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}
-gencode arch=compute_50,code=sm_50; -std=c++11; -lcurand;"
)
set(CUDA_PROPAGATE_HOST_FLAGS off)
# Add directories
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/build/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/core/)
if (${GPU_ACCELERATED})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/support/)
endif()
# Setup environments, depending on GPU accel. status
set(SRCS build/main.cpp core/callModels.cpp)
set(INCS core/callModels.h)
if (${GPU_ACCELERATED})
set(SRCS ${SRCS} support/prng.cu support/debugCFP.cu)
set(INCS ${INCS} support/prng.h support/debugCFP.h)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/core/callModels.cpp
PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ
)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}
-L/usr/local/cuda/lib64 -lcuda -lcudart"
)
endif()
# Create executable
message(STATUS "Sources: ${SRCS}")
message(STATUS "Includes: ${INCS}")
cuda_add_executable(stockModel ${SRCS} ${INCS})
The error I get when I attempt to build on my Jetson TX1 is as follows:
...
[ 80%] Building CXX object CMakeFiles/stockModel.dir/main.cpp.o
[100%] Linking CXX executable stockModel
c++: fatal error: no input files
compilation terminated.
...
Any ideas as to what is going wrong here? Obviously it has something to do with the CUDA 'extras', but I'm at a loss as to what is causing this.
Let me know if you need more details.
Here is the relevant part of the verbose output:
...
[100%] Linking CXX executable stockModel
/usr/local/bin/cmake -E cmake_link_script CMakeFiles/stockModel.dir/link.txt --verbose=1
/usr/bin/c++ -std=c++11 -pthread
c++: fatal error: no input files
compilation terminated.
I've uploaded the full make VERBOSE=1 output to this gist on GitHub.
CMake is sometimes finicky about spaces and list combinations. I know that doesn't sound like much of an explanation, but I'm not much of an expert.
What you need to do is replace this:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}
-L/usr/local/cuda/lib64 -lcuda -lcudart"
with this:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/cuda/lib64 -lcuda -lcudart")
(single line). That should do it. At least - it does on my system (I created dummy source files with your files' names to try this out).

cmake - Is it possible to link executable to shared library with relative path at runtime?

Lets say I have this:
../project_dir
main.cpp
mylib.cpp
mylib.h
Building steps will be:
g++ -c mylib.cpp -o mylib.o
g++ -shared -o libmylib.so mylib.o
g++ -L$(pwd) -Wl,-rpath='$ORIGIN' -o exec main.cpp -lmylib
exec will be my binary executable output. When I testing with:
ldd exec
the output line is:
libmylib.so => /full/path/to/build/directory/libmylib.so (0x00007f75fdd1f000)
That output line is my question, is it possible to get:
libmylib.so => ./libmylib.so
so whenever I move the executable file, I can move the shared library along with it. If it is possible, how to do this with cmake?
Juste add in your CMakefiles.txt
set(CMAKE_INSTALL_RPATH "$ORIGIN")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) # only if you want copy from the build tree
When you launch ldd to check your app shared library dependencies, it always prints absolute paths. But if you are using the -rpath oprtion together with the $ORIGIN variable, everything will work as you expect. You can move the executable and the shared library, remove the original build directory and you will still be able to launch your app.
This is how you can do it using cmake:
project(myapp)
cmake_minimum_required(VERSION 2.8)
set(APP_SRC main.cpp)
set(LIB_SRC mylib.cpp)
link_directories(${CMAKE_CURRENT_BINARY_DIR})
SET(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath -Wl,$ORIGIN")
add_library(mylib SHARED ${LIB_SRC})
add_executable(${PROJECT_NAME} ${APP_SRC})
target_link_libraries(${PROJECT_NAME} mylib)
I had to put curly braces around ${ORIGIN} and add path for the library to link:
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_BINARY_DIR} -lmyLibrary -Wl,-rpath -Wl,${ORIGIN}")
set(CMAKE_INSTALL_RPATH "${ORIGIN}")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)