4 votes

Comment structurer un projet cmake avec différentes bibliothèques tierces ?

Je suis nouveau avec cmake et j'essaie de créer un petit projet qui nécessite quelques librairies tierces. J'aimerais avoir les librairies sous forme de dépôts git pour être toujours à jour. Certaines librairies sont juste des fichiers .cpp et .hpp (glad, imgui) et d'autres sont des projets cmake (glfw, glm).

L'idée est d'avoir un projet tiers avec toutes les librairies comme une sorte de sous-projet et un projet sandbox qui utilise les librairies et les inclusions, etc. Et je voudrais utiliser un code cmake moderne qui n'installe pas quelque chose en dehors de la structure du framework.

Structure du dossier :

Framework
|--3rd_party
|  |--glad
|  |  |--include
|  |  |--src
|  |--glfw-master
|  |  |--...
|  |  |--CMakeLists.txt
|  |--glm-master
|  |  |--..
|  |  |--CMakeLists.txt
|  |--imgui-master
|  |  |--*.cpp
|  |  |--*.hpp
|  |  |--examples
|  |  |  |--*.cpp
|  |  |  |--*.hpp
|  |--CMakeLists.txt
|--sandbox
|  |--main.cpp
|  |--CMakeLists.txt
|--CMakeLists.txt

J'ai donc créé cette structure de dossiers et aussi quelques CMakeLists :

CMakeLists.txt (Cadre)

cmake_minimum_required(VERSION 3.10)

project(Framework)

add_subdirectory("3rd_party")
add_subdirectory("sandbox")

CMakeLists.txt (3rd_party)

#GLFW
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(glfw-master)

# GLM
set(GLM_TEST_ENABLE OFF CACHE BOOL "" FORCE)
add_subdirectory(glm-master)

# Glad
add_library(
    Glad STATIC
    "glad/src/glad.c"
)

target_include_directories(Glad PUBLIC "glad/include")

# ImGui
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD=1)

set(IMGUI_SOURCES
    "imgui-master/imgui.cpp"
    "imgui-master/imgui_demo.cpp"
    "imgui-master/imgui_draw.cpp"
    "imgui-master/imgui_widgets.cpp"
    "imgui-master/examples/imgui_impl_glfw.cpp"
    "imgui-master/examples/imgui_impl_opengl3.cpp"
)

set(IMGUI_HEADERS
    "imgui-master/imconfig.h"
    "imgui-master/imgui.h"
    "imgui-master/imgui_internal.h"
    "imgui-master/imstb_rectpack.h"
    "imgui-master/imstb_textedit.h"
    "imgui-master/imstb_truetype.h"
    "imgui-master/examples/imgui_impl_glfw.h"
    "imgui-master/examples/imgui_impl_opengl3.h"
)

add_library(
    ImGui STATIC
    ${IMGUI_SOURCES}
    ${IMGUI_HEADERS}
)

target_include_directories(ImGui PUBLIC "imgui-master" "glfw-master/include" "glad/include")

CMakeLists.txt (bac à sable)

project(Sandbox)

find_package(OpenGL REQUIRED)

add_executable(sandbox main.cpp)

# OpenGL
target_include_directories(Sandbox PUBLIC ${OPENGL_INCLUDE_DIR})
target_include_directories(Sandbox PUBLIC external)

# Glfw
target_include_directories(Sandbox PUBLIC "../3rd_party/glfw-master/include")

# Link libs
target_link_libraries(Sandbox PUBLIC
           ${OPENGL_LIBRARIES}
           "../3rd_party/glfw-master/src/Debug/glfw3"
           Glad
           ImGui
           glm_static
)

Le code fonctionne mais pas comme je l'attends. Au début, je sais que c'est un peu laid et qu'il y a peut-être une meilleure façon de gérer le chemin pour les includes et les sources, mais le plus gros problème est la structure du projet. Par exemple, lorsque je le construit pour ms vs studio, j'ai trois solutions

./framework.sln
./sandbox/sandbox.sln
./3rd_party/glfw-master/glfw.sln

Et heureusement, glm et imgui font partie de sandbox.sln.

Ce que j'aimerais avoir c'est une solution avec deux sous-solutions sandbox et 3rd_party qui a aussi des sous-solutions ou des projets pour toutes les librairies.

Alors est-ce possible et si oui, comment puis-je créer une telle structure avec cmake ?

3voto

boss0r Points 155

Après une enquête plus approfondie et beaucoup d'essais et d'erreurs avec CMake, je pense que j'ai commencé avec de mauvaises attentes et quelques malentendus.

Il n'est pas possible d'obtenir une structure de solution/projet utile pour Visual Studio à partir des fichiers CMake car tous les projets CMake donneront une solution VS et tous les add_library ou add_executable seront des projets VS. Si je veux créer un projet CMake pour mon framework et ajouter GLFW en tant que tierce partie, ce qui crée également un projet CMake, cela se terminera avec deux solutions VS différentes et bang la structure a disparu. Je pense que c'est la raison pour laquelle Microsoft a introduit un contexte d'ouverture spécial pour les fichiers CMake dans Visual Studio.

OpenCMakeProject_VS2019

Si un projet est ouvert dans ce contexte, le visualiseur "solution" montre la structure des dossiers du projet. Et c'est plus ou moins ce que j'attendais au départ.

FolderView_VS2019

Il y a aussi une option pour changer la vue et voir toutes les cibles CMake (exec, libs, ...).

J'ai aussi "mis à jour" mes CMakeLists. J'utilise différentes méthodes pour ajouter les librairies tierces :

  1. add_subdirectory pour les librairies avec CMakeLists comme GLFW
  2. add_library et INTERFACE pour les librairies à en-tête seulement comme glm
  3. add_library STATIC pour les librairies statiques comme ImGui (dans mon cas)

Les inclusions pour Sandbox sont fournies par l'interface publique des librairies et l'ordre de construction/dépendance est donné par l'ordre dans target_link_libraries.

J'espère que cela vous a aidé et vous fera gagner beaucoup de temps ;)

A la vôtre ! patron0r

CMakeLists.txt (Cadre)

cmake_minimum_required(VERSION 3.10)

project(OpenGL_Framework
    VERSION 0.0.1
    LANGUAGES CXX C    # C for GLFW
)

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

add_subdirectory(ThirdParty)
add_subdirectory(Sandbox)

CMakeLists.txt (3rd_party)

# GLFW
set(GLFW_LIB_NAME "GLFW")
set(GLFW_INC_PATH ${GLFW_LIB_NAME}/include)

set(GLFW_BUILD_DOCS     OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS    OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
#set(GLFW_VULKAN_STATIC  OFF CACHE BOOL "" FORCE)    # OFF by default
#set(BUILD_SHARED_LIBS   OFF CACHE BOOL "" FORCE)    # OFF by default
set(GLFW_INSTALL        OFF CACHE BOOL "" FORCE)

add_subdirectory(${GLFW_LIB_NAME})

# spdlog
set(SPDLOG_LIB_NAME "spdlog")

set(SPDLOG_MASTER_PROJECT OFF CACHE BOOL "" FORCE)

add_subdirectory(${SPDLOG_LIB_NAME})

# OR
#set(SPDLOG_LIB_NAME "spdlog")
#set(SPDLOG_SRC_PATH ${SPDLOG_LIB_NAME}/src)
#set(SPDLOG_INC_PATH ${SPDLOG_LIB_NAME}/include)

#add_library(${SPDLOG_LIB_NAME}
#    STATIC
#        ${SPDLOG_SRC_PATH}/spdlog.cpp
#)

#target_include_directories(${SPDLOG_LIB_NAME}
#    PUBLIC
#        ${SPDLOG_INC_PATH})

# glm
set(GLM_LIB_NAME "glm")
set(GLM_INC_PATH ${GLM_LIB_NAME}/glm)

add_library(${GLM_LIB_NAME} INTERFACE)

target_include_directories(${GLM_LIB_NAME}
    INTERFACE
        ${GLM_INC_PATH}
)

# OR
#set(GLM_LIB_NAME "glm")
#set(GLM_INC_PATH ${GLM_LIB_NAME}/glm)

#set(GLM_TEST_ENABLE OFF CACHE BOOL "" FORCE)

#add_subdirectory(${GLM_LIB_NAME})

#target_include_directories(${GLM_LIB_NAME}
#    PUBLIC
#        $(GLM_INC_PATH)
#)

# Glad
set(GLAD_LIB_NAME "Glad")
set(GLAD_SRC_PATH "${GLAD_LIB_NAME}/src")
set(GLAD_INC_PATH "${GLAD_LIB_NAME}/include")

add_library( ${GLAD_LIB_NAME}
    STATIC
        "${GLAD_SRC_PATH}/glad.c"
)

target_include_directories(${GLAD_LIB_NAME}
    PUBLIC
        "${GLAD_INC_PATH}"
)

# ImGui
set(IMGUI_LIB_NAME "ImGui")

set(IMGUI_SOURCES
    "${IMGUI_LIB_NAME}/imgui.cpp"
    "${IMGUI_LIB_NAME}/imgui_demo.cpp"
    "${IMGUI_LIB_NAME}/imgui_draw.cpp"
    "${IMGUI_LIB_NAME}/imgui_widgets.cpp"
    "${IMGUI_LIB_NAME}/examples/imgui_impl_glfw.cpp"
    "${IMGUI_LIB_NAME}/examples/imgui_impl_opengl3.cpp"
)

set(IMGUI_HEADERS
    "${IMGUI_LIB_NAME}/imconfig.h"
    "${IMGUI_LIB_NAME}/imgui.h"
    "${IMGUI_LIB_NAME}/imgui_internal.h"
    "${IMGUI_LIB_NAME}/imstb_rectpack.h"
    "${IMGUI_LIB_NAME}/imstb_textedit.h"
    "${IMGUI_LIB_NAME}/imstb_truetype.h"
    "${IMGUI_LIB_NAME}/examples/imgui_impl_glfw.h"
    "${IMGUI_LIB_NAME}/examples/imgui_impl_opengl3.h"
)

set(IMGUI_INC_PATH "${IMGUI_LIB_NAME}/")

add_library(${IMGUI_LIB_NAME}
    STATIC
        ${IMGUI_SOURCES}
        ${IMGUI_HEADERS}
)

target_compile_definitions(${IMGUI_LIB_NAME}
    PRIVATE
        IMGUI_IMPL_OPENGL_LOADER_GLAD=1
)

target_include_directories(${IMGUI_LIB_NAME}
    PUBLIC
        "${IMGUI_INC_PATH}"
        "${GLFW_INC_PATH}"
        "${GLAD_INC_PATH}"
)

CMakeLists.txt (bac à sable)

project(Sandbox)

find_package(OpenGL REQUIRED)

add_executable(${PROJECT_NAME} Sandbox.cpp)

target_include_directories(${PROJECT_NAME}
    PUBLIC
        external
        ${OPENGL_INCLUDE_DIR}
)

target_link_libraries(${PROJECT_NAME}
    PUBLIC
        ${OPENGL_gl_LIBRARY}
        glfw
        Glad
        ImGui
        glm
        #glm_static    # if build with add_subdirectory
        spdlog::spdlog
)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X