Python と C++ の同時デバッグDebugging Python and C++ together

ほとんどの標準的 Python デバッガーは、Python コードのみのデバッグをサポートします。Most regular Python debuggers support debugging of only Python code. ただし、実際には、高パフォーマンスやプラットフォーム API の直接呼び出しが必要なところで Python と、C または C++ が併用されています (例については、「Python 向け C++ 拡張機能の作成」をご覧ください)。In practice, however, Python is used in conjunction with C or C++ where high performance or the ability to directly invoke platform APIs is required (see Creating a C++ extension for Python for an example. Python プロジェクトが読み込まれるとき、Visual Studio には、Python とネイティブ C/C++ のデバッグを統合して同時に実行する混合モードのデバッグ機能があります。このモードでは、結合された呼び出し履歴、Python とネイティブ コード間でのステップ実行機能、両方の種類のコード内のブレークポイント、Python のオブジェクト表現をネイティブ フレームに表示する機能 (逆も可能) が提供されます。When a Python project is loaded, Visual Studio provides integrated, simultaneous mixed-mode debugging for Python and native C/C++, with combined call stacks, the ability to step between Python and native code, breakpoints in either type of code, and the ability to see Python representations of objects in native frames and vice versa:

混合モードのデバッグ

Visual Studio でのネイティブ C モジュールのビルド、テスト、およびデバッグの概要については「Deep Dive: Creating Native Modules (詳細情報: ネイティブ モジュールの作成)」(youtube.com、9 分 9 秒) をご覧ください。For an introduction to building, testing, and debugging native C modules with Visual Studio, see Deep Dive: Creating Native Modules (youtube.com, 9m9s). ビデオは、Visual Studio 2015 と 2017 の両方に適用されます。The video is applicable to both Visual Studio 2015 and 2017.

注意

混合モードのデバッグは、Python Tools for Visual Studio 1.x では使用できません。Mixed-mode debugging is not available with Python Tools for Visual Studio 1.x.

混合モードのデバッグの有効化Enabling mixed-mode debugging

  1. ソリューション エクスプローラーでプロジェクトを右クリックし、[プロパティ] を選択し、[デバッグ] タブを選択します。[ネイティブ コードのデバッグを有効にする] オプションをオンにします。Right-click the project in Solution Explorer, select Properties, select the Debug tab, and then turn on the option for Enable native code debugging. このオプションで、すべてのデバッグ セッションで、混合モードが有効になります。This option enables mixed-mode for all debugging sessions.

    ネイティブ コードのデバッグの有効化

    ヒント

    ネイティブ コードのデバッグを有効にすると、プログラムが通常の [続行するには、任意のキーを押してください] で一時停止せずに完了した場合に、Python の出力ウィンドウがすぐに消えることがあります。When you enable native code debugging, the Python output window may disappear immediately when the program has completed without giving you the usual "Press any key to continue..." pause. 強制的に一時停止するには、ネイティブ コードのデバッグを有効にするときに、[デバッグ] タブの [実行] > [インタープリターの引数] フィールドに、-i オプションを追加します。To force a pause, add the -i option to the Run > Interpreter Arguments field on the Debug tab when you enable native code debugging. この引数を使用すると、Python インタープリターはコード終了後に対話モードになり、この時点でユーザーが Ctrl + Z キー、Enter キーの順に押して終了するのを待機します。This argument puts the Python interpreter into interactive mode after the code finishes, at which point it waits for you to press Ctrl+Z, Enter to exit.

  2. 混合モードのデバッガーを既存のプロセスにアタッチ ([デバッグ] メニューの [プロセスにアタッチ] を選択) したら、[選択] ボタンをクリックして [コードの種類の選択] ダイアログを開きます。[次のコードの種類をデバッグする] オプションをオンにし、一覧の [ネイティブ][Python] の両方を選択します。When attaching the mixed-mode debugger to an existing process (Debug > Attach to Process...), select the Select... button to open the Select Code Type dialog, set the Debug these code types option, and select both Native and Python in the list:

    コードの種類 ([ネイティブ] と [Python]) の選択

    コードの種類の設定は永続的であるため、後で別のプロセスにアタッチするときに混合モードのデバッグを無効にする場合は、これらの手順を繰り返して Python コードの種類の選択を解除します。The code type settings are persistent, so if you want to disable mixed-mode debugging when attaching to a different process later, repeat these steps and clear the Python code type.

    [ネイティブ] に加えて、またはその代わりとして他のコードの種類を選択できます。It is possible to select other code types in addition to, or instead of, Native. たとえば、CPython をホストしてネイティブ拡張モジュールを使用するマネージ アプリケーションで、3 つすべてをデバッグする場合は、[Python][ネイティブ]、および [マネージ * ] をまとめて選択すると、結合された呼び出し履歴と 3 つすべてのランタイム間でのステップ実行を含む統合されたデバッグ エクスペリエンスを得ることができます。For example, if a managed application hosts CPython, which in turn uses native extension modules, and you want to debug all three, you can check **Python, **Native, and Managed* together for a unified debugging experience including combined call stacks and stepping between all three runtimes.

  3. 混合モードのデバッグを初めて開始したときに、Python シンボルが必要であることを示すダイアログが表示される可能性があります。When you start debugging in mixed mode for the first time, you may see a Python Symbols Required dialog. 詳細については、混合モードのデバッグ用のシンボルに関するページを参照してください。See Symbols for mixed-mode debugging for details. どの Python 環境でも、シンボルは 1 回だけインストールする必要があります。You need to install symbols only once for any given Python environment. Visual Studio 2017 のインストーラーで Python のサポートをインストールすると、シンボルが自動的に組み込まれます。Note that if you install Python support through the Visual Studio 2017 installer, symbols are included automatically.

  4. Python のソース コード自体を手元に置きたい場合もあります。You may also want to have the Python source code itself on hand. 標準の Python の場合は、https://www.python.org/downloads/source/ からソース コードを入手できます。For standard Python, source code is obtained from https://www.python.org/downloads/source/. バージョンに合ったアーカイブをダウンロードし、フォルダーに抽出します。Download the archive appropriate for your version and extract it to a folder. 要求されたら、そのフォルダーの特定のファイルを Visual Studio で参照します。You then point Visual Studio to specific files in that folder at whatever point it prompts you.

注意

ここで説明する混合モードのデバッグは、Python プロジェクトが Visual Studio に読み込まれている場合にのみ有効です。Mixed-mode debugging as described here is enabled only when you have a Python project loaded into Visual Studio. プロジェクトは Visual Studio のデバッグ モードを特定し、それによって混合モードのオプションを使用できるようにします。That project determines the Visual Studio's debugging mode, which is what makes the mixed-mode option available. ただし、C++ プロジェクトが読み込まれている場合は (python.org で説明されているように別のアプリケーションに Python を埋め込んでいるとき)、Visual Studio は混合モード デバッグをサポートしていないネイティブ C++ デバッガーを使います。If, however, you have a C++ project loaded (as you would when embedding Python in another application as described on python.org, then Visual Studio uses the native C++ debugger that doesn't support mixed-mode debugging.

この場合は、デバッグなしで C++ プロジェクトを開始し ([デバッグ] > [デバッグなしで開始] または Ctrl + F5 キー)、その後で [デバッグ] > [プロセスにアタッチ...] を使います。表示されるダイアログで適切なプロセスを選んだ後、[選択...] ボタンを使って [コードの種類の選択] ダイアログを開き、次に示すように Python を選びます。In this case, start the C++ project without debugging (Debug > Start without debugging or Ctrl+F5), and then use Debug > Attach to Process.... In the dialog that appears, select the appropriate process, then use the Select... button to open the Select Code Type dialog in which you can select Python as shown below. [OK] を選んでダイアログを閉じた後、[アタッチ] を選んでデバッガーを起動します。Select OK to close that dialog, then Attach to start the debugger. デバッガーをアタッチする前にデバッグ対象の Python が呼び出されないように、適切な一時停止または遅延を C++ アプリに組み込むことが必要になる場合があることに注意してください。Note that you may need to introduce a suitable pause or delay in the C++ app to ensure that it doesn't call the Python you want to debug before you can attach the debugger.

デバッガーをアタッチするときにデバッグの種類として Python を選ぶ

混合モード固有の機能Mixed-mode specific features

結合された呼び出し履歴Combined call stack

[呼び出し履歴] ウィンドウには、ネイティブと Python のスタック フレームの両方が、2 つの間の遷移情報を挟んで交互に表示されます。The Call Stack window shows both native and Python stack frames interleaved, with transitions marked between the two:

結合された呼び出し履歴

注意

[ツール]、[オプション]、[デバッグ]、[全般] の順に選択し、[マイ コードのみを有効にする] オプションをオンにした場合、遷移情報は "[外部コード]" として表示され、遷移の方向は示されません。Transitions appear as "[External Code]", without specifying the direction of transition, if the Tools > Options > Debugging > General > Enable Just My Code option is set.

呼び出しフレームをダブルクリックすると、それがアクティブになり、適切なソース コードが開きます (可能な場合)。Double-clicking any call frame makes it active and opens the appropriate source code, if possible. ソース コードが入手できない場合でも、フレームはアクティブになり、ローカル変数を調べることができます。If source code is not available, the frame is still made active and local variables can be inspected.

Python とネイティブ コード間のステップ実行Stepping between Python and native code

ステップ イン コマンドまたは ステップ アウト コマンドを使用したとき、混合モードのデバッガーは、コードの種類の変更を正しく処理します。When using the Step Into (F11) or Step Out (Shift+F11) commands, the mixed-mode debugger correctly handles changes between code types. たとえば、C で実装されている型のメソッドをPython で呼び出しているときに、そのメソッドへの呼び出しにステップ インすると、実行は、メソッドを実装しているネイティブ関数の先頭で停止します。For example, when Python calls a method of a type that is implemented in C, stepping in on a call to that method stops at the beginning of the native function implementing the method. 同様に、ネイティブ コードが Python API 関数を呼び出しているときは、呼び出されている Python コードで停止します。Similarly, when native code calls some Python API function that results in Python code being invoked. たとえば、Python で定義された関数値の PyObject_CallObject にステップ インすると、Python 関数の先頭で停止します。For example, stepping into a PyObject_CallObject on a function value that was originally defined in Python stops at the beginning of the Python function. Python からネイティブへのステップ インは、Python から ctypes 経由で呼び出されるネイティブ関数でもサポートされています。Stepping in from Python to native is also supported for native functions invoked from Python via ctypes.

ネイティブ コード内の PyObject 値の表示PyObject values view in native code

ネイティブ (C または C++) フレームがアクティブのときは、そのローカル変数がデバッガーの [ローカル] ウィンドウに表示されます。When a native (C or C++) frame is active, its local variables show up in the debugger Locals window. ネイティブの Python 拡張モジュールでは、これらの変数の多くは PyObject 型 (_object の typedef) であり、いくつかがその他の基本的な Python 型です (下の一覧を参照してください)。In native Python extension modules, many of these variables are of type PyObject (which is a typedef for _object), or a few other fundamental Python types (see list below). 混合モードのデバッグでは、これらの値は、[Python view (Python ビュー)] というラベルが付いた追加の子ノードに表示されます。In mixed-mode debugging, these values present an additional child node labeled "Python view." このノードを展開すると、変数の Python 表現が表示されます。これは、同じオブジェクトを参照しているローカル変数が Python フレームに存在している場合に表示されるものと同じです。When expanded, this node shows the variable's Python representation, identical to what you'd see if a local variable referencing the same object was present in a Python frame. このノードの子は編集可能です。The children of this node are editable.

Python ビュー

この機能を無効にするには、[ローカル] ウィンドウ内を右クリックし、[Python]、[Show Python View Nodes (Python ビュー ノードの表示)] メニュー オプションを切り替えます。To disable this feature, right-click anywhere in the Locals window and toggle the Python > Show Python View Nodes menu option:

Python ビューの有効化

"[Python View (Python ビュー)]" ノードを表示する C の型 (ビューが有効な場合):C types that show "[Python View]" nodes (if enabled):

  • PyObject
  • PyVarObject
  • PyTypeObject
  • PyByteArrayObject
  • PyBytesObject
  • PyTupleObject
  • PyListObject
  • PyDictObject
  • PySetObject
  • PyIntObject
  • PyLongObject
  • PyFloatObject
  • PyStringObject
  • PyUnicodeObject

自分で作成した型は、"[Python View (Python ビュー)]" に自動的に表示されることはありません。"[Python View]" does not automatically appear for types you author yourself. Python 3.x での拡張機能の作成では、すべてのオブジェクトに最終的には上記のいずれかの型の ob_base フィールドが存在し、それによって "[Python View (Python ビュー)]" に表示されるため、通常、この欠落は問題になりません。When authoring extensions for Python 3.x, this lack is usually not an issue because any object ultimately has an ob_base field of one of the types above, which causes "[Python View]" to appear.

ただし、Python 2.x では、通常は、各オブジェクト型でヘッダーをインライン フィールドのコレクションとして宣言するため、カスタム作成された型と PyObject の間には、C/C++ コードの型システム レベルでの関連付けがありません。For Python 2.x, however, each object type typically declares its header as a collection of inline fields, and there is no association between custom authored types and PyObject at the type system level in C/C++ code. このようなカスタム型に対して "[Python View (Python ビュー)]" ノードを有効にするには、Python ツールのインストール ディレクトリ PythonDkm.natvis を編集して、C 構造体または C++ クラスの XML に別の要素を追加します。To enable "[Python View]" nodes for such custom types, edit the PythonDkm.natvis in the Python tools install directory, and add another element in the XML for your C struct or C++ class.

別の (より優れた) 方法は、PEP 3123 に従って、PyObject_HEAD の代わりに明示的な PyObject ob_base; フィールドを使用することです。ただし、旧バージョンとの互換性の点で、この方法は常に可能であるとは限りません。An alternate (and better) option is to follow PEP 3123 and use an explicit PyObject ob_base; field rather than PyObject_HEAD, though that may not always be possible for backwards-compatibility reasons.

Python コード内のネイティブ値の表示Native values view in Python code

前のセクションに似ていますが、Python フレームがアクティブのときに、ネイティブ値を [ローカル] ウィンドウに表示する "[C++ View (C++ ビュー)]" を有効にできます。Similar to the previous section, you can enable a "[C++ View]" for native values in the Locals window when a Python frame is active. この機能は既定では有効になっていないため、[ローカル] ウィンドウ内を右クリックし、[Python] メニューの [Show C++ View Nodes ([C++ ビュー] ノードの表示)] オプションをオンにすることで有効にします。This feature is not enabled by default, so you turn it on by right-clicking in the Locals window and toggling the Python > Show C++ View Nodes menu option.

C++ ビューの有効化

"[C++ View (C++ ビュー)]" ノードは、値の基になる C/C++ 構造体の表現を提供します (これはネイティブ フレームに表示されるものと同じです)。The "[C++ View]" node provides a representation of the underlying C/C++ structure for a value, identical to what you'd see in a native frame. たとえば、Python の長整数型の _longobject インスタンス (その PyLongObject は typedef です) が表示され、カスタム作成されたネイティブ クラスの型の推測が試行されます。For example, it shows an instance of _longobject (for which PyLongObject is a typedef) for a Python long integer, and it tries to infer types for native classes that you have authored yourself. このノードの子は編集可能です。The children of this node are editable.

C++ ビュー

オブジェクトの子フィールドが PyObject 型であるか、サポートされているその他の型のいずれかである場合は、"[Python ビュー]" ノードが表示され (表示が有効な場合)、リンクが Python に直接公開されていないオブジェクト グラフに移動することができます。If a child field of an object is of type PyObject, or one of the other supported types, then it has a "[Python View]" representation node (if those representations are enabled), making it possible to navigate object graphs where links are not directly exposed to Python.

Python オブジェクトのメタデータを使用してオブジェクトの型を特定する "[Python ビュー]" ノードとは異なり、"[C++ ビュー]" には同じように信頼性の高いメカニズムはありません。Unlike "[Python View]" nodes, which use Python object metadata to determine the type of the object, there's no similarly reliable mechanism for "[C++ View]". 一般的に言えば、Python 値 (つまり PyObject 参照) が与えられた場合、そのバックにある C/C++ 構造体はどれかを確実に判断することはできません。Generally speaking, given a Python value (that is, a PyObject reference) it's not possible to reliably determine which C/C++ structure is backing it. 混合モードのデバッガーは、関数ポインターの型があるオブジェクトの型のさまざまなフィールドを調べて、型を推測しようとします (たとえば ob_type フィールドによって参照されている PyTypeObject)。The mixed-mode debugger tries to guess that type by looking at various fields of the object's type (such as the PyTypeObject referenced by its ob_type field) that have function pointer types. 関数ポインターのいずれかが解決可能な関数を参照し、その関数に PyObject* よりも型が明確な self パラメーターがあれば、その型はバッキング型であるとみなされます。If one of those function pointers references a function that can be resolved, and that function has a self parameter with type more specific than PyObject*, then that type is assumed to be the backing type. たとえば、特定のオブジェクトの ob_type->tp_init が次の関数をポイントしている場合、For example, if ob_type->tp_init of a given object points at the following function:

static int FobObject_init(FobObject* self, PyObject* args, PyObject* kwds) {
    return 0;
}

デバッガーは、オブジェクトの C の型は FobObject であることを正しく推測できます。then the debugger can correctly deduce that the C type of the object is FobObject. tp_init から正確な型を判別できない場合は、他のフィールドに移動します。If it's unable to determine a more precise type from tp_init, it moves on to other fields. どのフィールドからも型を推測できない場合、オブジェクトは "[C++ View (C++ オブジェクト)]" ノードに PyObject インスタンスとして表示されます。If it's unable to deduce the type from any of those fields, the "[C++ View]" node presents the object as a PyObject instance.

カスタム作成した型の有用な表現を常に取得する最善の方法は、型を登録するときに少なくとも 1 つの特殊な関数を登録し、厳密に型指定された self パラメーターを使用することです。To always get a useful representation for custom authored types, it's best to register at least one special function when registering the type, and use a strongly-typed self parameter. ほとんどの型は問題なくこの要件を満たしますが、当てはまらない場合、この目的で使用するための最も便利なエントリは、通常は tp_init です。Most types fulfill that requirement naturally; if that's not the case, then tp_init is usually the most convenient entry to use for this purpose. デバッガーの型推測を可能にするためにのみ存在する tp_init 型のダミー実装は、上のコード サンプルに示すように、すぐにゼロを返すことができます。A dummy implementation of tp_init for a type that is present solely to enable debugger type inference can just return zero immediately, as in the code sample above.

Python の標準的なデバッグとの違いDifferences from standard Python debugging

混合モードのデバッガーは、追加機能がいくつか導入されていますが、Python に関連するいくつかの機能が欠けているという点で、標準的な Python のデバッガーとは区別されます。The mixed-mode debugger is distinct from the standard Python debugger in that it introduces some additional features but lacks some Python-related capabilities:

  • サポートされていない機能: 条件付きブレークポイント、デバッグの対話型ウィンドウ、およびプラットフォーム間のリモート デバッグ。Unsupported features: conditional breakpoints, Debug Interactive window, and cross-platform remote debugging.
  • イミディエイト ウィンドウ: 使用できますが、その機能はサブセットに制限され、ここに記載されている制限もすべて適用されます。Immediate window: is available but with a limited subset of its functionality, including all the limitations listed here.
  • サポートされている Python のバージョン: CPython 2.7 と 3.3+ のみ。Supported Python versions: CPython 2.7 and 3.3+ only.
  • Visual Studio Shell: Visual Studio Shell で Python を使用する場合 (たとえば、統合インストーラーを使用してインストールした場合)、Visual Studio では C++ プロジェクトを開くことができません。また、C++ ファイルの編集方法は、基本的なテキスト エディターでの編集と同様です。Visual Studio Shell: When using Python with Visual Studio Shell (for example, if you installed it using the integrated installer), Visual Studio is unable to open C++ projects, and the editing experience for C++ files is that of a basic text editor only. ただし、C/C++ のデバッグと混合モードでのデバッグは Shell で完全にサポートされ、ソース コード、ネイティブ コードのステップ イン、およびデバッガー ウィンドウでの C++ 式の評価を実行できます。However, C/C++ debugging and mixed-mode debugging are fully supported in Shell with source code, stepping into native code, and C++ expression evaluation in debugger windows.
  • オブジェクトの表示と展開: デバッガー ツールの [ローカル] ウィンドウと [ウォッチ] ウィンドウに Python オブジェクトを表示するとき、混合モードのデバッガーでは、オブジェクトの構造のみが表示されます。Viewing and expanding objects: When viewing Python objects in the Locals and Watch debugger tool windows, the mixed-mode debugger shows only the structure of the objects. プロパティの自動評価や計算される属性の表示は行われません。It does not automatically evaluate properties, or show computed attributes. コレクションでは、組み込みコレクション型 (tuplelistdictset) の要素のみを表示します。For collections, it shows only elements for built-in collection types (tuple, list, dict, set). カスタム コレクション型は、組み込みコレクション型から継承される場合を除き、コレクションとして視覚化されません。Custom collection types are not visualized as collections, unless they are inherited from some built-in collection type.
  • 式の評価: 下記を参照してください。Expression evaluation: see below.

式の評価Expression evaluation

標準的な Python デバッガーでは、デバッグ対象のプロセスは、I/O 操作またはその他の同様のシステム呼び出しでブロックされていない限り、コード内のどのポイントで一時停止された場合でも、[ウォッチ] ウィンドウと [イミディエイト] ウィンドウですべての Python 式を評価することができます。The standard Python debugger allows evaluation of arbitrary Python expressions in Watch and Immediate windows when the debugged process is paused at any point in the code, so long as it is not blocked in an I/O operation or other similar system call. 混合モード デバッグの場合、Python コードで式が停止したとき、ブレークポイントの後、またはコードをステップ実行するときにのみ、任意の式を評価できます。In mixed-mode debugging, arbitrary expressions can be evaluated only when stopped in Python code, after a breakpoint, or when stepping into the code. 式は、ブレークポイントまたはステップ実行操作が発生したスレッドでのみ評価できます。Expressions can be evaluated only on the thread on which the breakpoint or the stepping operation occurred.

ネイティブコード内、または上記の条件が適用されない Python コード内で停止した (ステップ アウト操作の後や異なるスレッド上などで停止した) 場合、式の評価は、現在選択されているフレームのスコープ内のローカル変数とグローバル変数へのアクセス、それらのフィールドへのアクセス、および組み込みコレクション型のリテラルによるインデックス作成に限定されます。When stopped in native code, or in Python code where the conditions above do not apply (for example, after a step-out operation, or on a different thread), expression evaluation is limited to accessing local and global variables in scope of the currently selected frame, accessing their fields, and indexing built-in collection types with literals. たとえば、次の式は、すべてのコンテキストで評価できます (すべての識別子が既存の変数と適切な型のフィールドを参照していることを条件とします)。For example, the following expression can be evaluated in any context (provided that all identifiers refer to existing variables and fields of appropriate types):

foo.bar[0].baz['key']

混合モードのデバッガーも、このような式を異なる方法で解決します。The mixed-mode debugger also resolves such expressions differently. すべてのメンバー アクセス操作は、直接的にオブジェクトの一部であるフィールド (__dict__ または __slots__ 内のエントリや、tp_members 経由で Python に公開されているネイティブ構造体のフィールドなど) のみを検索し、すべての __getattr____getattribute__、または記述子ロジックを無視します。All member-access operations look up only fields that are directly part of the object (such as an entry in its __dict__ or __slots__, or a field of a native struct that is exposed to Python via tp_members), and ignore any __getattr__, __getattribute__ or descriptor logic. 同様に、すべてのインデックス作成操作は __getitem__ を無視して、コレクションの内部データ構造に直接アクセスします。Similarly, all indexing operations ignore __getitem__, and access the inner data structures of collections directly.

整合性を保つため、任意の式が現在の停止ポイントで評価できるかどうかに関係なく、制限された式の評価に対する制約と一致するすべての式に対して、この名前解決スキームが使用されます。For the sake of consistency, this name resolution scheme is used for all expressions that match the constraints for limited expression evaluation, regardless of whether arbitrary expressions are allowed at the current stop point. フル機能のエバリュエーターを使用できるときに Python の適切なセマンティクスを適用するには、式をかっこで囲みます。To force proper Python semantics when a full-featured evaluator is available, enclose the expression in parentheses:

(foo.bar[0].baz['key'])