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

# 目標
- c++14の並列計算(openmp)プログラムを書く
- g++-5で動けばよい(他のコンパイラだと手直しが必要)
- openmpが含まれているテストをgtestで書く
- とりあえず手元のPC(Ubuntu)で動くまで検証する(Macなど環境が違うとうまくいかないかもしれません)
- 参考
    - [Qiita: C++ のユニットテストをいい感じにする](http://qiita.com/janus_wel/items/4e6c12f9104f501104c7)

# 利用するソフト
- [gtest-1.8](https://github.com/google/googletest)
- ~~[gmock](https://github.com/google/googlemock)~~(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)

# 使い方

## コンパイル
```bash
git clone https://takeshi-uchitane@bitbucket.org/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を利用するプログラムのテストができた

```bash
$ ./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.
```

# ソースコード
- https://bitbucket.org/takeshi-uchitane/cmake_c-14_openmp_gtests

## Foo class
- OPM並列プログラムとそのテスト

```cpp: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);
}
```

```cpp: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)はテストを追加する前に見つけておく

```cmake: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()
```

```cmake: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

```cmake: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が変更になったり，仕様が変わっていたりで手間取ったのでメモを共有