How do I include and link a .dylib file using CMake in VSCode?

411 Views Asked by At

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_directories tells CMake where to look for header files, so I can use the #include pre-processor directive. This is working perfectly in main.cpp where I can #include <glfw3.h> and even see IntelliSense hints for the functions and types.
  • link_directories tells 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_sources specifies 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 the set_target_properties function (commented out) but it didn't work either (still got undefined symbols error).
  • Lastly, I link the glfw target to my main project's target using target_link_libraries. In my head, this tells the linker to link the glfw target. 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?

1

There are 1 best solutions below

0
michael.yql On

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 .dylib files at runtime. Adding one line fixed it.

set(CMAKE_BUILD_RPATH ${CMAKE_SOURCE_DIR}/dependencies/glfw/lib/libglfw.3.dylib)

Now I understand that RPATH is required to find ".dll" files and equivalents.