Linking with CMakeLists: ld cannot find library - c++

I have a CMakeLists.txt file, with the following:
target_link_libraries(${PROJECT_NAME} OpenNI2)
When I run cmake, I receive no errors. But when I run make, I receive the following error:
/usr/bin/ld: cannot find -lOpenNI2
However, I have a file called libOpenNI2.so in my build directory. So why can ld not find this? I thought that the build directory was on the search path for target_link_libraries?
Thanks!

That's because when linking, the linker doesn't look in the current directory but only in a set of predefined directories.
You need to tell CMake where the library is, for example by giving the full path to the library in the target_link_library command, or adding it as an imported library.

it works if adding like:
target_link_libraries(${PROJECT_NAME} /path_to_library_build/libOpenNI2.a)
details:
ld is looking for the libraries in a very short list of folders defined in
/etc/ld.so.conf
and it usually looks like following:
include /etc/ld.so.conf.d/*.conf
and actual paths list from those *.conf files usually is like:
# Legacy biarch compatibility support
/lib32
/usr/lib32
# Multiarch support
/usr/local/lib/x86_64-linux-gnu
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
if your project linking library is not in the folder of this list, ld won't find it unless either a special linking variable set LD_LIBRARY_PATH with the path to your library or a complete path/library name provided in cmake target_link_libraries directive.
details on how to proper setup LD_LIBRARY_PATH variable discussed here

Related

CMake include shared library and it's dependencies

I am trying to include this C++ library with CMake. As I understood, the file that I need to include is located at lib/libbinacpp/lib/libbinacpp.so (relative to the library root folder).
So, I created a new folder, with two subfolders
src, which only contains one file: src/main.cpp (a simple Hello, World)
lib, which contains a folder binacpp, the result of cloning the library
On the top level, I have my CMakeLists.txt. First, I tried to write the following:
cmake_minimum_required(VERSION 3.20)
project(RebalancerBot)
set(CMAKE_CXX_STANDARD 20)
#Include binacpp
add_library(binacpp SHARED IMPORTED)
set_target_properties(binacpp PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/binacpp/lib/libbinacpp/lib/libbinacpp.so)
add_executable(RebalancerBot src/main.cpp)
#Link everything after adding the executable
target_link_libraries(RebalancerBot PRIVATE binacpp)
Which resulted in the error
make[3]: *** No rule to make target 'lib/binacpp/lib/libbinacpp/lib/libbinacpp.so', needed by 'RebalancerBot'. Stop.
To my surprise, I got a different error after replacing ${CMAKE_BINARY_DIR} with the actual root path of my folder (i.e /home/actual_path/). I found this surprising since I thought that ${CMAKE_BINARY_DIR}$ should exactly be the path to the root CMakeLists.txt file. Anyway, after the replacement, I got the following new errors:
/usr/bin/ld: warning: libcrypto.so.1.0.0, needed by ../lib/binacpp/lib/libbinacpp/lib/libbinacpp.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libwebsockets.so.11, needed by ../lib/binacpp/lib/libbinacpp/lib/libbinacpp.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: ../lib/binacpp/lib/libbinacpp/lib/libbinacpp.so: undefined reference to `lws_client_connect_via_info'
/usr/bin/ld: ../lib/binacpp/lib/libbinacpp/lib/libbinacpp.so: undefined reference to `lws_callback_on_writable'
... (the list goes on)
If I understand correctly, these errors are due to the dependencies of libbinacpp.so. How can fix them?
PS: It should be noted that, if I cd into lib/binacpp/src and make inside of this directory, everything runs without errors.
EDIT: Thanks to #AlanBirtles comment, I found that the error with CMAKE_BINARY_DIR was due to the fact that it unfolds to the directory I run cmake in. What I needed was CMAKE_SOURCE_DIR: the directory containing my cmake file.
CMake offers the possibility to have a build directory which differs from the source directory. A offer we should gladly accept, because it keeps our build system from messing with our source and we can have different build directories, depending on build type, compiler, target system, etc.
${CMAKE_BINARY_DIR} is a shortcut to your top-level build directory. CMake will generate all files here during the build.
${CMAKE_SOURCE_DIR} is where CMake is looking for your sources. CMake is not intended to make changes in your source directory.
If you copied the library to your source directory, you need to reference it with the right shortcut.
By the way, are you sure, you want to copy the library to the source directory? Because you don't need to. You can use find_file (https://cmake.org/cmake/help/latest/command/find_file.html), find_library (https://cmake.org/cmake/help/latest/command/find_library.html), find_path (https://cmake.org/cmake/help/latest/command/find_path.html) or find_program (https://cmake.org/cmake/help/latest/command/find_program.html) to checkout the location of the item you need and use this path to define your imported library.

Link External Library when using CMakeLists used by CLion

I have build libmemcached.a and copied it to /usr/local/lib on my mac and I have tried all the following options to link libmemcached.a and yet get compile time errors that libmemcached/memcached.h is not found.
link_libraries (${libmemcached})
include_directories(SYSTEM ${libmemcached})
link_directories("/usr/local/lib")
find_package(libmemcached.a REQUIRED)
link_libraries`enter code here`(libmemcached.a)
find_library(RESULT libmemcached.a PATHS /usr/local/lib)
target_link_libraries(dnsa_pcl libmemcached.a)
It is a simple -L -l using MakeFile. Not sure what needs to be done to make this work using CMakeLists. Any help is much appreciated.
you should use so called imported library, like it's described in the official documentation
The solution that worked for me is a bit weird. I had to both set the CMAKE_PREFIX_PATH to the directory that has the lib and also have include_directories() with the include folder of the source. For some reason, I was under the impression that the libmemcached.a had the header files as well.

CMake can't find external library

I am trying to build an application that uses the LibUSB library.
In a previous question I asked here I was told to use find_path and find_library to make CMake search for the headers and binaries. However even after manually looking up the library's installation locations with dnf and specifying them as PATHS or HINTS I always still get the error:
/usr/bin/ld: cannot find -lUSB
collect2: error: ld returned 1 exit status
Below is the relevent cmakelists.txt, my import line in main.cpp is #include <libusb-1.0/libusb.h>
add_executable(project main.cpp)
find_path(LIBUSB_INCLUDE_DIR
NAMES libusb.h
PATHS "/usr/include/"
PATH_SUFFIXES "include" "libusb")
find_library(LIBUSB_LIBRARY
NAMES USB
HINTS "/usr/lib/" "/usr/lib64/" "/usr/include/"
PATH_SUFFIXES "lib" "lib32" "lib64")
target_include_directories(project PRIVATE "/usr/lib/" "/usr/lib64/")
target_link_libraries(project USB)
Clearly I'm doing something wrong in this kludge of hacks, but could someone tell me what?
You're not using the result of your find operations anywhere. You tell CMake to find the headers and store the found paths in LIBUSB_INCLUDE_DIR, and to find the library and store its location in LIBUSB_LIBRARY, and then you go to ignore these and use hardcoded "/usr/lib/" "/usr/lib64/" and USB instead. Try this:
target_include_directories(project PRIVATE ${LIBUSB_INCLUDE_DIR})
target_link_libraries(project ${LIBUSB_LIBRARY})
As shown Back in the original question, here, all of the finding and including functions can be replaced simply with:
target_link_libraries(project_name <other_dependencies> usb-1.0),
in the file where the build target is defined.

Cannot open shared object file

I am trying to compile one of the projects found here
USB-I2C/SPI/GPIO Interface Adapter.
I downloaded the i2c_bridge-0.0.1-rc2.tgz package. I installed libusb and that seemed to go well with no issues. I go into the i2c_bridge-0.0.1-rc2/ directory and make. That compiles. I move into the i2c_bridge-0.0.1-rc2/i2c folder and make. It compiles and gives me ./i2c. However, when I run it, it says error while loading shared libraries: libi2cbrdg.so: cannot open shared object file: No such file or directory
The makefile in i2c_bridge-0.0.1-rc2/i2c has the library directory as ../. The libi2cbrdg.so is in this directory (i2c_bridge-0.0.1-rc2). I also copied the file to /usr/local/lib. An ls of the i2c_bridge-0.0.1-rc2/ directory is
i2c i2cbrdg.d i2cbrdg.o libi2cbrdg.a Makefile tests
i2cbrdg.c i2cbrdg.h INSTALL libi2cbrdg.so README u2c4all.sh
(That i2c is a directory)
If I sudo ./i2c, it still gives me the problem.
I had to take away the -Werror and -noWdecrepated (spelling?) options in all the makefiles to get them to compile, but that shouldn't affect this should it?
What else is necessary for it to find the .so file? If anyone can help me find out what is wrong I would be very grateful. If more information is needed I can post it.
You have to distinguish between finding so's at compile-time and at run-time. The -L flag you give at compile-time has nothing to do with localizing the library at run-time. This is rather done via a number of variables and some paths embedded in the library.
The best hot-fix for this problem is often setting LD_LIBRARY_PATH to the directory with the .so file, e.g.:
$ LD_LIBRARY_PATH=.. ./i2c
For a long-term solution, you need to either have a close look at the whole LD system with rpath and runpath, or use libtool (which solves these issues for your portably).
Copying a file to /usr/local/lib is often insufficient because ld caches the available libraries, so you need to re-run ldconfig (as root) after you copied a library to /usr/local/lib.
If you are building the code from source that needs the the library, you can put the path that the library is in in the environment variable LD_RUN_PATH before building, and the linker will save that path into the binary, so that it will automatically be looked for in the right place at runtime.
Linux specific: Alternately, put the library in /lib, /usr/lib, or some other path referenced in your /etc/ld.so.conf or its imported config fragments, and then all you need to do is run /sbin/ldconfig to refresh ld.so (the dynamic linker)'s cache of libraries.
This works for my issue,hope will help anyone.
gcc test.c -Wl,-rpath /usr/local/lib -lfcgi -o test.fcg
And -Wl,-rpath option is the key trick.

Linking libraries (C++)

Using MinGW through Eclipse for C/C++, and attempting to get GLUT (OpenGL Utility Toolkit) working on it, but I suspect it's a simple problem.
Attempts to build result in:
g++ -LC:\Documents and Settings\C\workspace\GLUTtest\Debug -LC:\Tools\MinGW\include\GL -LC:\Tools\MinGW\include -oGLUTtest.exe main.o -lglut32.lib
C:\Tools\MinGW\bin..\lib\gcc\mingw32\3.4.5........\mingw32\bin\ld.exe: cannot find -lglut32.lib
I have glut32.lib in the workspace directory, C:\Documents and Settings\C\workspace\GLUTtest. Here are the options as given by eclipse:
-L"C:\Documents and Settings\C\workspace\GLUTtest" -L"C:\Documents and Settings\C\workspace\GLUTtest\Debug" -L"C:\Documents and Settings\C\workspace\GLUTtest\GL" -L"C:\Tools\MinGW\include\GL" -L"C:\Tools\MinGW\include"
Any idea why it isn't picking up the library?
Seems your trying to pass include directories as link directories. Find the directory that contains glut32.lib and add a link-directory parameter (-L) with the directory you find.
Let's say you have a library file named libxxx.a, libxxx.so or xxx.lib. When linking, you should put the parameter as -lxxx
And second, sometimes you have to put library path with ( -L/path/to/lib/dir )
Your are passing "C:\Tools\MinGW\include\GL -LC:\Tools\MinGW\include" as your linking directory ( -L ) which seems to be your include path. so pass your include directory in include path which will appear with -I option and just check that whether your linking path is present in the list given with -L options, if not then add it in the list otherwise it will say undefined references.