I'm new to CMake and having trouble getting my simple MacOS app (just the learn OpenGL tutorial at this point) to link against the MacOS frameworks required by GLFW. All my code is in main.cpp
and I'm using the generated glad source files. My source tree looks like this:
.
├── CMakeLists.txt
├── glad
│ └── glad.h
├── glad.c
├── KHR
│ └── khrplatform.h
└── main.cpp
Here's my CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(simple_repro)
set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
add_executable(app1 main.cpp glad.c)
target_include_directories(app1 PRIVATE
${CMAKE_SOURCE_DIR}
${GLFW_INCLUDE_DIRS}
)
target_link_libraries(app1 ${GLFW_STATIC_LDFLAGS})
When I build, I get this error:
/Library/Developer/CommandLineTools/usr/bin/c++ -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/app1.dir/main.cpp.o CMakeFiles/app1.dir/glad.c.o -o app1 -L/usr/local/lib -lglfw3 -framework -lCocoa -framework -lIOKit -framework -lCoreFoundation -lCocoa -lIOKit -lCoreFoundation
ld: framework not found -lCocoa
clang: error: linker command failed with exit code 1 (use -v to see invocation)
At the surface, the reason is pretty obvious: in the linker command, the frameworks parts of ${GLFW_STATIC_LDFLAGS}
are being mangled. The names of the framworks are pre-pended with -l
and they're repeated. For reference, after the pkg_search_module
call, GLFW_STATIC_LDFLAGS
is:
-L/usr/local/lib;-lglfw3;-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation
Please note I have no control over the format of this; it gets set by pkg_search_module
.
I think if the frameworks part got expanded as:
-framework Cocoa -framework IOKit -framework CoreFoundation
I'd be in business. But instead, it's coming out as
-framework -lCocoa -framework -lIOKit -framework -lCoreFoundation -lCocoa -lIOKit -lCoreFoundation
So the heart of my question is: what do I need to do to get the right linker command to be generated from the output of pkg_search_module
? I've googled everything I could think of and tried a ton of things, to no avail. Some highlights of my exploration:
- Based on this answer, I changed my
pkg_search_module
call to specify IMPORTED_TARGET and then link to that target:
pkg_search_module(GLFW REQUIRED IMPORTED_TARGET glfw3)
...
target_link_libraries(app1 PUBLIC PkgConfig::GLFW)
This results in basically no references to the MacOS frameworks in the linker command and (as I'd expect) a bunch of core platform undefined symbols:
/Library/Developer/CommandLineTools/usr/bin/c++ -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/app1.dir/main.cpp.o CMakeFiles/app1.dir/glad.c.o -o app1 /usr/local/lib/libglfw3.a
Undefined symbols for architecture x86_64:
"_CFArrayAppendValue", referenced from:
__glfwInitJoysticksNS in libglfw3.a(cocoa_joystick.m.o)
_matchCallback in libglfw3.a(cocoa_joystick.m.o)
"_CFArrayCreateMutable", referenced from:
... and many pages more
- I tried explicitly setting the link flags via
set_property(TARGET app1 PROPERTY LINK_FLAGS ${GLFW_STATIC_LDFLAGS})
This just interprets the whole semi-colon separated list inGLFW_STATIC_LDFLAGS
as a single string and giving a linker warning:
/Library/Developer/CommandLineTools/usr/bin/c++ -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names -L/usr/local/lib;-lglfw3;-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation CMakeFiles/app1.dir/main.cpp.o CMakeFiles/app1.dir/glad.c.o -o app1 /usr/local/lib/libglfw3.a
ld: warning: directory not found for option '-L/usr/local/lib;-lglfw3;-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation'
- I know I can make this work by doing explicity
find_library()
calls on Cocoa, IOKit, and CoreFoundation and then linking against the found library, but I do not want to hardcode into my CMakeLists.txt the knowledge that GLFW requires these frameworks, because that's platform specific.
Many thanks in advance for any help in figuring out what incantation will generate the right linker command from the pkg_search_module
output.
EDIT: in response to Tsyvarev's comment below, I changed the CMakeLists.txt to read:
cmake_minimum_required(VERSION 3.5)
project(simple_repro)
set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GLFW REQUIRED glfw3)
add_executable(app1 main.cpp glad.c)
target_include_directories(app1 PRIVATE
${CMAKE_SOURCE_DIR}
${GLFW_INCLUDE_DIRS}
)
target_link_libraries(app1 ${GLFW_LIBRARIES})
message(STATUS "GLFW_LIBRARIES is ${GLFW_LIBRARIES}")
target_compile_options(app1 PUBLIC ${GLFW_CFLAGS_OTHER})
This outputs -- GLFW_LIBRARIES is glfw3
and generates this linker command, which doesn't include the full path to glfw3 nor does it include the system frameworks needed:
/usr/local/Cellar/cmake/3.21.2/bin/cmake -E cmake_link_script CMakeFiles/app1.dir/link.txt --verbose=1
/Library/Developer/CommandLineTools/usr/bin/c++ -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/app1.dir/main.cpp.o CMakeFiles/app1.dir/glad.c.o -o app1 -lglfw3
This is the full list of GLFW_* variables, after the pkg_search_module
call, in case it helps:
-- GLFW_CFLAGS=-I/usr/local/include
-- GLFW_CFLAGS_I=
-- GLFW_CFLAGS_OTHER=
-- GLFW_FOUND=1
-- GLFW_INCLUDEDIR=/usr/local/include
-- GLFW_INCLUDE_DIRS=/usr/local/include
-- GLFW_LDFLAGS=-L/usr/local/lib;-lglfw3
-- GLFW_LDFLAGS_OTHER=
-- GLFW_LIBDIR=/usr/local/lib
-- GLFW_LIBRARIES=glfw3
-- GLFW_LIBRARY_DIRS=/usr/local/lib
-- GLFW_LIBS=
-- GLFW_LIBS_L=
-- GLFW_LIBS_OTHER=
-- GLFW_LIBS_PATHS=
-- GLFW_LINK_LIBRARIES=/usr/local/lib/libglfw3.a
-- GLFW_MODULE_NAME=glfw3
-- GLFW_PREFIX=/usr/local
-- GLFW_STATIC_CFLAGS=-I/usr/local/include
-- GLFW_STATIC_CFLAGS_I=
-- GLFW_STATIC_CFLAGS_OTHER=
-- GLFW_STATIC_INCLUDE_DIRS=/usr/local/include
-- GLFW_STATIC_LDFLAGS=-L/usr/local/lib;-lglfw3;-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation
-- GLFW_STATIC_LDFLAGS_OTHER=-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation
-- GLFW_STATIC_LIBDIR=
-- GLFW_STATIC_LIBRARIES=glfw3
-- GLFW_STATIC_LIBRARY_DIRS=/usr/local/lib
-- GLFW_STATIC_LIBS=
-- GLFW_STATIC_LIBS_L=
-- GLFW_STATIC_LIBS_OTHER=
-- GLFW_STATIC_LIBS_PATHS=
-- GLFW_VERSION=3.3.4
-- GLFW_glfw3_INCLUDEDIR=
-- GLFW_glfw3_LIBDIR=
-- GLFW_glfw3_PREFIX=
-- GLFW_glfw3_VERSION=
-- __pkg_config_arguments_GLFW=REQUIRED;glfw3
-- __pkg_config_checked_GLFW=1
-- pkgcfg_lib_GLFW_glfw3=/usr/local/lib/libglfw3.a