CMake Add own library to project using find_library() - cmake

I am currently creating a set of classes that should be used in
different projects using CLion. My question is how do I implement this
functionality. So far I looked into the following related issues
which didn't really solve my problem:
CMake link to external library
Add external libraries to CMakeList.txt c++
CMake reference for add_library(), find_library() which I don't fully understand yet since I am fairly new to CMake
I created two sample projects "TestLib" and "TestProj":
TestLib src Class.h Class.cpp
CMakeList.txt TestProj main.cpp
CMakeList.txt
The CMakeList.txt for "TestLib" currently looks as follows:
cmake_minimum_required(VERSION 3.5)
project(TestLib)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
set(SOURCE_FILES src/Class.cpp src/Class.h)
add_library(TestLib ${SOURCE_FILES})>
Now, I tried to use this library in "TestProj" using the following
CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(TestProj)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
find_library(CLASS_LIB TestLib HINTS /home/user/.CLion2016.1/system/cmake/generated/TestLib-7507f101/7507f101/Debug)
set(SOURCE_FILES main.cpp)
add_executable(TestProj ${SOURCE_FILES})
target_link_libraries(TestProj CLASS_LIB)
CMake finds the library but
I dont have access to Class.h of the library
Writing the whole /home/user/.CLion2016.1/...-Path to the library seems to be wrong
Any help is really appreciated. Thank you.

If the goal is to make your library available to multiple other projects, the recommended way to do that would be to have your library project's install procedure generate CMake configuration files. Unfortunately, the procedure to do that is a bit arcane, but https://cmake.org/cmake/help/git-master/manual/cmake-packages.7.html#creating-packages should give you a starting point on how to do this.

You can put at the root of your projects CMakeLists.txt
with such content:
add_subdirectory(TestLib)
add_subdirectory(TestProj)
after that you can write in TestProj's CMakeLists.txt just
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../TestLib)
target_link_libraries(TestProj TestList)
and no need to use find_library

Related

CMake build and install shared library from subdirectory before building main directory

Here is my source code structure:
cd my_git_repo/
CMakeLists.txt
src/
main.cpp
mylibrary/
a.hpp
b.hpp
a.cpp
b.cpp
CMakeLists.txt
Root CMakeLists.txt:
cmake_minimum_required(VERSION 3.9)
project(myexe CXX)
add_subdirectory(src/mylibrary)
find_library(mylib NAMES mylibrary.so PATHS "./src/mylibrary/mylibrary.so")
add_executable(myexe src/main.cpp)
target_link_libraries(myexe ${mylib})
mylibrary/CMakeLists.txt is very simple. It builds a shared library and installs them.
Ideally, mylibrary target should be built and installed before myexe is built. But this doesn't happen. mylibrary is built followed by myexe. Installation happens later. Because of this, find_library fails. pkg_check_modules() works for other shared libraries but fails here because of the same reason.
I appreciate your help.
Edit:
This question differs from the duplicate because the answers posted to that question seem to be statically linking the library target_link_libraries(game engine). I want to dynamically link the .so library.
The idea in CMake is to build modules and then link them together.
You haven't shared the CMakeLists.txt for my library, so we cannot tell what it is doing. However, assuming that it is something like:
ADD_LIBRARY(mylibrary
file1.cpp
file2.cpp
)
Since you specified that you want mylibrary to always be linked as shared, you need to tell CMake that as well by either setting BUILD_SHARED_LIBS TO ON or by specifying SHARED in add_library:
ADD_LIBRARY(mylibrary SHARED
file1.cpp
file2.cpp
)
This is your library module. We will keep it simple for now and not worry about packing the library archive and installation here.
Now, back to your main CMakeLists.txt and how to make myexe consume it. Since you have already add_subdirectory(src/mylibrary), CMake knows about mylibrary. So simply link it using the module name. There is no need to find_library as you have already defined the module.
add_executable(myexe src/main.cpp)
target_link_libraries(myexe mylibrary)
This should suffice.
Do note, however, this is a very basic example to explain to you how CMake is designed to work. If you aren't building the library, and it is already installed, you would call find_library. Modern CMake is a bit more sophisticated and uses generator expressions, so be sure to read up on that as you progress to more complex projects.

Cmakelist working outside of Clion

I've wanted to use Clion for awhile but I've always had trouble with Cmake. Armed with Cygwin, I've almost gotten this stupid thing to work.
The issue is while I can compile a cmake file from within a cygwin terminal, in Clion I am told it cannot find the library I want.
Error:A required package was not found
The cmakelist.txt file
cmake_minimum_required(VERSION 3.3)
project(Test)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(PKG_CONFIG_PATH /usr/lib/pkgconfig)
set(PKG_CONFIG_EXECUTABLE /usr/bin/pkg-config.exe)
set(SOURCE_FILES main.cpp)
add_executable(Test ${SOURCE_FILES})
INCLUDE(FindPkgConfig)
pkg_check_modules(SDL2 REQUIRED "sdl2")
MESSAGE(STATUS "SDL library: " ${SDL2_LDFLAGS})
TARGET_LINK_LIBRARIES(Test ${SDL2_LDFLAGS})
I have no idea if setting the variables PKG_CONFIG_PATH and others work, but they successfully build a makefile for my use in cygwin that builds correctly.
I've deleted the cache, remade the project and everything. It just refuses to work in Clion
If I understood correctly, your cmake config is unable to find SDL library. I found it better to use find_package command instead of pkg_check_modules.
In order to find_package(SDL2) to work, there must be FindSDL2.cmake module in directory, specified by CMAKE_MODULE_PATH variable (usually, it is cmake/Modules directory inside your source tree).
FindSDL2.cmake is not a part of CMake, but you can find one online easily (check my own modules, for example: https://github.com/dragn/cmake-modules).
Refer to this doc for details: https://cmake.org/Wiki/CMake:How_To_Find_Libraries.
Put FindSDL2.cmake to cmake/Modules directory and add this to your CMakeLists.txt:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/Modules)
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIR})
...
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARY})
NOTE: Sadly, it appears that Leonardo has not succeeded in finding volunteers for maintaining FindSDL2.cmake in SDL community: https://cmake.org/Bug/view.php?id=14826.

CMake execution order - first build shared library then look for it from another project

I have the following cmake setup:
colorizer_root
|
|-------colorizer_lib
|-------colorizer_template_project
The colorizer_root contains the top level CMakeLists.txt which is invoked when running cmake:
colorizer_root CMakeLists.txt
project(colorizer_root)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Debug)
add_subdirectory(colorizer_lib)
add_subdirectory(colorizer_template_project)
As you can see it contains 2 subdirectories each a project on its own. Basically what the colorizer_lib does is create a shared library named libcolorize.so (no executables here!), which then is to be used by the other project colorizer_template_project (the executable is created in this project). Here are the two CMakeLists.txt files for their respective projects:
colorizer_lib CMakeLists.txt
project(colorizer_lib)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CXX_FLAGS "--std=gnu++11 ${CMAKE_CXX_FLAGS}")
include_directories(. INCLUDES)
add_library(colorizer SHARED colorizer.cpp)
colorizer_template_project CMakeLists.txt
project(colorizer_template_project)
cmake_minimum_required(VERSION 2.8)
find_library(COLORIZER_LIB colorizer
PATHS ${CMAKE_BINARY_DIR}/colorizer_lib
)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${COLORIZER_LIB})
I'm having trouble figuring out how the whole lookup thing works. The problem here is that when I run the top level CMakeLists.txt it goes through both (obviously) but during processing the colorizer_template_project it breaks with a complaint:
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
COLORIZER_LIB
linked by target "colorizer_template_project" in directory /home/USER/Programming/C_Cpp/colorizer/colorizer_template_project
This is an expected behaviour since libcolorizer.so cannot be present at the time of running cmake because it is created after make has been invoked.
How do I tell cmake to first process the first project (including the build step!) and then go to the next one? I know that this works if I add an executable to the project that creates the library and then directly link it to the binary but in this case I want separate projects for the library and the executable that is using it.
PS: I haven't given any details about the sources because they are not important here. It is - I believe - a general question, which is not specific to whether I'm using C, C++ or something similar.
project command doesn't make subprojects independent, so colorizer target is actually accessible for colorizer_template_project, and you can directly link with it:
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} colorizer)

How would I build and link an external library using CMake?

To start off, I should say that I've seen the answers on questions that were similar to mine, yet none of them seem to make sense to me. Here goes:
Say I have the following simple CMakeLists:
cmake_minimum_required (VERSION 2.8)
project (Example)
add_executable (Example Main.cpp)
I would then like to link a library that already has its own CMakeLists (for example, glfw) against Example. Of course, this brings into question how to properly set up the build order.
How would I go about doing this?
First let me describe what to do for GLFW. See the notes below for variations.
Build GLFW. As the official GLFW head's CMake support is currently broken, use this shaxbee fork:
git clone https://github.com/shaxbee/glfw.git
cmake -Hglfw -Bbuild/glfw -DCMAKE_INSTALL_PREFIX=inst -DCMAKE_BUILD_TYPE=Release
cmake --build build/glfw --target install --config Release
This install step installs inst/lib/cmake/glfw3/glfw3Config.cmake, the glfw3 config-module which will be used by client projects to find GLFW.
Your project should look like this:
cmake_minimum_required(VERSION 2.8)
project(Example)
find_package(glfw3 REQUIRED)
add_executable(Example Main.cpp)
target_link_libraries(Example glfw3)
The find_package command finds the glfw3Config.cmake which creates an IMPORTED library, a CMake target, which incorporates all the information needed to use GLFW in your project.
The target_link_libraries command tells CMake not only to link to GLFW but to use its include directories and compile flags, too.
Configure your project with -DCMAKE_PREFIX_PATH=inst (use full path if necessary)
Note: Other config-modules or find-modules may not provide IMPORTED targets. See the actual config or find-module for help. They usually provide <PACKAGE>_INCLUDE_DIRS and <PACKAGE>_LIBRARIES variables which should be added to the appropriate settings of your target:
target_include_directories(mytarget ${ZLIB_INCLUDE_DIRS})
or
include_directories(${ZLIB_INCLUDE_DIRS})
Same for target_link_libraries / link_libraries.
Build the external dependency first.
add a function call to find your external library. That can either be FindGLFW.cmake with find_package if you can find that or write it yourself using find_library et al. More information about including external libraries can be found in the CMake wiki
Add the includes and libraries to your Example executable.
This is how CMake should be used, I don't see why is not answered in the sources in the Internet.

How do I tell CMake to link in a static library in the source directory?

I have a small project with a Makefile which I'm trying to convert to CMake, mostly just to get experience with CMake. For purposes of this example, the project contains a source file (C++, though I don't think the language is particularly relevant) and a static library file which I've copied from elsewhere. Assume for argument's sake that the source code to the library is unavailable; I only have the .a file and the corresponding header.
My handmade Makefile contains this build rule:
main: main.o libbingitup.a
g++ -o main main.o libbingitup.a
which works fine. How do I tell CMake to reproduce this? Not literally this exact makefile, of course, but something that includes an equivalent linking command. I've tried the obvious but naive ways, like
add_executable(main main.cpp libbingitup.a)
or
add_executable(main main.cpp)
target_link_libraries(main libbingitup.a)
as well as various things with link_directories(.) or add_library(bingitup STATIC IMPORTED) etc. but nothing so far that results in a successful linkage. What should I be doing?
Version details: CMake 2.8.7 on Linux (Kubuntu 12.04) with GCC 4.6.3
CMake favours passing the full path to link libraries, so assuming libbingitup.a is in ${CMAKE_SOURCE_DIR}, doing the following should succeed:
add_executable(main main.cpp)
target_link_libraries(main ${CMAKE_SOURCE_DIR}/libbingitup.a)
If you don't want to include the full path, you can do
add_executable(main main.cpp)
target_link_libraries(main bingitup)
bingitup is the same name you'd give a target if you create the static library in a CMake project:
add_library(bingitup STATIC bingitup.cpp)
CMake automatically adds the lib to the front and the .a at the end on Linux, and .lib at the end on Windows.
If the library is external, you might want to add the path to the library using
link_directories(/path/to/libraries/)
I found this helpful...
http://www.cmake.org/pipermail/cmake/2011-June/045222.html
From their example:
ADD_LIBRARY(boost_unit_test_framework STATIC IMPORTED)
SET_TARGET_PROPERTIES(boost_unit_test_framework PROPERTIES IMPORTED_LOCATION /usr/lib/libboost_unit_test_framework.a)
TARGET_LINK_LIBRARIES(mytarget A boost_unit_test_framework C)
I want to add to the other comments, the project name is the first argument. I had a project called cmakecompile and i wanted to add libusb to it, the code is as follows,
add_executable(cmakecompile main.c)
target_link_libraries(cmakecompile "D:/msys2/mingw64/lib/libusb-1.0.a")
the project had just only a main.c file, the first parameter in target_link_libraries is the name of your project and the second parameter is the path of the library.
Note that may help: Since i am compiling under windows, i had to install msys2 because the library you have has to be compiled with the same compiler. For example if you get libusb and try to use it in a qt-creator project, it will not work and you may get unreferenced functions, therefore i had to install msys2 and install libusb from inside msys2, install make and create a QT Cmake project and compile from Qt creator using the msys2 make.
The full cmakelists.txt is as follow
cmake_minimum_required(VERSION 3.5)
project(cmakecompile LANGUAGES C)
add_executable(cmakecompile main.c)
target_link_libraries(cmakecompile "D:/msys2/mingw64/lib/libusb-1.0.a")