Visual Studio에 함께 있는 디버그 Python과 C++

일반적인 Python 디버거 대부분은 Python 코드 디버깅만 지원하지만 개발자는 C 또는 C++과 Python을 같이 사용하는 것이 일반적입니다. 혼합 코드를 사용하는 일부 시나리오는 고성능이 필요하거나 플랫폼 API를 직접 호출하는 기능이 Python 및 C 또는 C++로 코딩되는 경우가 많습니다.

Visual Studio는 Python 및 네이티브 C/C++ 코드에 대한 통합된 동시 혼합 모드 디버깅을 제공합니다. 지원이 가능한 경우는 Python 네이티브 개발 도구 옵션을 Visual Studio 설치 관리자의 Python 개발 워크로드에 대해 선택하는 경우입니다.

Visual Studio 설치 관리자에서 선택된 Python 원시 개발 도구 옵션을 보여 주는 스크린샷

이 문서에서는 다음과 같은 혼합 모드 디버깅 기능을 사용하는 방법을 알아봅니다.

  • 결합된 호출 스택
  • Python 코드와 네이티브 코드 간 단계
  • 두 가지 코드 형식의 중단점
  • 네이티브 프레임에서 객체의 Python 표현과 Python 프레임에서 객체의 네이티브 표현 보기
  • Python 프로젝트 또는 C++ 프로젝트의 컨텍스트 내에서 디버깅

Visual Studio에서 Python 및 C++ 코드의 혼합 모드 디버깅 예를 보여 주는 스크린샷

필수 조건

  • Visual Studio 2017 및 이상 버전입니다. 혼합 모드 디버깅은 Visual Studio 2015 및 이전 버전의 Visual Studio용 Python 도구 1.x 에서 사용할 수 없습니다.

  • Python 워크로드에 대한 지원과 함께 설치된 Visual Studio. 자세한 내용은 Visual Studio에서 Python 지원 설치를 참조하세요.

Python 프로젝트에서 혼합 모드 디버깅 사용

다음 단계에서는 Python 프로젝트에서 혼합 모드 디버깅을 활성화하는 방법을 설명합니다.

  1. 솔루션 탐색기에서, Python 프로젝트를 마우스 우클릭한 후, 속성을 선택합니다.

  2. 속성 창에서, 디버그 탭을 선택한 후, 디버그>네이티브 코드 디버깅 활성화 옵션을 선택합니다.

    Visual Studio에서 네이티브 코드 디버깅 속성 사용을 설정하는 방법을 보여 주는 스크린샷

    이 옵션을 사용하면 모든 디버깅 세션에서 혼합 모드를 사용할 수 있습니다.

    네이티브 코드 디버깅을 활성화하면, Python 출력 창이 일시 정지 후에 뜨는 계속하려면 아무 키나 누르세요. 메시지를 보여주지 않고 프로그램이 끝나자마자 바로 닫힐 수 있습니다. 네이티브 코드 디버깅을 활성화한 후 일시 정지 및 프롬프트를 강제로 설정하려면 추가해야 하는 -i 인수의 위치인 실행>인터프리터 인수 필드는 디버그 탭에 있습니다. 코드 실행 후, 해당 인수는 Python 인터프리터를 대화형 모드로 전환합니다. 프로그램에서 Ctrl+Z+Enter 를 선택하여 창이 닫힐 때까지 기다립니다.

  3. 속성 변경 내용을 저장하려면 파일>저장 (또는 Ctrl+S)를 선택합니다.

  4. 혼합 모드 디버거를 기존 프로세스에 연결하려면 디버그>프로세스에 연결을 선택합니다. 대화 상자를 엽니다.

    1. 프로세스에 연결 대화상자의 목록에서 적절한 프로세스를 선택합니다.

    2. 연결 필드의 경우, 선택 옵션으로 코드 형식 선택 대화 상자를 엽니다.

    3. 코드 형식 선택 대화 상자에서, 다음 코드 형식 디버그 를 선택합니다.

    4. 목록에서, Python(네이티브) 체크 박스를 선택한 후, 확인을 선택합니다.

      Visual Studio에서 디버깅을 위해 Python(네이티브) 코드 형식을 선택하는 방법을 보여 주는 스크린샷

    5. 디버거를 시작하려면 연결 을 선택합니다.

    코드 형식 설정은 영구적입니다. 혼합 모드 디버깅을 비활성화하고 이후에 다른 프로세스에 연결하려면, Python(네이티브) 코드 형식 체크 박스 선택을 취소하고 네이티브 코드 형식 체크 박스를 선택합니다.

    선택할 수 있는 다른 코드 형식을 네이티브 옵션에 추가하거나 대신할 수 있습니다. 예를 들어, 관리되는 애플리케이션이 CPython을 호스트하고 네이티브 확장 모듈을 사용하며 세 코드 프로젝트를 모두 디버그하려는 경우 Python을 선택한 후, 네이티브, 및 관리 체크 박스를 선택합니다. 이 방법을 사용하면 결합된 호출 스택과 세 런타임 간의 단계별 실행을 비롯한 통합 디버깅 경험을 제공합니다.

가상 환경에서의 작업

가상 환경(venvs)에 혼합 모드 디버깅 방법을 사용하면 Windows용 Python은 Visual Studio가 찾아 하위 프로세스로 로드하는 venv용 python.exe 스텁 파일을 사용합니다.

  • Python 3.8 및 이후 버전에서는, 다중 프로세스 디버깅이 혼합 모드에서 지원되지 않습니다. 디버깅 세션을 시작하면 스텁 하위 프로세서가 애플리케이션이 아니라 디버그됩니다. 연결 시나리오의 경우 해결 방법은 올바른 python.exe 파일에 연결하는 것입니다. 디버깅을 사용하여 애플리케이션을 시작할 때(예: F5 바로 가기 키를 통해) 명령을 사용하여 venv를 만들 수 C:\Python310-64\python.exe -m venv venv --symlinks있습니다. 명령에서 선호하는 버전의 Python을 삽입합니다. 기본적으로 관리자만이 기호화된 링크를 Windows에 만들 수 있습니다.

  • 3.8 이전의 Python 버전의 경우, 혼합 모드 디버깅이 venv에서 예상대로 작동해야 합니다.

전역 환경에서 실행하면 어떤 Python 버전에서도 이러한 문제가 발생하지 않습니다.

Python 기호 설치

처음으로 혼합 모드에서 디버깅을 시작하면 Python 기호 필요 대화 상자가 표시될 수 있습니다. 기호는 지정된 Python 환경에 한 번만 설치해야 합니다. Visual Studio 설치 관리자(Visual Studio 2017 및 이후 버전)를 통해 Python 지원을 설치하면 기호가 자동으로 포함됩니다. 자세한 내용은 Visual Studio에서 Python 인터프리터용 디버깅 기호 설치를 참조하세요.

Python 소스 코드 액세스

디버깅할 때 표준 Python 자체의 소스 코드를 사용할 수 있도록 할 수 있습니다.

  1. https://www.python.org/downloads/source/(으)로 이동합니다.

  2. 버전에 적합한 Python 소스 코드 아카이브를 다운로드하고 폴더에 코드를 추출합니다.

  3. Visual Studio에서 Python 소스 코드의 위치를 묻는 메시지가 표시되면 추출 폴더의 특정 파일을 가리킵니다.

C/C++ 프로젝트에서 혼합 모드 디버깅 사용

Visual Studio 2017 버전 15.5 및 이후 버전에서는 C/C++ 프로젝트에서 혼합 모드 디버깅을 지원합니다. 이 사용 사례로는 python.org에 설명된 대로 다른 애플리케이션에 Python을 포함하려는 경우입니다.

다음 단계에서는 C/C++ 프로젝트에 대해 혼합 모드 디버깅을 활성화하는 방법을 설명합니다.

  1. 솔루션 탐색기에서 C/C++ 프로젝트를 마우스 우클릭하고 속성을 선택합니다.

  2. 속성 페이지 창에서, 구성 속성>디버깅 탭을 선택합니다.

  3. 옵션을 시작하려는 디버거 에 대한 드롭다운 메뉴를 확장하고 Python/네이티브 디버깅을 선택합니다.

    Visual Studio에서 C/C++ 프로젝트의 Python 네이티브 디버깅 옵션을 선택하는 방법을 보여 주는 스크린샷

    참고 항목

    Python/네이티브 디버깅 옵션이 없는 경우, 먼저 VS 설치 관리자를 사용하여 Python 네이티브 개발 도구 를 설치해야 합니다. 네이티브 디버깅 옵션은 Python 개발 워크로드에서 사용할 수 있습니다. 자세한 내용은 Visual Studio에서 Python 지원 설치를 참조하세요.

  4. 확인을 선택하여 변경 내용을 저장합니다.

프로그램 시작 관리자 디버그

이 메서드를 사용하는 경우, py.exe를 프로그램 시작 관리자가 디버그할 수 없는 이유는 하위 python.exe 하위프로세스를 생성하기 때문입니다. 디버거는 하위 프로세스에 연결되지 않습니다. 이 시나리오에서, 해결 방법은 다음과 같이 인수를 사용하여 python.exe 프로그램을 직접 시작하는 것입니다.

  1. C/C++ 포르젝트의 속성 페이지 창에서 구성 속성>디버깅 탭으로 가세요.

  2. 명령 옵션의 경우, python.exe 프로그램 파일로 이어지는 전체 경로를 지정합니다.

  3. 원하는 인수를 명령 인수 필드에 지정합니다.

혼합 모드 디버거 연결

Visual Studio 2017 버전 15.4 및 이전 버전의 경우, Visual Studio에서 Python 프로젝트를 시작할 때만 직접 혼합 모드 디버깅이 활성화됩니다. C/C++ 프로젝트는 네이티브 디버거만 사용하므로 지원이 제한됩니다.

이 시나리오의 경우 해결 방법은 디버거를 별도로 연결하는 것입니다.

  1. 디버깅하지 않고 C++ 프로젝트를 시작하려면 디버그>디버깅하지 않고 시작 을 선택하거나 바로 가기 단축키 Ctrl+F5를 사용하면 됩니다.

  2. 혼합 모드 디버거를 기존 프로세스에 연결하려면 디버그>프로세스에 연결을 선택합니다. 대화 상자를 엽니다.

    1. 프로세스에 연결 대화상자의 목록에서 적절한 프로세스를 선택합니다.

    2. 연결 필드의 경우, 선택 옵션으로 코드 형식 선택 대화 상자를 엽니다.

    3. 코드 형식 선택 대화 상자에서, 다음 코드 형식 디버그 를 선택합니다.

    4. 목록에서, Python(네이티브) 체크 박스를 선택한 후, 확인을 선택합니다.

    5. 디버거를 시작하려면 연결 을 선택합니다.

디버거를 연결하기 전에 디버그할 Python을 호출하지 않도록 C++ 애플리케이션에서 일시 중지 또는 지연을 추가할 수 있습니다.

혼합 모드의 특정 기능 탐색

Visual Studio는 애플리케이션을 더 쉽게 디버그할 수 있도록 혼합 모드 디버깅 기능 몇 가지를 제공합니다.

결합된 호출 스택 사용

호출 스택 창에는 네이티브 프레임과 Python 스택 프레임 사이에 표시된 전환으로 두 프레임이 모두 인터리브되어 있습니다.

Visual Studio에서 혼합 모드 디버깅과 결합된 호출 스택 창 스크린샷

  • 전환 방향을 지정하지 않고 전환을 [외부 코드] 로 표시되게 하려면, 도구>옵션>디버깅>일반>내 코드만 활성화 옵션을 설정합니다.

  • 호출 프레임을 활성화하려면 프레임을 더블클릭합니다. 이 작업은 가능한 경우 해당 소스 코드도 엽니다. 소스 코드를 사용할 수 없으면 프레임은 여전히 활성 상태로 남아 있고 지역 변수를 검사할 수 있습니다.

Python 코드와 네이티브 코드 간 단계

Visual Studio는 한 단계씩 코드 실행 (F11) 또는 프로시저 나가기 (Shift+F11) 명령을 제공하여 혼합 모드 디버거가 코드 형식 간 변경 내용을 올바르게 처리할 수 있도록 합니다.

  • Python에서 C로 구현된 형식의 메서드를 호출할 때, 해당 메서드에 대한 호출을 단계별로 실행하면 메서드를 구현하는 네이티브 함수의 시작 부분에서 중지합니다.

  • 네이티브 코드에서 Python 코드를 호출시키는 Python API 함수를 호출하면 같은 동작이 발생합니다. 원래 Python에서 정의된 함수 값에 대해 단계별로 PyObject_CallObject 호출을 실행하면 Python 함수의 시작 부분에서 중지합니다.

  • 또한 Python에서 네이티브로의 단계별 실행은 ctypes를 통해 Python에서 호출된 네이티브 함수에 대해서도 지원됩니다.

네이티브 코드에서 PyObject 값 사용하기

네이티브(C 또는 C++) 프레임이 활성 상태이면 디버거 로컬 창에 지역 변수가 표시됩니다. 네이티브 Python 확장 모듈에서, 이러한 변수들 상당수가 PyObject ( _object에 대한 형식 정의)이거나 몇 가지 다른 기본 Python 형식입니다. 혼합 모드 디버깅에서, 이러한 값은 [Python 보기]라는 레이블이 지정된 또 다른 자식 노드를 나타냅니다.

  • 변수의 Python 표현을 보려면 노드를 확장합니다. 변수 보기는 동일한 객체를 참조하는 지역 변수가 Python 프레임에 있는지 확인하는 것과 동일합니다. 이 노드의 자식 항목은 편집할 수 있습니다.

    Visual Studio의 로컬 창에 있는 Python 보기를 보여 주는 스크린샷

  • 이 기능을 사용하지 않도록 설정하려면 로컬 창에서 아무 곳이나 마우스 오른쪽 단추를 클릭하고 Python>Python 보기 노드 표시 메뉴 옵션을 설정/해제합니다.

    로컬 창에 Python 보기 노드 표시 옵션을 사용하는 방법을 보여 주는 스크린샷

Python 보기 노드를 보여주는 C 형식

다음의 C 형식은 [Python 보기] 노드를 보여줍니다(사용 가능한 경우).

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

[Python 보기] 는 사용자가 직접 작성하는 형식으로 자동 표시되지 않습니다. Python 3.x용 확장을 작성할 때, 이러한 부족은 일반적으로 문제가 되지 않습니다. 모든 객체에는 궁극적으로 ob_base 나열된 C 형식 중 하나의 필드가 있으므로 [Python 보기] 가 나타납니다.

Python 코드에서 네이티브 값 보기

Python 프레임이 활성 상태로 있을 때 [C++ 보기]로컬 창에서 네이티브 값에 대해 활성화할 수 있습니다. 이 기능은 기본적으로 사용되지 않습니다.

  • 이 기능을 활성화하려면 로컬 창에서 아무 곳이나 마우스 우클릭하고 Python>C++ 보기 노드 표시 메뉴 옵션을 설정합니다.

    로컬 창에 C++ 노드 보기 옵션을 사용하는 방법을 보여 주는 스크린샷

  • [C++ 보기] 노드는 네이티브 프레임에서 표시하는 것과 동일하게, 값에 대한 기본 C/C++ 구조의 표현을 제공합니다. Python 정수에 대한 _longobject ( PyLongObject 이 형식 정의임) 인스턴스를 보여주며, 사용자가 직접 작성한 네이티브 클래스의 형식을 추론하려고 합니다. 이 노드의 자식 항목은 편집할 수 있습니다.

    Visual Studio의 로컬 창에 있는 C++ 보기를 보여 주는 스크린샷

객체의 자식 필드가 형식 PyObject이거나 지원되는 다른 형식인 경우, [Python 뷰] 표현 노드가 있습니다(해당 표현이 활성화된 경우). 이 동작을 사용하면 링크가 Python에 직접 노출되지 않는 객체 그래프를 탐색할 수 있습니다.

Python 개체 메타데이터를 사용하여 개체 형식을 결정하는 [Python 보기] 노드와 달리 [C++ 보기]에는 비슷한 방식으로 신뢰할 수 있는 메커니즘이 없습니다. 일반적으로 Python 값(즉, PyObject 참조)이 있다고 가정하면 어떤 C/C++ 구조에서 이를 지원하는지 확인할 수 없습니다. 혼합 모드 디버거에서는 함수 포인터 형식을 가진 객체 형식의 여러 필드(예를 들어 PyTypeObjectob_type 필드에 의해 참조되는 경우)를 보고 해당 형식을 추측하려고 합니다. 이러한 함수 포인터 중 하나에서 해결할 수 있는 함수를 참조하고 해당 함수가 갖는 self 매개 변수가 PyObject*보다 구체적인 형식인 경우, 해당 형식은 지원 형식으로 간주됩니다.

다음 예제에서는 ob_type->tp_init 지정된 객체의 값이 다음 함수를 가리킵니다.

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

이러한 경우, 디버거에서 객체의 C 형식이 FobObject임을 올바르게 추론할 수 있습니다. 디버거가 tp_init에서 더 정밀하게 형식을 확인할 수 없는 경우, 다른 필드로 이동합니다. 이러한 필드 중 하나에서 형식을 추론할 수 없는 경우 [C++ 보기] 노드는 해당 개체를 PyObject 인스턴스로 표시합니다.

작성된 사용자 지정 형식에 대해 항상 유용한 표현을 얻으려면, 형식을 등록할 때 하나 이상의 특수 함수를 등록하고 강력한 형식의 self 매개 변수를 사용하는 것이 좋습니다. 대부분의 형식은 해당 요구 사항을 자연스럽게 충족합니다. 다른 유형의 경우, tp_init 검사가 일반적으로 이 용도로 사용하기에 가장 편리한 항목입니다. 디버거 형식 유추만을 활성화하려고 존재하는 형식에 대한 tp_init 더미 구현은 이전 샘플에서와 같이 즉시 0을 반환할 수 있습니다.

표준 Python 디버깅과의 차이점 검토

혼합 모드 디버거는 표준 Python 디버거와 다릅니다. 몇 가지 추가 기능을 도입하지만 다음과 같은 Python 관련 기능 일부가 부족합니다.

  • 지원되지 않는 기능에는 조건부 중단점, 대화형 디버그 창 및 플랫폼 간 원격 디버깅이 있습니다.
  • 직접 실행 창은 사용 가능하지만 이 섹션에서 나열하는 모든 제한을 포함하여 기능 하위 세트가 제한적입니다.
  • 지원되는 Python 버전에는 CPython 2.7과 3.3 및 이후 버전만이 포함됩니다.
  • Visual Studio Shell에서 Python을 사용하려면(예: 통합 설치 관리자와 함께 설치하는 경우) Visual Studio에서 C++ 프로젝트를 열 수 없습니다. 따라서 C++ 파일에 대한 편집 경험은 기본 텍스트 편집기 전용입니다. 그러나 C/C++ 디버깅 및 혼합 모드 디버깅은 셸에서 원본 코드, 네이티브 코드 단계별 실행 및 디버거 창의 C++ 식 계산을 통해 완벽하게 지원됩니다.
  • Python 객체를 로컬조사식 디버거 도구 창에서 보면, 혼합 모드 디버거는 객체의 구조만 표시합니다. 속성을 자동으로 평가하거나 계산된 속성을 표시하지 않습니다. 컬렉션의 경우 기본 제공 컬렉션 형식(tuple, list, dict, set)에 대한 요소만 표시합니다. 일부 빌트인 컬렉션 형식에서 상속되지 않는 한 사용자 지정 컬렉션 형식은 컬렉션으로 시각화되지 않습니다.
  • 식 평가는 다음 섹션에 설명된 대로 처리됩니다.

식 계산 사용

표준 Python 디버거를 사용하면, 디버그된 프로세스가 I/O 오퍼레이션 또는 다른 유사한 시스템 호출에서 차단되는 경우를 제외하고 코드의 어느 지점에서 일시 중지될 때 조사식직접 실행 창에서 임의의 Python 식을 계산할 수 있습니다. 혼합 모드 디버깅에서 임의의 식은 Python 코드에서 중지된 경우, 중단점 이후 또는 단계별로 코드를 실행한 후에만 계산할 수 있습니다. 중단점이나 단계별 실행 작업이 발생한 스레드에서만 식을 계산할 수 있습니다.

디버거가 네이티브 코드에서 중지되거나 단계별 오퍼레이션 이후 또는 다른 스레드와 같이, 설명된 조건이 적용되지 않는 Python 코드에서 중지되는 경우입니다. 식 평가는 현재 선택된 프레임 범위에서 로컬 및 전역 변수에 액세스하고, 해당 필드에 액세스하며, 리터럴을 사용하여 빌트인 컬렉션 형식을 인덱싱하는 것으로 제한됩니다. 예를 들어 다음 식은 모든 컨텍스트에서 계산될 수 있습니다(모든 식별자가 적절한 형식의 기존 변수와 필드를 참조하는 경우).

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

또한 혼합 모드 디버거는 이러한 식을 다르게 확인합니다. 모든 멤버 액세스 오퍼레이션은 객체(예: __dict__ 또는 __slots__나, tp_members을 통해 Python에 노출되는 네이티브 구조체의 필드)의 직접적 요소인 필드만 조회하며, __getattr__, __getattribute__ 또는 설명자 논리를 무시합니다. 마찬가지로 모든 인덱싱 작업은 __getitem__을 무시하고 컬렉션의 내부 데이터 구조에 직접 액세스합니다.

일관성을 위해 이 이름 확인 체계는 제한된 식 계산에 대한 제약 조건과 일치하는 모든 식에 사용됩니다. 이 체계는 현재 중지점에서 임의 식이 허용되는지 여부에 관계없이 적용됩니다. 모든 기능을 제공하는 계산기를 사용할 수 있을 때 적절한 Python 의미 체계를 강제로 적용하려면 식을 괄호로 묶습니다.

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