How to create a shared library with cmake?

I wrote a library that I used to compile using a proprietary Makefile, but now I want to switch to cmake. The tree looks like this (I deleted all unnecessary files):

. β”œβ”€β”€ include β”‚  β”œβ”€β”€ animation.h β”‚  β”œβ”€β”€ buffers.h β”‚  β”œβ”€β”€ ... β”‚  β”œβ”€β”€ vertex.h β”‚  └── world.h └── src β”œβ”€β”€ animation.cpp β”œβ”€β”€ buffers.cpp β”œβ”€β”€ ... β”œβ”€β”€ vertex.cpp └── world.cpp 

So what I'm trying to do is simply compile the source code into a shared library and then install it using the header files.

Most of the examples I found compile executables with some shared libraries, but not just a regular shared library. It would also be helpful if someone could just tell me a very simple library that uses cmake, so I can use this as an example.

+115
c ++ compilation cmake shared-libraries
Jul 07 '13 at 10:52
source share
4 answers

Always specify the minimum required version of cmake

 cmake_minimum_required(VERSION 3.9) 

You must declare a project. cmake says it's mandatory, and it will define the convenient variables PROJECT_NAME , PROJECT_VERSION and PROJECT_DESCRIPTION (this last variable requires cmake 3.9):

 project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") 

Announce a new library target. Please avoid using file(GLOB...) . This feature does not provide mastery during the compilation process. If you are lazy, copy and paste the output of ls -1 sources/*.cpp :

 add_library(mylib SHARED sources/animation.cpp sources/buffers.cpp [...] ) 

Set the VERSION property (optional, but this is good practice):

 set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION}) 

You can also set SOVERSION to the primary VERSION number. So libmylib.so.1 will be symbolic libmylib.so.1.0.0 on libmylib.so.1.0.0 .

 set_target_properties(mylib PROPERTIES SOVERSION 1) 

Declare the public API of your library. This API will be installed for the third-party application. It is recommended that you isolate it in the project tree (for example, put it in the include/ directory). Please note that private headers should not be set, and I highly recommend placing them along with the source files.

 set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h) 

If you work with subdirectories, it is not very convenient to include a relative path, for example "../include/mylib.h" . So, pass the top directory to the included directories:

 target_include_directories(mylib PRIVATE .) 

or

 target_include_directories(mylib PRIVATE include) target_include_directories(mylib PRIVATE src) 

Create an installation rule for your library. I suggest using the CMAKE_INSTALL_*DIR variables defined in GNUInstallDirs :

 include(GNUInstallDirs) 

And declare the files to install:

 install(TARGETS mylib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 

You can also export the pkg-config file. These files allow a third-party application to easily import your library:

Create a template file named mylib.pc.in (see mylib.pc.in pc (5) for more information):

 prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: @PROJECT_DESCRIPTION@ Version: @PROJECT_VERSION@ Requires: Libs: -L${libdir} -lmylib Cflags: -I${includedir} 

In your CMakeLists.txt add a rule for the @ macros extension ( @ONLY ask cmake not to expand the variables of the form ${VAR} ):

 configure_file(mylib.pc.in mylib.pc @ONLY) 

Finally, install the generated file:

 install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) 

You can also use the CMake EXPORT function . However, this function is only compatible with cmake and it is difficult for me to use it.

Finally, the whole CMakeLists.txt should look like this:

 cmake_minimum_required(VERSION 3.9) project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") include(GNUInstallDirs) add_library(mylib SHARED src/mylib.c) set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 PUBLIC_HEADER api/mylib.h) configure_file(mylib.pc.in mylib.pc @ONLY) target_include_directories(mylib PRIVATE .) install(TARGETS mylib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) 
+154
Aug 23 '17 at 15:20
source share

This minimal CMakeLists.txt file compiles a simple shared library:

 cmake_minimum_required(VERSION 2.8) project (test) set(CMAKE_BUILD_TYPE Release) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) add_library(test SHARED src/test.cpp) 

However, I have no experience copying files to another destination using CMake. The file command with the signature COPY / INSTALL looks like it might be useful.

+73
Jul 07 '13 at 11:22 on
source share

I'm trying to figure out how to do this myself, and it looks like you can install the library as follows:

 cmake_minimum_required(VERSION 2.4.0) project(mycustomlib) # Find source files file(GLOB SOURCES src/*.cpp) # Include header files include_directories(include) # Create shared library add_library(${PROJECT_NAME} SHARED ${SOURCES}) # Install library install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME}) # Install library headers file(GLOB HEADERS include/*.h) install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME}) 
+23
Jul 01 '16 at 8:07
source share

Firstly, this is the layout of the directory that I use:

 . β”œβ”€β”€ include β”‚ β”œβ”€β”€ class1.hpp β”‚ β”œβ”€β”€ ... β”‚ └── class2.hpp └── src β”œβ”€β”€ class1.cpp β”œβ”€β”€ ... └── class2.cpp 

After days of learning this, this is my favorite way to do this thanks to modern CMake:

 cmake_minimum_required(VERSION 3.5) project(mylib VERSION 1.0.0 LANGUAGES CXX) set(DEFAULT_BUILD_TYPE "Release") if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() include(GNUInstallDirs) set(SOURCE_FILES src/class1.cpp src/class2.cpp) add_library(${PROJECT_NAME} ...) target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> PRIVATE src) set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1) install(TARGETS ${PROJECT_NAME} EXPORT MyLibConfig ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) install(EXPORT MyLibConfig DESTINATION share/MyLib/cmake) export(TARGETS ${PROJECT_NAME} FILE MyLibConfig.cmake) 

After starting CMake and installing the library, there is no need to use Find ***. Cmake files, it can be used like this:

 find_package(MyLib REQUIRED) #No need to perform include_directories(...) target_link_libraries(${TARGET} mylib) 

What if it is installed in the standard directory, it will be found, and nothing else will need to be done. If it was installed in a non-standard way, it is also easy, just tell CMake where to find MyLibConfig.cmake using:

 cmake -DMyLib_DIR=/non/standard/install/path .. 

Hope this helps everyone as much as I do. Old ways to do this were rather cumbersome.

+9
Apr 16 '18 at 17:27
source share



All Articles