我最近将我的C ++项目的构建系统切换到了CMake。我正在尝试使用ExternalProject_Add函数下载所需的库(目前有3个,GLM和TINYOBJ是静态的,GLFW可以是静态的还是动态的),然后使用git链接到我的项目中。我希望能够以最小的努力链接这些库(以及可能的其他库),以便我可以在多个平台上构建。或者,如果有其他人参与该项目的工作,他们不必过于担心安装正确的库。
但是,在构建时(在使用MinGW的Windows 10上),我一直收到这些错误:
[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)
我的主要&#34;位于Main.cpp的&#34; src&#34;目录以及错误中引用的所有文件&#34;未定义的引用&#34;。我已经为所有库添加了include目录(在ExternalProject_Add命令之后),并尝试链接为GLFW构建的动态库,但它似乎仍然无效。
为了正确构建,我缺少什么?任何帮助将不胜感激。
更新
我已经改变了一些东西并将ExternalProject_Add
命令移动到另一个文件,这些文件在我的构建的配置阶段执行,正如Craig Scott所建议的那样。我确保所有外部库都已链接。我甚至在不同的测试项目中分别测试了每个库,以确保CMake文件有效。
所有&#34;未定义的引用&#34;我来自我写的文件,并且在我的源代码树中。它们如何/为什么不被包括在内?
注意:我还试图包含&#34; src&#34;目录,但似乎没有做任何事情。
答案 0 :(得分:1)
虽然您的CMakeLists.txt文件确实构建了外部项目,但您的OpenGLTest目标并未链接到它们。据推测,它们是提供链接器抱怨的缺失符号的原因。简单地将这些外部项目添加为依赖项也不会将它们添加到OpenGLTest目标中。
要解决此问题,您需要将外部库添加到target_link_libraries
命令。不幸的是,当你运行CMake时,这些库将不存在(好吧,不是第一次),所以你必须手动计算出库的细节(但是请参阅下面的替代方案)。仅知道ExternalProject
将放置它们的目录就足够了。它应该可以预测每个构建,所以你可以通过查看你的一个测试版本来计算出它是什么。我相信您可以将该路径添加到链接器搜索路径并在target_link_libraries
命令中列出库的基本名称(基本名称意味着在类似unix的平台上删除任何前导“lib”以及文件后缀)。如果这不起作用,则需要构建库的完整路径并将其添加到target_link_libraries
命令中。这需要更多的工作,特别是如果你想在多个平台上构建(一组CMake变量CMAKE _..._ LIBRARY_PREFIX和CMAKE _..._ LIBRARY_SUFFIX可能在这里有用)。
如果手动指定库详细信息困扰您,并且外部项目也使用CMake,则可以让ExternalProject
为您下载源代码,然后使用add_subdirectory
将它们直接导入你的项目。然后,他们将拥有可用于在target_link_libraries
命令上指定的CMake目标,并且具有始终使用一致的编译器/链接器标志构建的额外好处作为项目的其余部分。该技术将以Google Test为例进行讨论:
https://crascit.com/2015/07/25/cmake-gtest/
如果您愿意,可以修改该方法以在CMake时间执行整个构建,然后使用find_library
或类似方法,但这会使CMake步骤成本非常高,通常不建议使用。
答案 1 :(得分:0)
我遇到的主要问题是由于没有将源文件添加到最终的可执行文件。我通过在file(GLOB...
命令之前添加add_executable
来修复此问题,如下所示:
# get all *.cpp files recursively
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
# add the executable
add_executable(OpenGLTest ${SRC_FILES})
由于不推荐使用GLOB
,我可能会转向一种涉及更明确添加源文件的方法的解决方案。
感谢Craig Scott的帮助。