Reputation: 245
I'm new with cmake and try to create a small project which needs some 3rd-party libs. I would like to have the libs as git repos to always be up-to-date. Some libs are just .cpp and .hpp files (glad, imgui) and others are cmake projects (glfw, glm).
The idea is to have a 3rd-party project with all the libs as a kind of subprojects and a sandbox project which uses the libs and includes etc. And I would like to use modern cmake code which is not installing something outside the framework structure.
Folder structure:
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
So I created this folder structure and also some CMakeLists:
CMakeLists.txt (Framework)
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 (sandbox)
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
)
The code works but not as I expect. At first I know it's a little bit ugly maybe there is a better way to handle the path for includes and sources but the bigger problem is project structure. For example, when I build it for ms vs studio I have three solutions
./framework.sln
./sandbox/sandbox.sln
./3rd_party/glfw-master/glfw.sln
And glad, glm and imgui are part of sandbox.sln
What I would like to have is a solution with two sub-solutions sandbox and 3rd_party which also has sub-solutions or projects for all the libs.
So is it possible at all and if yes how can I create such a structure with cmake?
Upvotes: 9
Views: 4393
Reputation: 245
After further investigation and a lot of try and error with CMake, I guess I started with wrong expectations and some missunderstandings.
It is not possible to get a useful solution/project structure for Visual Studio from CMake files because all CMake-projects will result in a VS-solution and all add_library or add_executable will be a VS-project. If I want to create a CMake-project for my framework and add GLFW as third party, which also creates a CMake-project, it will end with two different VS-solutions and bang the structure is gone. I think that is why Microsoft introduced a special open context for CMake files in Visual Studio.
If a project is opened with this context, the "solution" viewer shows the folder structure of the project. And that is more or less what I expected in the beginning.
There is also an option to switch the view to see all CMake targets (exec, libs, ...).
I also "upgraded" my CMakeLists. I use different ways to add the third party libs:
The includes for Sandbox are provided by the public interface of the libs and the build/dependency order is given by order in target_link_libraries.
I hope that is was helpul and will spare you a lot of time ;)
Cheers! boss0r
CMakeLists.txt (Framework)
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 (sandbox)
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
)
Upvotes: 7