0

我最近将我的 C++ 项目的构建系统切换到了 CMake。我正在尝试使用 ExternalProject_Add 函数下载所需的库(目前有 3 个,GLM 和 TINYOBJ 是静态的,GLFW 可以是静态的或动态的),然后在我的项目中链接到它们。我希望能够以最小的努力链接这些库(可能还有其他库),以便我可以在多个平台上构建。或者,如果其他人来参与该项目,他们不必太担心安装正确的库。

但是,在构建时(在带有 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)

我的“main”与错误中引用的所有文件一起位于“src”目录中的 Main.cpp 中作为“未定义的引用”。我已经为所有库添加了包含目录(就在 ExternalProject_Add 命令之后),并尝试链接为 GLFW 构建的动态库,但它似乎仍然不起作用。

为了正确构建它,我缺少什么?任何帮助,将不胜感激。

更新:

正如克雷格斯科特所建议的那样,我已经改变了一些东西并将ExternalProject_Add命令移动到另一个文件,该文件在我的构建的配置阶段执行。我已确保所有外部库都已链接。我什至在不同的测试项目中分别测试了每个库,以确保 CMake 文件正常工作。

我得到的所有“未定义引用”都来自我编写的文件,并且在我的源代码树中。他们如何/为什么不被包括在内?

注意:我也尝试过包含“src”目录,但似乎没有做任何事情。

4

2 回答 2

1

我遇到的主要问题是没有将源文件添加到最终的可执行文件中。我通过在这样的命令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由于不建议使用 s,因此我可能会转向涉及一种更明确的方式来添加源文件的解决方案。

感谢克雷格斯科特的帮助。

于 2015-11-03T19:52:20.163 回答
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将它们直接带入您的项目。然后,他们将拥有 CMake 目标,您可以使用这些目标在您的target_link_libraries命令中指定,并且将始终使用一致的编译器/链接器标志作为项目的其余部分进行构建,从而获得额外的好处。此处以 Google Test 为例讨论了该技术:

https://crascit.com/2015/07/25/cmake-gtest/

如果您愿意,您可以修改该方法以在 CMake 时进行整个构建,然后使用find_library或类似方法,但这会使 CMake 步骤可能非常昂贵,通常不推荐使用。

于 2015-09-28T22:04:10.660 回答