I've just started learning how to use CMake and I'm trying to include glfw files into my project.
The structure of my project is as follows:
main.cpp
CMakeLists.txt
build
dependencies
- glfw
- lib
- libglfw.3.dylib
- include
- glfw3.h
- glfw3native.h
I downloaded the pre-built binaries for MacOS from https://www.glfw.org/download.html and moved the header files and .dylib file into my project's directory.
My CMakeLists.txt file currently looks like this:
cmake_minimum_required(VERSION 3.27)
project(demo)
add_executable(demo main.cpp)
include_directories(${CMAKE_SOURCE_DIR}/dependencies/glfw/include)
link_directories(${CMAKE_SOURCE_DIR}/dependencies/glfw/lib)
if (APPLE)
target_link_libraries(demo PRIVATE
"-framework OpenGL"
)
endif()
add_library(glfw SHARED IMPORTED)
target_sources(glfw INTERFACE ${CMAKE_SOURCE_DIR}/dependencies/glfw/lib/libglfw.3.dylib)
target_link_libraries(demo INTERFACE glfw)
# set_target_properties(glfw PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/dependencies/glfw/lib/libglfw.3.dylib)
Running CMake: Build on VSCode reports that there are undefined symbols for glfw. I understand that this means I've not linked the library properly, but I do not know where I've went wrong.
My conceptual understanding of CMake is:
include_directoriestells CMake where to look for header files, so I can use the#includepre-processor directive. This is working perfectly inmain.cppwhere I can#include <glfw3.h>and even see IntelliSense hints for the functions and types.link_directoriestells CMake where to look for libraries. It does not actually do the linking, only where to search.add_library(<name> <type> IMPORTED)"references a library file located outside the project" [source]. It creates the target named<name>, making it available in my CMake project. (In this case, the library is technically not 'outside' the project directory, but I thought it didn't matter as I just had to provide the full path to the binary files.)target_sourcesspecifies which files to use to build a target, a.k.a the source files. I'm not sure if I need to be 'building' the target since it's already a pre-compiled binary, so I thought I did something wrong here. I also tried to use theset_target_propertiesfunction (commented out) but it didn't work either (still got undefined symbols error).- Lastly, I link the
glfwtarget to my main project's target usingtarget_link_libraries. In my head, this tells the linker to link theglfwtarget. And since I specified (1) where to search for the file, and (2) what file to search for, it should work.
Previously, I was using vcpkg in my project and installed the glfw files locally. I used
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake)
set(CMAKE_PREFIX_PATH ${CMAKE_SOURCE_DIR}/vcpkg/packages/glfw3_arm64-osx/share/glfw3 ${CMAKE_PREFIX_PATH})
find_package(glfw3 CONFIG REQUIRED)
target_link_libraries(demo PRIVATE glfw)
target_include_directories(demo PRIVATE ${CMAKE_SOURCE_DIR}/vcpkg/packages/glfw3_arm64-osx/include/GLFW)
This was actually working perfectly fine but I didn't like the fact that I was linking a static libglfw3.a file. I didn't want to statically link the file as I understood that it contributed to overall file size of the executable. I wanted to learn how to link dynamic files properly at runtime.
I really wish to learn how to use CMake well and don't want to be defeated by its apparent complexity. Am I headed in the right direction?
I was linking the libraries correctly, but I did not set the runtime path (CMAKE_BUILD_RPATH) variable. The compiler required the RPATH to be set so that it can correctly find the
.dylibfiles at runtime. Adding one line fixed it.Now I understand that RPATH is required to find ".dll" files and equivalents.