Travis CIでOpenCV + GTest + Coverallsを実行する方法

こんにちはtatsyです。

最近、これまでに作ったプログラムをまとめてGithub上で公開する作業を行っていたのですが、その際にOpenCV + GTestをTravis上でテストするのに結構苦労したのでやり方をまとめておきます。

Travis上でやりたいことは次の4つです。

  1. OpenCVをwgetしてきて、Travis上でビルドする
  2. GTestをapt-get installしてTravis上でビルドする
  3. 自分の書いたプログラムをCMakeでビルドする
  4. Coverallsにカバレッジを送信する

それでは個々のやり方についてみていきます。

1. OpenCVのビルド


実際のビルドに行く前に1点確認ですが、TravisサーバーはOSにUbuntu 12.04 LTSを使っているらしいです(2015年2月現在)。

ですので少し昔のバージョンで良ければ、apt-getをしてOpenCVをインストールすることも可能ですが、僕が作成中のライブラリはOpenCV 3.0ベースだったので、ソースをOpenCVのページからwgetしてきてビルドしました。

sudo apt-get update
sudo apt-get -y install libopencv-dev build-essential cmake git libgtk2.0-dev pkg-config python-dev python-numpy libdc1394-22 libdc1394-22-dev libjpeg-dev libpng12-dev libtiff4-dev libjasper-dev libavcodec-dev libavformat-dev libswscale-dev libxine-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libv4l-dev libtbb-dev libqt4-dev libfaac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev x264 v4l-utils unzip
mkdir opencv
cd opencv
wget https://github.com/Itseez/opencv/archive/3.0.0-beta.zip
unzip 3.0.0-beta.zip
cd opencv-3.0.0-beta
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D WITH_QT=ON -D WITH_OPENGL=ON ..
make
sudo make install
sudo /bin/bash -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
sudo ldconfig

ちなみにビルドのためのスクリプトは以下のページを参考にさせていただきました(というかほぼコピー)

Installing OpenCV 3.0.0 on Ubuntu 14.04

2. GTestのインストール


GTestはUbuntuだとlibgtest-devというパッケージからインストールできるのですが、インストールされるのはヘッダとソースなので、これを自分でビルドしないといけません。

ちなみにインストールされる場所はヘッダが/usr/incllude/gtest、ソースが/usr/src/gtestです。

以下ビルドのためのスクリプトです。ビルド後にできるライブラリlibgtest.aとlibgtest_main.aは/usr/local/libに移動しています。

sudo apt-get install libgtest-dev
cd /usr/src/gtest
sudo cmake .
sudo cmake --build .
sudo mv libg* /usr/local/lib

3. CMakeファイルの用意


通常CMakeでfind_packageを呼べばおおよそのファイルは見つけてくれるはずなのですが、Travis上ではOpenCVは見つかってもGTestは見つけてくれません。

そこで、必要な変数を環境変数にエクスポートしてCMakeファイル内で使うということをします。

まずcmakeを実行する前に、以下のエクスポートを行います。

export GTEST_LIBRARY=/usr/local/lib/libgtest.a
export GTEST_MAIN_LIBRARY=/usr/local/lib/libgtest_main.a
export GTEST_INCLUDE_DIRS=/usr/include

これができたら次のコードをCMakeLists.txtに追加します。

# Test for Point
set(POINT_SOURCE_FILES test_source.cpp)

add_executable(test_program ${POINT_SOURCE_FILES})
target_link_libraries(test_program ${GTEST_LIBRARY})
target_link_libraries(test_program ${GTEST_MAIN_LIBRARY})
target_link_libraries(test_program ${OpenCV_LIBS})

add_test(NAME test_program COMMAND test_program)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS test_point test_random)

# Include directories
include_directories(${CMAKE_CURRENT_LIST_DIR})
include_directories(${GTEST_INCLUDE_DIRS})
include_directories(${OpenCV_INCLUDE_DIRS})

上記のコードの中でtest_programというのが実際に作られるプログラム名になりますので、適宜読み替えていただけると助かります。

おおむねコード内容はお分かりいただけるかと思うのですが、大事なポイントは2つあります。

  1. GTestをOpenCVよりも先にリンクする
  2. add_custom_testを使ってmake checkからテストが走るようにする

1つ目のポイントについてですが、OpenCVはGTestを一部用いてテストしているためか、OpenCVを先にリンクすると、GTestの関数が重複定義でリンクエラーになります。

2つ目のポイントは僕の理解不足かもしれませんが、CMakeからmake testが呼び出されなかったため、custom testを使ってテストを呼び出しているというだけです。

これでcmakeを実行すればプログラムがビルドでき、さらにmake checkでテストが走ります。

4. Code Coverageを取る


Web上でいろいろ調べてみるとcpp-coverallsというPythonのプログラムが見つかるのですが、サンプル通りに書いても動かないのと、使い方についての解説が少なすぎるのとであきらめました。

これとは別にrubygemから落とせるlcov-coverallsというプログラムを使ってカバレッジをCoverallsに送信します。

やらなければならないことは大きく分けて2つです。

1つ目はgccのコンパイル時引数に–coverageというのを追加し、さらに-g -O0で最適化をオフにすることです。

これはCMakeLists.txtに次のコードを追加すればOKです。

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")

2つ目は当たり前ですがgemからlcov-coverallsを落とす必要があります。

まず、lcov-coverallsをwgetしてきて、そのあとでgem installです。

wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz
tar xf lcov_1.11.orig.tar.gz
sudo make -C lcov-1.11/ install
gem install coveralls-lcov

ここまでできたら、テスト実行後にlcov-coverallsを使ってカバレッジを送るだけです。

lcov --directory . --capture --output-file coverage.info
lcov --remove coverage.info 'tests/*' 'examples/*' '/usr/*' 'opencv/*' 'CMakeFiles/*' --output-file coverage.info
lcov --list coverage.info
coveralls-lcov --repo-token (Coverallsのトークン) coverage.info

まとめ


これでめでたく、OpenCV + GTestでテストを走らせてなおかつカバレッジも取れます!

結構さらっと書いてますが、サイドワークでちょこちょこやって1週間以上はかかったんじゃないかな?

実際の.travis.ymlを見たい方はこちらからどうぞ → https://github.com/tatsy/lime

かなり用途が限られている気もしますが、何かの参考にしていただければ幸いです。

それでは、最後までおよみいただきありがとうございました。