Cmake: How to check if a library is linked to an executable - makefile

I am linking a 3rd party library with my executable. There are buch of other libraries which I have successfully linked against. I'm not able understand what I am doing wrong.
This is the piece which is causing the issue
# Build libssh 0.7.3
ExternalProject_Add(libssh2
URL ${PROJECT_SOURCE_DIR}/packages/libssh.tar.gz
PREFIX ${CMAKE_BINARY_DIR}/external/libssh2
CONFIGURE_COMMAND ""
UPDATE_COMMAND ""
BUILD_COMMAND mkdir -p <SOURCE_DIR>/build && cd <SOURCE_DIR>/build &&
cmake -DWITH_STATIC_LIB=1 -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> -DCMAKE_BUILD_TYPE=Debug .. && make
INSTALL_COMMAND cd <SOURCE_DIR>/build && make install PREFIX=<INSTALL_DIR>
)
ExternalProject_Get_Property(libssh2 install_dir)
add_library(libssh STATIC IMPORTED)
set_property(TARGET libssh PROPERTY IMPORTED_LOCATION
${install_dir}/lib/libssh.a)
add_dependencies(libssh libssh2)
include_directories(${install_dir}/include)
This is another 3rd party which is linking correctly
ExternalProject_Add(libevent2
URL ${PROJECT_SOURCE_DIR}/packages/libevent-2.0.21-stable.tar.gz
PREFIX ${CMAKE_BINARY_DIR}/external/libevent2
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR>
UPDATE_COMMAND ""
)
ExternalProject_Get_Property(libevent2 install_dir)
add_library(libevent STATIC IMPORTED)
set_property(TARGET libevent PROPERTY IMPORTED_LOCATION
${install_dir}/lib/libevent.a)
add_dependencies(libevent libevent2)
include_directories(${install_dir}/include)
Error which I am seeing
Linking C executable ../../bin/nixia
CMakeFiles/nixia.dir/main_config.c.o: In function `main_config_dump':
/home/nikhil/nixia/src/main/main_config.c:88: undefined reference to `ssh_new'
/home/nikhil/nixia/src/main/main_config.c:91: undefined reference to `ssh_options_set'
collect2: ld returned 1 exit status
The library is created correctly
[nikhil#nikhil lib]$ ls
cmake libssh.a libssh.so libssh.so.4 libssh.so.4.4.1 libssh_threads.a libssh_threads.so libssh_threads.so.4 libssh_threads.so.4.4.1 pkgconfig
[nikhil#nikhil lib]$ pwd
/home/nikhil/nixia/build/external/libssh2/lib
The library contains the function definition
[nikhil#nikhil lib]$ ar x libssh.a | nm * | grep ssh_new
nm: Warning: 'cmake' is not an ordinary file
U ssh_new
0000000000000000 T ssh_new
00000000000351b0 T ssh_new
00000000000351b0 T ssh_new
00000000000351b0 T ssh_new

I suggest you to compile using CMake verbose mode in order to check the full command used to compile it.
In order to do so you have to compile using the following command:
make VERBOSE=1
In this manner you can check which is the library that was linked identifying the problem.
Possible reasons of the undefined reference error:
The library has not been found (check if -L and -l flags in the g++ command are correct and, in case of errors, modify the CMake to obtain the desired result);
On the same system there are more versions of the same library (in your case libssh): the compiler could use the header files of a version and the library of another which could have a different signature producing linking errors.

Related

Why cant mingw find libraries that gcc can find?

I am trying to compile a c program for windows and ubuntu to do that i am using mingw but it seems that it cant find the required libraries that gcc can find
when i execute this command
gcc decode_video.c -o dv -lavcodec -lavutil
Everything compiles normally but when i use this
x86_64-w64-mingw32-gcc decode_video.c -o dv.exe -lavcodec -lavutil
it says that header files arent found
after changing the build command to
x86_64-w64-mingw32-gcc decode_video.c -o dv.exe -I /usr/include/x86_64-linux-gnu -L /usr/lib/x86_64-linux-gnu -l avcodec -l avutil
it know gives me this error even though the libraries are linked
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x138): undefined reference to `avcodec_send_packet'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x192): undefined reference to avcodec_receive_frame'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x33f): undefined reference toav_packet_alloc'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x37d): undefined reference to avcodec_find_decoder'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x3d0): undefined reference toav_parser_init'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x421): undefined reference to avcodec_alloc_context3'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x481): undefined reference toavcodec_open2'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x512): undefined reference to av_frame_alloc'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x5fc): undefined reference toav_parser_parse2'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x6f8): undefined reference to av_parser_close'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x707): undefined reference toavcodec_free_context'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x716): undefined reference to av_frame_free'
/tmp/ccgn1NTi.o:decode_video.c:(.text+0x722): undefined reference toav_packet_free'
collect2: error: ld returned 1 exit status
Finally, it turned that you tried to link against libraries for an incompatible architecture:
Why can't mingw find libraries that gcc can find?
Either compiler are using different default options for the linker.
Even with same -L <path> and same LD_LIBRARY_PATH etc., the linker will skip incompatible libraries. In your case, gcc is presumably hosted by
x86_64-linux-gnu, whereas x86_64-w64-mingw32-gcc is obviously hosted by x86_64-w64-mingw32. Both are incompatible.
Try adding -I <path> to the compilation where <path> contains libavcodec/avcodec.h. Add more -I if you need more paths. Use -isystem <path> if it's supposed to be system headers. Add -v -H to the compilation to see what include paths are in use. gcc prints:
#include "..." search starts here:
#include <...> search starts here:
Try adding -L <path> to the link stage where <path> contains the libraries like lib*.a / lib*.so to be linked against. Add -Wl,-v to see which options the compiler driver passes to the GNU linker ld.
Make sure the symbols are in the libraries, e.g. using tools like nm or x86_64-w64-mingw32-nm.
Make sure you are using libraries cross-compiled using the x86_64-w64-mingw32 toolchain.

Linking ports libraries under FreeBSD

I have built some libraries (gtk3, qt5, ...) through the ports collection under FreeBSD 11.2. In order to test them I just built minimal examples. Each time the linker complains about not finding these libraries.
Correct me if I am wrong, but under FreeBSD, regular packages (those which are setup with pkg) are installed under /usr/include and /usr/lib, however ports lie, by default, under /usr/local/include and /usr/local/lib.
Is there a simple way to tell the compiler to search under these directories rather than having huge compilation commands with the -I and -L options?
Thank you for your answers.
Edit
Here is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
project(gtk-test)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
find_package(GTK3 REQUIRED)
include_directories(${GTK3_INCLUDE_DIRS})
link_directories(${GTK3_LIBRARY_DIRS})
add_executable(gtk-test gtk-test.c)
target_link_libraries(gtk-test ${GTK3_LIBRARIES})
I have solved the dependencies issue by grabbing the following CMake script:
https://github.com/eiskaltdcpp/eiskaltdcpp/blob/master/cmake/FindGTK3.cmake
However, another problem has pop up:
[100%] Linking C executable gtk-test
/usr/lib/crt1.o: In function `_start':
crt1.c:(.text+0x91): undefined reference to `main'
collect2: error: ld returned 1 exit status
Edit
I am stupid, I even did not notice that there was no main function in the sample. It works fine except that, by default, CMake cannot locate GTK3 library and its dependencies.
Here is the content of my CMake config scripts:
Qt5
Qt53DQuick
Qt53DRender
Qt5DataVisualization
Qt5Location
Qt5OpenGLExtensions
Qt5QuickTest
Qt5SerialBus
Qt5UiPlugin
Qt5WebKit
Qt5XmlPatterns
Qt53DAnimation
Qt53DQuickAnimation
Qt5Bluetooth
Qt5Designer
Qt5Multimedia
Qt5Positioning
Qt5QuickWidgets
Qt5SerialPort
Qt5UiTools
Qt5WebKitWidgets
assimp-4.1
Qt53DCore
Qt53DQuickExtras
Qt5Charts
Qt5Gamepad
Qt5MultimediaWidgets
Qt5PrintSupport
Qt5Script
Qt5Sql
Qt5WebChannel
Qt5WebSockets
harfbuzz
Qt53DExtras
Qt53DQuickInput
Qt5Concurrent
Qt5Gui
Qt5Network
Qt5Qml
Qt5ScriptTools
Qt5Svg
Qt5WebEngine
Qt5Widgets
libxml2
Qt53DInput
Qt53DQuickRender
Qt5Core
Qt5Help
Qt5Nfc
Qt5Quick
Qt5Scxml
Qt5Test
Qt5WebEngineCore
Qt5X11Extras
Qt53DLogic
Qt53DQuickScene2D
Qt5DBus
Qt5LinguistTools
Qt5OpenGL
Qt5QuickControls2
Qt5Sensors
Qt5TextToSpeech
Qt5WebEngineWidgets
Qt5Xml

Linking custom boost with CMake

I have boost 1.53 which was installed by yum. But I need to built my application required boost version 1.64. So I built boost 1.64 and installed with prefix /usr/local. The boost version detected by CMake is 1.64 (shown is message generated by CMake). But when I use ldd to check, its is version 1.53
I tried to reproduce the problem by create a small project and create a simple boost test linking to Boost::unit_test_framework. But it linking to the correct Boost version. When I looking in to link.txt of the executable, I saw that line:
c++ -g main.cpp.o -o Test -Wl,-rpath,/usr/local/lib /usr/local/lib/libboost_unit_test_framework.so
But in my main projects, it was
c++ -g -o ...... -lnsl -lrt -lboost_program_option -lboost_filesystem -lboost_thread
I check ld search path by this command:
$ gcc -m64 -Xlinker --verbose 2>/dev/null | grep SEARCH | sed 's/SEARCH_DIR("=\?\([^"]\+\)"); */\1\n/g' | grep -vE '^$'
and the result is:
/usr/local/lib64
/lib64
/usr/lib64
/usr/local/lib
......
The boost 1.53 install path is /lib64 and the install path of 1.64 is /usr/local/lib. So I think the test version is correct because of boost's absolute path is specified. And if the absolute path is not specified, ld will use version 1.53 because it was located first.
I tried set BOOT_ROOT and Boost_NO_SYSTEM_PATHS but can't solve this problem.
Update: I found the problem. The original cmake file was look like this:
find_package(Boost 1.64 REQUIRED COMPONENTS program_options)
target_link_library(MyProgram PRIVATE Boost::program_options) #original cmake
#target_link_library(MyProgram PRIVATE boost_program_options) #my cmake
#target_link_library(MyProgram PRIVATE ${Boost_LIBRARIES}) #fixed cmake
I fix the cmake because I can not run cmake with original cmake. cmake told me that Boost:program_options was not found on my computer. When I replace with boost_program_options, then it work but this library is not result of find_package.

Configure an autotools project with Clang sanitizers in a static lib configuration?

EDIT: If its TLDR, just skip to the bottom. Its where I ask: How do I configure an autotools project to use a static library?
I'm working with a couple of open source libraries, and I'm trying to run their test suite under Clang's sanitizers. To run under Clang sanitizers, we need to (1) specify some options, and (2) link static libraries from Clang's Compiler-RT as required. Note: there are no dynamic libraries or shared objects.
Setting the options is easy:
export DYLD_FALLBACK_LIBRARY_PATH=/usr/local/lib/clang/3.3/lib/darwin/
export CC=/usr/local/bin/clang
export CXX=/usr/local/bin/clang++
export CFLAGS="-g3 -fsanitize=address -fsanitize=undefined"
export CXXFLAGS="-g3 -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr"
./configure
However, this will generate some archive warnings (when AR is run) and link errors (when LD is run) with undefined symbols. The message will be similar to:
libjpeg.a(jmemmgr.o): In function `do_sarray_io':
/home/jwalton/jpeg-6b/jmemmgr.c:695: undefined reference to
`__ubsan_handle_type_mismatch'
/home/jwalton/jpeg-6b/jmemmgr.c:695: undefined reference to
`__ubsan_handle_type_mismatch'
/home/jwalton/jpeg-6b/jmemmgr.c:696: undefined reference to
`__ubsan_handle_type_mismatch'
I know the libraries that need to be linked. For the sanitizers that I use, they are libclang_rt.asan_osx.a and libclang_rt.ubsan_osx.a (or libclang_rt.full-x86_64.a and libclang_rt.ubsan-x86_64.a on Linux).
To supply the libraries, I then export the following. Note: it is LIBS, and not LDLIBS as expected by most other make related tools.
export LIBS="/usr/local/lib/clang/3.3/lib/darwin/libclang_rt.asan_osx.a \
/usr/local/lib/clang/3.3/lib/darwin/libclang_rt.ubsan_osx.a"
This results in a configure problem of:
configure: error: cannot run C compiled programs.
If you meant to cross compile, use `--host'.
...
Looking at config.log, it looks like two problems are occurring. First, the path is being butchered by changing from /usr/local/... to /Users/jwalton/.... And second, the filename is being butchered by changing from a static lib to a dynamic lib:
configure:3346: ./conftest
dyld: Library not loaded: /Users/jwalton/clang-llvm/llvm-3.3.src/Release+Asserts/lib/clang/3.3/lib/darwin/libclang_rt.asan_osx_dynamic.dylib
Referenced from: /Users/jwalton/libpng-1.6.7/./conftest
Reason: image not found
In another attempt, I tried using LDFLAGS:
export LDFLAGS="-L/usr/local/lib/clang/3.3/lib/darwin/"
export LIBS="libclang_rt.asan_osx.a libclang_rt.ubsan_osx.a"
That results in a similar error:
configure: error: in `/Users/jwalton/libpng-1.6.7':
configure: error: C compiler cannot create executables
And config.log:
configure:3209: /usr/local/bin/clang -g3 -fsanitize=address -fsanitize=undefined -L/usr/local/lib/clang/3.3/lib/darwin/ conftest.c libclang_rt.asan_osx.a libclang_rt.ubsan_osx.a >&5
clang: error: no such file or directory: 'libclang_rt.asan_osx.a'
clang: error: no such file or directory: 'libclang_rt.ubsan_osx.a'
And dropping the lib prefix and .a suffix from the LIBS results in:
configure:3209: /usr/local/bin/clang -g3 -fsanitize=address -fsanitize=undefined -L/usr/local/lib/clang/3.3/lib/darwin/ conftest.c clang_rt.asan_osx clang_rt.ubsan_osx >&5
clang: error: no such file or directory: 'clang_rt.asan_osx'
clang: error: no such file or directory: 'clang_rt.ubsan_osx'
And adding the -l to LIBS results in:
configure:3335: /usr/local/bin/clang -o conftest -g3 -fsanitize=address -fsanitize=undefined
-L/usr/local/lib/clang/3.3/lib/darwin/ conftest.c -lclang_rt.asan_osx -lclang_rt.ubsan_osx >&5
configure:3339: $? = 0
configure:3346: ./conftest
dyld: could not load inserted library: /Users/jwalton/libpng-1.6.7/./conftest
./configure: line 3348: 38224 Trace/BPT trap: 5 ./conftest$ac_cv_exeext
Finally, the -L argument is valid:
$ ls /usr/local/lib/clang/3.3/lib/darwin/
libclang_rt.10.4.a libclang_rt.ios.a
libclang_rt.asan_osx.a libclang_rt.osx.a
libclang_rt.asan_osx_dynamic.dylib libclang_rt.profile_ios.a
libclang_rt.cc_kext.a libclang_rt.profile_osx.a
libclang_rt.cc_kext_ios5.a libclang_rt.ubsan_osx.a
libclang_rt.eprintf.a
After all the background: how do I configure an autotools project to use a static library?
Bonus points: why has something so easy been made so difficult?
You need to add -fsanitize flags to LDFLAGS as well.
Shipping versions of GNU libtool do not pass -fsanitize=... arguments to the linker. You will need to update libtool with the patch from http://savannah.gnu.org/patch/?8775 Specifically:
diff --git a/build-aux/ltmain.in b/build-aux/ltmain.in
index 0c40da0..b99b0cd 100644
--- a/build-aux/ltmain.in
+++ b/build-aux/ltmain.in
## -5362,10 +5362,11 ## func_mode_link ()
# -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
# -specs=* GCC specs files
# -stdlib=* select c++ std lib with clang
+ # -fsanitize=* Clang memory and address sanitizer
-64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
-t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|#*|-tp=*|--sysroot=*| \
-O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
- -specs=*)
+ -specs=*|-fsanitize=*)
func_quote_for_eval "$arg"
arg=$func_quote_for_eval_result
func_append compile_command " $arg"
As for getting libtool to accept a static library, you should be able to just include the full path to the static library on the command line, or you can use options like -L/usr/local/lib/clang/3.3/lib/darwin/ -lclang_rt.ubsan_osx. However, cfe should take care of the library magic for you once libtool tells it to use -fsanitize=... for linking.
As for the undefined symbol issue, if you are linking C++ objects, then you must use clang++ instead of clang. Otherwise you can get error such as:
/bin/bash libtool --tag=CC --mode=link clang-3.6 ... -fsanitize=undefined -o freeswitch ...
libtool: link: clang-3.6 ... -fsanitize=undefined -o .libs/freeswitch ./.libs/libfreeswitch.so ...
./.libs/libfreeswitch.so: undefined reference to `__ubsan_vptr_type_cache'
./.libs/libfreeswitch.so: undefined reference to `__ubsan_handle_dynamic_type_cache_miss'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
In the above case, the atrocious libtool used clang instead of clang++ because automake thought that you wanted to link a set of C objects (it does not understand that linking a libtool archive (libfreeswitch.la) using C++ means that a C++ linker is needed (note the --tag=CC). See also https://lists.debian.org/debian-mentors/2003/06/msg00004.html.
To work around this issue, follow the instructions at https://www.gnu.org/software/automake/manual/html_node/Libtool-Convenience-Libraries.html and add a (dummy/real) C++ source to your sources in your Makefile.am:
SUBDIRS = sub1 sub2 …
lib_LTLIBRARIES = libtop.la
libtop_la_SOURCES =
# Dummy C++ source to cause C++ linking.
nodist_EXTRA_libtop_la_SOURCES = dummy.cxx
libtop_la_LIBADD = \
sub1/libsub1.la \
sub2/libsub2.la \
…

Problem with linking against libexpat in Boost Build - for building graphml

On my system, expat is located at
/usr/include/expat.h
/usr/include/expat_external.h
/usr/lib/libexpat.1.5.0.dylib
/usr/lib/libexpat.1.dylib
/usr/lib/libexpat.dylib
/usr/lib/libexpat.la
So I export the required variables for boost to build graphml
export EXPAT_INCLUDE=/usr/include
export EXPAT_LIBPATH=/usr/lib
then I run (where $DIR and $BOOST generate the paths I want the includes and libs to go)
./configure --includedir=$DIR/$BOOST --libdir=$DIR/$BOOST/lib \
--with-libraries=test,graph
I get this error:
ld: library not found for -lexpat collect2: ld returned 1 exit status
which boost says is caused by the line:
g++ -dynamiclib -install_name "libboost_graph-mt-1_35.dylib" -L"/usr/lib"
-o "bin.v2/libs/graph/build/darwin/release/macosx-version-10.4/threading-multi/libboost_graph-mt-1_35.dylib"
"bin.v2/libs/graph/build/darwin/release/macosx-version-10.4/threading-multi/read_graphviz_spirit.o"
"bin.v2/libs/graph/build/darwin/release/macosx-version-10.4/threading-multi/graphml.o"
-lexpat -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -Wl,-dead_strip -no_dead_strip_inits_and_terms
I don't get how it's not finding the expat library with -L"/usr/lib" and -lexpat as arguments? My understanding is that /usr/lib/libexpat.dylib is exactly referenced as -L"/usr/lib" and -lexpat.
The Jamfile for building graphml is here. If EXPAT_INCLUDE and EXPAT_LIBPATH aren't set then it warns you (lines 39-41 of jamfile)
warning: Graph library does not contain optional GraphML reader.
note: to enable GraphML support, set EXPAT_INCLUDE and
note: directories containing the Expat headers and libraries, respectively.
Another update:
I don't see an .so or a .a file in your list of where EXPAT is... doesn't that seem a bit strange? Normally it will create an alias for the library name
for example /usr/lib/libblah.so -> /usr/lib/libblaah.so.1.2
Is dynalib some Macintoshism (I don't use Macs much)
is .la the static version extension on this platform?
Update:
The quotes around the path seem troublesome...
-L"/usr/lib"
Try changing this to -L/usr/lib and -L /usr/lib
Older stuff:
The directive for the linker to include paths during the link step is -L. You need to look for some linker flags to update to include -L path_to_expat. I don't think the linker pays any attention to LD_LIBRARY_PATH. I am not sure what documentation you have read to set EXPAT_INCLUDE or EXPAT_LIBPATH.

Resources