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

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.

Related

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?

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")

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

How to compile cpp source to full static binary and except for: libc, libpthread, libdl, libstdc++, and libm

I want to compile a binary linux to full static, But I always fail with this configuration:
CFLAGS="--static" CPPFLAGS="-I/home/alan/arm/arm-none-linux-gnueabi/libc/usr/include" LDFLAGS="-L/home/alan/arm/arm-none-linux-gnueabi/libc//usr/lib" LIBS="-lcrypt -ldl -lpthread -lm -lc -lstdc++" CC=arm-none-linux-gnueabi-gcc AR=arm-none-linux-gnueabi-ar CXX=arm-none-linux-gnueabi-g++ ./configure --host=arm-none-linux-gnueabi target=arm-none-linux-gnueabi --prefix=/home/alan/armbin/test --without-pcre --without-zlib --without-bzip2 --without-openssl --disable-ipv6 --enable-static
But I always get warning dlopen, gethostbyname, etc. If I not except libc, libm, etc to shared. I get warning approximately as below:
warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
Thank you very much.
Use -pthread instead of -lpthread.
Source.
Your link command should look like this:
g++ objectFiles $(CFLAGS) -o executable -Wl,-Bstatic -L/path/to/static/lib1/ -ls1 -L/path/to/static/lib2 -ls2 -Wl,-Bdynamic
You only have to explicitly call the static libraries libs1.a, libs2.a . The shared system libraries you are referring to (libc.so, libpthreads.so, libm.so, libdl.so, libstdc++.so etc.) should be found implicitly by your linker and are affected by -Wl, -Bdynamic. You don't have to pass them explicitly. Try and do a
"ldd executable" to see the dynamic dependencies.

Linking problems with cmake and cygwin

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?