Linking problems with cmake and cygwin - c++

Here's the setup:
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .dll.a .a)
set(MATLAB_MEXFILE_EXT mexw64)
find_file(MATLAB_ROOT matlab $ENV{ProgramW6432})
set(MATLAB_LIBRARIES_DIR ${MATLAB_ROOT}/extern/lib/win64/microsoft)
find_path(MATLAB_INCLUDE_DIR
NAMES mex.h
PATHS ${MATLAB_ROOT}
PATH_SUFFIXES extern/include
NO_DEFAULT_PATH
)
include_directories(${MATLAB_INCLUDE_DIR})
find_library(MATLAB_MEX_LIB mex ${MATLAB_LIBRARIES_DIR} NO_DEFAULT_PATH)
find_library(MATLAB_MX_LIB mx PATHS ${MATLAB_LIBRARIES_DIR} NO_DEFAULT_PATH)
find_library(MATLAB_MAT_LIB mat PATHS ${MATLAB_LIBRARIES_DIR} NO_DEFAULT_PATH)
set(MATLAB_LIBRARIES ${MATLAB_MEX_LIB} ${MATLAB_MX_LIB} ${MATLAB_MAT_LIB})
add_library(mytest SHARED mytest.cpp)
target_link_libraries(mytest ${MATLAB_LIBRARIES})
But when I run make I get errors of the type:
undefined reference to `_mexErrMsgIdAndTxt'
Clearly a linking issue. But why is it occuring? Here is the output of the make command:
/usr/bin/c++.exe -Dmytest_EXPORTS -I"/cygdrive/c/Program Files/matlab/extern/include" -o CMakeFiles/mytest.dir/mytest.cpp.o -c /home/hous/workspace/mytest.cpp
/usr/bin/c++.exe -shared -Wl,--enable-auto-import -o mytest.mexw64 -Wl,--out-implib,libmytest.dll.a -Wl,--major-image-version,0,--minor-image-version,0 CMakeFiles/mytest.dir/mytest.cpp.o "/cygdrive/c/Program Files/matlab/extern/lib/win64/microsoft/libmex.lib" "/cygdrive/c/Program Files/matlab/extern/lib/win64/microsoft/libmex.lib" "/cygdrive/c/Program Files/matlab/extern/lib/win64/microsoft/libmx.lib" "/cygdrive/c/Program Files/matlab/extern/lib/win64/microsoft/libmat.lib"
All seems to be correct?

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.

Why doesn't CMake put the `-L` flag in appropriate places?

I'm trying to build a shared library with cmake on linux. The portion of code responsible for setting this up is:
if (BUILD_SHARED)
set(BUILD_SHARED_LIBS ON)
set(CMAKE_VERBOSE_MAKEFILE ON)
# shared library
add_library(semsim SHARED "${SEMSIM_HEADERS}" "${SEMSIM_SOURCES}")
#Note: not sure if this command does anything. It was supposed to be to link static libraries into my shared one
# target_link_options(semsim PUBLIC -Wl,--whole-archive)
#
message(STATUS "LIBBZ_INCLUDE_DIR ${LIBBZ_INCLUDE_DIR}")
target_include_directories(semsim PUBLIC # make public so include dirs propagate into test binaries
${CMAKE_SOURCE_DIR}
${LIBXML2_INCLUDE_DIR}
${LIBSBML_DEPS_INCLUDE_DIR}
${LIBSBML_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${ZIPPER_INCLUDE_DIR}
${LIBCOMBINE_INCLUDE_DIR}
${BZ2_INCLUDE_DIR}
${REDLAND_INCLUDE_DIR}
${RASQAL_INCLUDE_DIR}
${RAPTOR2_INCLUDE_DIR}
)
target_link_libraries(semsim PUBLIC # make public so libraries propagate into test binaries
${LIBCOMBINE_STATIC_LIBRARY}
${ZIPPER_STATIC_LIBRARY}
${ZLIB_STATIC_LIBRARY}
${LIBSBML_STATIC_LIB}
${LIBBZ_STATIC_LIBRARY}
${REDLAND_LIBRARY}
${RASQAL_LIBRARY}
${RAPTOR2_LIBRARY}
${LIBXML2_STATIC_LIBRARY}
dl
${BZ2_STATIC_LIBRARY}
curl xslt
)
endif ()
This produces the following command for execution:
/usr/bin/c++ -fPIC -std=c++14 -g -shared -Wl,-soname,libsemsim.so -o libsemsim.so CMakeFiles/semsim.dir/CurlGet.cpp.o CMakeFiles/semsim.dir/RDFNode.cpp.o CMakeFiles/semsim.dir/Subject.cpp.o CMakeFiles/semsim.dir/Predicate.cpp.o CMakeFiles/semsim.dir/Resource.cpp.o CMakeFiles/semsim.dir/Triple.cpp.o CMakeFiles/semsim.dir/SemsimUtils.cpp.o CMakeFiles/semsim.dir/MetaID.cpp.o CMakeFiles/semsim.dir/XmlAssistant.cpp.o CMakeFiles/semsim.dir/Reader.cpp.o CMakeFiles/semsim.dir/Editor.cpp.o CMakeFiles/semsim.dir/Writer.cpp.o CMakeFiles/semsim.dir/RDF.cpp.o CMakeFiles/semsim.dir/Participant.cpp.o CMakeFiles/semsim.dir/PhysicalEntity.cpp.o CMakeFiles/semsim.dir/PhysicalPhenomenon.cpp.o CMakeFiles/semsim.dir/PhysicalProcess.cpp.o CMakeFiles/semsim.dir/PhysicalPropertyResource.cpp.o CMakeFiles/semsim.dir/PhysicalForce.cpp.o CMakeFiles/semsim.dir/Query.cpp.o CMakeFiles/semsim.dir/SemsimCombineArchive.cpp.o CMakeFiles/semsim.dir/Triples.cpp.o ../../third_party/libCombine-0.2.3/INSTALL/lib/libCombine-static.a ../../third_party/zipper/INSTALL/lib/libZipper-static.a ../../third_party/zlib-1.2.11/INSTALL/lib/libz.a /usr/local/lib/libxml2.a -ldl ../../third_party/libsbml-dependencies/INSTALL/lib/libbz2.a -lcurl -lxslt
If I let CMake try to build with this command I get the following error:
/usr/bin/ld: /usr/local/lib/libxml2.a(uri.o): relocation R_X86_64_PC32 against symbol `xmlFree' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
However, I've noticed that the command produced by CMake is lacking -L flags. So I changed the command to :
/usr/bin/c++ -fPIC -std=c++14 -g -shared -o libsemsim.so CMakeFiles/semsim.dir/CurlGet.cpp.o CMakeFiles/semsim.dir/RDFNode.cpp.o CMakeFiles/semsim.dir/Subject.cpp.o CMakeFiles/semsim.dir/Predicate.cpp.o CMakeFiles/semsim.dir/Resource.cpp.o CMakeFiles/semsim.dir/Triple.cpp.o CMakeFiles/semsim.dir/SemsimUtils.cpp.o CMakeFiles/semsim.dir/MetaID.cpp.o CMakeFiles/semsim.dir/XmlAssistant.cpp.o CMakeFiles/semsim.dir/Reader.cpp.o CMakeFiles/semsim.dir/Editor.cpp.o CMakeFiles/semsim.dir/Writer.cpp.o CMakeFiles/semsim.dir/RDF.cpp.o CMakeFiles/semsim.dir/Participant.cpp.o CMakeFiles/semsim.dir/PhysicalEntity.cpp.o CMakeFiles/semsim.dir/PhysicalPhenomenon.cpp.o CMakeFiles/semsim.dir/PhysicalProcess.cpp.o CMakeFiles/semsim.dir/PhysicalPropertyResource.cpp.o CMakeFiles/semsim.dir/PhysicalForce.cpp.o CMakeFiles/semsim.dir/Query.cpp.o CMakeFiles/semsim.dir/SemsimCombineArchive.cpp.o CMakeFiles/semsim.dir/Triples.cpp.o -L ../../third_party/libCombine-0.2.3/INSTALL/lib/libCombine-static.a -L ../../third_party/
zipper/INSTALL/lib/libZipper-static.a -L ../../third_party/zlib-1.2.11/INSTALL/lib/libz.a -L /usr/local/lib/libxml2.a -l
dl -L ../../third_party/libsbml-dependencies/INSTALL/lib/libbz2.a -lcurl -lxslt
ran it in a shell and it worked. Could anybody suggest why CMake is not using the -L flag in the appropriate places?

linux linking to a .so , but still getting undefined reference

I am trying to create an executable that uses code from both static libraries and a shared library:
The static libs are several boost .a , pthread and libbus.a. The shared lib is a libwrap.so.
Note that the libwrap , uses code from libbus and libbus uses code from pthread. Finally, the executable uses code from libwrap and from boost.
Since the order of libraries included in the linker matters I am trying to find the "winning" sequence.
The linking stage is the following (pasted in multiple lines for convenience):
$ /usr/bin/c++
-Wall -Wextra
-fPIC
-fvisibility=hidden -fno-strict-aliasing -Wno-long-long
-m64
-rdynamic
-D_UNICODE -DUNICODE
CMakeFiles/Wrapper_Test.dir/test.cpp.o
/usr/local/lib/libboost_log.a
/usr/local/lib/libboost_system.a
/usr/local/lib/libboost_filesystem.a
/usr/local/lib/libboost_date_time.a
/usr/local/lib/libboost_thread.a
/usr/local/lib/libboost_log_setup.a
/usr/local/lib/libboost_chrono.a
-pthread
/home/nass/dev/Data_Parser/trunk/external/lib/linux64_gcc_release/libbus.a
-L/home/nass/dev/Data_Parser_build/lib #this is where the libwrap.so is located
-Wl,-rpath,/home/nass/dev/Data_Parser_build/lib
-lwrap #the shared lib
-o ../../../bin/Wrapper_Test
The link error is
CMakeFiles/Wrapper_Test.dir/test.cpp.o: In function `main':
test.cpp:(.text+0x2e): undefined reference to `wrapperNamespace::GetWrapper()'
collect2: error: ld returned 1 exit status
The GetWrapper() is located in libwrap.so of course, and I can verify it is a symbol that can be found in there:
$ nm -Ca ../../../lib/libwrap.so | grep GetWrapper
00000000000423d6 t wrapperNamespace::GetWrapper()
However, the linker cannot find it. what am I doing wrong here?
EDIT:
The linking command above is generated by the following CMakeLists.txt file:
set(TARGET_NAME Wrapper_Test)
#set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)
#set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
#set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# INCLUDE INTERNAL FOLDER
include_directories(${CMAKE_SOURCE_DIR}/include/Wrapper)
add_executable(${TARGET_NAME} test.cpp)
add_boost_lib(${TARGET_NAME} log system filesystem date_time thread log_setup chrono)
setup_libbus(${TARGET_NAME}) #the libbus.a
target_link_libraries(${TARGET_NAME} -L../../../lib -lwrap)
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER test)
I would start by looking at the cmake file which generates these lines.
It should be simple to add shared libaries to your path, for example:
find_library(
LIBWrapper
NAMES wrap
PATHS /home/nass/dev/Data_Parser_build/lib
)
And then link them to your test file, for example
add_executable(test src/test.cpp)
target_link_libraries(test ${LIBWrapper})
Similar should work for static libraries. This has the advantage that you don't have to deal with all the compiler/platform specific details which CMake supposedly handles for you, and which can be fairly complex & obscure.
If your library is generated dynamically, i.e. before cmake configuration time, you could just pass the appropriate linking flags to target_link_libraries:
target_link_libraries(test -L/home/nass/dev/Data_Parser_build/lib -lwrap)
I have used this suggestion in a few projects (e.g. https://github.com/caskorg/cask/blob/master/CMakeLists.txt) which dynamically generate the library, then link against it. If this doesn't work I suspect something else is wrong.
You should use -Wl,-Bstatic in front of static libs and -Wl,-Bdynamic for the dynamic ones. You also need to use -l for libraries and -L for library paths.
Something like:
$ /usr/bin/c++ test.cpp.o \
-L/usr/local/lib \
-Wl,-Bstatic \
-lboost_log \
-lsystem \
-L/home/nass/dev/Data_Parser_build/lib \
-Wl-Bdynamic \
-Wl,-rpath,/home/nass/dev/Data_Parser_build/lib \
-lwrap \
-o ../../../bin/Wrapper_Test
looks better. Many things depend on the version of your compiler/linker/OS.

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

eclipse CDT: searching /usr/lib although not in lib search path

I am trying to run a bit of pcl code (from their website). I am currently, on ubuntu, using boost 1_51 (that I built) and in my Eclipse C++ Build->Settings I have
/home/aly/libs/boost_1_51_0/stage/include in the include path and /home/aly/libs/boost_1_51_0/stage/lib in the library search path. I do not have /usr/include or /usr/lib.
At runtime I am getting some boost error, which made me think perhaps it is not running against the correct libraries as boost_1_46 is built in /usr/lib (this is the most up to date version in the ubuntu repos). So I removed a lib file (libboost_timer.so) from the /usr/lib dir and recompiled (which was fine) and then ran. At runtime I got the following error:
error while loading shared libraries: libboost_thread.so.1.46.1: cannot open shared object file: N
My question is, why if /usr/include and /usr/lib aren't in my include path and library search paths, is my program looking for the 1.46 version?
Additional info:
To compile eclipse is doing:
Invoking: Cross G++ Linker
g++ -L/home/aly/libs/OpenCV-2.4.3/release/lib -L/home/aly/libs/boost_1_51_0/stage/lib -o "3DObjectDetection" ./src/HFNodeSplitCalculator.o ./src/HFNodeUtils.o ./src/HFTreeNode.o ./src/HoughForest.o ./src/ImagePatch.o ./src/Main.o ./src/PatchGenerator.o ./src/utils.o -lvtkmetaio -lvtkImaging -lvtkIO -lvtkViews -lvtkVolumeRendering -lvtkalglib -lvtkDICOMParser -lvtkInfovis -lvtkFiltering -lvtkGeovis -lGL -lopencv_core -lopencv_highgui -lopencv_imgproc -lpcl_io -lpcl_visualization -lpcl_common -lpcl_surface -lpcl_kdtree -lpcl_search -lpcl_geometry -lpcl_features -lvtkproj4 -lvtkParallel -lvtksys -lvtkRendering -lvtkCommon -lboost_serialization -lboost_timer -lpthread -lboost_context -lboost_date_time -lboost_system -lboost_thread -lboost_filesystem -lboost_random -lboost_regex -lglut -lvtkexoIIc -lvtkCharts -lvtkGenericFiltering
Finished building target: 3DObjectDetection
And my $LD_LIBRARY_PATH is
:/home/aly/libs/boost_1_51_0/stage/lib/:/home/aly/libs/OpenCV-2.4.2/build/lib/:/usr/lib/:/home/aly/libs/cuda-5.0/lib:/home/aly/libs/cuda-5.0/lib64
As you can see the boost lib dir appears before /usr/lib