はじめに
include-what-you-useはC/C++のコードから不要な#includeを洗い出し、前方宣言への置き換えや削除を提案してくれるツールです。コードから不要な#includeが減るとコンパイル時間が短くなり、コードが読みやすくリファクタリングしやすくなります1。不要な#includeを減らすにはまず洗い出しが必要です。この作業はinclude-what-you-useを使うと簡単に済ませることができます。ここではinclude-what-you-useの導入方法とinclude-what-you-useの結果をJenkinsで集計する方法を紹介します。
インストール
- Windows/Macの人はinclude-what-you-use公式HPのdownloadからビルド済バイナリをダウンロードしてください。
- Ubuntuの人はapt-getでインストールできます
ひとつのコードをinclude-what-you-useしてみる
まずはひとつのコードに対してinclude-what-you-useをしてみます。
$ include-what-you-use test.cpp
追加のインクルードパスが必要であれば -I オプションを利用てください。
$ include-what-you-use test.cpp -IhogeLibInclude -IfugaLibInclude
結果はこのようになります。
test.cpp should add these lines:
class Piyo;
test.cpp should remove these lines:
- #include "Fuga.h" // lines 2-2
- #include "Piyo.h" // lines 3-3
The full include-list for test.cpp:
#include "Hoge.h" // for Hoge
class Piyo;
---
この例では#include "Piyo.h"は前方宣言に置き換え、#include "Fuga.h"は削除できることがinclude-what-you-wantにより指摘されています。
プロジェクトにinclude-what-you-useを実行する
プロジェクトがCMakeを利用している場合
いくつかやり方があります。
1. CMAKE_C(XX)_INCLUDE_WHAT_YOU_USEを利用する
cmake3.3以降で使える方法です。通常のコンパイルと並行してinclude-what-you-useします。cmakeするときにCMAKE_C(XX)_INCLUDE_WHAT_YOU_USE変数にinclude-what-you-useへのパスをセットします。
cmake . -DCMAKE_C_INCLUDE_WHAT_YOU_USE=path/to/include_what_you_use -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=path/to/include_what_you_use
2. CMAKE_C(XX)_COMPILERを利用する
コンパイラをinclude-what-you-useに置き換える方法です。cmakeするときにCMAKE_C(XX)_COMPILER変数にinclude-what-you-useへのパスをセットします。このときcmakeによるコンパイラの簡易チェックをパスするために、CMAKE_C(XX)_COMPILER_WORKSを1にセットしなければいけません。
cmake . -DCMAKE_C_COMPILER=path/to/include_what_you_use -DCMAKE_CXX_COMPILER=path/to/include_what_you_use -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER_WORKS=1
CMake以外のビルドシステムを使っている場合
基本的にはコンパイラをinclude-what-you-useに置き換えればよいはずです。(やったことないので正直わかりません)
Jenkinsで集計する
include-what-you-useの結果はJenkins Warning Pluginで集計することができます。
Jenkins Warning Pluginにinclude-what-you-use用のパーサーを追加する
"Jenkinsの管理"->"システムの設定" を開き、"コンパイラの警告"にinclude-what-you-use用の設定をしていきます。"名前"、"リンク名"、"推移レポート名"にはなんでも良いのですがとりあえずinclude-what-you-useを入力してください。"正規表現"には次の内容を入力してください。
(.*) should (.*) these lines:$|^The full include-list for (.*)|(.*) // lines (.*)-(.*)$|(.+)
"マッピングスクリプト"には次のスクリプトを入力してください。
import hudson.plugins.warnings.parser.Warning
import hudson.plugins.analysis.util.model.Priority
public class Line{
def public static String filename;
def public static String category;
}
if (matcher.group(2) == "add" || matcher.group(2) == "remove"){
Line.filename = matcher.group(1);
Line.category = matcher.group(2);
return;
}
if (matcher.group(3) != null){
Line.filename = null;
Line.category = null;
return;
}
if(Line.category == "remove"){
return new Warning(Line.filename, matcher.group(6).toInteger(), "iwyu", Line.category, Line.category + " " + matcher.group(4), Priority.HIGH)
}
else if(Line.category == "add"){
return new Warning(Line.filename, 0, "iwyu", Line.category, Line.category + " " + matcher.group(7).replaceAll("<|>", ""), Priority.LOW)
}
return;
include-what-you-use用のジョブを作成する
- Jenkinsにジョブを新規作成(フリースタイル・プロジェクトのビルド)し、ジョブ内でinclude-what-you-useで全ビルドかけるようなシェルスクリプト・バッチファイルを用意します。
- ジョブの"設定"->"ビルド後の処理"に"コンパイラの警告の集計(scan for compiler warnings)"を追加します。
- "コンパイラの警告の集計"の"パーサー"にinclude-what-you-useを指定します。
- "コンパイラの警告の集計"の"常に実行"にチェックを入れます。
結果の扱い方
基本的にはinclude-what-you-useの提案通りにコードを修正していけばよいのですが例外があります。include-what-you-useは「他のヘッダファイルで宣言されたシンボル(型や関数、マクロなど)を利用するときは、それらが宣言されているヘッダファイルを直接#includeするべきだ」というポリシーを持っています。このポリシーと相容れないコードについては、include-what-you-useの提案を無視しなければいけません。例えばクライアントコードにおける#includeの数を減らすため、もしくはモジュール外に提供するシンボルを限定するために複数の#includeをまとめているヘッダファイルなどはinclude-what-you-useのポリシーに反するものです。(まとめヘッダファイルの#includeを削除し、まとめヘッダファイルが#includeしていた実際にシンボルが宣言されているヘッダファイルを#includeするように提案されてしまいます。)