c++14 with openmp + gtest-1.8のcmake環境を整備する


目標

  • c++14の並列計算(openmp)プログラムを書く
  • g++-5で動けばよい(他のコンパイラだと手直しが必要)
  • openmpが含まれているテストをgtestで書く
  • とりあえず手元のPC(Ubuntu)で動くまで検証する(Macなど環境が違うとうまくいかないかもしれません)
  • 参考

利用するソフト

  • gtest-1.8
  • gmock(gtest-1.8に統合されたので不要)
  • cmake
  • g++-5 (c++14 and openmp)

環境

  • 環境1
    • Ubuntu 16.04
    • cmake 3.5
    • g++5.4 (system default)
  • 環境2
    • Ubuntu 14.04
    • cmake 2.8
    • g++5.4 (sudo apt-get install g++-5)

使い方

コンパイル

git clone https://[email protected]/takeshi-uchitane/cmake_c-14_openmp_gtests.git
cd cmake_c-14_openmp_gtests
mkdir build
cd build
cmake .. # if you have another version of g++, you should set CXX=g++-5
make

実行

  • OpenMPを利用するプログラムのテストができた
$ ./utest/tests/Foo/foo-test 
Running main() from gtest_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Foo
[ RUN      ] Foo.constractor
thread 3
thread 1
thread thread 2
0
[       OK ] Foo.constractor (53 ms)
[----------] 1 test from Foo (53 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (53 ms total)
[  PASSED  ] 1 test.

ソースコード

Foo class

  • OPM並列プログラムとそのテスト
src/Foo.cpp
#include "Foo.hpp"
#include <omp.h>
#include <iostream>

Foo::Foo() { for(unsigned int i=0u;i<4u;i++) { v.push_back(i); } }

std::vector<double> Foo::calc() {
  std::vector<double> array(v.size());
#pragma omp parallel for
  for(unsigned int i=0u;i<v.size();i++) {
    array[i]=double(v[i]);
    std::cout << "thread " << omp_get_thread_num() << std::endl;
  }
  sort(array.begin(), array.end());
  return std::move(array);
}
utest/tests/Foo/main.cpp
#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include "Foo.hpp"

TEST(Foo, constractor) {
  Foo foo;
  EXPECT_THAT(foo.v, testing::ElementsAre(0,1,2,3));
  EXPECT_THAT(foo.calc(), testing::ElementsAre(0.0,1.0,2.0,3.0));
}

CmakeLists.txt

  • CMakeLists.txtはプロジェクト用とテスト用の2つ
  • OPENMPのフラグ(OpenMP_CXX_FLAGS)はテストを追加する前に見つけておく
CmakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

#if you use special compiler, set the compiler
#SET(CMAKE_CXX_COMPILER  "g++-5")
#or
#set option -DCMAKE_CXX_COMPILER="g++-5"

PROJECT(hoge CXX)
include_directories(${PROJECT_SOURCE_DIR}/include)
aux_source_directory(${PROJECT_SOURCE_DIR}/src SOURCES)

ADD_EXECUTABLE(hoge.out main.cpp ${SOURCES})

if (NOT DEFINED ${CMAKE_CXX_FLAGS})
  SET (CMAKE_CXX_FLAGS "-Wall -O3 -std=c++14")
  find_package(OpenMP)
  if (OPENMP_FOUND)
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
  endif()
endif ()
MESSAGE( STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS} )

#gtest
if(NOT without-test)
  enable_testing()
  include(${PROJECT_SOURCE_DIR}/utest/include/gtest.cmake)
  add_subdirectory(${PROJECT_SOURCE_DIR}/utest/tests)
endif()
utest/test/Foo/CmakeLists.txt
cmake_minimum_required(VERSION 2.8)

add_executable(foo-test main.cpp ${SOURCES})
target_link_libraries(foo-test
  gtest
  gtest_main
  gmock
  gmock_main
  pthread
)
add_test(
  NAME foo
  COMMAND $<TARGET_FILE:foo-test>
  )

# run with: ctest -L lib
set_property(
  TEST foo
  PROPERTY LABELS lib foo
  )

gtest.cmake

  • ダウンドーロ先のURLをgtest-1.8用に変更
  • gmockはgtest1.8からgtestに統合された(gmockを別途インストールする必要は無い)
  • 統合によりincludeファイルのパスが変更された
    • ${source_dir}/googletest/include
    • ${source_dir}/googlemock/include
  • 静的ライブラリの作成されるパスが微妙(なんでこんなパスにしたんでしょう)
    • ${binary_dir}/googlemock/gtest/libgtest.a
    • ${binary_dir}/googlemock/gtest/libgtest_main.a
    • ${binary_dir}/googlemock/libgmock.a
    • ${binary_dir}/googlemock/libgmock_main.a
utest/include/gtest.cmake
cmake_minimum_required(VERSION 2.8)

# Google Test settings
include(ExternalProject)

ExternalProject_Add(
    GoogleTest
    URL https://github.com/google/googletest/archive/release-1.8.0.zip
    CMAKE_ARGS -DCMAKE_CXX_COMPILER=g++-5;-DCMAKE_C_COMPILER=gcc-5
    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/lib
    INSTALL_COMMAND ""
    LOG_DOWNLOAD ON
    LOG_CONFIGURE ON
    LOG_BUILD ON
    )

ExternalProject_Get_Property(GoogleTest source_dir)
include_directories(${source_dir}/googletest/include)
include_directories(${source_dir}/googlemock/include)

ExternalProject_Get_Property(GoogleTest binary_dir)
add_library(gtest STATIC IMPORTED)
set_property(
    TARGET gtest
    PROPERTY IMPORTED_LOCATION ${binary_dir}/googlemock/gtest/libgtest.a
    )
add_library(gtest_main STATIC IMPORTED)
set_property(
    TARGET gtest_main
    PROPERTY IMPORTED_LOCATION ${binary_dir}/googlemock/gtest/libgtest_main.a
    )
add_library(gmock STATIC IMPORTED)
set_property(
    TARGET gmock
    PROPERTY IMPORTED_LOCATION ${binary_dir}/googlemock/libgmock.a
    )
add_library(gmock_main STATIC IMPORTED)
set_property(
    TARGET gmock_main
    PROPERTY IMPORTED_LOCATION ${binary_dir}/googlemock/libgmock_main.a
    )

所感

  • 自分のメモ用に初投稿
  • 以下のニーズを満たした開発環境が欲しかった
    • c++-14で書きたい
    • 並列計算プログラムが必要
    • TDDしたい
    • cmake使いたい
  • 探したけど,上記が統合されている開発環境は落ちていなかった
    • きっとニッチな要求なんだろう
    • じゃあ,作ろう
  • gtest1.7とgmock1.7用に作っていたがダウンロードURLが変更になったり,仕様が変わっていたりで手間取ったのでメモを共有