web-dev-qa-db-ja.com

GTestとCMakeの使用を開始する方法

私は最近、C++プロジェクトのコンパイルにCMakeを使用して販売されており、コードの単体テストの作成を開始したいと考えています。これを支援するためにGoogle Testユーティリティを使用することにしましたが、開始するには多少の助けが必要です。

一日中、さまざまなガイドと例を読んでいます。 PrimerIBMでの紹介 、およびSOに関するいくつかの質問( こちら および ここ )と、私が見落とした他のソース。私はそこにたくさんあることを認識していますが、どういうわけか私はまだ困難を抱えています。

現在、gtestを正しくコンパイル/インストールしたことを確認するために、最も基本的なテストを実装しようとしていますが、動作していません。唯一のソースファイル(testgtest.cpp)は、 this 前の回答からほぼ正確に取得されます。

#include <iostream>

#include "gtest/gtest.h"

TEST(sample_test_case, sample_test)
{
    EXPECT_EQ(1, 1);
}

私の関連するCMakeLists.txtは次のとおりです。

cmake_minimum_required(VERSION 2.6)
project(basic_test)

# Setup testing
enable_testing()
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIR})

# Add test cpp file
add_executable(runUnitTests
    testgtest.cpp
)

# Link test executable against gtest & gtest_main
target_link_libraries(runUnitTests ${GTEST_LIBRARY_DEBUG} ${GTEST_MAIN_LIBRARY_DEBUG})

add_test(
    NAME runUnitTests
    COMMAND runUnitTests
)

Cppファイルの最後にメインを提供する代わりに、gtest_mainにリンクすることを選択したことに注意してください。これにより、テストを複数のファイルに簡単にスケールアップできるようになります。

生成された.slnファイルをビルドするとき(Visual C++ 2010 Express)、残念ながらフォームのエラーの長いリストを取得します

2>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: virtual __thiscall std::basic_iostream<char,struct std::char_traits<char> >::~basic_iostream<char,struct std::char_traits<char> >(void)" (??1?$basic_iostream@DU?$char_traits@D@std@@@std@@UAE@XZ) already defined in gtestd.lib(gtest-all.obj)

これは、gtestライブラリに正常にリンクしていないことを意味すると思います。デバッグライブラリに対してリンクするときに、デバッグモードでビルドしようとしたことを確認しました。

編集

さらに掘り下げてみると、私の問題はgtestを構築しているライブラリのタイプに関係していると思います。 CMakeでgtestをビルドするときに、BUILD_SHARED_LIBSのチェックを外して、プログラムをこれらの.libファイルにリンクすると、上記のエラーが発生します。ただし、BUILD_SHARED_LIBSがチェックされている場合は、一連の.libおよび.dllファイルを生成します。これらの.libファイルに対してリンクすると、プログラムはコンパイルされますが、実行するとgtest.dllが見つからないと文句が言います。

SHAREDライブラリとnot SHAREDライブラリの違いは何ですか。共有しないことを選択した場合、なぜ機能しないのですか?プロジェクトのCMakeLists.txtに欠落しているオプションはありますか?

110
Chris

ソリューションには、gtestソースディレクトリをプロジェクトのサブディレクトリとして配置する必要がありました。誰かに役立つ場合は、以下の作業CMakeLists.txtを含めました。

cmake_minimum_required(VERSION 2.6)
project(basic_test)

################################
# GTest
################################
ADD_SUBDIRECTORY (gtest-1.6.0)
enable_testing()
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})

################################
# Unit Tests
################################
# Add test cpp file
add_executable( runUnitTests testgtest.cpp )
# Link test executable against gtest & gtest_main
target_link_libraries(runUnitTests gtest gtest_main)
add_test( runUnitTests runUnitTests )
69
Chris

ここに、私がテストしたばかりの完全な実例を示します。固定tarball、または最新のSubversionディレクトリのいずれかから、Webから直接ダウンロードします。

cmake_minimum_required (VERSION 3.1)

project (registerer)

##################################
# Download and install GoogleTest

include(ExternalProject)
ExternalProject_Add(gtest
  URL https://googletest.googlecode.com/files/gtest-1.7.0.Zip
  # Comment above line, and uncomment line below to use Subversion.
  # SVN_REPOSITORY http://googletest.googlecode.com/svn/trunk/ 
  # Uncomment line below to freeze a revision (here the one for 1.7.0)
  # SVN_REVISION -r700

  PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest
  INSTALL_COMMAND ""
)
ExternalProject_Get_Property(gtest source_dir binary_dir)

################
# Define a test
add_executable(registerer_test registerer_test.cc)

######################################
# Configure the test to use GoogleTest
#
# If used often, could be made a macro.

add_dependencies(registerer_test gtest)
include_directories(${source_dir}/include)
target_link_libraries(registerer_test ${binary_dir}/libgtest.a)
target_link_libraries(registerer_test ${binary_dir}/libgtest_main.a)

##################################
# Just make the test runnable with
#   $ make test

enable_testing()
add_test(NAME    registerer_test 
         COMMAND registerer_test)
28
user1427799

ほとんどの場合、テストバイナリとGoogle Testライブラリのコンパイラオプションの違いは、このようなエラーのせいです。そのため、ソース形式でGoogle Testを取り込み、テストとともにビルドすることをお勧めします。 CMakeで行うのは非常に簡単です。 gtestルートへのパスでADD_SUBDIRECTORYを呼び出すだけで、そこに定義されているパブリックライブラリターゲット(gtestおよびgtest_main)を使用できます。 googletestframeworkグループの CMake thread には、さらに詳しい背景情報があります。

[編集] BUILD_SHARED_LIBSオプションは、現時点ではWindowsでのみ有効です。 CMakeでビルドするライブラリのタイプを指定します。 ONに設定すると、CMakeは静的ライブラリではなくDLLとしてビルドします。その場合、-DGTEST_LINKED_AS_SHARED_LIBRARY = 1を使用してテストをビルドし、CMakeによって生成されたDLLファイルをテストバイナリのディレクトリにコピーする必要があります(CMakeはデフォルトで別の出力ディレクトリに配置します)。静的ライブラリのgtestが機能しない場合を除き、そのオプションを設定しない方が簡単です。

13
VladLosev

両方の長所を活用できます。 ExternalProjectを使用してgtestソースをダウンロードし、add_subdirectory()を使用してビルドに追加することができます。これには次の利点があります。

  • gtestはメインビルドの一部としてビルドされるため、同じコンパイラフラグなどを使用するため、質問で説明されているような問題を回避できます。
  • Gtestソースを独自のソースツリーに追加する必要はありません。

通常の方法で使用すると、ExternalProjectは構成時(つまりCMakeの実行時)にダウンロードと解凍を行いませんが、ほんの少しの作業でそれを行うことができます。これを行う方法に関するブログ記事を書きました。これには、gtestだけでなく、CMakeをビルドシステムとして使用する外部プロジェクトで機能する一般化された実装も含まれています。ここで見つけることができます:

更新:このアプローチは現在も googletestドキュメントの一部 です。

10
Craig Scott

さらに掘り下げてみると、私の問題はgtestを構築しているライブラリのタイプに関係していると思います。 CMakeでgtestをビルドするときに、BUILD_SHARED_LIBSのチェックを外して、プログラムをこれらの.libファイルにリンクすると、上記のエラーが発生します。ただし、BUILD_SHARED_LIBSがチェックされている場合、.libおよび.dllファイルのセットを作成します。これらの.libファイルに対してリンクすると、プログラムはコンパイルされますが、実行するとgtest.dllが見つからないと文句が言います。

これは、gtestを共有ライブラリとして使用する場合、プロジェクトのコンパイラ定義に-DGTEST_LINKED_AS_SHARED_LIBRARY = 1を追加する必要があるためです。

Gtest_force_shared_crtオプションをオンにしてコンパイルした場合は、静的ライブラリを使用して、表示されたエラーを排除することもできます。

ライブラリは気に入っていますが、プロジェクトに追加するのは本当に大変です。そして、gtestのcmakeファイルを掘る(そしてハックする)ことをしない限り、正しく実行する機会はありません。恥。特に、gtestをソースとして追加するという考えは好きではありません。 :)

2
Slava

このスレッドの回答といくつかの試行錯誤から抽出した最も単純なCMakeLists.txtは次のとおりです。

project(test CXX C)
cmake_minimum_required(VERSION 2.6.2)

#include folder contains current project's header filed
include_directories("include")

#test folder contains test files
set (PROJECT_SOURCE_DIR test) 
add_executable(hex2base64 ${PROJECT_SOURCE_DIR}/hex2base64.cpp)

# Link test executable against gtest nothing else required
target_link_libraries(hex2base64 gtest pthread)

Gtestはすでにシステムにインストールされているはずです。

0
AlexBriskin

あなたとVladLosevsのソリューションはおそらく私のソリューションよりも優れています。ただし、ブルートフォースソリューションが必要な場合は、これを試してください。

SET(CMAKE_EXE_LINKER_FLAGS /NODEFAULTLIB:\"msvcprtd.lib;MSVCRTD.lib\")

FOREACH(flag_var
    CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
    CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
    if(${flag_var} MATCHES "/MD")
        string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
    endif(${flag_var} MATCHES "/MD")
ENDFOREACH(flag_var)
0
Torleif