web-dev-qa-db-fra.com

Gérer les dépendances des fichiers d'en-tête avec cmake

J'utilise CMake sur un petit projet C++ et jusqu'à présent cela fonctionne très bien ... avec une torsion: x

Lorsque je modifie un fichier d'en-tête, cela nécessite généralement de recompiler un certain nombre de fichiers sources (ceux qui l'incluent, directement ou indirectement), mais il semble que cmake n'en détecte que certains des fichiers source à recompiler, conduisant à un état corrompu. Je peux contourner cela en effaçant le projet et en reconstruisant à partir de zéro, mais cela contourne l'objectif d'utiliser un utilitaire make: recompiler uniquement ce qui est nécessaire.

Par conséquent, je suppose que je fais quelque chose de mal.

Mon projet est très simplement organisé:

  • un répertoire supérieur où toutes les ressources se trouvent, le principal CMakeLists.txt s'y trouve
  • un répertoire "include" où se trouvent tous les en-têtes publics (dans divers sous-répertoires)
  • un répertoire "src" où se trouvent tous les sous-répertoires des fichiers sources, le src CMakeLists.txt s'y trouve
  • un CMakeLists.txt par sous-répertoire dans le répertoire "src"

Le répertoire principal a:

cmake_minimum_required(VERSION 2.8)

project(FOO)

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

# Compiler Options
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++0x -Wall -Wextra -Werror")

include_directories($(FOO_SOURCE_DIR)/include)

add_subdirectory(src)

Le répertoire "src":

add_subdirectory(sub1)
add_subdirectory(sub2)
add_subdirectory(sub3)
add_subdirectory(sub4)

add_executable(foo main.cpp)

target_link_libraries(foo sub1 sub2 sub3 sub4)

sub4 dépend de sub3 qui dépend de sub2 qui dépend de sub1

Et un exemple de sous-répertoire (sub3):

set(SUB3_SRCS
    File1.cpp
    File2.cpp
    File3.cpp
    File4.cpp
    File5.cpp
    File6.cpp
    )

add_library(sub3 ${SUB3_SRCS})

target_link_libraries(sub3 sub1 sub2)

Je serais heureux si quelqu'un pouvait me signaler mon erreur, la recherche ici ou sur CMake n'a rien donné, donc je suppose que c'est très facile ou devrait fonctionner hors de la boîte ...

(pour référence, j'utilise la version 2.8.2 de cmake sur MSYS)

MODIFIER :

Grâce à la suggestion de Bill, j'ai vérifié le depend.make fichier généré par CMake, et il manque en effet (gravement). Voici un exemple:

src/sub3/CMakeFiles/sub3.dir/File1.cpp.obj: ../src/sub3/File1.cpp

Oui, c'est tout, aucun des inclusions n'a été référencé du tout: x

45
Matthieu M.

Vous devriez regarder le depend.make fichiers dans votre arbre binaire. Ce sera dans CMakeFiles/target.dir/depend.make. Essayez de trouver l'un de ceux auxquels il manque un .h fichier que vous pensez qu'il devrait avoir. Créez ensuite un rapport de bogue pour cmake ou envoyez un e-mail à la liste de diffusion cmake.

15
Bill Hoffman

Je viens de toucher le même problème. Après avoir changé les chemins dans include_directories() d'absolu en relatif, il a ajouté les dépendances appropriées.

On dirait que CMake essaie de deviner quels en-têtes sont du système et lesquels sont liés au projet. Je soupçonne que les répertoires commençant par / passé comme -isystem /some/path et ne sont donc pas présentés dans les dépendances générées.

Si vous ne pouvez pas remplacer ${FOO_SOURCE_DIR} avec un chemin relatif, vous pouvez essayer de calculer le chemin relatif en utilisant les fonctions CMake appropriées. C'est à dire.:

file(RELATIVE_PATH FOO_SOURCE_REL_DIR
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${FOO_SOURCE_DIR}/.)
include_directories(${FOO_SOURCE_REL_DIR}/include)
9
ony

Avez-vous exécuté cmake avant ou après avoir ajouté les inclusions à vos fichiers cpp?

J'ai rencontré ce problème et relancer cmake l'a corrigé. J'avais ajouté l'inclusion post-cmake.

3
Edward Strange

Apparemment, cmake supprime les chemins d'accès au système des arbres de dépendance (merci @ony pour ce conseil). Cela a probablement du sens la plupart du temps, mais parfois cmake ne sait pas ce que le compilateur pense être un chemin système ou non. Nous utilisons une version gcc personnalisée qui ignore /usr/include, mais cmake pense qu'il ne l'ignore pas. Pour forcer cmake à faire /usr/include une dépendance qui n'est PAS optimisée, essayez cette astuce: ajoutez /. au chemin.

J'essaie de faire en sorte que toutes les dépendances de bibliothèque utilisent la fonction de dépendance cmake, y compris certaines bibliothèques "tierces" qui ne sont pas toujours installées par défaut sur Linux ou même disponibles. Par exemple, la compression Z-lib.

La cible d'interface suivante a bien fonctionné si les inclusions de la bibliothèque Z n'étaient pas dans /usr/include, mais se casserait s'ils l'étaient.

find_package(ZLIB REQUIRED)
message(status "found zlib ${ZLIB_LIBRARIES}")
message(status "found zlib includes ${ZLIB_INCLUDE_DIRS}")
target_link_libraries(zlib_target INTERFACE ${ZLIB_LIBRARIES})
target_include_directories(zlib_target INTERFACE ${ZLIB_INCLUDE_DIRS})

J'ai changé la dernière ligne en

target_include_directories(zlib_target INTERFACE /.${ZLIB_INCLUDE_DIRS})

et ça a marché. Désormais, les cibles qui dépendaient de zlib_target obtiendrait automatiquement -I/./usr/include lors de la compilation.

2
Mark Lakata