CMake Link 错误 1 使用 ExternalProject_Add
CMake Link error 1 using ExternalProject_Add
我最近将我的 C++ 项目的构建系统切换到了 CMake。我正在尝试使用 ExternalProject_Add 函数下载所需的库(目前有 3 个,GLM 和 TINYOBJ 是静态的,GLFW 可以是静态的也可以是动态的)使用 git 然后 link 在我的项目中给他们。我希望能够以最小的努力 link 这些库(可能还有其他库),以便我可以在多个平台上构建。或者,如果其他人参与该项目,他们将不必太担心安装正确的库。
但是,我在构建时不断遇到这些错误(在 Windows 10 上使用 MinGW):
[100%] Linking CXX executable app\OpenGLTest.exe
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xd): undefined reference to `FPSCounter::getElapsedTime()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x2b): undefined reference to `FPSCounter::reset()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x54): undefined reference to `FPSCounter::setLastTick()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x5e): undefined reference to `FPSCounter::addFrame()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x12d): undefined reference to `GLCamera::getCameraZoom()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x149): undefined reference to `GLCamera::setCameraZoom(float)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x1de): undefined reference to `GLCamera::getCameraPosition()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x747): undefined reference to `GLCamera::setCameraTarget(glm::tvec3<float, (glm::precision)0>)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x771): undefined reference to `GLCamera::setCameraPosition(glm::tvec3<float, (glm::precision)0>)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x968): undefined reference to `GLRenderer_Deferred::GLRenderer_Deferred()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xb98): undefined reference to `FPSCounter::FPSCounter()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xba2): undefined reference to `FPSCounter::FPSCounter()'
collect2.exe: error: ld returned 1 exit status
CMakeFiles\OpenGLTest.dir\build.make:98: recipe for target 'app/OpenGLTest.exe' failed
mingw32-make[2]: *** [app/OpenGLTest.exe] Error 1
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/OpenGLTest.dir/all' failed
mingw32-make[1]: *** [CMakeFiles/OpenGLTest.dir/all] Error 2
Makefile:126: recipe for target 'all' failed
mingw32-make: *** [all] Error 2
我的目录结构如下所示:
|-Project
|-BUILD (all the CMake output files are here)
| |-app (this is where the .exe is output to)
| |-downloads (dependencies are downloaded here)
| |-deps
|-OpenGL (this is the source directory)
|-deps-CMakeLists.txt
|-CMakeLists.txt
|-src
|-Main.cpp
|-**Other source files and headers of the "undefined reference" errors are in this directory**
|-RenderSystem
|-More Source files
这是我的 CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(OpenGLTest)
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/app)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(EX_PROJ_SOURCE_DIR ${CMAKE_BINARY_DIR}/downloads/deps/Source)
set(EX_PROJ_BUILD_DIR ${CMAKE_BINARY_DIR}/downloads/deps/Build)
# Include OpenGL
find_package(OpenGL REQUIRED)
if (OPENGL_FOUND)
include_directories(${OPENGL_INCLUDE_DIR})
endif()
# Include GLEW
find_package(GLEW REQUIRED)
if (GLEW_FOUND)
include_directories(${GLEW_INCLUDE_DIRS})
endif()
set(GLFW_LIB_DIR ${EX_PROJ_BUILD_DIR}/GLFW_EX/src)
link_directories(${GLFW_LIB_DIR})
# Download and unpack gtest at configure time
configure_file(deps-CMakeLists.txt downloads/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/downloads)
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/downloads)
# Add gtest directly to our build
add_subdirectory(${EX_PROJ_SOURCE_DIR}/GLM_EX
${EX_PROJ_BUILD_DIR}/GLM_EX
EXCLUDE_FROM_ALL )
add_subdirectory(${EX_PROJ_SOURCE_DIR}/GLFW_EX
${EX_PROJ_BUILD_DIR}/GLFW_EX
EXCLUDE_FROM_ALL )
add_subdirectory(${EX_PROJ_SOURCE_DIR}/TINYOBJ_EX
${EX_PROJ_BUILD_DIR}/TINYOBJ_EX
EXCLUDE_FROM_ALL )
# Add the gtest include directory, since gtest
# doesn't add that dependency to its gtest target
include_directories(${EX_PROJ_SOURCE_DIR}/GLM_EX/glm
${EX_PROJ_SOURCE_DIR}/GLFW_EX/include
${EX_PROJ_SOURCE_DIR}/TINYOBJ)
# add the executable
add_executable(OpenGLTest src/Main.cpp)
target_link_libraries(OpenGLTest tinyobjloader glm glfw3 ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES})
add_custom_command(TARGET OpenGLTest POST_BUILD # Adds a post-build event to MyTest
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${GLFW_LIB_DIR}/glfw3.dll" # <--this is in-file
$<TARGET_FILE_DIR:OpenGLTest>) # <--this is out-file path
这是 deps-CMakeLists.txt 文件:
cmake_minimum_required(VERSION 3.2)
project(deps-download LANGUAGES NONE)
include(ExternalProject)
set_directory_properties(PROPERTIES EP_BASE "./deps")
# Include GLFW
ExternalProject_Add (
GLFW_EX
GIT_REPOSITORY "https://github.com/glfw/glfw.git"
GIT_TAG "master"
CMAKE_ARGS -DGLFW_BUILD_EXAMPLES=OFF
-DGLFW_BUILD_TESTS=OFF
-DGLFW_BUILD_DOCS=OFF
-DGLFW_INSTALL=OFF
-DBUILD_SHARED_LIBS=ON
UPDATE_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
# Include GLM
ExternalProject_Add (
GLM_EX
GIT_REPOSITORY "https://github.com/g-truc/glm.git"
GIT_TAG "master"
UPDATE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
# Include TINYOBJ
ExternalProject_Add (
TINYOBJ_EX
GIT_REPOSITORY "https://github.com/syoyo/tinyobjloader.git"
GIT_TAG "master"
UPDATE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
add_dependencies(GLFW_EX GLM_EX TINYOBJ_EX)
我的 "main" 位于 "src" 目录中的 Main.cpp 以及错误中引用的所有文件 "undefined reference"。我已经为所有库添加了包含目录(就在 ExternalProject_Add 命令之后)并尝试 link 正在为 GLFW 构建的动态库,但它似乎仍然不起作用。
我缺少什么才能正确构建它?任何帮助将不胜感激。
更新:
我改变了一些东西并将 ExternalProject_Add
命令移动到另一个文件,该文件在我的构建的配置阶段执行,正如 Craig Scott 所建议的那样。我已确保所有外部库都已 linked。我什至在不同的测试项目中分别测试了每个库,以确保 CMake 文件正常工作。
我得到的所有 "undefined references" 都来自我编写的文件,并且在我的源代码树中。 How/Why他们不包括在内吗?
注意:我也尝试包含 "src" 目录,但似乎没有做任何事情。
虽然您的 CMakeLists.txt 文件会构建外部项目,但您的 OpenGLTest 目标不会 link 它们。大概是它们提供了您的 linker 抱怨的缺失符号。简单地将这些外部项目添加为依赖项不会将它们也添加到您的 OpenGLTest 目标中。
要解决此问题,您需要将外部库添加到 target_link_libraries
命令中。不幸的是,当您 运行 CMake 时,这些库将不存在(嗯,无论如何不是第一次),因此您必须手动计算库的详细信息(但请参阅下面的替代方法)。只知道 ExternalProject
将放置它们的目录就足够了。每个构建都应该是可预测的,因此您可以通过查看其中一个测试构建来弄清楚它是什么。我相信您可以将该路径添加到 linker 搜索路径并在 target_link_libraries
命令中列出库的基本名称(基本名称意味着在 unix 上删除任何前导 "lib" -like 平台以及文件后缀)。如果这不起作用,您将需要构建库的完整路径并将其添加到 target_link_libraries
命令中。这将需要更多的工作,特别是如果你想在多个平台上构建(CMake 变量集 CMAKE_..._LIBRARY_PREFIX 和 CMAKE_..._LIBRARY_SUFFIX 在这里可能会有帮助)。
如果手动指定库详细信息困扰您,并且如果外部项目也使用 CMake,则有一种方法可以让 ExternalProject
为您下载源代码,然后使用 add_subdirectory
来获取它们直接进入你的项目。然后,他们将拥有您可以用来在 target_link_libraries
命令上指定的 CMake 目标,并且会获得额外的好处,即始终使用与项目其余部分一致的 compiler/linker 标志进行构建。该技术在此处以 Google 测试为例进行讨论:
https://crascit.com/2015/07/25/cmake-gtest/
如果您愿意,可以修改该方法以在 CMake 时完成整个构建,然后使用 find_library
或类似方法,但这会使 CMake 步骤的成本可能非常高,通常不推荐使用。
我遇到的主要问题是没有将源文件添加到最终的可执行文件中。我通过在 add_executable
命令之前添加 file(GLOB...
解决了这个问题,如下所示:
# get all *.cpp files recursively
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
# add the executable
add_executable(OpenGLTest ${SRC_FILES})
由于不推荐 GLOB
s,因此我将来可能会转向涉及更明确的添加源文件方式的解决方案。
感谢 Craig Scott 的帮助。
我最近将我的 C++ 项目的构建系统切换到了 CMake。我正在尝试使用 ExternalProject_Add 函数下载所需的库(目前有 3 个,GLM 和 TINYOBJ 是静态的,GLFW 可以是静态的也可以是动态的)使用 git 然后 link 在我的项目中给他们。我希望能够以最小的努力 link 这些库(可能还有其他库),以便我可以在多个平台上构建。或者,如果其他人参与该项目,他们将不必太担心安装正确的库。
但是,我在构建时不断遇到这些错误(在 Windows 10 上使用 MinGW):
[100%] Linking CXX executable app\OpenGLTest.exe
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xd): undefined reference to `FPSCounter::getElapsedTime()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x2b): undefined reference to `FPSCounter::reset()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x54): undefined reference to `FPSCounter::setLastTick()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x5e): undefined reference to `FPSCounter::addFrame()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x12d): undefined reference to `GLCamera::getCameraZoom()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x149): undefined reference to `GLCamera::setCameraZoom(float)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x1de): undefined reference to `GLCamera::getCameraPosition()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x747): undefined reference to `GLCamera::setCameraTarget(glm::tvec3<float, (glm::precision)0>)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x771): undefined reference to `GLCamera::setCameraPosition(glm::tvec3<float, (glm::precision)0>)'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0x968): undefined reference to `GLRenderer_Deferred::GLRenderer_Deferred()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xb98): undefined reference to `FPSCounter::FPSCounter()'
CMakeFiles\OpenGLTest.dir/objects.a(Main.cpp.obj):Main.cpp:(.text+0xba2): undefined reference to `FPSCounter::FPSCounter()'
collect2.exe: error: ld returned 1 exit status
CMakeFiles\OpenGLTest.dir\build.make:98: recipe for target 'app/OpenGLTest.exe' failed
mingw32-make[2]: *** [app/OpenGLTest.exe] Error 1
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/OpenGLTest.dir/all' failed
mingw32-make[1]: *** [CMakeFiles/OpenGLTest.dir/all] Error 2
Makefile:126: recipe for target 'all' failed
mingw32-make: *** [all] Error 2
我的目录结构如下所示:
|-Project
|-BUILD (all the CMake output files are here)
| |-app (this is where the .exe is output to)
| |-downloads (dependencies are downloaded here)
| |-deps
|-OpenGL (this is the source directory)
|-deps-CMakeLists.txt
|-CMakeLists.txt
|-src
|-Main.cpp
|-**Other source files and headers of the "undefined reference" errors are in this directory**
|-RenderSystem
|-More Source files
这是我的 CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(OpenGLTest)
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/app)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(EX_PROJ_SOURCE_DIR ${CMAKE_BINARY_DIR}/downloads/deps/Source)
set(EX_PROJ_BUILD_DIR ${CMAKE_BINARY_DIR}/downloads/deps/Build)
# Include OpenGL
find_package(OpenGL REQUIRED)
if (OPENGL_FOUND)
include_directories(${OPENGL_INCLUDE_DIR})
endif()
# Include GLEW
find_package(GLEW REQUIRED)
if (GLEW_FOUND)
include_directories(${GLEW_INCLUDE_DIRS})
endif()
set(GLFW_LIB_DIR ${EX_PROJ_BUILD_DIR}/GLFW_EX/src)
link_directories(${GLFW_LIB_DIR})
# Download and unpack gtest at configure time
configure_file(deps-CMakeLists.txt downloads/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/downloads)
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/downloads)
# Add gtest directly to our build
add_subdirectory(${EX_PROJ_SOURCE_DIR}/GLM_EX
${EX_PROJ_BUILD_DIR}/GLM_EX
EXCLUDE_FROM_ALL )
add_subdirectory(${EX_PROJ_SOURCE_DIR}/GLFW_EX
${EX_PROJ_BUILD_DIR}/GLFW_EX
EXCLUDE_FROM_ALL )
add_subdirectory(${EX_PROJ_SOURCE_DIR}/TINYOBJ_EX
${EX_PROJ_BUILD_DIR}/TINYOBJ_EX
EXCLUDE_FROM_ALL )
# Add the gtest include directory, since gtest
# doesn't add that dependency to its gtest target
include_directories(${EX_PROJ_SOURCE_DIR}/GLM_EX/glm
${EX_PROJ_SOURCE_DIR}/GLFW_EX/include
${EX_PROJ_SOURCE_DIR}/TINYOBJ)
# add the executable
add_executable(OpenGLTest src/Main.cpp)
target_link_libraries(OpenGLTest tinyobjloader glm glfw3 ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES})
add_custom_command(TARGET OpenGLTest POST_BUILD # Adds a post-build event to MyTest
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${GLFW_LIB_DIR}/glfw3.dll" # <--this is in-file
$<TARGET_FILE_DIR:OpenGLTest>) # <--this is out-file path
这是 deps-CMakeLists.txt 文件:
cmake_minimum_required(VERSION 3.2)
project(deps-download LANGUAGES NONE)
include(ExternalProject)
set_directory_properties(PROPERTIES EP_BASE "./deps")
# Include GLFW
ExternalProject_Add (
GLFW_EX
GIT_REPOSITORY "https://github.com/glfw/glfw.git"
GIT_TAG "master"
CMAKE_ARGS -DGLFW_BUILD_EXAMPLES=OFF
-DGLFW_BUILD_TESTS=OFF
-DGLFW_BUILD_DOCS=OFF
-DGLFW_INSTALL=OFF
-DBUILD_SHARED_LIBS=ON
UPDATE_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
# Include GLM
ExternalProject_Add (
GLM_EX
GIT_REPOSITORY "https://github.com/g-truc/glm.git"
GIT_TAG "master"
UPDATE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
# Include TINYOBJ
ExternalProject_Add (
TINYOBJ_EX
GIT_REPOSITORY "https://github.com/syoyo/tinyobjloader.git"
GIT_TAG "master"
UPDATE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND "")
add_dependencies(GLFW_EX GLM_EX TINYOBJ_EX)
我的 "main" 位于 "src" 目录中的 Main.cpp 以及错误中引用的所有文件 "undefined reference"。我已经为所有库添加了包含目录(就在 ExternalProject_Add 命令之后)并尝试 link 正在为 GLFW 构建的动态库,但它似乎仍然不起作用。
我缺少什么才能正确构建它?任何帮助将不胜感激。
更新:
我改变了一些东西并将 ExternalProject_Add
命令移动到另一个文件,该文件在我的构建的配置阶段执行,正如 Craig Scott 所建议的那样。我已确保所有外部库都已 linked。我什至在不同的测试项目中分别测试了每个库,以确保 CMake 文件正常工作。
我得到的所有 "undefined references" 都来自我编写的文件,并且在我的源代码树中。 How/Why他们不包括在内吗?
注意:我也尝试包含 "src" 目录,但似乎没有做任何事情。
虽然您的 CMakeLists.txt 文件会构建外部项目,但您的 OpenGLTest 目标不会 link 它们。大概是它们提供了您的 linker 抱怨的缺失符号。简单地将这些外部项目添加为依赖项不会将它们也添加到您的 OpenGLTest 目标中。
要解决此问题,您需要将外部库添加到 target_link_libraries
命令中。不幸的是,当您 运行 CMake 时,这些库将不存在(嗯,无论如何不是第一次),因此您必须手动计算库的详细信息(但请参阅下面的替代方法)。只知道 ExternalProject
将放置它们的目录就足够了。每个构建都应该是可预测的,因此您可以通过查看其中一个测试构建来弄清楚它是什么。我相信您可以将该路径添加到 linker 搜索路径并在 target_link_libraries
命令中列出库的基本名称(基本名称意味着在 unix 上删除任何前导 "lib" -like 平台以及文件后缀)。如果这不起作用,您将需要构建库的完整路径并将其添加到 target_link_libraries
命令中。这将需要更多的工作,特别是如果你想在多个平台上构建(CMake 变量集 CMAKE_..._LIBRARY_PREFIX 和 CMAKE_..._LIBRARY_SUFFIX 在这里可能会有帮助)。
如果手动指定库详细信息困扰您,并且如果外部项目也使用 CMake,则有一种方法可以让 ExternalProject
为您下载源代码,然后使用 add_subdirectory
来获取它们直接进入你的项目。然后,他们将拥有您可以用来在 target_link_libraries
命令上指定的 CMake 目标,并且会获得额外的好处,即始终使用与项目其余部分一致的 compiler/linker 标志进行构建。该技术在此处以 Google 测试为例进行讨论:
https://crascit.com/2015/07/25/cmake-gtest/
如果您愿意,可以修改该方法以在 CMake 时完成整个构建,然后使用 find_library
或类似方法,但这会使 CMake 步骤的成本可能非常高,通常不推荐使用。
我遇到的主要问题是没有将源文件添加到最终的可执行文件中。我通过在 add_executable
命令之前添加 file(GLOB...
解决了这个问题,如下所示:
# get all *.cpp files recursively
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
# add the executable
add_executable(OpenGLTest ${SRC_FILES})
由于不推荐 GLOB
s,因此我将来可能会转向涉及更明确的添加源文件方式的解决方案。
感谢 Craig Scott 的帮助。