.NET プロジェクトにおける RelWithDebInfo ビルド構成

1 概要

RelWithDebInfo (Release with Debug Information) は、リリース最適化を適用しながらデバッグ情報も含めるビルド構成です。CMake などのビルドシステムで一般的に使用されている概念を .NET プロジェクトに適用したものです。

2 RelWithDebInfo の意義

2.1 標準的なビルド構成との比較

.NET プロジェクトでは、標準で以下の2つのビルド構成が提供されています:

構成 最適化 デバッグシンボル 用途
Debug 無効 有効 開発・デバッグ時
Release 有効 無効(または限定的) 本番リリース時(デバッグ情報不要の場合)
RelWithDebInfo 有効 有効 本番リリース時・パフォーマンス測定・トラブルシューティング

2.2 RelWithDebInfo が有用な場面

  1. 本番リリース時の推奨構成
    • 最適化によるパフォーマンス維持
    • デバッグシンボルにより、本番環境での問題発生時に詳細なスタックトレースを取得可能
    • クラッシュダンプ解析時に関数名やソースファイル情報が利用可能
    • .pdb ファイルをシンボルサーバーに配置することで、必要時のみ利用可能
  2. パフォーマンス測定・プロファイリング
    • 本番環境と同等の最適化された状態でプロファイリング
    • デバッグシンボルにより、ボトルネックの関数名・行番号を特定可能
    • CPU プロファイラーやメモリプロファイラーでの詳細な解析
  3. 本番環境のトラブルシューティング
    • 最適化されたコードで問題を正確に再現
    • エラーログやスタックトレースに関数名やソースファイル情報が含まれる
    • デバッガーをアタッチしての調査が可能
  4. 統合テスト・受け入れテスト
    • 本番リリースと同じビルド構成でテスト実行
    • 問題発生時のデバッグが容易
    • パフォーマンステストでの正確な測定
  5. 継続的インテグレーション (CI)
    • デフォルトのビルド構成として設定することで、開発中も本番に近い最適化を常に適用
    • パフォーマンス劣化の早期発見
    • デバッグシンボルを含むため、CI でのテスト失敗時の調査が容易

3 .NET における RelWithDebInfo の実装

3.1 構成の定義

RelWithDebInfo 構成は、以下の MSBuild プロパティで定義されます。

<PropertyGroup Condition="'$(Configuration)' == 'RelWithDebInfo'">
  <Optimize>true</Optimize>
  <DebugType>portable</DebugType>
  <DebugSymbols>true</DebugSymbols>
</PropertyGroup>

3.1.1 プロパティの説明

  • Optimize: true に設定することで、Release と同等のコンパイラ最適化を有効化
  • DebugType: portable を指定することで、クロスプラットフォーム対応の .pdb ファイルを生成
  • DebugSymbols: true に設定することで、デバッグシンボルの生成を有効化

4 実装手順

4.1 1. 各プロジェクトファイル (.csproj) への構成追加

プロジェクト内のすべての .csproj ファイルに RelWithDebInfo 構成を追加します。

追加場所: </PropertyGroup><ItemGroup> の間など、適切な位置

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <!-- 既存のプロパティ -->
  </PropertyGroup>

  <!-- RelWithDebInfo 構成の追加 -->
  <PropertyGroup Condition="'$(Configuration)' == 'RelWithDebInfo'">
    <Optimize>true</Optimize>
    <DebugType>portable</DebugType>
    <DebugSymbols>true</DebugSymbols>
  </PropertyGroup>

  <ItemGroup>
    <!-- 既存のアイテム -->
  </ItemGroup>
</Project>

4.2 2. ソリューションファイル (.sln) への構成追加

4.2.1 2.1 ソリューション構成の追加

GlobalSection(SolutionConfigurationPlatforms) に RelWithDebInfo を追加します。

Global
  GlobalSection(SolutionConfigurationPlatforms) = preSolution
    RelWithDebInfo|Any CPU = RelWithDebInfo|Any CPU
    Debug|Any CPU = Debug|Any CPU
    Release|Any CPU = Release|Any CPU
  EndGlobalSection

重要: RelWithDebInfo を最初に配置することで、一部の IDE でデフォルト構成として認識されやすくなります。

4.2.2 2.2 各プロジェクトの構成マッピング追加

GlobalSection(ProjectConfigurationPlatforms) で、各プロジェクトに RelWithDebInfo のマッピングを追加します。

GlobalSection(ProjectConfigurationPlatforms) = postSolution
  {PROJECT-GUID}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|Any CPU
  {PROJECT-GUID}.RelWithDebInfo|Any CPU.Build.0 = RelWithDebInfo|Any CPU
  {PROJECT-GUID}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  {PROJECT-GUID}.Debug|Any CPU.Build.0 = Debug|Any CPU
  {PROJECT-GUID}.Release|Any CPU.ActiveCfg = Release|Any CPU
  {PROJECT-GUID}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection

各プロジェクトの GUID について、同様のマッピングを追加します。

4.3 3. Directory.Build.props でのデフォルト構成設定

プロジェクトのルートディレクトリに Directory.Build.props ファイルを作成し、デフォルトのビルド構成を RelWithDebInfo に設定します。

<Project>
  <!--
    .NET用 Directory.Build.props

    このファイルは、.NET SDK のビルドシステムにより自動的に認識され、
    このディレクトリおよびサブディレクトリ内のすべての .csproj プロジェクトに対して
    プロジェクトファイルよりも先に評価されます。

    主な用途:
    - プロジェクト全体で共通のプロパティやビルド設定を一元管理
    - デフォルト値の設定 (プロジェクトファイルで上書き可能)

    参考: https://learn.microsoft.com/ja-jp/visualstudio/msbuild/customize-by-directory
  -->

  <!-- デフォルトのビルド構成を RelWithDebInfo に設定 -->
  <!--
    -c オプション未指定時の動作:
    - dotnet build → RelWithDebInfo でビルド
    - dotnet test → RelWithDebInfo でビルド
    - dotnet run → RelWithDebInfo でビルド

    明示的な構成指定で上書き可能:
    - dotnet build -c Debug → Debug でビルド
    - dotnet build -c Release → Release でビルド
  -->
  <PropertyGroup>
    <Configuration Condition="'$(Configuration)' == ''">RelWithDebInfo</Configuration>
  </PropertyGroup>
</Project>

4.3.1 Directory.Build.props の仕組み

  • このファイルは、.NET SDK により自動的に検出され、すべてのプロジェクトファイルよりも先に評価されます
  • プロジェクトファイル内で <Configuration> を設定することもできますが、SDK の評価タイミングの問題で効果がない場合があります
  • Directory.Build.props を使用することで、確実にデフォルト構成を設定できます

5 使用方法

5.1 コマンドラインでのビルド

5.1.1 デフォルト構成でビルド (RelWithDebInfo)

dotnet build

Directory.Build.props の設定により、構成を指定しない場合は RelWithDebInfo でビルドされます。

5.1.2 明示的に構成を指定

dotnet build -c Debug

dotnet build -c Release

dotnet build -c RelWithDebInfo

5.2 テストの実行

dotnet test

dotnet test -c Debug
dotnet test -c RelWithDebInfo

5.3 アプリケーションの実行

dotnet run --project <project-path>

dotnet run --project <project-path> -c Release

5.4 ビルド出力の確認

構成が正しく適用されているかは、ビルド出力のパスで確認できます:

dotnet build

dotnet build -c Debug

6 IDE における対応状況

6.1 Visual Studio Code + C# Dev Kit

制限事項: C# Dev Kit には、UI からビルド構成を選択する機能が現時点で存在しません。

  • ソリューションエクスプローラーでの構成選択 UI がない
  • csharp.preview.improvedLaunchExperience 設定は起動構成の選択用で、ビルド構成の切り替えには使用できない

回避策:
1. 統合ターミナルを使用 (推奨)
- VS Code の統合ターミナルから dotnet build -c <構成> を実行
- Directory.Build.props の設定により、デフォルトで RelWithDebInfo が使用される

  1. tasks.json でビルドタスクを定義
    • .vscode/tasks.json に異なる構成のビルドタスクを作成
    • キーボードショートカットでタスクを実行
  2. launch.json でデバッグ構成を指定
    • デバッグ実行時の構成を変更可能

6.2 Visual Studio (Windows)

  • ソリューションエクスプローラーの上部にある構成ドロップダウンで RelWithDebInfo を選択可能
  • .sln ファイルで RelWithDebInfo を最初に配置することで、デフォルトとして認識されやすい

6.3 JetBrains Rider

  • ツールバーの構成ドロップダウンで選択可能
  • ビルド構成の管理 UI が充実

7 ベストプラクティス

7.1 1. 継続的インテグレーション (CI) での使用

RelWithDebInfo をデフォルト構成に設定することで、以下のメリットがあります:

  • パフォーマンス劣化の早期発見: 開発中も常に最適化されたコードでテスト
  • 本番環境に近い状態でのテスト: より実環境に近い条件でのテスト実行
  • 問題発生時のデバッグが容易: デバッグシンボルにより、スタックトレースが詳細

7.2 2. プロジェクト構成の推奨事項

project-root/
+-- Directory.Build.props        # デフォルト構成: RelWithDebInfo
+-- solution.sln                 # RelWithDebInfo を最初に配置
+-- src/
|   +-- Project1/
|   |   +-- Project1.csproj     # RelWithDebInfo 構成を定義
|   +-- Project2/
|       +-- Project2.csproj     # RelWithDebInfo 構成を定義
+-- test/
    +-- Tests/
        +-- Tests.csproj         # RelWithDebInfo 構成を定義

7.3 3. チーム開発での運用

  • Directory.Build.props をリポジトリに含める: チーム全体で同じデフォルト構成を使用
  • ドキュメント化: プロジェクトの README に RelWithDebInfo を使用していることを明記
  • CI/CD パイプラインでの明示的指定: CI では -c RelWithDebInfo を明示的に指定することを推奨

8 トラブルシューティング

8.1 デフォルト構成が適用されない

症状: dotnet build を実行しても Debug でビルドされる

原因と対策:
1. Directory.Build.props がプロジェクトルートに存在するか確認
2. ファイルのエンコーディングが UTF-8 であることを確認
3. XML の構文エラーがないか確認

8.2 C# Dev Kit で RelWithDebInfo が選択できない

症状: C# Dev Kit のソリューションエクスプローラーに RelWithDebInfo が表示されない

対策:
1. VS Code のウィンドウをリロード
2. .sln ファイルが正しく更新されているか確認
3. ソリューションをクローズして再度開く

8.3 ビルド出力のパスが想定と異なる

症状: bin/Debug/ にビルドされる

確認事項:
1. プロジェクトファイルで明示的に <Configuration>Debug</Configuration> が設定されていないか確認
2. IDE の設定で構成がオーバーライドされていないか確認

9 参考資料

10 まとめ

RelWithDebInfo ビルド構成を .NET プロジェクトに追加することで、以下の利点が得られます:

  1. 本番環境での運用改善:
    • リリース最適化によるパフォーマンス維持
    • デバッグシンボルにより、本番環境での問題発生時に詳細なスタックトレースを取得
    • クラッシュダンプやエラーログからの迅速な原因特定
  2. 開発効率の向上:
    • パフォーマンス測定とデバッグを同時に実施可能
    • プロファイリング時に関数名・行番号を特定可能
  3. 品質の向上:
    • 本番環境と同じビルド構成でのテスト実施
    • 最適化による問題の早期発見(Release のみで発生する問題の検出)
  4. トラブルシューティングの効率化:
    • 本番環境での問題再現時にデバッグ情報が利用可能
    • シンボルサーバーとの連携による柔軟な運用

推奨事項: 多くのプロダクションシステムでは、RelWithDebInfo を本番リリースのデフォルト構成として採用しています。デバッグシンボルのオーバーヘッドは最小限であり、トラブルシューティングの効率向上による利点が大きく上回ります。

特に CI/CD パイプラインのデフォルト構成として RelWithDebInfo を採用することで、継続的にパフォーマンスを監視しながら、問題発生時には迅速なデバッグが可能になります。