Cómo agregar correctamente directorios de inclusión con CMake

Resuelto Matthieu M. asked hace 12 años • 11 respuestas

Hace aproximadamente un año pregunté sobre las dependencias de los encabezados en CMake .

Recientemente me di cuenta de que el problema parecía ser que CMake consideraba que esos archivos de encabezado eran externos al proyecto. Al menos, al generar un proyecto Code::Blocks, los archivos de encabezado no aparecen dentro del proyecto (los archivos fuente sí). Por lo tanto, me parece que CMake considera que esos encabezados son externos al proyecto y no los rastrea en las dependencias.

Una búsqueda rápida en el tutorial de CMake solo señaló include_directoriesque no parece hacer lo que deseo...

¿Cuál es la forma correcta de indicarle a CMake que un directorio en particular contiene encabezados que se incluirán y que el Makefile generado debe realizar un seguimiento de esos encabezados?

Matthieu M. avatar Dec 04 '12 20:12 Matthieu M.
Aceptado

Hay que hacer dos cosas.

Primero agregue el directorio que se incluirá:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

En caso de que tengas una versión muy antigua de CMake (2.8.10 o anterior) sin soporte para target_include_directories, también puedes usar la versión heredada include_directories:

include_directories(${YOUR_DIRECTORY})

Luego también debes agregar los archivos de encabezado a la lista de tus archivos fuente para el destino actual, por ejemplo:

set(SOURCES file.cpp file2.cpp ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_executable(test ${SOURCES})

De esta manera, los archivos de encabezado aparecerán como dependencias en el Makefile y también, por ejemplo, en el proyecto de Visual Studio generado, si genera uno.

Cómo utilizar esos archivos de encabezado para varios objetivos:

set(HEADER_FILES ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)

add_library(mylib libsrc.cpp ${HEADER_FILES})
target_include_directories(mylib PRIVATE ${YOUR_DIRECTORY})
add_executable(myexec execfile.cpp ${HEADER_FILES})
target_include_directories(myexec PRIVATE ${YOUR_DIRECTORY})
SirDarius avatar Dec 04 '2012 13:12 SirDarius

Primero, suele include_directories()decirle a CMake que agregue el directorio -Ia la línea de comando de compilación. En segundo lugar, enumera los encabezados de tu llamada add_executable()o add_library().

Como ejemplo, si las fuentes de tu proyecto están en srcy necesitas encabezados de include, puedes hacerlo así:

include_directories(include)

add_executable(MyExec
  src/main.c
  src/other_source.c
  include/header1.h
  include/header2.h
)

Estructura del proyecto

.
├── CMakeLists.txt
├── external //We simulate that code is provided by an "external" library outside of src
│   ├── CMakeLists.txt
│   ├── conversion.cpp
│   ├── conversion.hpp
│   └── README.md
├── src
│   ├── CMakeLists.txt
│   ├── evolution   //propagates the system in a time step
│   │   ├── CMakeLists.txt
│   │   ├── evolution.cpp
│   │   └── evolution.hpp
│   ├── initial    //produces the initial state
│   │   ├── CMakeLists.txt
│   │   ├── initial.cpp
│   │   └── initial.hpp
│   ├── io   //contains a function to print a row
│   │   ├── CMakeLists.txt
│   │   ├── io.cpp
│   │   └── io.hpp
│   ├── main.cpp      //the main function
│   └── parser   //parses the command-line input
│       ├── CMakeLists.txt
│       ├── parser.cpp
│       └── parser.hpp
└── tests  //contains two unit tests using the Catch2 library
    ├── catch.hpp
    ├── CMakeLists.txt
    └── test.cpp

Cómo hacerlo

1. El CMakeLists.txt de nivel superior es muy similar a la Receta 1, Reutilización de código con funciones y macros.

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
  
project(recipe-07 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})

# defines targets and sources
add_subdirectory(src)

# contains an "external" library we will link to
add_subdirectory(external)

# enable testing and define tests
enable_testing()
add_subdirectory(tests)

2. Los objetivos y las fuentes se definen en src/CMakeLists.txt (excepto el objetivo de conversión)

add_executable(automata main.cpp)
  
add_subdirectory(evolution)
add_subdirectory(initial)
add_subdirectory(io)
add_subdirectory(parser)

target_link_libraries(automata
  PRIVATE
    conversion
    evolution
    initial
    io
    parser
  )

3.La biblioteca de conversión está definida en external/CMakeLists.txt

add_library(conversion "")

target_sources(conversion
  PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/conversion.cpp
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}/conversion.hpp
  )

target_include_directories(conversion
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}
  )

4.El archivo src/CMakeLists.txt agrega más subdirectorios, que a su vez contienen archivos CMakeLists.txt. Todos son similares en estructura; src/evolution/CMakeLists.txt contiene lo siguiente:

add_library(evolution "")

target_sources(evolution
  PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/evolution.cpp
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}/evolution.hpp
  )
target_include_directories(evolution
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}
  )

5.Las pruebas unitarias están registradas en tests/CMakeLists.txt.

add_executable(cpp_test test.cpp)

target_link_libraries(cpp_test evolution)

add_test(
  NAME
    test_evolution
  COMMAND
    $<TARGET_FILE:cpp_test>
  )

como ejecutarlo

$ mkdir -p build
$ cd build
$ cmake ..
$ cmake --build .

Consulte: https://github.com/sun1211/cmake_with_add_subdirectory

sun1211 avatar Jul 13 '2021 10:07 sun1211