Cómo crear una biblioteca compartida con cmake?


He escrito una biblioteca que solía compilar usando un Makefile auto-escrito, pero ahora quiero cambiar a cmake. El árbol se ve así (he eliminado todos los archivos irrelevantes):

.
├── include
│   ├── animation.h
│   ├── buffers.h
│   ├── ...
│   ├── vertex.h
│   └── world.h
└── src
    ├── animation.cpp
    ├── buffers.cpp
    ├── ...
    ├── vertex.cpp
    └── world.cpp

Así que lo que estoy tratando de hacer es solo compilar el código fuente en una biblioteca compartida y luego instalarlo con los archivos de encabezado.

La mayoría de los ejemplos que he encontrado compilan ejecutables con algunas bibliotecas compartidas, pero nunca solo una biblioteca compartida simple. También sería útil si alguien pudiera solo dime una biblioteca muy simple que use cmake, para que pueda usar esto como ejemplo.

Author: Jezz, 2013-07-07

4 answers

Siempre especifica la versión mínima requerida de cmake

cmake_minimum_required(VERSION 3.9)

Debe declarar un proyecto. cmake dice que es obligatorio y definirá variables convenientesPROJECT_NAME, PROJECT_VERSION y PROJECT_DESCRIPTION (esta última variable requiere cmake 3.9):

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")

Declare un nuevo destino de biblioteca. Evite el uso de file(GLOB ...). Esta característica no proporciona un dominio asistido del proceso de compilación. Si es perezoso, copie y pegue la salida de ls -1 sources/*.cpp:

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

Set VERSION propiedad (opcional, pero es una buena práctica):

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})

También puede establecer SOVERSION a número mayor de VERSION. Así que libmylib.so.1 será un enlace simbólico a libmylib.so.1.0.0.

set_target_properties(mylib PROPERTIES SOVERSION 1)

Declare la API pública de su biblioteca. Esta API se instalará para aplicaciones de terceros. Es una buena práctica aislarlo en el árbol del proyecto (como colocarlo en el directorio include/). Tenga en cuenta que, las cabeceras privadas no deben ser instaladas y le sugiero encarecidamente que las coloque con los archivos de origen.

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)

Si trabaja con subdirectorios, no es muy conveniente incluir ruta relativa como "../include/mylib.h". Por lo tanto, pase el directorio superior en los directorios incluidos:

target_include_directories(mylib PRIVATE .)

O

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

Cree una regla de instalación para su biblioteca. Sugiero usar variables CMAKE_INSTALL_*DIR definidas en GNUInstallDirs:

include(GNUInstallDirs)

Y declarar archivos a instalar:

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

También puede exportar un archivo pkg-config. Este archivo permite a la aplicación de terceros importar fácilmente su biblioteca:

Crear un archivo de plantilla llamado mylib.pc.in (ver pc(5) página de manual para más información):

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}

En su CMakeLists.txt, agregue una regla para expandir @ macros (@ONLY pregunte a cmake para no expandir variables de la forma ${VAR}):

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

Y finalmente, instale el archivo generado:

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

También puede usar cmake EXPORT feature . Sin embargo, esta característica solo es compatible con cmake y me resulta difícil de usar.

Finalmente todo CMakeLists.txt debería verse como:

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)
 75
Author: Jezz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-04 07:13:18

Este CMakeLists mínimo.el archivo txt compila una biblioteca compartida simple:

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)

Sin embargo, no tengo experiencia copiando archivos a un destino diferente con CMake. El comando file con la firma COPY/INSTALL parece que podría ser útil.

 68
Author: Robert Franke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-07 11:22:26

Estoy tratando de aprender a hacer esto yo mismo, y parece que puede instalar la biblioteca de esta manera:

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})
 16
Author: gromit190,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-04 14:55:01

Primero, este es el diseño del directorio que estoy usando:

.
├── include
│   ├── class1.hpp
│   ├── ...
│   └── class2.hpp
└── src
    ├── class1.cpp
    ├── ...
    └── class2.cpp

Después de un par de días echando un vistazo a esto, esta es mi forma favorita de hacerlo gracias a la moderna 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)

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)

Después de ejecutar CMake e instalar la biblioteca, no es necesario usar Find***.archivos cmake, se puede usar así:

find_package(MyLib REQUIRED)

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

Eso es todo, si se ha instalado en un directorio estándar se encontrará y no hay necesidad de hacer nada más. Si se ha instalado en un ruta no estándar, también es fácil, solo dile a CMake dónde encontrar MyLibConfig.cmake usando:

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

Espero que esto ayude a todos tanto como me ha ayudado a mí. Las viejas formas de hacer esto eran bastante engorrosas.

 5
Author: Luis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-16 17:27:04