0

最近、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)

私の「メイン」は、エラーで「未定義の参照」として参照されているすべてのファイルとともに、「src」ディレクトリの Main.cpp にあります。すべてのライブラリのインクルード ディレクトリを追加し (ExternalProject_Add コマンドの直後)、GLFW 用にビルドされている動的ライブラリをリンクしようとしましたが、まだ機能していないようです。

これを正しくビルドするには何が欠けていますか? どんな助けでも大歓迎です。

アップデート:

ExternalProject_AddCraig Scott が提案したように、ビルドの構成フェーズ中に実行されるコマンドを別のファイルに移動し、いくつかのことをシャッフルしました。すべての外部ライブラリがリンクされていることを確認しました。CMake ファイルが機能することを確認するために、別のテスト プロジェクトで各ライブラリを個別にテストしました。

私が取得している「未定義の参照」はすべて、私が作成したファイルからのもので、ソース ツリーにあります。どのように/なぜそれらが含まれていないのですか?

注:「src」ディレクトリも含めようとしましたが、何もしていないようです。

4

2 に答える 2

1

私が抱えていた主な問題は、最終的な実行可能ファイルにソース ファイルを追加しなかったことが原因でした。次のようにコマンドのfile(GLOB...直前にa を追加して問題を修正しました。add_executable

# get all *.cpp files recursively
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
# add the executable
add_executable(OpenGLTest ${SRC_FILES})

GLOBs は推奨されないため、将来的には、ソース ファイルを追加するより明示的な方法を含むソリューションに移行する可能性があります。

助けてくれた Craig Scott に感謝します。

于 2015-11-03T19:52:20.163 に答える
1

CMakeLists.txt ファイルは外部プロジェクトをビルドしますが、OpenGLTest ターゲットはそれらにリンクしません。おそらく、それらは、リンカが不平を言っている不足しているシンボルを提供するものです。これらの外部プロジェクトを依存関係として追加するだけでは、OpenGLTest ターゲットにも追加されません。

この問題を解決するには、target_link_librariesコマンドに外部ライブラリを追加する必要があります。残念ながら、これらのライブラリは CMake を実行するときには存在しないため (とにかく初めてではありません)、ライブラリの詳細を手動で作成する必要があります (ただし、別の方法については以下を参照してください)。それらを配置するディレクトリだけを知っていれば十分かもしれませんExternalProject。すべてのビルドで予測可能であるべきなので、テスト ビルドの 1 つを見ることでそれが何であるかを理解できます。次に、そのパスをリンカー検索パスに追加し、コマンドでライブラリのベース名をリストするだけでよいと思います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 に答える