このリポジトリは、さまざまな CI サービスをセットアップする方法と、分析ツールをこれらのサービスに統合する方法の簡単な例を提供します。これらのツールは、包括的なソフトウェア開発プロセス (SDP) の一部として使用する必要があり、C または C++ アプリケーションの開始テンプレートとしても使用できます。次の CI ツールが使用され、Windows、Cygwin、Linux、macOS のテスト サポートを提供します。
次のチェックが実行されます。
次の実際のプロジェクトでは、SDP の一部としてこれらのさまざまなテクニックが使用されています。
このリポジトリはほとんどのシステムで実行できるようになりますが、サポートされているプラットフォームとその依存関係は次のとおりです。
sudo apt-get install git build-essential cmake
setup-x86_64.exe -q -P git,make,gcc-core,gcc-g++,cmake
次のパッケージをインストールします。
この例をコンパイルしてインストールするには、次の手順を使用します。
git clone https://github.com/ainfosec/ci_helloworld.git
mkdir ci_helloworld/build
cd ci_helloworld/build
cmake ..
make
make test
git clone https://github.com/ainfosec/ci_helloworld.git
mkdir ci_helloworld/build
cd ci_helloworld/build
cmake -G "NMake Makefiles" ..
nmake
nmake test
git clone https://github.com/ainfosec/ci_helloworld.git
mkdir ci_helloworld/build
cd ci_helloworld/build
cmake -G "Visual Studio 15 2017 Win64" ..
msbuild ci_helloworld.sln
ctest
git clone https://github.com/ainfosec/ci_helloworld.git
mkdir ci_helloworld/build
cd ci_helloworld/build
cmake ..
make
make test
以下では、このプロジェクトで使用される CI サービスに統合されているすべての分析ツールについて、その仕組みの説明も含めて説明します。
CI は、doxygen を使用してドキュメントの不足をチェックするようにセットアップされています。このプロジェクトで使用されているほとんどの分析ツールとは異なり、doxygen の make ターゲットはなく、代わりに次のスクリプトで doxygen を手動で使用して実行されます。
- doxygen .doxygen.txt
- |
if [[ -s doxygen_warnings.txt ]]; then
echo "You must fix doxygen before submitting a pull request"
echo ""
cat doxygen_warnings.txt
exit -1
fi
このスクリプトはソース コードに対して doxygen を実行し、警告はdoxygen_warnings.txt
というファイルに書き込まれます。このファイルが空の場合は、doxygen 分析に合格し、すべてのコードが.doxygen.txt
構成ファイルの設定に基づいて文書化されていることを意味します。このファイルが空でない場合、テストは失敗し、doxygen によって生成された警告が出力されます。
git diff --check
ホワイトスペース エラーがリポジトリにチェックインされたときを検出する簡単な方法を提供し、ファイル末尾の改行が欠落しているか、または多すぎる改行が含まれているかをチェックします。このチェックの詳細については、こちらをご覧ください。このチェックは、PR に特定の変更とは関係のない変更が含まれている場合、開発者にとって非常に役立ちます。
- |
if [[ -n $(git diff --check HEAD^) ]]; then
echo "You must remove whitespace before submitting a pull request"
echo ""
git diff --check HEAD^
exit -1
fi
このチェックは単にgit diff --check
実行するだけで、チェックが失敗した場合はエラーが返されます。この問題が発生した場合、ユーザーが確認できるように差分が表示されます。
ソース コードの書式設定は、コードの外観と操作性の一貫性を保つための優れた方法です。ソースのフォーマットに関する問題は、全員がそれを使用していない限り、開発者の PR には特定の変更とは関係のない変更が含まれることです。さらに悪いことに、ソースのフォーマットを定期的に修正しようとすると、ソースをフォーマットするたびにリポジトリの Git 履歴が破壊されてしまうことです。したがって、ソース形式を使用する場合は、すべてのコードの差分をチェックして、形式が正しいことを確認する必要があります。
この例では Astyle を使用しますが、Clang Format も機能します。 Astyle を簡単な方法でサポートするために、開発者がmake format
実行するだけでソース コードをフォーマットできるようにする make ターゲットを提供します。これを行うには、まず Astyle を取得する必要があります。
list ( APPEND ASTYLE_CMAKE_ARGS
"-DCMAKE_INSTALL_PREFIX= ${CMAKE_BINARY_DIR} "
)
ExternalProject_Add(
astyle
GIT_REPOSITORY https://github.com/Bareflank/astyle.git
GIT_TAG v1.2
GIT_SHALLOW 1
CMAKE_ARGS ${ASTYLE_CMAKE_ARGS}
PREFIX ${CMAKE_BINARY_DIR} /astyle/ prefix
TMP_DIR ${CMAKE_BINARY_DIR} /astyle/tmp
STAMP_DIR ${CMAKE_BINARY_DIR} /astyle/stamp
DOWNLOAD_DIR ${CMAKE_BINARY_DIR} /astyle/download
SOURCE_DIR ${CMAKE_BINARY_DIR} /astyle/src
BINARY_DIR ${CMAKE_BINARY_DIR} /astyle/ build
)
この cmake ロジックは、ExternalProject_Add を使用して、Astyle を自動的にダウンロードし、プラットフォーム用にコンパイルして、カスタム make ターゲットで使用できるようにビルド ディレクトリにインストールします。簡単にするために、ビルド システムを Astyle のカスタム Makefile セットから CMake ビルド システムに変更する、独自のパッチ適用済みバージョンの Astyle を使用していることに注意してください。
list ( APPEND ASTYLE_ARGS
--style=1tbs
--lineend=linux
-- suffix =none
--pad-oper
--unpad-paren
--break-closing-brackets
--align-pointer= name
--align-reference= name
--indent-preproc-define
--indent-switches
--indent-col1-comments
--keep-one-line-statements
--keep-one-line-blocks
--pad-header
--convert-tabs
--min-conditional-indent=0
--indent=spaces=4
--close-templates
--add-brackets
--break-after-logical
${CMAKE_SOURCE_DIR} / include /*.h
${CMAKE_SOURCE_DIR} /src/*.cpp
${CMAKE_SOURCE_DIR} / test /*.cpp
)
if ( NOT WIN32 STREQUAL "1" )
add_custom_target (
format
COMMAND ${CMAKE_SOURCE_DIR} /bin/astyle ${ASTYLE_ARGS}
COMMENT "running astyle"
)
else ()
add_custom_target (
format
COMMAND ${CMAKE_SOURCE_DIR} /bin/astyle.exe ${ASTYLE_ARGS}
COMMENT "running astyle"
)
endif ()
カスタムの astyle make ターゲットを作成するには、上記の CMake コードを使用します。これにより、CMake はプラットフォームに応じて結果として得られる astyle バイナリを参照し、このプロジェクトに固有の書式設定オプションとソース ファイルを備えた astyle を提供します。
- cmake -DENABLE_ASTYLE=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make format
- |
if [[ -n $(git diff) ]]; then
echo "You must run make format before submitting a pull request"
echo ""
git diff
exit -1
fi
最後に、コード変更が Astyle 設定に従っていることを各 PR で確認するために、上記のコードを Travis CI スクリプトに追加します。これにより、 make format
ターゲットが作成され、それが実行されてコードがフォーマットされます。 make format
コードをフォーマットすると、 git diff
使用して検出できる diff が作成されます。 diff が作成されない場合は、すべてのソースが Astyle 構成に従っており、テストに合格したことを意味します。
Clang Tidy は静的分析を提供します。このツールのサポートは、次のコードを CMakeLists.txt に追加することで開始されます。
set (CMAKE_EXPORT_COMPILE_COMMANDS ON )
これにより、CMake に対して、フラグや定義を含む、プロジェクトのコンパイルに使用されるすべてのコンパイル命令を記録するように指示されます。 Clang Tidy はこの情報を使用して、コンパイル時と同じ方法でプロジェクトを静的に分析します。このアプローチの利点は、精度が大幅に向上することです。このアプローチの主な欠点は、Clang Tidy がこのコンパイル データベースに表示されないファイル (ヘッダー ファイルなど) を静的に分析するのが苦手であることです。このため、ヘッダーを解析したい場合は、コンパイル データベースに含まれるソース ファイルにヘッダーを含める必要があります。
list ( APPEND RUN_CLANG_TIDY_BIN_ARGS
-clang-tidy-binary ${CLANG_TIDY_BIN}
-header- filter =.*
-checks=clan*,cert*,misc*,perf*,cppc*,read*,mode*,-cert-err58-cpp,-misc-noexcept-move-constructor
)
add_custom_target (
tidy
COMMAND ${RUN_CLANG_TIDY_BIN} ${RUN_CLANG_TIDY_BIN_ARGS}
COMMENT "running clang tidy"
)
最後に、Clang Tidy には、使用を簡素化するために独自の make ターゲットが与えられています。ここでは、 run-clang-tidy-4.0.py
スクリプトに、どの Clang Tidy バイナリを使用するか、どのチェックを実行するか、どのヘッダー ファイルを含めるか (それらのすべて) を指示します。 -cert-err58-cpp テストは、catch.hpp からコードをトリガーするためオフにします。また、-misc-noreason-move-constructor は、4.0 ではまだバグがあるため、オフにします。 Clang Tidy の特定のバージョンを選択することに注意してください。Clang Tidy の新しいバージョンごとにバグが修正され、新しいチェックが追加され、使用するバージョンに応じて結果が異なるため、これは重要です。
- cmake -DENABLE_CLANG_TIDY=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make tidy > output.txt
- |
if [[ -n $(grep "warning: " output.txt) ]] || [[ -n $(grep "error: " output.txt) ]]; then
echo "You must pass the clang tidy checks before submitting a pull request"
echo ""
grep --color -E '^|warning: |error: ' output.txt
exit -1;
else
echo -e " 33[1;32mxE2x9Cx93 passed: 33[0m $1";
fi
Travis CI から Clang Tidy を有効にし、その出力をファイルにダンプします。このファイルに「警告」または「エラー」が含まれている場合、テストは不合格となり、Clang Tidy によって報告された問題が修正されるようにユーザーに出力されます。これにより、すべての PR が静的にチェックされることが保証されます。
CppCheck も静的解析ツールです。
list ( APPEND CPPCHECK_CMAKE_ARGS
"-DCMAKE_INSTALL_PREFIX= ${CMAKE_BINARY_DIR} "
)
ExternalProject_Add(
cppcheck
GIT_REPOSITORY https://github.com/danmar/cppcheck.git
GIT_TAG 1.79
GIT_SHALLOW 1
CMAKE_ARGS ${CPPCHECK_CMAKE_ARGS}
PREFIX ${CMAKE_BINARY_DIR} /external/cppcheck/ prefix
TMP_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/tmp
STAMP_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/stamp
DOWNLOAD_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/download
SOURCE_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/src
BINARY_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/ build
)
Ubuntu 14.04 が提供する CppCheck のバージョンは古く、C++11 を十分にサポートしていないため、GitHub から特定のバージョンの CppCheck を取得し、プロジェクトのすべてのユーザーが同じバージョンを使用できるようにします。
list ( APPEND CPPCHECK_ARGS
--enable=warning,style,performance,portability,unusedFunction
--std=c++11
--verbose
--error-exitcode=1
-- language =c++
-DMAIN=main
-I ${CMAKE_SOURCE_DIR} / include
${CMAKE_SOURCE_DIR} / include /*.h
${CMAKE_SOURCE_DIR} /src/*.cpp
${CMAKE_SOURCE_DIR} / test /*.cpp
)
add_custom_target (
check
COMMAND ${CMAKE_BINARY_DIR} /bin/cppcheck ${CPPCHECK_ARGS}
COMMENT "running cppcheck"
)
次に、新しく構築した CppCheck アプリケーションのカスタム ターゲットを追加し、すべてのチェック (衒学的警告を除く) を有効にし、すべてのソース ファイルをチェックするように CppCheck に指示します。 CppCheck は MAIN=main であることを認識する必要があることに注意してください。そうでない場合は、main 関数が実行されていないと判断され、次のいずれかの場合に Travis CI が失敗したテストを報告するように、CppCheck に 0 以外のエラー コードでエラーを通知する必要があります。チェックは失敗します。
- cmake -DENABLE_CPPCHECK=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make check
Travis CI テストの実行は、CppCheck をオンにしてカスタム make ターゲットを実行するのと同じくらい簡単です。
Coverity Scan も静的分析ツールで、見つけにくいコードの構造的問題を見つけるのに非常に優れています。 Coverity Scan にアクセスできる場合は、SDP に追加する価値があります。
- os : linux
env :
- TEST="Coverity Scan"
addons :
apt :
sources :
- ubuntu-toolchain-r-test
packages :
- gcc-6
- g++-6
coverity_scan :
project :
name : " ainfosec/ci_helloworld "
description : " A simple example of how to setup a complete CI environment for C and C++ "
notification_email : [email protected]
build_command_prepend : " cmake -DCMAKE_CXX_COMPILER=g++-6 .. "
build_command : " make "
branch_pattern : master
script :
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
Coverity Scan のセットアップも非常に簡単です。上記の Travis CI テストは、プロジェクトを登録した後に Web サイトから切り取って貼り付けたものです。私たちがしなければならないのは、Coverity Scan にソース コードがどのようにコンパイルされるかを伝えるソースをコンパイルすることだけです。そこから、Web サイトはディレクトリを除外し、コードの問題を確認する手段を提供します。この例では、マスターへの変更の数が少ないため、マスターへのすべての変更に対してスキャンを実行しますが、1 日に多くのマージが行われる大規模なプロジェクトでは、Coverity Scan はスキャンに特定の coverity_scan ブランチを使用することを提案します。これが完了した場合は、master ブランチを取得し、それを毎晩 coverity_scan ブランチにプッシュすることで、夜間のスキャンをセットアップする必要があります。このようにして、Coverity Scan の問題を迅速に特定できます。
Codecov は強力でありながら、セットアップが簡単なカバレッジ ツールです。
if (ENABLE_COVERAGE)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -g " )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -O0" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fprofile-arcs" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -ftest-coverage" )
set ( CMAKE_EXE_LINKER_FLAGS " ${CMAKE_EXE_LINKER_FLAGS} --coverage" )
endif ()
カバレッジを設定するには、コンパイラで GCOV サポートを有効にする必要があります (GCC または Clang を想定しています)。このサポートが有効になると、 make test
実行すると、Codecov が分析できるカバレッジ統計が生成され、どのコードが単体テストされているか、またはされていないかをレポートできます。
- cmake -DENABLE_COVERAGE=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make test
- cd ..
- bash <(curl -s https://codecov.io/bash)
Travis CI テストは、単体テストをコンパイルして実行し、Codecov の bash スクリプトを実行するだけで簡単です。これが完了すると、結果は Codecov の Web サイトで確認できます。
カバーオールもカバー ツールです。
if (ENABLE_COVERAGE)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -g " )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -O0" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fprofile-arcs" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -ftest-coverage" )
set ( CMAKE_EXE_LINKER_FLAGS " ${CMAKE_EXE_LINKER_FLAGS} --coverage" )
endif ()
Codecov と同様に、GCOV を有効にする必要があります。
- pip install --user git+git://github.com/eddyxu/cpp-coveralls.git
- cmake -DENABLE_COVERAGE=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make test
- cd ..
- |
coveralls --build-root build --gcov-options '-lp'
-e build/external
-e build/include
-e build/CMakeFiles/3.8.0
-e build/CMakeFiles/feature_tests.c
-e build/CMakeFiles/feature_tests.cxx
Codecov とは異なり、Coveralls はセットアップがはるかに困難です。 Codecov は、Git リポジトリにあるファイルを追跡し、リポジトリ内のファイルのレポートのみを生成します。一方、Coveralls は、CMake によって生成されたファイルを含む、表示されるすべてのファイルのカバレッジ レポートを生成します。 Coveralls には、カバレッジ データをサーバーにレポートするための単純な bash スクリプトもありませんが、代わりに、GCOV データを収集するための外部 C++ 固有ツールのインストールが必要です。これらの理由から、cpp-coveralls をインストールし、収集されるべきではない特定のファイル/ディレクトリを除外するように指示する必要があります。
Google Sanitizers は、GCC および Clang/LLVM に含まれる動的分析ツールです。
if (ENABLE_ASAN)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -g" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -O1" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fuse-ld=gold" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=address" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=leak" )
endif ()
if (ENABLE_USAN)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fuse-ld=gold" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=undefined" )
endif ()
if (ENABLE_TSAN)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fuse-ld=gold" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=thread" )
endif ()
各消毒剤は個別に実行する必要があるため、消毒剤グループごとに 1 つのテストが行われます。各セットのフラグは、Google の GitHub ページおよび Clang の使用法ドキュメントにあります。
- cmake -DENABLE_ASAN= ON -DCMAKE_CXX_COMPILER= "g++-6" ..
- make
- make test
テストごとに、特定のチェックと単体テストをオンにします。チェックが失敗すると、単体テストは 0 以外の終了コードで終了し、Travis CI がテストに失敗します。 GCC と Clang の各新しいバージョンにはより優れたサポートが付属しているため、他のツールと同様に、特定のバージョンを使用する必要があることに注意してください。
Valgrind は、リーク検出を提供するもう 1 つの動的分析ツールです。
set (MEMORYCHECK_COMMAND_OPTIONS " ${MEMORYCHECK_COMMAND_OPTIONS} --leak-check=full" )
set (MEMORYCHECK_COMMAND_OPTIONS " ${MEMORYCHECK_COMMAND_OPTIONS} --track-fds=yes" )
set (MEMORYCHECK_COMMAND_OPTIONS " ${MEMORYCHECK_COMMAND_OPTIONS} --trace-children=yes" )
set (MEMORYCHECK_COMMAND_OPTIONS " ${MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1" )
Valgrind を実行する最も簡単な方法は、エラー ロジックを処理する CMake の組み込みサポートを使用することです。このため、CMake にどのようなフラグを Valgrind に与えるかを指示する必要があります。この場合、すべてのチェックを有効にし、0 以外の終了コードで終了するように Valgrind に指示します。これにより、チェックが失敗した場合、Travis CI はテストに失敗します。
- cmake -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- ctest -T memcheck
テストを実行するには、コードをコンパイルし、ctest を使用して単体テストを実行し、memcheck モードを有効にするだけです。
このプロジェクトは MIT ライセンスに基づいてライセンスされています。