使用ExternalProject_Add

时间:2015-09-28 21:18:49

标签: c++ git cmake mingw external-project

我最近将我的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;目录,但似乎没有做任何事情。

2 个答案:

答案 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的帮助。