Search code examples
c++cmakeglfwimgui

How can i link GLFW and Dear ImGUI in CMAKE


the last few days i was messing with CMake, and everything worked fine, except that i can't find a way to link ImGUI with GLFW

Everything is build from source

Here is the error :

Consolidate compiler generated dependencies of target glad
[  2%] Built target glad
Consolidate compiler generated dependencies of target stb
[  5%] Built target stb
Consolidate compiler generated dependencies of target glfw
[ 29%] Built target glfw
Consolidate compiler generated dependencies of target imgui
[ 30%] Building CXX object CMakeFiles/imgui.dir/lib/imgui/imgui.cpp.o
[ 31%] Building CXX object CMakeFiles/imgui.dir/lib/imgui/imgui_demo.cpp.o
[ 33%] Building CXX object CMakeFiles/imgui.dir/lib/imgui/imgui_draw.cpp.o
[ 34%] Building CXX object CMakeFiles/imgui.dir/lib/imgui/imgui_tables.cpp.o
[ 36%] Building CXX object CMakeFiles/imgui.dir/lib/imgui/imgui_widgets.cpp.o
[ 37%] Building CXX object CMakeFiles/imgui.dir/lib/imgui/imgui_impl_glfw.cpp.o
/home/erik/Workspace/LearnOpenGL/lib/imgui/imgui_impl_glfw.cpp:45:10: fatal error: GLFW/glfw3.h: No such file or directory
   45 | #include <GLFW/glfw3.h>
      |          ^~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [CMakeFiles/imgui.dir/build.make:146: CMakeFiles/imgui.dir/lib/imgui/imgui_impl_glfw.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:228: CMakeFiles/imgui.dir/all] Error 2
make: *** [Makefile:156: all] Error 2

And here is my CMakeLists.txt :

cmake_minimum_required(VERSION 3.1)

project(LearnOpenGL)


set(SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/source")
set(LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib")

set(SOURCES "${SRC_DIR}/Main.cpp"
    )


add_executable(${PROJECT_NAME} ${SOURCES})

target_include_directories(${PROJECT_NAME} PRIVATE "${SRC_DIR}")

set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)


# GLFW

set(GLFW_DIR "${LIB_DIR}/glfw")

set(GLFW_BUILD_EXAMPLES OFF CACHE INTERNAL "Build the GLFW example programs")
set(GLFW_BUILD_TESTS OFF CACHE INTERNAL "Build the GLFW test programs")
set(GLFW_BUILD_DOCS OFF CACHE INTERNAL "Build the GLFW documentation")
set(GLFW_INSTALL OFF CACHE INTERNAL "Generate installation target")

add_subdirectory("${GLFW_DIR}")

target_link_libraries(${PROJECT_NAME} "glfw" "${GLFW_LIBRARIES}")
target_include_directories(${PROJECT_NAME} PRIVATE "${GLFW_DIR}/include")
target_compile_definitions(${PROJECT_NAME} PRIVATE "GLFW_INCLUDE_NONE")


# Glad

set(GLAD_DIR "${LIB_DIR}/glad")

add_library("glad" "${GLAD_DIR}/src/glad.c")

target_include_directories("glad" PRIVATE "${GLAD_DIR}/include")
target_include_directories(${PROJECT_NAME} PRIVATE "${GLAD_DIR}/include")
target_link_libraries(${PROJECT_NAME} "glad" "${CMAKE_DL_LIBS}")


# GLM 

set(GLM_DIR "${LIB_DIR}/glm")

add_subdirectory(${GLM_DIR})

target_link_libraries(${PROJECT_NAME} "glm")


# STB

set(STB_DIR "${LIB_DIR}/stb")

add_library("stb" "${STB_DIR}/src/stb_image.cpp")

target_include_directories("stb" PRIVATE "${STB_DIR}/include")
target_include_directories(${PROJECT_NAME} PRIVATE "${STB_DIR}/include")
target_link_libraries(${PROJECT_NAME} "stb" "${CMAKE_DL_LIBS}")


# Freetype

set(FREETYPE_DIR "${LIB_DIR}/freetype")

add_subdirectory("${FREETYPE_DIR}")

target_link_libraries(${PROJECT_NAME} "${FREETYPE_LIBRARIES}")
target_include_directories(${PROJECT_NAME} PRIVATE "${FREETYPE_DIR}/include")


# ImGUI

set(IMGUI_DIR "${LIB_DIR}/imgui")

add_library("imgui" "${IMGUI_DIR}/imgui.cpp"
                  "${IMGUI_DIR}/imgui_demo.cpp"
                  "${IMGUI_DIR}/imgui_draw.cpp"
                  "${IMGUI_DIR}/imgui_tables.cpp"
                  "${IMGUI_DIR}/imgui_widgets.cpp"
                  
                  "${IMGUI_DIR}/imgui_impl_glfw.cpp"
                  "${IMGUI_DIR}/imgui_impl_opengl3.cpp")

target_include_directories("imgui" PRIVATE "${IMGUI_DIR}")
target_include_directories(${PROJECT_NAME} PRIVATE "${IMGUI_DIR}")
target_link_libraries(${PROJECT_NAME} "imgui" "${CMAKE_DL_LIBS}")

And here is my folder construction

 1. build
 2. lib
    -  freetype
    -  glad
    -  glfw
    -  glm
    -  imgui
    -  stb
 3. source
    -  Main.cpp
 4. CMakeLists.txt

Here is my question : How i can tell imgui that glfw is already here and he can use it?

Thanks in advance


Solution

  • Your build should consist of nothing but the following:

    cmake_minimum_required(VERSION 3.20)
    project(LearnOpenGL)
    
    ## Find dependencies
    find_package(glfw3 REQUIRED)
    find_package(glad REQUIRED)
    find_package(glm REQUIRED)
    find_package(freetype REQUIRED)
    find_package(imgui REQUIRED)
    
    # stb does not have a CMake build, but is header-only
    find_path(STB_INCLUDE_DIRS "stb.h") 
    
    ## Create main executable
    add_executable(main source/Main.cpp)
    target_include_directories(main 
      PRIVATE 
        ${STB_INCLUDE_DIRS}
        "${CMAKE_CURRENT_LIST_DIR}/source"
    )
    target_link_libraries(
      main
      PRIVATE
        freetype
        glfw
        glad::glad
        glm::glm
        imgui::imgui
    )
    

    If you aren't using CMake 3.20, (a) you should be, but (b) you can try with an earlier version. But never put a version below the one you test with. CMake is only backwards compatible, not forwards compatible.

    If you only need freetype as a dependency of imgui, then you can remove the references to it in the CMakeLists.txt.

    To build this, you'll want to use vcpkg. To that end, create a file called vcpkg.json next to your CMakeLists.txt with the following contents:

    {
      "name": "learn-opengl",
      "version": "0.1.0",
      "dependencies": [
        "glfw3",
        "glad",
        "glm",
        "freetype",
        "stb",
        {
          "name": "imgui",
          "features": ["freetype", "glfw-binding", "opengl3-glad-binding"]
        }
      ]
    }
    

    This is just telling vcpkg which dependencies you want, and that you want imgui built with freetype support and the glfw bindings.

    Then you just need to run three commands.

    $ git clone https://github.com/microsoft/vcpkg.git
    $ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
            -DCMAKE_TOOLCHAIN_FILE=$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake
    $ cmake --build build
    

    The only thing here that might be unexpected is setting CMAKE_TOOLCHAIN_FILE, this is just telling CMake to use vcpkg. The first time this runs, vcpkg will download your dependencies, build them, cache them in ~/.cache/vcpkg and install them into your build folder. Subsequent runs will build just your code.

    This sequence successfully built your code for me on my Ubuntu 20.04 LTS machine.


    To make this easier, consider creating a CMakePresets.json file, also in your root directory, with the following contents:

    {
      "version": 2,
      "cmakeMinimumRequired": {
        "major": 3,
        "minor": 20,
        "patch": 0
      },
      "configurePresets": [
        {
          "name": "default",
          "displayName": "Default Config",
          "description": "Default build using Make and vcpkg",
          "generator": "Unix Makefiles",
          "binaryDir": "${sourceDir}/build",
          "cacheVariables": {
            "CMAKE_BUILD_TYPE": "Release",
            "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake"
          }
        },
        {
          "name": "default-msvc",
          "displayName": "Default MSVC",
          "description": "Default build using Visual Studio and vcpkg",
          "generator": "Visual Studio 16 2019",
          "binaryDir": "${sourceDir}/build",
          "cacheVariables": {
            "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake"
          }
        }
      ]
    }
    

    Then you can just run cmake --preset=default instead of the longer command above.