Link a shared library with CMake - c++

I'm trying to link in a pre-compiled shared library file called libtest-lib.so. This is what I have at the bottom of my CMakeLists.txt:
link_directories("/projectspath/LinkTest/TestLib/app/build/intermediates/cmake/debug/obj/armeabi-v7a")
add_library(testlib libtest-lib.so)
target_link_libraries(testlib libtest-lib.so)
As above, I get the following error:
CMake Error at CMakeLists.txt:49 (add_library):
Cannot find source file:
libtest-lib.so
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
CMake Error: CMake can not determine linker language for target: testlib
If I comment out the add_library line, I get the following:
CMake Error at CMakeLists.txt:51 (target_link_libraries):
Cannot specify link libraries for target "testlib" which is not built by this project.
It seems that source files (.c, cpp, etc) are absolutely required when linking in a library. But how do I link in an .so file? The docs say the following about target_link_libraries():
The named must have been created in the current directory by a command such as add_executable() or add_library().
If I substitute add_library() with add_executable() I get the same error. What is the proper way to link an .so file in CMake?

I think that what you want is to import a library for CMake:
add_library(testlib SHARED IMPORTED)
set_property(TARGET testlib PROPERTY IMPORTED_LOCATION "/projectspath/LinkTest/TestLib/app/build/intermediates/cmake/debug/obj/armeabi-v7a/libtest-lib.so")
See https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/Exporting-and-Importing-Targets for more information

add_library creates a new library.
Instead you want to link your library to some other target.
Let's say
add_executable(main main.cpp)
target_link_libraries(main libtest-lib)
This should already work.

You should have:
link_directories("/projectspath/LinkTest/TestLib/app/build/intermediates/cmake/debug/obj/armeabi-v7a")
set(MY_SOURCES mylib.cpp)
add_library(testlib ${MY_SOURCES})
target_link_libraries(testlib libtest-lib)
which means that you should specify the sources of YOUR library as second argument to add_library() or add_executable() and not the library that is already compiled.
You need your sources because generally you build something (a library or an executable) that requires linking to some library that already exist.
Otherwise, what would you build? Nothing? And link the library to what? Who would be the consumer of that library?

I found another workaround, to mention path where the library is present while linking lib to the executable file.
INCLUDE_DIRECTORIES(/path/to/headers)
ADD_EXECUTABLE(TARGET target.c)
TARGET_LINK_LIBRARIES(TARGET_FILE "-L/path/to/shared/library" SHARED_LIB_name)
Which is indirect including library search path flag. One might also have to link the location of header files while using the library.

The proper way to do this is:
target_link_libraries(native-lib "/projectspath/LinkTest/TestLib/app/build/intermediates/cmake/debug/obj/${ANDROID_ABI}/libtest-lib.so")

Related

How to add library to C++ Project using homebrew, cMake and, cLion

I am really new to C++ and I am a bit confused.
I am trying to add this lib to my project (https://github.com/mrtazz/restclient-cpp).
I have installed it using Homebrew
brew tap mrtazz/oss
brew install restclient-cpp
then I tried adding the library to my CMakeLists by including and linking the Homebrew install directories.
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(POS)
set(CMAKE_CXX_STANDARD 14)
include_directories(/usr/local/include)
link_directories(/usr/local/lib)
add_library(
restclient-cpp STATIC
connection.h
helpers.h
restclient.h
version.h
)
add_executable(POS main.cpp program.cpp program.h programs/find.cpp programs/find.h tools/db.cpp tools/db.h)
target_link_libraries(POS PUBLIC restclient-cpp)
then I get this error...
CMake Error at CMakeLists.txt:16 (add_library):
Cannot find source file:
connection.h
Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
.hpp .hxx .in .txx
CMake Error at CMakeLists.txt:16 (add_library):
No SOURCES given to target: restclient-cpp
I know something is wrong with the directories but I just cannot figure it out, I would greatly appreciate as much information as possible. I'm just trying to have some fun with this and I cannot figure out why I cannot add this simple library to my build.
Thank you.
You are trying to add header files to the add_library command. Those files need to be in a directory that you include via include_directory. You also should not put header files into the add_executable command.
To link an existing library you can call target_link_libraries.
example:
include_directories(${MY_INCLUDE_DIRS})
add_executable(main source.cpp)
target_link_libraries(main extlib)
It's probably best to find a simple CMake setup and try to use it as template.

Should I use only add_executable() with raw cpp files or make a library via add_library()?

I'm learning CMake and I'm struggling with it a little. My "project" is using JsonCpp "library" that was provided as one .cpp file and two .h files. The structure looks like this:
myProject
build/
json/
CMakeLists.txt
jsoncpp.cpp
include/
json.h
json-forward.h
CMakeLists.txt
main.cpp
build/CMakeLists.txt:
cmake_minimum_required(VERSION 3.6.0)
project(myProject)
add_subdirectory(json)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE json)
# add_executable(app main.cpp json/jsoncpp.cpp json/include/json.h json/include/json-forwards.h)
json/CMakeLists.txt:
cmake_minimum_required(VERSION 3.6.0)
add_library(
json
jsoncpp.cpp
include/json.h
include/json-forwards.h
)
target_include_directories(json PUBLIC '${CMAKE_CURRENT_SOURCE_DIR}/include')
What's a difference between using only add_executable() with all .cpp files and using target_link_libraries that transforms jsoncpp into static library and then link it? What approach should I choose?
A next thing confusing me is a target_include_directories(). What are the benefits using this function? If I comment it, and run cmake (then makefile and launch the app) everything still works fine. If I delete "include/json.h" "include/json-forward.h" from add_library(), everything still works.
What's a difference between using only add_executable() with all .cpp files and using target_link_libraries that transforms jsoncpp into static library and then link it? What approach should I choose?
Using add_library is required when you have 2 executables using the same jsoncpp code. In this case, if you list jsoncpp sources in both add_executable() calls, you'd have to compile it twice. Grouping them into add_library() will make it compile only once and then linked to both executables.
Another reason to use add_library is purely logical composition of modules.

Cmake configuration for multiple sub-libraries in a "packages" directory

Here is a sample project I am trying to build with a "Packages" directory which includes all the libraries to be used in the main code.
I am trying to keep my root cmake file as clean as possible and avoid relative path such as
include_directory(packages/lib1)
but I am struggling. Is there a way of including sub-directories of a directory for the purposes of header inclusion.
First a few minor remarks:
always name the CMake configuration files CMakeLists.txt (because of)
bookmark the documentation on CMake: https://cmake.org/documentation/
Sometimes it's not that easy to read, but very specific once you adopt your head to the "CMake world" ;-)
make yourself comfortable with the scope of CMake variables
include_directories(DIR1 [DIR2 [...]])
Tells CMake where the compiler should look for header files, i.e. -IDIR1 -IDIR2 ....
add_library(NAME [STATIC|SHARED] SOURCES)
This command creates the required compiler commands to create a static or shared library out of a given list of source files. No need to add in the header files. The make target will be called NAME and the library target is known to CMake as NAME.
add_subdirectory(DIR)
Tells CMake to look into DIR and parse the included CMakeLists.txt with all its content.
target_link_libraries(TARGET LIB1 [LIB2 [...]])
Tells CMake to instruct the linker to link LIB1, LIB2, etc. to the TARGET, i.e. -LLIB1 -LLIB2 .... TARGET is a CMake/make target previously defined/created with a call to add_{library,executable,custom_target}.
CMakeLists.txt:
include_directories(libraries)
# a header file in `libraries/lib1/foo.hpp` can be included
# in the whole CMake project by `#include "lib1/foo.hpp"`.
add_subdirectory(libraries)
add_subdirectory(tests)
libraries/CMakeLists.txt:
add_subdirectory(lib1)
add_subdirectory(lib2)
libraries/lib1/CMakeLists.txt:
add_library(lib1 STATIC ${LIB1_SOURCES})
libraries/lib2/CMakeLists.txt:
add_library(lib2 STATIC ${LIB2_SOURCES})
tests/CMakeLists.txt:
add_executable(tests ${TEST_SOURCES})
target_link_libraries(tests lib1 lib2)

Cmake linking to shared library cannot find library

On Ubuntu, I have two directories: build and src. In src, my CMakeLists.txt file has the lines:
add_executable(Test main.cpp)
target_link_libraries(Test libCamera.so)
After running cmake in the build directory (cmake ../src), I then copy my library file libCamera.so into the build directory. After running make, the main.cpp.o file compiles successfully, but I receive the following error during linking:
/usr/bin/ld: cannot find -lCamera
Why is this? The shared library is in the same directory that I am building in... and the same thing happens if I copy the library to /usr/bin...
You should not put prefix lib and suffix .so of the library, so just use:
target_link_libraries(Test Camera)
if your library not found you may need to add directory, where library is located:
link_directories( /home/user/blah ) # for specific path
link_directories( ${CMAKE_CURRENT_BINARY_DIR} ) # if you put library where binary is generated
Note: you copied lib to /usr/bin but unlike Windows where dll files stored with executables, in Linux that is not the case, so it would be /usr/lib, not /usr/bin. Also you may change LD_LIBRARY_PATH variable to make your program to find a library in a custom location.

Weird Linker Error

#include path
include_directories(
${PROJECT_SOURCE_DIR}/include
${HGE_INCLUDE_DIR}
${IKL_INCLUDE_DIR}
${BOOST_DIRECTORY}
)
#include all files
FILE(GLOB CORE_SRCS source/core/*.cpp)
FILE(GLOB TOOL_SRCS source/tools/*.cpp)
FILE(GLOB GAME_SRCS source/game/*.cpp)
#Making a compiled library
add_library(GAMECORE_LIBRARY ${CORE_SRCS} ${HGE_LIBRARY} ${HGE_HELPER_LIBRARY})
#add executable
add_executable(DemoGame ${GAME_SRCS})
##link executable to HGE lib
TARGET_LINK_LIBRARIES(DemoGame ${HGE_LIBRARY} ${HGE_HELPER_LIBRARY} ${IKL_LIBRARY} GAMECORE_LIBRARY)
if(BUILD_TOOLS)
add_executable(EntityTool ${TOOL_SRCS})
TARGET_LINK_LIBRARIES(EntityTool ${HGE_LIBRARY} ${HGE_HELPER_LIBRARY} ${IKL_LIBRARY} GAMECORE_LIBRARY)
endif(BUILD_TOOLS)
this is my current cmake ..
I get a weird linker error for hgeGUI class
eg : DemoGame/source/core/GameMainMenu.cpp:74: undefined reference to `hgeGUI::hgeGUI()'
This only happens when I try to compile the core files into a static library.
When I add the executable with the CORE_SRCS and remove the dependencies on my current compiled library .. it will work fine..
Also I tried copy pasting the hgegui.cpp file into my core sources directory .. and change the #include "..\..\include\hgegui.h" to #include "hgegui.h"
After that my linker code resolves the issue but I get segmentation faults but I m guessing linking the file in the previous step was not right ..
Here's a link to their .h file
http://trac.assembla.com/snowscape/browser/hge/include/hgegui.h
It looks like you're misusing the ${HGE_LIBRARY} and ${HGE_HELPER_LIBRARY} variables.
In an add_library call, you include all the source files which make up that library.
In a target_link_libraries call, you specify libraries or flags to use when linking the target.
So, if ${HGE_LIBRARY} and ${HGE_HELPER_LIBRARY} specify paths to libraries which you want to specify as dependencies of GAMECORE_LIBRARY, you need to do:
add_library(GAMECORE_LIBRARY ${CORE_SRCS})
target_link_libraries(GAMECORE_LIBRARY ${HGE_LIBRARY} ${HGE_HELPER_LIBRARY})
The dependencies are transitive, so this means when you specify GAMECORE_LIBRARY as a dependency of DemoGame and EntityTool, then CMake recognises that ${HGE_LIBRARY} and ${HGE_HELPER_LIBRARY} are also dependencies, so you can remove them from the target_link_libraries calls for DemoGame and EntityTool if you want.
For further info on add_library and target_link_libraries, run:
cmake --help-command add_library
cmake --help-command target_link_libraries