CMake Linking custom libraries with executable results in undef. references - c++

I'm new to CMake and have a feeling that I miss something.
Here is the problem:
I build a shared object called "wrapper" as shown below.
add_library(wrapper SHARED
dh-wrap.cpp)
target_link_options(wrapper PUBLIC -Wl,--no-as-needed)
target_include_directories(wrapper
PUBLIC /usr/local/include/dahua)
target_link_directories(wrapper
PUBLIC /usr/local/lib/dahua)
target_link_libraries(wrapper dhnetsdk)
Then I use it to build another target called "library" (also shared object)
add_library(lib SHARED
library.c buffer.c)
target_link_options(lib PUBLIC -Wl,--no-as-needed)
target_include_directories(lib
PUBLIC /usr/local/include/dahua)
target_link_directories(lib
PUBLIC /usr/local/lib/dahua
PUBLIC ../cmake-build-debug-gcc/wrapper)
target_link_libraries(lib wrapper)
Finally I want to build a test executable and link it with those targets built before.
# Test executable
add_executable(test_x main.c)
target_link_options(test_x PUBLIC -Wl,--no-as-needed)
target_include_directories(test_x
PUBLIC /usr/local/include/dahua)
target_link_directories(test_x
PUBLIC /usr/local/lib/dahua
PUBLIC ../cmake-build-debug-gcc/wrapper
PUBLIC ../cmake-build-debug-gcc/library)
target_link_libraries(test_x lib)
When I try to build it I get a bunch of undefined references for functions that "wrapper" implement and functions that are implemented in 3rd party lib "dhnetsdk".
ld: ../wrapper/libwrapper.so: undefined reference to `CLIENT_SetDeviceMode(long, __EM_USEDEV_MODE, void*)'
ld: ../library/liblib.so: undefined reference to `DH_SDK_Init'
ld: ../library/liblib.so: undefined reference to `DH_DownloadByTime'
ld: ../library/liblib.so: undefined reference to `DH_SDK_Cleanup'
ld: ../library/liblib.so: undefined reference to `DH_Logout'
ld: ../library/liblib.so: undefined reference to `DH_SetDeviceMode'
ld: ../library/liblib.so: undefined reference to `DH_Login'
ld: ../wrapper/libwrapper.so: undefined reference to `CLIENT_StopDownload(long)'
...
At first, using ldd I've noticed that my "wrapper" and "lib" aren't even linked against this 3rd party library "dhnetsdk". So I added -Wl,--no-as-needed. After that ldd showed the dependency. But undefined references in the executable are still present.
When I readelf -s libwrapper.so it shows that all symbols in "dhnetsdk" lib are undefined. But as far as I understand this is expected as it will be resolved later, when it's actually used. The same is true for symbols defined in "wrapper", when I readelf -s liblib.so.
For me it looks like CMake knows about all the libs, knows where to find them, but for some mysterious reason denies to link it and resolve symbols when I try to build an executable. What am I missing here?

Related

dl libs and pthreads required in GitHub Actions

I'm developing a dynamic C++17 library that uses SQLite. It's a CMake project and the requirement for it to be dynamic comes because I plan to mainly use the library through JNI.
So, in my project I build SQLite as a static library:
add_library(sqlite3 STATIC "${sqlite3_SOURCE_DIR}/sqlite3.c") # STATIC to efficiently link to SHARED main library
set_target_properties(sqlite3 PROPERTIES POSITION_INDEPENDENT_CODE ON) # Required to link STATIC to SHARED
target_include_directories(sqlite3 PUBLIC "${sqlite3_SOURCE_DIR}")
And my main library as shared:
add_library(${PROJECT_NAME} SHARED <library sources>)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) # To include headers without using relative paths
target_link_libraries(${PROJECT_NAME} PRIVATE sqlite3)
Then if I link my library to some executable like this it builds and runs absolutely fine on my PC:
add_executable(app <app's sources>)
target_compile_features(app PUBLIC cxx_std_17)
target_include_directories(app PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} <main library src dir>) # Including the main library like this is a temporary solution, because there is no separate include dir yet
target_link_libraries(app PUBLIC ${PROJECT_NAME})
But when I try to build it in GitHub Actions I get these errors:
[100%] Linking CXX executable app
/usr/bin/ld: ../src/mylib.so: undefined reference to `pthread_mutexattr_destroy'
/usr/bin/ld: ../src/mylib.so: undefined reference to `pthread_create'
/usr/bin/ld: ../src/mylib.so: undefined reference to `dlopen'
/usr/bin/ld: ../src/mylib.so: undefined reference to `pthread_mutex_trylock'
/usr/bin/ld: ../src/mylib.so: undefined reference to `dlclose'
/usr/bin/ld: ../src/mylib.so: undefined reference to `dlerror'
/usr/bin/ld: ../src/mylib.so: undefined reference to `dlsym'
/usr/bin/ld: ../src/mylib.so: undefined reference to `pthread_mutexattr_settype'
/usr/bin/ld: ../src/mylib.so: undefined reference to `pthread_join'
/usr/bin/ld: ../src/mylib.so: undefined reference to `pthread_mutexattr_init'
collect2: error: ld returned 1 exit status
I can fix it by linking the library target to ${CMAKE_DL_LIBS} and Threads::Threads, but I'm not sure if I'm doing what should be done and not just silencing some other mistakes of mine.
To be clear, I don't use any of the functions mentioned in the errors above in the code of my library.
The questions are:
Why does the original code work on my PC and doesn't on GitHub Actions?
Is what I did the right way to fix this?
I'm building the project locally on Ubuntu 22.04 (WSL) with a compiler identified as GNU 11.3.0, while GitHub Actions runs Ubuntu 20.04 using GNU 9.4.0 compiler.

fmt linking for dummies [duplicate]

This question already has answers here:
How to use the fmt library without getting "Undefined symbols for architecture x86_64"
(3 answers)
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed last year.
I'd like to make a python-like dynamic integer class in C++ as an experiment. It requires me to change many integers to string types. As in here: https://www.zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html it states that fmt format_int will be best for that kind of job.
So I installed fmt with command sudo apt-get install libfmt-dev
I added a header #include <fmt/format.h>
Used it in a simple test main
int main()
{
std::cout<<fmt::format_int(124236695253045068).str();
}
And tried to compile with g++ -lfmt -std=c++17 dynamic\ mem.cc
Output of the compiler is as follows:
/usr/bin/ld: /tmp/ccLBcSNm.o: in function `fmt::v6::format_int::format_decimal(unsigned long long)':
dynamic mem.cc:(.text._ZN3fmt2v610format_int14format_decimalEy[_ZN3fmt2v610format_int14format_decimalEy]+0x94): undefined reference to `fmt::v6::internal::basic_data<void>::digits'
/usr/bin/ld: dynamic mem.cc:(.text._ZN3fmt2v610format_int14format_decimalEy[_ZN3fmt2v610format_int14format_decimalEy]+0xad): undefined reference to `fmt::v6::internal::basic_data<void>::digits'
/usr/bin/ld: dynamic mem.cc:(.text._ZN3fmt2v610format_int14format_decimalEy[_ZN3fmt2v610format_int14format_decimalEy]+0xfa): undefined reference to `fmt::v6::internal::basic_data<void>::digits'
/usr/bin/ld: dynamic mem.cc:(.text._ZN3fmt2v610format_int14format_decimalEy[_ZN3fmt2v610format_int14format_decimalEy]+0x113): undefined reference to `fmt::v6::internal::basic_data<void>::digits'
/usr/bin/ld: /tmp/ccLBcSNm.o: in function `std::make_unsigned<long>::type fmt::v6::internal::to_unsigned<long>(long)':
dynamic mem.cc:(.text._ZN3fmt2v68internal11to_unsignedIlEENSt13make_unsignedIT_E4typeES4_[_ZN3fmt2v68internal11to_unsignedIlEENSt13make_unsignedIT_E4typeES4_]+0x2b): undefined reference to `fmt::v6::internal::assert_fail(char const*, int, char const*)'
collect2: error: ld returned 1 exit status
Do you have any ideas what went wrong? I don't usually link non-standard libraries so I don't have any idea what to do about it.
Use
$ g++ -std=c++17 dynamic\ mem.cc -lfmt
fmt is provided as a static library (.a). With those, the order is important as the linker takes out of a library only the objects which are needed to provide symbols to other objects or libraries which precede them in the command line. If you start with a library, there is only main which is missing and usually libraries don't provide main, so they are ignored. When putting the library after your source code, the symbols missing in your code are searched in the library.
(In case of circular dependencies, you may even have to provide a library several times)

Boost ld: final link failed: Bad value: relocation R_X86_64_PC32 against undefined hidden symbol

I'm Trying to Link boost library with our code, I'm Getting the Following error
ld: /boost/lib/laxno/libboost_thread.a(thread.o): relocation R_X86_64_PC32 against undefined hidden symbol `_ZTCN5boost10wrapexceptINS_21thread_resource_errorEEE0_NS_16exception_detail10clone_implINS3_19error_info_injectorIS1_EEEE' can not be used when making a shared object
ld: final link failed: Bad value
I have built the boost with the GCC 7.4.0 with the following command
./b2 cxxflags="-fPIC -std=c++14" cflags="-fPIC" -j4
Getting the following error if I exclude the "-fPIC" flag while building the boost libs:
/boost/lib/laxno/libboost_thread.a(thread.o): relocation R_X86_64_32 against `.text' can not be used when making a shared object; recompile with -fPIC
/boost/lib/laxno/libboost_thread.a: could not read symbols: Bad value
Using the boost libs and boost .so files from the boost install location instead of build location fixed the issue.

Static linking OpenCV on Eclipse running on Windows

I am trying to static link OpenCV libraries on Windows. I already built the library with BUILD_SHARED_LIBS OFF and I created a project on the Eclipse (am using MinGW by the way). C:\opencv is set as my source while C:\opencv\build\x86\mingw is set as the destination on the cmake-gui. I then executed mingw32-make and mingw32-make install on C:\opencv\build\x86\mingw.
My question is, how do I static link those libraries on the Eclipse, I tried several ways but my OpenCV application still doesn't work on computers without OpenCV installed.
Here's what I tried so far, I set
C:\opencv\build\x86\mingw\install\include as the include folder;
C:\opencv\build\x86\mingw\lib as the library path on the "Linker" and I have opencv_core246, opencv_highgui246, opencv_objdetect246 and opencv_imgproc246.
This way it seems like it still uses "dynamic linking" so I tried adding -static on the Miscellaneous option but then I got these errors:
C:\opencv\build\x86\mingw\lib\libopencv_imgproc246.a(templmatch.cpp.obj):templmatch.cpp:
(.text$_ZN2cv9crossCorrERKNS_3MatES2_RS0_NS_5Size_IiEEiNS_6Point_IiEEdi+0x1ce5):
undefined reference to `cv::dft(cv::_InputArray const&, cv::_OutputArray const&, int, int)'
C:\opencv\build\x86\mingw\lib\libopencv_imgproc246.a(templmatch.cpp.obj):templmatch.cpp:
(.text$_ZN2cv9crossCorrERKNS_3MatES2_RS0_NS_5Size_IiEEiNS_6Point_IiEEdi+0x1dab):
undefined reference to `cv::mulSpectrums(cv::_InputArray const&, cv::_InputArray const&, cv::_OutputArray const&, int, bool)'
C:\opencv\build\x86\mingw\lib\libopencv_imgproc246.a(templmatch.cpp.obj):templmatch.cpp:
(.text$_ZN2cv9crossCorrERKNS_3MatES2_RS0_NS_5Size_IiEEiNS_6Point_IiEEdi+0x1ded):
undefined reference to `cv::dft(cv::_InputArray const&, cv::_OutputArray const&, int, int)'
collect2: ld returned 1 exit status
Anyone can provide me real step-by-step to static link OpenCV library on Windows using Eclipse and MinGW?
EDIT: I found out that in VS we have to add libraries such as: libtiff.lib libpng.lib libjpeg.lib libjasper.lib IlmImf.lib zlib.lib to the Linker which I did but the problem persists. Then I heard adding Vfw32.Lib comctl32.lib solved the problem but unfortunately I guess they are VS-specific.
Adding 3rd party libraries -llibjasper -llibtiff -lopencv_lapack -lzlib -lpng -ljpeg -lpthread -lrt should solve the issue.
Try compiling a very basic OpenCV code. The order of the libraries that are linked is important while linking static libraries.
If libraryA is depend on libraryB, then libraryA must be defined before defining libraryB.

Linking issues with wxWidget sample on Ubuntu 12.04 (amd64)

I have a problem linking the wxWidget sample application (http://www.wxwidgets.org/docs/tutorials/hello.htm) with is stored in main.cpp. I try to compile and link it using:
g++ `wx-config --cxxflags --libs` main.cpp
The output I get is the following:
/tmp/ccFHWUaX.o: In function `wxCreateApp()':
main.cpp:(.text+0x31): undefined reference to `wxAppConsole::CheckBuildOptions(char const*, char const*)'
/tmp/ccFHWUaX.o: In function `main':
main.cpp:(.text+0x91): undefined reference to `wxEntry(int&, char**)'
/tmp/ccFHWUaX.o: In function `MyFrame::MyFrame(wxString const&, wxPoint const&, wxSize const&)':
main.cpp:(.text+0x1d2): undefined reference to `wxFrameNameStr'
main.cpp:(.text+0x267): undefined reference to `wxEmptyString'
main.cpp:(.text+0x2ea): undefined reference to `wxEmptyString'
main.cpp:(.text+0x366): undefined reference to `wxMenuBar::wxMenuBar()'
main.cpp:(.text+0x3d1): undefined reference to `wxFrameBase::SetMenuBar(wxMenuBar*)'
main.cpp:(.text+0x3da): undefined reference to `wxStatusLineNameStr'
main.cpp:(.text+0x407): undefined reference to `wxFrame::CreateStatusBar(int, long, int, wxString const&)'
main.cpp:(.text+0x44f): undefined reference to `wxFrameBase::SetStatusText(wxString const&, int)'
main.cpp:(.text+0x533): undefined reference to `wxFrame::~wxFrame()'
(and many lines more...)
WxWidgets-2.8 is installed using the ubuntu repository and its libs are located in /usr/lib/x86_64-linux-gnu. I also tried to build specifying the library path with:
-L/usr/lib/x86_64-linux-gnu/
but, this does not change the output. I was blaming multiarch for my problem, but actually only as I don't know how it works exactly.
Can someone tell me how to build the sample correctly?
Thank you
Michael
When using static linking, the libraries must always come after the object files using the symbols from them, otherwise they're simply ignored by the linker as they're not needed at the moment when it first sees them. So us2012 is correct, you need to put wx-config part after your source file.
You could also use shared wxWidgets libraries, then the order wouldn't matter. But it's still a good habit to use the right order, which works for both static and shared libraries, anyhow.