CMake check_symbol_exists doesn't work because of missing -pthread - c++

I'm trying to build https://github.com/iovisor/bpftrace.git on Ubuntu 18.04. I built and installed its dependency bcc by hand (the bpftrace repo build docs suggest that because the packaged version on ubuntu lacks required header files).
I found that cmake would complain for me as follows:
-- Looking for bcc_prog_load - not found
After some CMakeLists.txt edits to ensure suitable -I flags are passed, and looking in CMakeFiles/CMakeError.log, I see that the build fails like this:
/usr/bin/cc -I/home/me/dev/bcc/src/cc -I/home/me/dev/bcc/src/cc/libbpf/src -o CMakeFiles/cmTC_653d8.dir/CheckSymbolExists.c.o -c /home/me/dev/bpftrace/build/CMakeFiles/CMakeTmp/CheckSymbolExists.c
Linking C executable cmTC_653d8
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_653d8.dir/link.txt --verbose=1
/usr/bin/cc -rdynamic CMakeFiles/cmTC_653d8.dir/CheckSymbolExists.c.o -o cmTC_653d8 -lbcc
CMakeFiles/cmTC_653d8.dir/CheckSymbolExists.c.o: In function `main':
CheckSymbolExists.c:(.text+0x1b): undefined reference to `pthread_create'
collect2: error: ld returned 1 exit status
If I run with --debug-trycompile and run the failing commands by hand, I see that passing the -pthread command line option to gcc fixes that error. From this answer I glean that something like the following is supposed to fix that:
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(my_app Threads::Threads)
However, the thing that is failing here is not some target I have added, but merely a check for the presence of a symbol:
check_symbol_exists(bcc_prog_load "libbpf.h" HAVE_BCC_PROG_LOAD)
I therefore don't know how to specify a target for target_link_libraries. I tried replacing the target_link_libraries with link_libraries (dropping the first argument my_app), but that does not cause CMake to pass the -pthread argument to gcc when testing for the presence of the symbol.
What can I do to make the check_symbol_exists work?

Related

`ld` undefined reference error, but libraries are linked to by CMake and symbols exist

I have a CMake file like this:
cmake_minimum_required(VERSION 3.12)
project(cpp-service VERSION 0.1.0)
add_compile_definitions(OPENVDB_7_ABI_COMPATIBLE)
list(APPEND CMAKE_MODULE_PATH "/usr/local/lib64/cmake/OpenVDB/")
find_package(OpenVDB REQUIRED)
### https://stackoverflow.com/a/69290761/3405291
list(APPEND CMAKE_MODULE_PATH "deps/tbb/cmake/")
find_package(TBB REQUIRED)
add_executable(${PROJECT_NAME}
src/main.cpp
)
target_link_libraries(${PROJECT_NAME} PUBLIC
OpenVDB::openvdb
TBB::tbb
)
All the libraries are linked-to by CMake. The symbols are all available. But, linker cannot link find symbols at all. With many errors like this:
...
[ 92%] Building CXX object ...
[ 96%] Building CXX object ...
[100%] Linking CXX executable cpp-service
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: CMakeFiles/cpp-service.dir/src/main.cpp.o: in function `hollowing::mesh_to_grid(hollowing::Contour const&, openvdb::v7_2::math::Transform const&, float, float, int)':
/home/m3/repos/cpp-service/src/hollowing.h:268: undefined reference to `openvdb::v7_2::initialize()'
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: CMakeFiles/cpp-service.dir/src/main.cpp.o: in function `tbb::task_group_context::task_group_context(tbb::task_group_context::kind_type, unsigned long)':
/home/m3/repos/cpp-service/deps/tbb/include/tbb/task.h:499: undefined reference to `tbb::task_group_context::init()'
...
Guess
One guess is that I'm having this problem:
...It seems that gcc now send the linker flag --as-needed to ld. This has the effect of discarding any specified libraries that do not have symbols that are required for linking.
Tried
I tried this, but it had no effect. The same link errors are thrown:
target_link_options(${PROJECT_NAME} PUBLIC
"LINKER:-no-as-needed"
)
Question
I ran out of options debugging this problem. Does anybody have any suggestion to try out?
CMake commands
export CC=/usr/bin/gcc-11
export CXX=/usr/bin/g++-11
mkdir build
cd build
cmake ..
cmake --build . --verbose >> log.txt 2>&1 # Save log to file.
Compile commands
CMake shows the compile logs are like:
[ 3%] Building CXX object CMakeFiles/cpp-service.dir/src/main.cpp.o
/usr/bin/g++-11 -I/home/m3/repos/cpp-service/deps/tbb/include -I/.../more/include/paths/.../... -g -std=c++17 -MD -MT CMakeFiles/cpp-service.dir/src/main.cpp.o -MF CMakeFiles/cpp-service.dir/src/main.cpp.o.d -o CMakeFiles/cpp-service.dir/src/main.cpp.o -c /home/m3/repos/cpp-service/src/main.cpp
Link command
CMake log shows the link command is:
[100%] Linking CXX executable cpp-service
/usr/local/bin/cmake -E cmake_link_script CMakeFiles/cpp-service.dir/link.txt --verbose=1
/usr/bin/g++-11 -g CMakeFiles/cpp-service.dir/src/main.cpp.o CMakeFiles/cpp-service.dir/src/***.cpp.o CMakeFiles/cpp-service.dir/src/***more***object***files***.cpp.o -o cpp-service
The errors are thrown exactly right after the above link command. Errors like:
undefined reference to `openvdb::v7_2::initialize()'
Symbols
Symbols are defined inside the linked libraries:
nm /usr/local/lib64/libopenvdb.so | less
The above command shows the initialize symbol is available:
Fix 🔧
The cause of the linker errors was this statement:
if(LINUX)
The fix was to replace it with this:
if(UNIX AND NOT APPLE)
This commit fixes the problem:
Reference: https://stackoverflow.com/a/40152725/3405291
Strangely, CMake wasn't complaining about anything and just throwing random linker errors.

libgtest.so error adding symbols: DSO missing from command line

I have been using gtests for unit testing a personal project. Last week I upgraded to the LTS version of Linux Mint. Unfortunately, after that event, I haven't been able to compile my project due to gtests linking problems.
The following error is being issued:
/usr/bin/x86_64-linux-gnu-ld: build/tests/policies/roundrobin_tests.o: undefined reference to symbol '_ZN7testing4TestC2Ev'
/home/myuser/Documents/googletest-release-1.8.0/googletest/libgtest.so: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
I have generated both libgtest.so and libgtest_main.so through CMake 3.10.2. The gtest version is the release-1.8.0, the same I used to have before.
Those libraries are located in /usr/lib and the corresponding include folder has also been copied to /usr/include. I made sure that this location is in my ld path and that is not the problem.
My compiler is g++ v7.3.0 and the command Im using to compile the testes is:
g++ -std=c++14 -Wall -O3 -Iinclude build/tests/policies/roundrobin_tests.o -lgtest_main -pthread -o bin/policies/roundrobin_tests
I have tried altering the order of the elements in the command, explicitly adding -L/usr/lib and -I/usr/include without luck. A funny fact is that if I take off the -pthread flag, the error is still the same.
The same command was used before and the only difference is the compiler version I am using now as I used g++ 5.4.0 before. Any insights on how to solve this?
edit: Just tested the same process with g++ 5.4.0 and CMake 3.5 and the same problems ocurred.

Cmake cannot find library

I have a library called Kinova.API.CommLayerUbuntu.so which I want to link against with cmake. So, in my CMakeLists.txt file, I have the line:
target_link_libraries(demo ~/Libraries/Kinova.API.CommLayerUbuntu.so)
However, during compilation, I receive the error:
cannot find -lKinova.API.CommLayerUbuntu
This baffles me because I am telling cmake to look for Kinova.API.CommLayerUbuntu.so, not for -lKinova.API.CommLayerUbuntu. Please could somebody explain what is going on?
In verbose mode, the cmake output gives the following:
Linking CXX executable demo
/usr/bin/cmake -E cmake_link_script CMakeFiles/demo.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/demo.dir/demo.cpp.o -o demo -L/home/karnivaurus/Libraries -rdynamic -lKinova.API.CommLayerUbuntu -Wl,-rpath,/home/karnivaurus/Libraries
/usr/bin/ld: cannot find -lKinova.API.CommLayerUbuntu
The -l is just the flag used to tell the compiler to link a library. Your library name is nonstandard. The compiler will remove the -l and prepend lib to the string you use, and look for a file called libKinova.API.CommLayerUbuntu.so.
This looks like an issue with the distribution of this API. You can try working around it by creating a symbolic link from libKinova.API.CommLayerUbuntu.so to Kinova.API.CommLayerUbuntu.so.

gcc does not link properly against gsoap

I'm migrating my C++ application build system to cmake. One dependency is gsoap++, which generates a SOAP service and client. To link against it, I specify
set(CMAKE_CXX_LINK_FLAGS "-lgsoap++ ... [other flags]")
in the root CMakeLists.txt. The generated sources are created with
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/src/generated/c++/ws)
set(GEN_WS_SOURCES ws/Bar.h ws/Bar_USCOREBinding.nsmap ws/soapBar_USCOREBindingProxy.h ws/soapBar_USCOREBindingProxy.cpp ws/soapBar_USCOREBindingService.h ws/soapBar_USCOREBindingService.cpp ws/soapH.h ws/soapC.cpp ws/soapStub.h)
add_custom_command(OUTPUT ${GEN_WS_SOURCES}
COMMAND wsdl2h -o ${CMAKE_BINARY_DIR}/src/generated/c++/ws/Bar.h -t wsdl/typemap.dat wsdl/bar.wsdl
COMMAND soapcpp2 -Lwxi -I/usr/include/gsoap ${CMAKE_BINARY_DIR}/src/generated/c++/ws/Bar.h -d ${CMAKE_BINARY_DIR}/src/generated/c++/ws
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
add_library(GEN_WS ${GEN_WS_SOURCES})
Everything seems to work properly, the sources get created. But when linking the application, I get lots of errors like
undefined reference to `soap_end'
undefined reference to `soap_sender_fault'
more undefined references to `soap_sender_fault' follow
If I compile with make VERBOSE=1, I see that -lgsoap++ is passed to /usr/bin/c++ when linking. Other libraries I link against don't throw any errors, but for some reason, the linker does not seem to find gsoap's functions. The library is present and there is no error that the linker can't find it.
The old, custom build script worked as expected; it also just passed -lgsoap++ to the linker. The only real difference I see is that my cmake build groups the sources into static libraries before attempting to link everything together. But I don't see how this can lead to all the symbols from the library not being found.
What's the problem here? Why can't the linker find gsoap's symbols?
Host OS is debian.
Edit: This is the complete linker command executed by cmake:
/usr/bin/c++ -w -Wall -pedantic -fdata-sections -ffunction-sections -std=c++0x
-lgsoap++ -lsoci_core -lsoci_sqlite3 -lmicrohttpd -lfetcp -lfeisc -lFedmIscCore
-lboost_system -lboost_thread -lboost_program_options -lboost_date_time
-lboost_unit_test_framework CMakeFiles/bar.dir/main.cpp.o
CMakeFiles/bar.dir/mainapp.cpp.o -o bar -rdynamic ../../libs/c++/libLIB_JSONXX.a
../../libs/c++/libLIB_CONFIG.a ../../libs/c++/libLIB_DB.a ../../libs/c++/libLIB_OBID.a
../../libs/c++/libLIB_HELPER.a ../../generated/c++/libGEN_WS.a
../../generated/c++/libGEN_DB.a ../../generated/c++/libGEN_CONFIG.a
libMAIN_CONTROLLERS.a libMAIN_HARDWARE.a libMAIN_HELPER.a libMAIN_MODEL.a
libMAIN_NETWORK.a libMAIN_SYSTEM.a ../../generated/c++/libGEN_DB.a
../../libs/c++/libLIB_DB.a ../../generated/c++/libGEN_CONFIG.a
../../libs/c++/libLIB_JSONXX.a ../../libs/c++/libLIB_CONFIG.a
../../libs/c++/libLIB_HELPER.a ../../libs/c++/libLIB_OBID.a
../../generated/c++/libGEN_WS.a
I'm not sure if it will directly solve your problem, but this:
set(CMAKE_CXX_LINK_FLAGS "-lgsoap++ ... [other flags]")
Should be:
set(CMAKE_CXX_LINK_FLAGS "[other flags]")
target_link_library(GEN_WS gsoap++) # after add_library of course

Ffmpeg linking problems using CMake

I'm writing an application containig 2 internal libraries and depends on more 2 external libraries (ffmpeg and opencv). I'm also using CMake to produce UNIX makefiles. And the problem is when i'm trying to build sources, it compiles but don't link with ffmpeg at all and the next output the linker gives:
../../Decoder/libDecoder.a(ConverterAVFrameToRGB.cpp.o): In function `FaceVideo::ConverterAVFrameToRGB::to_rgb_conversion(std::vector<AVFrame*, std::allocator<AVFrame*> >&, int, int, int)':
ConverterAVFrameToRGB.cpp:(.text+0x990): undefined reference to `av_frame_free'
../../Decoder/libDecoder.a(FfmpegDecoder.cpp.o): In function `FaceVideo::FfmpegDecoder::destroy()':
FfmpegDecoder.cpp:(.text+0xa30): undefined reference to `av_frame_free'
../../Decoder/libDecoder.a(FfmpegDecoder.cpp.o): In function `FaceVideo::FfmpegDecoder::decode_next_chunk(int)':
FfmpegDecoder.cpp:(.text+0xb6b): undefined reference to `av_frame_clone'
FfmpegDecoder.cpp:(.text+0xc13): undefined reference to `av_frame_free'
../../Decoder/libDecoder.a(FfmpegEncoder.cpp.o): In function `FaceVideo::FfmpegEncoder::destroy()':
FfmpegEncoder.cpp:(.text+0x132): undefined reference to `avcodec_free_frame'
../../Decoder/libDecoder.a(FfmpegEncoder.cpp.o): In function `FaceVideo::FfmpegEncoder::encode()':
FfmpegEncoder.cpp:(.text+0x4c4): undefined reference to `avcodec_encode_video2'
FfmpegEncoder.cpp:(.text+0x592): undefined reference to `avcodec_encode_video2'
../../Decoder/libDecoder.a(FrameSaver.cpp.o): In function `FaceVideo::FrameSaver::saver(std::vector<AVFrame*, std::allocator<AVFrame*> >&, int, int, int)':
FrameSaver.cpp:(.text+0x869): undefined reference to `av_frame_free'
collect2: ld returned 1 exit status
That's excatly what i don't want to see.
There are three Cmake files: two for internal libraries (use
add_library(Decoder ${SOURCES_DECODER})
and
add_library(Detector ${SOURCES_DETECTOR})
in them) and one for main executable (use
add_executable(Tool ${SOURCES_TOOL})
and
target_link_libraries (Tool Decoder avutil avcodec swscale avformat Detector ${OpenCV_LIBS})
in it).
As far as i understand from CMake manuals and examples, this should make linker link this libraries together, but no effect.
I've been trying lot of things such as:
1) Adding link_directories() with path to libraries (/usr/lib/x86_64-linux-gnu/ for me) wherever it's possile, nothing changed.
2) Linking every library separately, i mean i tried do something like this in my internal libraries CMake files: target_link_libraries (Decoder avutil avcodec swscale avformat). And then link library together into my Tool CMake file: target_link_libraries (Tool Decoder Detector).
3) Editing output makefiles.
4) Compiling simple one-file application just to test whether i can do it or not. I can. g++ -lavcodec -o out mysource.cpp works perfectly.
5) Compling ffmpeg manually and installing it.
The fact is i realy don't know what should i do. I have no idea. And i would very appreciate your every answer.
UPD1:
Output when CMAKE_VERBOSE_MAKEFILE is set
!
/usr/bin/c++ -march=x86-64 -Wall -fPIC -pthread -std=c++0x -D__STDC_CONSTANT_MACROS -march=x86-64 -fPIC CMakeFiles/FaceDetectorTool.dir/home/anton/Programming/facevideo/branches/Stream_Prototype/src/tools/FaceDetectorTool/facedetector.cpp.o -o FaceDetectorTool -rdynamic ../../Detector/libDetector.a ../../Decoder/libDecoder.a -lavutil -lavcodec -lswscale -lavformat /usr/local/lib/libopencv_videostab.so.2.4.7 /usr/local/lib/libopencv_video.so.2.4.7 /usr/local/lib/libopencv_ts.a /usr/local/lib/libopencv_superres.so.2.4.7 /usr/local/lib/libopencv_stitching.so.2.4.7 /usr/local/lib/libopencv_photo.so.2.4.7 /usr/local/lib/libopencv_ocl.so.2.4.7 /usr/local/lib/libopencv_objdetect.so.2.4.7 /usr/local/lib/libopencv_nonfree.so.2.4.7 /usr/local/lib/libopencv_ml.so.2.4.7 /usr/local/lib/libopencv_legacy.so.2.4.7 /usr/local/lib/libopencv_imgproc.so.2.4.7 /usr/local/lib/libopencv_highgui.so.2.4.7 /usr/local/lib/libopencv_gpu.so.2.4.7 /usr/local/lib/libopencv_flann.so.2.4.7 /usr/local/lib/libopencv_features2d.so.2.4.7 /usr/local/lib/libopencv_core.so.2.4.7 /usr/local/lib/libopencv_contrib.so.2.4.7 /usr/local/lib/libopencv_calib3d.so.2.4.7 -ldl -lm -lpthread -lrt /usr/local/lib/libopencv_nonfree.so.2.4.7 /usr/local/lib/libopencv_ocl.so.2.4.7 /usr/local/lib/libopencv_gpu.so.2.4.7 /usr/local/lib/libopencv_photo.so.2.4.7 /usr/local/lib/libopencv_objdetect.so.2.4.7 /usr/local/lib/libopencv_legacy.so.2.4.7 /usr/local/lib/libopencv_video.so.2.4.7 /usr/local/lib/libopencv_ml.so.2.4.7 /usr/local/lib/libopencv_calib3d.so.2.4.7 /usr/local/lib/libopencv_features2d.so.2.4.7 /usr/local/lib/libopencv_highgui.so.2.4.7 /usr/local/lib/libopencv_imgproc.so.2.4.7 /usr/local/lib/libopencv_flann.so.2.4.7 /usr/local/lib/libopencv_core.so.2.4.7 -Wl,-rpath,/usr/local/lib
UPD2
Cmake example looks like that.
cmake_minimum_required (VERSION 2.8)
project (Decoder)
include(../CMakeInit.cmake)
include_directories(${FFMPEG_INCLUDE_DIR})
include_directories(${Stream_Facevideo_SOURCE_DIR}/../src/kernel/decoder/)
include_directories(${Stream_Facevideo_SOURCE_DIR}/../src/kernel/stuff/)
set(SOURCES_VIDEODECODER
*sources*
)
if(WINDOWS)
set(SOURCES_VIDEODECODER ${SOURCES_VIDEODECODER}
*headers*
)
endif(WINDOWS)
set (SOURCES_DECODER
${SOURCES_VIDEODECODER}
)
add_library(Decoder ${SOURCES_DECODER})
link_directories("/usr/lib/x86_64-linux-gnu/")
target_link_libraries(Decoder swscale avformat avcodec avutil)
Seems this solution should work: Findavutil.cmake & CMakeLists.txt
Your problem looks like you forget to add LINK_DIRECTORIES for ffmpeg lib.
If it's ok then try to change order of linking libs in target_link_libraries for executable or add target_link_libraries for your internal libs, that use external ones.