gcc does not link properly against gsoap - c++

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

Related

CMake check_symbol_exists doesn't work because of missing -pthread

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?

CMake target_link_libraries not preserving order

I am using CMake 3.8.2 (shipped with JetBrains CLion) and linking several static libraries of a custom project.
As I am required to preserve static symbols (legacy), I am including my own program parts with target_link_libraries(${TARGET} -Wl,--whole-archive ${MY_LIBRARY} -Wl,--no-whole-archive).
This works most of the time, but at some point the linker command will be like this:
/usr/bin/c++ -g CMakeFiles/my_exe.dir/my_exe.cpp.o -o my_exe libmy_other_lib.a -Wl,--whole-archive -Wl,--no-whole-archive
This is rather useless, as the library is added beforehand and then the -Wl,--whole-archive -Wl,--no-whole-archive occurs.
Note, that I need to add something like -Wl,--no-whole-archive after linking my_other_lib.a because I do not want to use this option for external dependencies.
Any thoughs on this?
Try passing these flags as a single argument to target_link_libraries, and not as a list:
target_link_libraries(${TARGET} "-Wl,--whole-archive ${MY_LIBRARY} -Wl,--no-whole-archive")

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.

How to cope with older library installed in `/usr/lib` by sysadmin

I have recently got an account on a supercomputer grid, and I'm trying to compile my code in theri system. Problem is that program won't link with following errors:
/mnt/opt/tools/slc6/binutils/2.22/bin/ld: warning: libboost_system.so.1.55.0, needed by /mnt/home/jbzdak/tools/boost_1_55//lib/libboost_thread.so, may conflict with libboost_system.so.5
/mnt/opt/tools/slc6/binutils/2.22/bin/ld: /mnt/home/jbzdak/tools/boost_1_55//lib/libboost_thread.so: undefined reference to symbol '_ZN5boost6system15system_categoryEv'
/mnt/opt/tools/slc6/binutils/2.22/bin/ld: note: '_ZN5boost6system15system_categoryEv' is defined in DSO /mnt/home/jbzdak/tools/boost_1_55//lib/libboost_system.so.1.55.0 so try adding it to the linker command line
/mnt/home/jbzdak/tools/boost_1_55//lib/libboost_system.so.1.55.0: could not read symbols: Invalid operation
collect2: error: ld returned 1 exit status
Which is due to the fact that my program needs boost 1.55, and only 1.39 is instlled on the system in /usr/lib64. I have installed my version of boost in local folder, but somehow still system one is loaded first.
Here is excerpt from flags passed to the compiler:
-std=gnu++11 -Werror -Wall -lboost_thread -lboost_filesystem -lboost_system -lboost_iostreams -g -DG4OPTIMISE -Iinclude
-W -Wall -ansi -pedantic -Wno-non-virtual-dtor -Wno-long-long -Wwrite-strings -Wpointer-arith -Woverloaded-virtual -pipe -O2
full listing of flags is here (they should be irrevelant).
Here are revelant config variables:
LIBRARY_PATH /mnt/home/jbzdak/tools/boost_1_55/lib:
CPLUS_INCLUDE_PATH /mnt/home/jbzdak/tools/boost_1_55/include:/mnt/home/jbzdak/tools/geant4.9.6.3/compile/include/Geant4
LD_LIBRARY_PATH /mnt/home/jbzdak/tools/boost_1_55/lib:/mnt/opt/tools/slc6/gcc/4.8.3/lib64: ...
Directory /mnt/home/jbzdak/tools/boost_1_55 contains installed boost library.
I use GCC 4.8.3 with ld 2.22.
I have very little experience with linker errors hence the question. Is there any way to exclude boost libraries in /usr/lib64, or make the linker use locally installed libraries, and and ignore the system one?
I said in a comment:
There's no -L/alternative/location/of/boost/lib shown, so the compiler (linker) doesn't know it needs to look somewhere else for your modern Boost library. You may need -Wl,rpath,/alternative/location/of/boost/lib as well.
And the question was asked:
Why didn't LD_LIBRARY_PATH solve the issue?
Because LD_LIBRARY_PATH is a run-time variable rather than a link-time variable. It affects where the /lib/ld.so.1 (or equivalent) dynamic loader looks for libraries when you run a program, not where the linker looks to find its libraries.
After some additional debugging and asking another question, I found out the root cause of problem. Any -L parameter has precedence over LIBRARY_PATH and somehow -L/usr/lib64 was added (hence it had precedence over my version).
To check what options are sent to gcc pass -v parameter.

Linking a static library into Boost Python (shared library) - Import Error

I am building a Boost Python module (.so shared library file) which depends on another external library (STXXL)
While I can build and import the example Boost Python modules, I run into problems when STXXL is thrown into the mix. Specifically when running import fast_parts in python
I get ImportError: ./fast_parts.so: undefined symbol: _ZN5stxxl10ran32StateE
This says to me that the STXXL library isn't being linked, but I am not sure how that could be as I am linking against it and the linker isn't giving me any errors. It's worth noting I can successfully build and run standalone programs using STXXL and as far as I know the libraries are stored in a .a archive in the lib directory shown below. I have reduced my Makefile down to a single command as follows:
g++ -I/home/zenna/Downloads/stxxl-1.3.0/include -include stxxl/bits/defines.h -I/home/zenna/local/include -I/usr/include/python2.6 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -O3 -Wall -g -DFOO=BAR -pthread -L/home/zenna/Downloads/stxxl-1.3.0/lib/ -lstxxl -L/home/zenna/local/lib/ -lboost_python -lpython2.6 -fPIC -shared -o fast_parts.so partition.cpp
Any advice?
I'm assuming Linux, please comment if this is incorrect. What does the ldd output for libfast_parts.so look like? Does it indicate libstxxl.so is not found?
You might need to add /home/zenna/Downloads/stxxl-1.3.0/lib/ in your LD_LIBRARY_PATH or the rpath for libfast_parts.so.
-Wl,-rpath,/home/zenna/Downloads/stxxl-1.3.0/lib -L/home/zenna/Downloads/stxxl-1.3.0/lib -lstxxl