# C/C++の開発環境 - [C/C++の開発環境](#ccの開発環境) - [Linter](#linter) - [導入方法](#導入方法) - [Dockerを活用する](#dockerを活用する) - [Linterの使い方](#linterの使い方) - [clang-tidy の使い方(C++向け)](#clang-tidy-の使い方c向け) - [ccppcheck の使い方(C / C++ 両対応)](#ccppcheck-の使い方c--c-両対応) - [テスト](#テスト) - [テスト環境を構築する](#テスト環境を構築する) - [Doc(ドキュメンテーション)](#docドキュメンテーション) - [環境構築](#環境構築) - [Dockerを活用する](#dockerを活用する-1) - [doxygen 使い方](#doxygen-使い方) - [CI / CDによる実行](#ci--cdによる実行) - [Doxyfileの設定](#doxyfileの設定) - [Docコメントの書き方](#docコメントの書き方) ## Linter ライブラリの候補 * **clang-tidy** * 精度はかなり高い * C++向け(Cはカバー範囲が狭い) * **cppcheck** * C/C++ 両方対応・軽量 * 導入が簡単にできる ### 導入方法 **Macの場合** ```sh brew install cppcheck llvm # パスの追加が必要 export PATH="/opt/homebrew/opt/llvm/bin:$PATH" clang-tidy --version cppcheck --version ``` * llvm: clang-tidy は llvm に含まれています **Linux(Ubuntu)の場合** ```sh sudo apt install cppcheck clang-tidy clang-tidy --version cppcheck --version ``` #### Dockerを活用する [Dockerfileはこちら](../Dockerfile.devtools) Dockerイメージをビルドする ```sh docker build -f Dockerfile.devtools -t c-dev-tools . ``` ```sh # docker run --rm -v "$(pwd)":/work -w /work c-dev-tools <コマンド> ``` ### Linterの使い方 #### clang-tidy の使い方(C++向け) **単一ファイルをチェックする例** ```sh clang-tidy src/cpp/hello.cpp -- -Iinclude -std=c++17 # Docker docker run --rm -v "$(pwd)":/work -w /work clang-tidy src/cpp/hello.cpp -- -Iinclude -std=c++17 ``` * `--`以降がコンパイラフラグ(g++に渡すものと同じ) * -Iinclude : ヘッダファイルのパス * -std=c++17 : 使用している C++ のバージョン **チェック内容を絞る使い方** ```sh clang-tidy src/cpp/hello.cpp \ -checks='modernize-*,bugprone-*,readability-*' \ -- -Iinclude -std=c++17 ``` よく使うチェックカテゴリ: * bugprone-* : バグにつながるコード * modernize-* : モダンC++スタイルへの改善提案 * readability-* : 可読性の改善 **プロジェクト全体** CMake + compile_commands.jsonがある場合に以下の内容でできます (clang-tidy は「コンパイル情報」がないと正しく解析できない) compile_commands.jsonについては別途解説します。 ```sh mkdir -p build cd build cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. # プロジェクト全体に対して実行 run-clang-tidy -p build ``` #### ccppcheck の使い方(C / C++ 両対応) cppcheckはコンパイル不要で実行できる静的解析ツールです。 CでもC++でも同じコマンドで使えます。 **基本的な使い方** ```sh cppcheck src/ # Docker docker run --rm -v "$(pwd)":/work -w /work c-dev-tools cppcheck src/ ``` **チェックレベルを広げる(おすすめ)** ```sh cppcheck --enable=warning,style,performance,portability src/ # Docker docker run --rm -v "$(pwd)":/work -w /work c-dev-tools \ cppcheck --enable=warning,style,performance,portability src/ ``` * warning : 危険なコードやバグの可能性 * style : コーディングスタイル上の問題 * performance : 非効率なコード * portability : 環境依存のコード ## テスト テストフレームワークの選定 * **C** * Unity: * 最軽量・C専用 * C言語の組込み開発でもよく使われる * シングルヘッダに近い軽量テストツール * doctest / googletest の C版のような位置付け * CMocka: Unity より“しっかりしたテスト”をしたいときに最適 * Criterion: C言語でも“近代的なテスト開発”をしたい場合に良い * **C++** * GoogleTest: * C++テストで最も使われる * 機能が豊富:モック、パラメトリック、DeathTestなど * Catch2: シンプルで読みやすいテストを作りたい人向け * doctest: 個人開発や高速実行が必要なプロジェクトに最適 ### テスト環境を構築する * Unity(C言語の軽量テストフレームワーク)はパッケージとして提供されていません。https://github.com/ThrowTheSwitch/Unityから必要なファイルをダウンロードして使う ```sh # unity.c,unity.h,unity_internals.h git clone https://github.com/ThrowTheSwitch/Unity /opt/unity ``` * Alpine(musl libc)ではGTestのABIが合わず、gtest が正常にビルドできないケースが多い * doctestとCatch2は普通にビルドで使えます [Dockerfileはこちら](../Dockerfile.testtools) テスト用のDockerイメージをビルドする ```sh docker build -f Dockerfile.testtools -t c-test-tools . ``` ## Doc(ドキュメンテーション) C / C++ の自動ドキュメンテーションをしたい場合、 Doxygen(+Graphviz)が圧倒的スタンダードで、最もおすすめです。 * C / C++ / Java / Python などメジャー言語に対応 * コメントを解析して HTML / PDF / Markdown などへ出力 * 関数・構造体・クラスの関係図(UML・依存グラフ)を自動生成 * C++ テンプレートや名前空間にも対応 * Graphvizを入れれば図が自動で描かれる ### 環境構築 **Macの場合** ```sh brew install doxygen graphviz ``` **Linux(Ubuntu)の場合** ```sh sudo apt install doxygen graphviz ``` #### Dockerを活用する [Dockerfileはこちら](../Dockerfile.devtools) Dockerイメージをビルドする ```sh docker build -f Dockerfile.devtools -t c-dev-tools . ``` Linuxでコマンドを実行する ```sh mkdir -p docs # docker run --rm -v "$(pwd)":/work -w /work/docs c-dev-tools <コマンド> # 初期化コマンド docker run --rm -v "$(pwd)":/work -w /work/docs c-dev-tools doxygen -g # ドキュメントを生成する docker run --rm -v "$(pwd)":/work -w /work/docs c-dev-tools doxygen Doxyfile ``` ### doxygen 使い方 **設定ファイルを生成** ```sh doxygen -g ``` Doxyfileが作成される **ドキュメント生成** ```sh doxygen Doxyfile ``` * html/ に HTML ドキュメント * latex/ に PDF 用のファイルが出力される(必要なら make) ### CI / CDによる実行 **Git Actionsで生成の場合** ```yaml - name: Generate Doxygen docs run: doxygen docs/Doxyfile - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./docs/html ``` ### Doxyfileの設定 `docs/Doxyfile`を設定する * `PROJECT_NAME`を実際のプロジェクト名に変更する ```sh # ドキュメント化したいディレクトリ INPUT = ../src ../include # INPUT 内を再帰的に探索 RECURSIVE = YES # C向け出力最適化 OPTIMIZE_OUTPUT_FOR_C = YES # 全シンボル抽出 EXTRACT_ALL = YES ``` 図形の設定(クラス図などの生成) ```sh # クラス図の生成を有効にする HAVE_DOT = YES CLASS_DIAGRAMS = YES # コールグラフと呼び出しグラフを有効にする CALL_GRAPH = YES CALLER_GRAPH = YES # グラフとダイアグラムのサポートを有効にする DOT_GRAPH = YES DOT_CLEANUP = YES # 詳細なクラス図を生成する UML_LOOK = YES ``` ### Docコメントの書き方 C言語の場合 ```c /** * @brief 二数の最大値を返す関数 * @param a 整数 * @param b 整数 * @return 最大値 */ int max(int a, int b); ``` C++言語の場合 ```c /** * @class User * @brief ユーザー情報を扱うクラス */ class User { public: /** * @brief コンストラクタ */ User(std::string name, int age); /** * @brief 名前を取得する */ std::string getName() const; ```