How to develop shared library in KDevelop? - cmake

I want to develop shared library in KDevelop. But i don't see any template for library.
I guess i have to create project from c++ template and edit CMake files in both projects. Unfortunately i have got no experience with library development with CMake, also i want good integration with KDevelop - automatic build of library when i build/run project which uses that library.

To create a library use the add_library command:
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 source2 ... sourceN)
For example:
add_library(mylib SHARED
a.h
a.cpp
b.h
b.cpp)
Would create a shared library from the four files listed.
If your program (created with add_executable) uses the library, when you specify the link with target_link_libraries, CMake will add the dependency, so that if you changed a.cpp the library mylib would be rebuilt and your application would be re-linked.
For example
add_executable(myprog
main.cpp)
target_link_libraries(myprog
mylib)
Edit:
When your library and project are in different folders, you can use add_subdirectory.
Create a CMakeList.txt in each directory, in the library folder use add_library in the application, use add_program and target_link_libraries.
In the parent folder use add_subdirectory, add the library folder first, then the program folder. This will make the library available to the application. Then run cmake against the parent CMakeList.

Related

Providing include directory outside source folder for static library users

I am developing a simple static C library for learning purposes using cmake.
Some projects like GLFW provide an include folder on the root, so library users can copy it and use it as an include directory.
In my library, I want to have an include folder on the root, so when I use the library on other projects, I can just copy this folder and set it as an include directory.
Here is a simplified folder structure of my library:
include
+--mylib.h
src
+--myheader.h
+--mysource.c
+--CMakeLists.txt
CmakeLists.txt
The src folder has my headers and implementation files, and a CMakeLists.txt for building a static library out of mysource.c.
The CMakeLists on the root folder just sets the project and adds src as a subdirectory.
I want the mylib.h file to have a #include <myheader.h>.
Here's a detour to talk about how I want to use it when it's done.
The idea is that when using the lib on another project, I can have something like this:
deps
+--include
+--mylib.h
src
+--main.c
And in the main.c file, include mylib.h and use what's defined on myheader.h
Here the detour ends, and I'm talking about my actual lib project again.
How can I achieve this using cmake? As far as I know, the mylib.h file needs to know it's including files from the src diretory, but I see no way of setting that, as for exemple in GLFW this directory does not have a CMakeLists.txt.
I am gonna quess that this is a design issue since it would make sense to you if you would have installed the library to a system before you tried to use it. That is, not using add_subdirectory() but find_library() at usage.
First, if you are using a external library, but not installing it, you would include all files in you deps-folder. All files then include source-files and so on and will be compiled besides you main.c. This is done with add_subdirectory(deps/MyLib) and later also included in you main-project.
Example:
add_subdirectory(deps/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
If you do not want to compile it all the time, then you must instruct cmake where it can find headers and library-files. Preferred way is to use find_library() which does some magic for you. Since you do not mention any installation i will assume that it does not exist and your only option is then to use add_subdirectory().
"I can just copy this folder and set it as an include directory."
CMake wants to handle these things for you so you should never copy headers around. You should either use add_subdirectory() to include a project/headers or make use of the find_library() which make sure you find where the headers are in the system.
I suggest that you push yourself to learn howto install a library into a system and how to utilize it later, but only by using find_library(). Then the library will be global for all projects and also not duplicated.
Adding some kind of psudo-code in hope it all makes more sense. Although it is around add_subdirectory() since the code for installing is quite large unfortunately.
CMakeLists.txt for main.c
cmake_minimum_required(VERSION 3.8)
project(MyLibTest)
add_executable(${PROJECT_NAME}
src/main.c
)
add_subdirectory(external/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
CMakeLists.txt for library
cmake_minimum_required(VERSION 3.8)
project(MyLib)
add_library(${PROJECT_NAME} STATIC
src/MyLib.c
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
The structure for the project would then be:
/
external/MyLib
external/MyLib/src
MyLib.c
external/MyLib/include
MyLib.h
src
main.c
CMakeLists.txt

How to setup a Find*.cmake for find_package in Module mode?

I have an external dependency (headers and shared libraries as well as version.txt file in a known install location) for my project. This dependency has no built-in support for CMake find_package(). After reading the find_package() docs and this SO answer, my understanding is that I should use module mode for find_package(). In the Find*.cmake cmake directory, my guess is that it should:
Setup and verify paths to the header and shared libraries
Read in the version file
Define a project using the version file text
Add an interface library target (${PROJECT_NAME})
Add an alias to the interface library using a namespace (${MY_NAMESPACE})
Add a library target for each shared library path
Set the imported path property for each shared library
Link the shared libraries to the interface library target
Link the include directory to the interface library target
export(TARGETS ${PROJECT_NAME} NAMESPACE ${MY_NAMESPACE}::)
export(PACKAGE ${PROJECT_NAME})
Profit?
Am I doing this right and/or taking the right approach?

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.

Linking Shared library (which has dependency on other shared library) in CMake

I am trying to build an executable which links to a shared library (named 'caffe'). The shared library is dependent on another shared library (named 'cblas'). When I try to link to caffe in my CMake file it shows the following error:
libcblas.so.3, needed by libcaffe.so, not found (try using -rpath or
-rpath-link)
I am using the following statements in my CMakeLists.txt:
link_directories(${BINARIES}/lib)
add_library(CAFFE_LIBRARY SHARED IMPORTED)
set_target_properties(CAFFE_LIBRARY PROPERTIES IMPORTED_LOCATION ${BINARIES}/lib/libcaffe.so)
target_link_libraries(${PROJECT_NAME} CAFFE_LIBRARY)
Both 'cblas' and 'caffe' libraries are present in ${BINARIES}/lib folder.
Do I need to add cblas.so to target_link_libraries also? Also, i am not building caffe.so so building it via CMake and keeping it as a dependency is not an option
Is there any other feasible solution for the same problem where dependency tree of shared library needs to be resolved while linking?
Browsing through the library's GitHub tree, it seems to me that it provides a package config file. Therefore, if you have installed it in the normal way, you should be able to find it as a package, instead of defining the imported target yourself:
find_package(Caffe)
include_directories(${Caffe_INCLUDE_DIRS})
add_definitions(${Caffe_DEFINITIONS}) # ex. -DCPU_ONLY
add_executable(caffeinated_application main.cpp)
target_link_libraries(caffeinated_application ${Caffe_LIBRARIES})
The example above comes from the Caffe documentation on the topic.

cmake "exporting" shared library on windows

I'm writing a small library.
I'd like to build it as shared library and generate "MyLibraryConfig.cmake" file which then can be used by my other projects to find my library.
The only problem I have is to figure out the name/path to file which is used for linking under Windows - there are two files being generated: mylibrary.dll and mylibrary.dll.a.
So I'd like to generate MyLibraryConfig.cmake file with something like:
"set(MYLIBRARY_LIBRARIES /blah/blah/mylibrary.dll.a)"
so then MYLIBRARY_LIBRARIES can be used with target_link_libraries for my other projects.
How can I get name for this linkable file? I'd be nice if the solution was platform independed (returning .so wile on Linux and .dll.a on Windows)
thanks in advance
If you're planning on making your library available to your other projects without installing it then you want the CMake command export. For example:
export(TARGETS MyLib FILE ${CMAKE_SOURCE_DIR}/MyLibraryConfig.cmake)
This creates the file MyLibraryConfig.cmake in the same directory as your top-level CMakeLists.txt, and can just be included in other CMake projects.
If you're planning on installing your library, then you want to make use of install(EXPORT ...) instead:
install(TARGETS MyLib EXPORT MyLibraryConfig
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(EXPORT MyLibraryConfig DESTINATION cmake)
This will install the file MyLibraryConfig.cmake to <install path>/cmake, and can then be included by other projects.