Skip to content

Commit

Permalink
C++26対応として<debugging>ライブラリを追加 (close #1232)
Browse files Browse the repository at this point in the history
  • Loading branch information
faithandbrave committed Sep 18, 2024
1 parent 806a8c8 commit 07e9e02
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 2 deletions.
1 change: 1 addition & 0 deletions GLOBAL_QUALIFY_LIST.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
* <cstdio>[link /reference/cstdio.md]
* <cstdlib>[link /reference/cstdlib.md]
* <ctime>[link /reference/ctime.md]
* <debugging>[link /reference/debugging.md]
* <deque>[link /reference/deque/deque.md]
* std::deque[link /reference/deque/deque.md]
* <exception>[link /reference/exception.md]
Expand Down
2 changes: 1 addition & 1 deletion lang/cpp26.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ C++26とは、2026年中に改訂される予定の、C++バージョンの通
- 文字列エンコーディングを識別するライブラリとして、[`<text_encoding>`](/reference/text_encoding.md.nolink)を追加
- 並行処理におけるデータの参照・更新を行うRCU (Read Copy Update) のライブラリとして、[`<rcu>`](/reference/rcu.md.nolink)を追加
- 並行処理において参照中のデータが更新されないよう保護するハザードポインタのライブラリとして、[`<hazard_pointer>`](/reference/hazard_pointer.md.nolink)を追加
- デバッグサポートのライブラリとして[`<debugging>`](/reference/debugging.md.nolink)を追加
- デバッグサポートのライブラリとして[`<debugging>`](/reference/debugging.md)を追加
- 線形代数ライブラリとして[`<linalg>`](/reference/linalg.md)を追加
- コンパイル時に容量を固定する可変長配列クラスのライブラリとして[`<inplace_vector>`](/reference/inplace_vector.md.nolink)を追加

Expand Down
2 changes: 1 addition & 1 deletion reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@

| ヘッダ | 説明 | 対応バージョン |
|----------------------------------------|------------------|----------------|
| [`<debugging>`](/reference/debugging.md.nolink) | デバッグサポート | C++26 |
| [`<debugging>`](/reference/debugging.md) | デバッグサポート | C++26 |


## <a id="io" href="#io">入出力ライブラリ</a>
Expand Down
42 changes: 42 additions & 0 deletions reference/debugging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# debugging
* debugging[meta header]
* cpp26[meta cpp]

`<debugging>`ヘッダでは、プログラムのデバッグ実行をサポートする機能を提供する。

| 名前 | 説明 | 対応バージョン |
|------|------|----------------|
| [`breakpoint`](debugging/breakpoint.md) | ブレークポイントを設置する (functional) | C++26 |
| [`breakpoint_if_debugging`](debugging/breakpoint_if_debugging.md) | デバッガ実行のみブレークポイントを設置する (functional) | C++26 |
| [`is_debugger_present`](debugging/is_debugger_present.md) | デバッガ実行中か判定する (functional) | C++26 |


## この機能が必要になった背景・経緯
開発プラットフォームによってデバッガやブレークポイントの機能は提供されているが、本ライブラリのようにプログラム中に明示的にブレークポイントを設置し、プログラムとデバッガを対話させることでデバッグ体験が向上することがある。

実装経験としては以下のようなものがあり、これらをこのライブラリで標準化した:

| 開発環境 | 機能 |
|----------|------|
| Microsoft C/C++ Optimizing Compiler | `__debugbreak()`関数 (無条件ブレークポイント) |
| Win32 API | `IsDebuggerPresent()`関数 (デバッガ実行中か判定) |
| LLVM Clang | `__builtin_debugtrap()`組み込み関数 (無条件ブレークポイント) |
| arm Keil, ARM Compiler | `__breakpoint()`関数 (無条件ブレークポイント) |
| Portable Snippetsライブラリ | `psnip_trap()`関数 (無条件ブレークポイント) |
| Debug Breakライブラリ | `debug_break()`関数 (無条件ブレークポイント) |
| Boost.Testライブラリ | `debugger_break()`関数 (無条件ブレークポイント)<br/> `under_debugger()`関数 (出張っg実行中か判定) |
| EASTLライブラリ | `EASTL_DEBUG_BREAK()`マクロ (無条件ブレークポイント)、 |
| Catch2ライブラリ | `CATCH_TRAP`マクロ (無条件ブレークポイント)<br/> `CATCH_BREAK_INTO_DEBUGGER`マクロ (条件付きブレークポイント)<br/> `isDebuggerActive()`関数 (デバッガ実行中か判定) |
| JUCEライブラリ | `JUCE_BREAK_IN_DEBUGGER`マクロ (無条件ブレークポイント)<br/> `juce_isRunningUnderDebugger()`関数、`Process::isRunningUnderDebugger()`関数 (デバッガ実行中か判定) |
| ImGuiライブラリ | `IM_DEBUG_BREAK()`マクロ (無条件ブレークポイント) |
| AWS C SDK | `aws_debug_break()`関数 (条件付きブレークポイント)<br/> `aws_is_debugger_present()`関数 (デバッガ実行中か判定) |
| UnrealEngine | `UE_DEBUG_BREAK`マクロ (条件付きブレークポイント)<br/> `IsDebuggerPresent()`関数 (デバッガ実行中か判定) |


## バージョン
### 言語
- C++26


## 参照
- [P2546R5 Debugging Support](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2546r5.html)
81 changes: 81 additions & 0 deletions reference/debugging/breakpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# breakpoint
* debugging[meta header]
* std[meta namespace]
* function[meta id-type]
* cpp26[meta cpp]

```cpp
namespace std {
void breakpoint() noexcept; // (1) C++26
}
```
## 概要
ブレークポイントを設置する。
この関数は無条件のブレークポイントであり、デバッガがプログラムを監視しているかに関わらずプログラムの一時停止 (ブレーク) を試みる。
## 効果
標準規格としては、この関数の意味論は実装定義である。
実際の動作としては、この関数が呼び出されるとプログラムの実行が一時停止され、以下のいずれかの時点までデバッガに制御が渡される:
- デバッガによってプログラムが終了される、または
- デバッガが、この関数が呼び出されなかったかのようにプログラムの実行を再開する
## 例外
投げない
## 備考
- 実装としては、生成されるコードがプラットフォームに対して可能な限り最小になるように最適化することが期待される。例として、x86ターゲット環境ではINT3命令をひとつだけ生成することが期待される
## 例
```cpp example
#include <print>
#include <debugging>
#include <cmath>
// なんらかの処理
double g(double a, double b) {
return a / b;
}
double f(double a, double b) {
double ret = g(a, b);
if (std::isnan(ret)) {
// 演算結果でNaNが発生したらブレークし、
// デバッガでパラメータ (ローカル変数) などを確認する
std::breakpoint();
}
}
int main() {
double ret = f(2.0, 0.0);
std::println("{}", ret);
}
```
* std::breakpoint[color ff0000]
* std::isnan[link /reference/cmath/isnan.md]

### 出力
```
```


## バージョン
### 言語
- C++26

### 処理系
- [Clang](/implementation.md#clang): 19 [mark noimpl]
- [GCC](/implementation.md#gcc): 14 [mark noimpl]
- [Visual C++](/implementation.md#visual_cpp): 2022 Update 10


## 参照
- [P2546R5 Debugging Support](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2546r5.html)
83 changes: 83 additions & 0 deletions reference/debugging/breakpoint_if_debugging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# breakpoint_if_debugging
* debugging[meta header]
* std[meta namespace]
* function[meta id-type]
* cpp26[meta cpp]

```cpp
namespace std {
void breakpoint_if_debugging() noexcept; // (1) C++26
}
```
## 概要
デバッガ実行のみブレークポイントを設置する。
この関数は条件付きブレークポイントであり、デバッガがプログラムを監視中であればプログラムを一時停止 (ブレーク) するが、そうでなければ何もしないよう動作する。
## 効果
以下と等価:
```cpp
if (is_debugger_present()) {
breakpoint();
}
```
* is_debugger_present()[link is_debugger_present.md]
* breakpoint()[link breakpoint.md]


## 例外
投げない


## 備考
- 実装としては、生成されるコードがプラットフォームに対して可能な限り最小になるように最適化することが期待される。例として、x86ターゲット環境ではINT3命令をひとつだけ生成することが期待される


##
```cpp example
#include <print>
#include <debugging>
#include <cmath>

// なんらかの処理
double g(double a, double b) {
return a / b;
}

double f(double a, double b) {
double ret = g(a, b);
if (std::isnan(ret)) {
// 演算結果でNaNが発生したらブレークし、
// デバッガでパラメータ (ローカル変数) などを確認する
std::breakpoint_if_debugging();
}
}

int main() {
double ret = f(2.0, 0.0);
std::println("{}", ret);
}
```
* std::breakpoint_if_debugging[color ff0000]
* std::isnan[link /reference/cmath/isnan.md]
### 出力
```
```
## バージョン
### 言語
- C++26
### 処理系
- [Clang](/implementation.md#clang): 19 [mark noimpl]
- [GCC](/implementation.md#gcc): 14 [mark noimpl]
- [Visual C++](/implementation.md#visual_cpp): 2022 Update 10
## 参照
- [P2546R5 Debugging Support](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2546r5.html)
93 changes: 93 additions & 0 deletions reference/debugging/is_debugger_present.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# is_debugger_present
* debugging[meta header]
* std[meta namespace]
* function[meta id-type]
* cpp26[meta cpp]

```cpp
namespace std {
bool is_debugger_present() noexcept; // (1) C++26
}
```
## 概要
デバッガ実行中か判定する。
この関数は、デバッガがプログラムを監視中かどうかを判定する。プラットフォーム固有の結果を決定できない場合、ユーザーがこの関数を定義することで柔軟に動作を制御できる。
## 置き換え可能
ユーザーのプログラムでこの関数を定義することで、標準ライブラリで定義されるデフォルトの動作を置き換えることができる。
## 要求される振る舞い
- この関数は事前条件をもたないこと
## デフォルトの振る舞い
- 実装定義
## 効果
デバッガがプログラムを監視中である場合、実装は`true`を返す。
## 例外
投げない
## 備考
- 実装は、プログラムがデバッガによって監視されているかどうかを判定するために、必要に応じて即時クエリを実行する
- Windowsまたは同等のシステムでは、この関数の動作はWin32関数の`::IsDebuggerPresent()`を呼び出すことで実現できる
- POSIX環境では、監視親プロセスをチェックすることで実現できる。その際、監視親プロセスがデバッガであるかどうかは最善の努力で判定する
- この関数は、結果のキャッシュを規定しない。既存の実装もデバッガの存在クエリについての結果をキャッシュするようなことはしておらず、そのコストが問題にはなっていなかった。また、結果をキャッシュする場合、[`std::breakpoint_if_debugging()`](breakpoint_if_debugging.md)のインタフェースにも影響してしまう
## 例
```cpp example
#include <print>
#include <debugging>
#include <cmath>
// なんらかの処理
double g(double a, double b) {
return a / b;
}
double f(double a, double b) {
double ret = g(a, b);
if (std::isnan(ret)) {
// 演算結果でNaNが発生したらブレークし、
// デバッガでパラメータ (ローカル変数) などを確認する
if (std::is_debugger_present()) {
std::breakpoint();
}
}
}
int main() {
double ret = f(2.0, 0.0);
std::println("{}", ret);
}
```
* std::is_debugger_present[color ff0000]
* std::breakpoint[link breakpoint.md]
* std::isnan[link /reference/cmath/isnan.md]

### 出力
```
```


## バージョン
### 言語
- C++26

### 処理系
- [Clang](/implementation.md#clang): 19 [mark noimpl]
- [GCC](/implementation.md#gcc): 14 [mark noimpl]
- [Visual C++](/implementation.md#visual_cpp): 2022 Update 10


## 参照
- [P2546R5 Debugging Support](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2546r5.html)
- [P2810R4 `is_debugger_present` `is_replaceable`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2810r4.html)

0 comments on commit 07e9e02

Please sign in to comment.