Visual Studio에서 Python용 C++ 확장 만들기

이 문서에서는 쌍곡 탄젠트를 계산하고 Python 코드에서 호출하는 CPython용 C++ 확장을 빌드하는 방법에 대해 설명합니다. C++에서 동일한 루틴을 구현할 경우의 관련된 성능 향상을 보여 주기 위해 Python에서 먼저 루틴을 구현합니다.

C++(또는 C)로 작성된 코드 모듈은 일반적으로 Python 인터프리터의 기능을 확장하는 데 사용됩니다. 모듈에는 확장 형식이 세 가지가 있습니다.

  • 가속기 모듈: 가속 성능을 활성화합니다. Python은 해석된 언어이기 때문에 성능 향상을 위해 C++로 가속기 모듈을 작성할 수 있습니다.
  • 래퍼 모듈: 기존 C/C++ 인터페이스를 Python 코드에 노출하거나 Python에서 사용하기 용이한 python과 유사한 API를 노출합니다.
  • 하위 수준 시스템 액세스 모듈: 시스템 액세스 모듈을 만들어 하위 수준 기능의 CPython 런타임, 운영 체제, 기본 하드웨어에 도달합니다.

이 문서에서는 Python에서 C++ 확장 모듈을 사용할 수 있도록 하는 방법 두 가지도 보여 줍니다.

  • Python 설명서에 설명된 표준 CPython 확장을 사용합니다.
  • 단순성 때문에 C++11에 권장되는 PyBind11을 사용합니다. 호환성을 보장하려면 사용 중인 Python이 최신 버전 중에 해당하는지 확인하세요.

이 연습에서 완성된 샘플은 GitHub( python-samples-vs-cpp-extension)에서 찾을 수 있습니다.

필수 조건

  • Python 개발 워크로드가 설치된 Visual Studio 2017 및 이후 버전. 워크로드에는 네이티브 확장에 필요한 C++ 워크로드 및 툴셋을 추가하는 Python 네이티브 개발 도구가 포함되어 있습니다.

    Screenshot of a list of Python development options, highlighting the Python native development tools option.

    설치 옵션에 대한 자세한 내용은 Visual Studio용 Python 지원 설치를 참조하세요.

    참고 항목

    데이터 과학 및 분석 애플리케이션 워크로드를 설치하면 Python 및 Python 네이티브 개발 도구 옵션이 기본적으로 설치됩니다.

  • Python을 별도로 설치하는 경우, 선택하는 리버깅 기호 다운로드 가 Python 설치 관리자의 고급 옵션 에 있어야 합니다. 이 옵션은 Python 코드와 네이티브 코드 간에 혼합 모드 디버깅을 사용하는 데 필요합니다.

Python 애플리케이션 만들기

Python 애플리케이션을 만들려면 다음 단계를 수행합니다.

  1. 파일>새로 만들기>프로젝트를 선택하여 Visual Studio에서 새 Python 프로젝트를 만듭니다.

  2. 새 포르젝트 만들기 대화 상자에서, python을 검색하세요. 이 Python 애플리케이션 템플릿을 선택하고 다음을 선택합니다.

  3. 프로젝트 이름위치를 입력하고, 만들기를 선택합니다.

    Visual Studio가 새 프로젝트를 만듭니다. 프로젝트가 솔루션 탐색기 에서 열리고 프로젝트 파일은 (.py) 코드 편집기에서 열립니다.

  4. .py 파일에, 다음 코드를 붙여 넣습니다. Python 편집 기능의 일부를 경험하려면 코드를 수동으로 입력해 보세요.

    이 코드는 수학 라이브러리를 사용하지 않고 쌍곡 탄젠트를 계산하며, Python 네이티브 확장을 사용하여 가속화됩니다.

    코드는 순수 Python에서 작성한 후에 C++로 다시 작성하세요. 이렇게 하면 네이티브 Python 코드가 올바른지 더 쉽게 확인할 수 있습니다.

    from random import random
    from time import perf_counter
    
    # Change the value of COUNT according to the speed of your computer.
    # The value should enable the benchmark to complete in approximately 2 seconds.
    COUNT = 500000
    DATA = [(random() - 0.5) * 3 for _ in range(COUNT)]
    
    e = 2.7182818284590452353602874713527
    
    def sinh(x):
        return (1 - (e ** (-2 * x))) / (2 * (e ** -x))
    
    def cosh(x):
        return (1 + (e ** (-2 * x))) / (2 * (e ** -x))
    
    def tanh(x):
        tanh_x = sinh(x) / cosh(x)
        return tanh_x
    
    def test(fn, name):
        start = perf_counter()
        result = fn(DATA)
        duration = perf_counter() - start
        print('{} took {:.3f} seconds\n\n'.format(name, duration))
    
        for d in result:
            assert -1 <= d <= 1, " incorrect values"
    
    if __name__ == "__main__":
        print('Running benchmarks with COUNT = {}'.format(COUNT))
    
        test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d] (Python implementation)')
    
  5. 프로그램을 실행하려면 디버그>디버깅 없이 시작 또는 키보드 바로 가기 단축키 Ctrl+F5를 선택하면 됩니다.

    프로그램 출력을 표시하는 명령 창이 열립니다.

  6. 출력에서 벤치마크 프로세스에 대해 보고된 시간을 확인합니다.

    이 연습에서는 벤치마크 프로세스에 약 2초가 소요됩니다.

  7. 필요에 따라 COUNT 코드의 변수의 값을 조정해 컴퓨터에서 벤치마크가 약 2초 안에 완료되도록 합니다.

  8. 프로그램을 다시 실행하고 수정된 COUNT 값이 약 2초 만에 벤치마크를 생성하는지 확인합니다.

벤치마크를 실행할 때는 항상 디버그>디버깅하지 않고 시작 옵션을 사용합니다. 이 메서드로 Visual Studio 디버거 내에서 코드를 실행할 때 발생하는 오버헤드를 방지할 수 있습니다.

핵심 C++ 프로젝트 만들기

다음 단계에 따라 두 개의 동일한 C++ 프로젝트인 superfastcodesuperfastcode2를 만듭니다. 나중에 각 프로젝트에 다른 방법을 사용하여 Python에 C++ 코드를 노출합니다.

  1. 솔루션 탐색기에서 솔루션 이름을 마우스 우클릭하고 추가>새 프로젝트를 선택합니다.

    Visual Studio 솔루션에는 Python과 C++ 프로젝트 둘 다 포함될 수 있으며, 이는 Python 개발용 Visual Studio를 사용하는 장점 중 하나입니다.

  2. 새 프로젝트 추가 대화 상자에서, 언어 필터를 C++로 설정하고 empty검색 상자에 입력합니다.

  3. 프로젝트 템플릿 결과 목록에서, 빈 프로젝트를 선택한 후 다음을 선택합니다.

  4. 새 프로젝트 구성 대화 상자에서, 프로젝트 이름을 입력합니다.

    • 첫 번째 프로젝트의 경우, 이름을 superfastcode라고 입력합니다.
    • 두 번째 프로젝트의 경우, 이름을 superfastcode2라고 입력합니다.
  5. 만들기를 실행합니다.

이러한 단계를 반복하여 프로젝트를 두 개 만들어야 합니다.

Visual Studio에 Python 네이티브 개발 도구가 설치되어 있는 경우 다른 방법을 사용할 수 있습니다. 먼저 Python 확장 모듈 템플릿을 시작하여 이 문서에서 설명하는 많은 단계를 미리 완료할 수 있습니다.

이 문서에 나온 해당 연습에서는, 빈 프로젝트로 시작하여 확장 모듈을 단계별로 빌드하는 법을 보여줍니다. 프로세스를 이해한 후에는 직접 확장을 작성할 때 대체 템플릿을 사용하여 시간을 절약할 수 있습니다.

프로젝트에 C++ 파일 추가하기

다음으로, 각 프로젝트에 C++ 파일을 추가합니다.

  1. 솔루션 탐색기에서, 프로젝트를 확장하고 소스 파일 노드를 마우스 우클릭한 후 추가>새 항목을 선택합니다.

  2. 파일 템플릿 목록에서 C++ 파일(.cpp)을 선택합니다.

  3. 파일의 이름을 바로 module.cpp로 입력한 다음, 추가를 선택합니다.

    Important

    파일 이름에 .cpp 확장자가 포함되어 있는지 확인하십시오. Visual Studio는 C++ 프로젝트 속성 페이지 표시를 활성화하기 위해 .cpp 확장이 있는 파일을 찾습니다.

  4. 툴바에서 구성 드롭다운 메뉴를 확장하고 대상 구성 유형을 선택합니다.

    Screenshot that shows how to set the target configuration type for the C++ project in Visual Studio.

    • 64비트 Python 런타임의 경우 x64 구성을 활성화합니다.
    • 32비트 Python 런타임의 경우 Win32 구성을 활성화합니다.

두 프로젝트 모두에 이러한 단계를 반복해야 합니다.

프로젝트 속성 구성하기

새 C++ 파일에 코드를 추가하기 전에, 각 C++ 모듈 프로젝트에 대한 속성을 구성하고 구성을 테스트하여 모든 것이 작동하는지 확인합니다.

각 모듈의 디버그릴리스 빌드 구성에 대한 프로젝트 속성을 설정해야 합니다.

  1. 솔루션 탐색기에서, C++ 모듈 프로젝트(superfastcodesuperfastcode2)를 우클릭한 후, 속성을 선택합니다.

  2. 모듈의 디버그 빌드에 대한 속성을 구성한 다음 릴리스 빌드에 대한 동일한 속성을 구성합니다.

    프로젝트 속성 페이지 대화 상자의 맨 위에서 다음의 파일 구성 옵션을 구성합니다.

    Screenshot that shows how to set the project build and platform options for the C++ file in Visual Studio.

    1. 구성을 위해, 디버그 또는 릴리스를 선택합니다. (옵션 중 활성 접두사가 있는 옵션이 표시될 수 있습니다.)

    2. 이전 단계에서 선택한 항목에 따라 플랫폼활성(x64) 또는 활성(Win32)을 선택합니다.

      참고 항목

      고유한 프로젝트를 만들 때, 특정 시나리오 요구 사항에 따라 디버그릴리스 구성을 별도로 구성할 수 있습니다. 이 연습에서는, CPython의 릴리스 빌드를 사용하는 구성을 설정합니다. 이 구성은 어설션을 포함하여 C++ 런타임의 일부 디버깅 기능을 사용하지 않도록 설정합니다. CPython 디버그 이진 파일(python_d.exe)을 사용하려면 다른 설정이 필요합니다.

    3. 다음 표에 설명된 대로 다른 프로젝트 속성을 설정합니다.

      속성 값을 변경하려면 속성 필드에 값을 입력합니다. 일부 필드의 경우, 현재 값을 선택하여 선택 항목의 드롭다운 메뉴를 확장하거나 대화 상자를 열어 값을 정의할 수 있습니다.

      탭에서 값을 업데이트한 후, 적용 을 다른 탭으로 전환하기 전에 선택합니다. 이 작업을 통해 변경 내용이 그대로인지 확인할 수 있습니다.

      탭 및 섹션 속성
      구성 속성>일반을 선택합니다. 대상 이름 모듈의 이름을 from...import 문에 있는 Python에서 참조하여 superfastcode같이 이름을 지정합니다 . Python에 대한 모듈을 정의하는 경우 C++ 코드에서 이 동일한 이름을 사용합니다. 프로젝트의 이름을 모듈 이름으로 사용하려는 경우 $<ProjectName>의 기본값을 그대로 둡니다. python_d.exe의 경우 이름 끝에 _d를 추가합니다.
      구성 형식 동적 라이브러리(.dll)
      구성 속성>고급 대상 파일 확장명 .pyd (Python 확장 모듈)
      C/C++>일반 추가 포함 디렉터리 설치에 맞게 Python include 폴더를 추가합니다(예: c:\Python36\include).
      C/C++>전처리기 전처리기 정의 있을 경우, _DEBUG 값을 NDEBUG 로 변경하여 CPython의 nondebug 버전과 일치시킵니다. 만약 python_d.exe를 사용하는 경우, 이 값을 변경하지 않고 그대로 유지합니다.
      C/C++>코드 생성 런타임 라이브러리 Multi-threaded DLL (/MD) 와 릴리스 (nondebug) 버전의 CPython을 일치시킵니다. 만약 python_d.exe를 사용하는 경우, 이 값을 다중 스레드 디버그 DLL(/MDd)로 유지합니다.
      기본 런타임 검사 기본값
      링커>일반 추가 라이브러리 디렉터리 설치에 맞게 .lib 파일을 포함하는 Python libs 폴더를 추가합니다(예: c:\Python36\libs). .py 파일을 포함하는 Lib 폴더가 ‘아니라’ .lib 파일을 포함하는 libs 폴더를 가리켜야 합니다.

      Important

      만약 C/C++ 탭이 프로젝트 속성에 옵션으로 표시되지 않으면, Visual Studio가 C/C++ 소스 파일로 식별하는 코드 파일이 프로젝트에 포함되어 있지 않은 것입니다. 이 상태는 .c 또는 .cpp 파일 확장명을 사용하지 않고 소스 파일을 만드는 경우에 발생할 수 있습니다.

      C++ 파일을 만들었는데 실수로 module.coo 모듈을 module.cpp 대신 입력한다면, Visual Studio에서 파일을 만들지만 파일 형식을 C/C+ compiler로 설정하지는 않습니다. 파일 형식은 프로젝트 속성 대화 상자에서 C/C++ 속성 탭의 존재를 활성화하는 데 필요합니다. 만약 .cpp 파일 확장을 갖고 있는 코드의 이름을 재지명한다면 오인이 계속 됩니다.

      코드 파일 형식을 제대로 설정하려면 솔루션 탐색기에서 코드 파일을 마우스 우클릭하고 속성을 선택합니다. 이 항목 유형에 대해 C/C++ 컴파일러를 선택합니다.

    4. 모든 속성을 업데이트한 후 확인을 선택합니다.

    다른 빌드 구성에서 해당 단계를 반복합니다.

  3. 현재 구성을 테스트합니다. 두 C++ 프로젝트의 디버그릴리스 빌드에 대한 다음 단계를 반복합니다.

    1. Visual Studio 툴바에서, 빌드 구성을 디버그 또는 릴리스로 설정합니다.

      Screenshot that shows how to set the build configuration for the C++ project in Visual Studio.

    2. 솔루션 탐색기에서, C++ 프로젝트를 마우스 우클릭한 후 빌드를 선택합니다.

      .pyd 파일은 솔루션 폴더에 있는데, 이는 디버그릴리스하에 있지, C++ 폴더 자체에 있는 것이 아닙니다.

코드 추가 및 테스트 구성

이제 C++ 파일에 코드를 추가하고 릴리스 빌드를 테스트할 준비가 되었습니다.

  1. superfastcode C++ 프로젝트에 대해, 코드 편집기에서 module.cpp 파일을 엽니다.

  2. module.cpp 파일에서, 다음 코드를 붙여 넣습니다.

    #include <Windows.h>
    #include <cmath>
    
    const double e = 2.7182818284590452353602874713527;
    
    double sinh_impl(double x) {
        return (1 - pow(e, (-2 * x))) / (2 * pow(e, -x));
    }
    
    double cosh_impl(double x) {
        return (1 + pow(e, (-2 * x))) / (2 * pow(e, -x));
    }
    
    double tanh_impl(double x) {
        return sinh_impl(x) / cosh_impl(x);
    }
    
  3. 변경 내용을 저장합니다.

  4. C++ 프로젝트에 대한 릴리스 구성을 빌드하여 코드가 올바른지 확인합니다.

단계를 반복하여 superfastcode 프로젝트의 C++ 파일에 코드를 추가하고 릴리스 빌드를 테스트합니다.

C++ 프로젝트를 Python용 확장으로 변환

C++ DLL을 Python용 확장으로 만들려면, 먼저 내보낸 메서드를 Python 형식과 상호 작용하도록 수정합니다. 그런 다음, 모듈의 메서드 정의와 함께 모듈을 내보내는 함수를 추가해야 합니다.

다음 섹션에서는 CPython 확장 및 PyBind11을 사용하여 확장을 만드는 방법을 보여 줍니다. 이 superfasctcode 프로젝트는 CPython 확장을 사용하고 superfasctcode2 프로젝트는 PyBind11을 구현합니다.

CPython 확장 사용

이 섹션에 표시된 코드에 대한 자세한 배경 정보는 Python/C API 참조 설명서, 특히 모듈 객체 페이지를 참조하세요. 참조 콘텐츠를 검토할 때 오른쪽 위에 있는 드롭다운 목록에서 Python 버전을 선택해야 합니다.

  1. superfastcode C++ 프로젝트에 대해, 코드 편집기에서 module.cpp 파일을 엽니다.

  2. 문을 module.cpp 파일 맨 위에 추가하여 Python.h 헤더 파일을 포함합니다.

    #include <Python.h>
    
  3. tanh_impl 메서드 코드를 대체하여 Python 형식(즉, PyObject*)을 허용하고 반환합니다.

    PyObject* tanh_impl(PyObject* /* unused module reference */, PyObject* o) {
        double x = PyFloat_AsDouble(o);
        double tanh_x = sinh_impl(x) / cosh_impl(x);
        return PyFloat_FromDouble(tanh_x);
    }
    
  4. 파일의 끝에, C++ tanh_impl 함수를 Python에 제공하는 방법을 정의하는 구조를 추가합니다.

    static PyMethodDef superfastcode_methods[] = {
        // The first property is the name exposed to Python, fast_tanh
        // The second is the C++ function with the implementation
        // METH_O means it takes a single PyObject argument
        { "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr },
    
        // Terminate the array with an object containing nulls
        { nullptr, nullptr, 0, nullptr }
    };
    
  5. 다른 구조를 추가하여 from...import 문을 사용할 때 특히 Python 코드에서 참조하려는 모듈을 정의합니다.

    이 코드에서 가져오는 이름은 구성 속성>일반>대상 이름아래의 프로젝트 속성 값과 일치해야 합니다.

    다음 예제에서 "superfastcode" 이름은 from superfastcode import fast_tanh Python에서 문를 사용할 수 있음을 의미하는데, fast_tanhsuperfastcode_methods내에 정의되어 있기 때문입니다. module.cpp와 같이 C++ 프로젝트 내부에 있는 파일 이름은 중요하지 않습니다.

    static PyModuleDef superfastcode_module = {
        PyModuleDef_HEAD_INIT,
        "superfastcode",                        // Module name to use with Python import statements
        "Provides some functions, but faster",  // Module description
        0,
        superfastcode_methods                   // Structure that defines the methods of the module
    };
    
  6. Python이 모듈을 로드할 때 호출하는 메서드를 추가합니다. 메서드 이름은 PyInit_<module-name>반드시 <모듈 이름> 이 C++ 프로젝트의 구성 속성>일반>대상 이름 속성과 정확히 일치해야 합니다. 즉, 프로젝트에서 빌드되는 .pyd 파일의 파일 이름과 메서드 이름이 일치합니다.

    PyMODINIT_FUNC PyInit_superfastcode() {
        return PyModule_Create(&superfastcode_module);
    }
    
  7. C++ 프로젝트를 빌드하고 코드를 확인합니다. 오류가 발생할 경우 컴파일 오류 문제 해결 섹션을 참조하세요.

PyBind11 사용

만약 superfastcode 프로젝트에 대한 이전 섹션에서의 단계를 완료한 경우, C++ CPython 확장에 대한 모듈 구조를 만드는 상용구 코드가 연습에서 필요하다는 것을 알 수 있습니다. 이 연습에서는 PyBind11이 코딩 프로세스를 간소화한다는 것을 알게 됩니다. C++ 헤더 파일에서 매크로를 사용하여 동일한 결과를 수행하지만 수반되는 코드는 훨씬 적습니다. 그러나 Visual Studio에서 PyBind11 라이브러리를 찾고 파일을 포함할 수 있도록 하기 위해서는 추가 단계가 필요합니다. 이 섹션의 코드에 대한 자세한 내용은 PyBind11 basics(PyBind11 기본 사항)를 참조하세요.

PyBind11 설치

첫 번째 단계는 프로젝트 구성에 PyBind11을 설치하는 것입니다. 이 연습에서는, 개발자 PowerShell 창을 사용합니다.

  1. 도구>명령줄>개발자 PowerShell 창을 엽니다.

  2. 개발자 PowerShell 창에서, pip 명령 pip install pybind11 또는 py -m pip install pybind11를 사용하여 PyBind11을 설치합니다.

    Visual Studio는 PyBind11 및 종속 패키지를 설치합니다.

프로젝트에 PyBind11 경로 추가

PyBind11이 설치되면, PyBind11 경로를 프로젝트의 추가 포함 디렉터리 속성에 추가해야 합니다.

  1. 개발자 PowerShell 창에서, 명령 python -m pybind11 --includes 또는 py -m pybind11 --includes을 실행합니다.

    이 작업은 프로젝트 속성에 추가해야 하는 PyBind11 경로 목록을 출력합니다.

  2. 창에서 경로 목록을 강조 표시하고 창 툴바에서 (두 페이지) 복사 를 선택합니다.

    Screenshot that shows how to highlight and copy the list of paths from the Developer PowerShell window in Visual Studio.

    연결된 경로 목록이 클립보드에 추가됩니다.

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

  4. 속성 페이지 대화상자의 맨 위에서, 구성 필드에 대해 릴리스를 선택합니다. (옵션 중 활성 접두사가 있는 옵션이 표시될 수 있습니다.)

  5. 대화 상자의 C/C++>일반 탭에서 추가 포함 디렉토리 속성의 드롭다운 메뉴를 확장하고 편집을 선택합니다.

  6. 팝업 대화 상자에서, 복사한 경로 목록을 추가합니다.

    개발자 PowerShell 창에서 복사한 연결된 목록의 각 경로에 대해 해당 단계를 반복합니다.

    1. 팝업 대화 상자 도구 모음에서 새 줄 (더하기 기호가 있는 폴더)을 선택합니다.

      Screenshot that shows how to add a PyBind11 path to the Additional Include Directories property.

      Visual Studio는 경로 목록 맨 위에 빈 줄을 추가하고 삽입 커서를 시작 부분에 배치합니다.

    2. PyBind11 경로를 빈 줄에 붙여 넣습니다.

      또한 추가 옵션 (...)을 선택하고 팝업 파일 탐색기 대화 상자를 사용하여 경로 위치를 찾아볼 수도 있습니다.

      Important

      • 만약 경로에 -I 접두사를 포함하는 경우, 경로에서 접두사를 제거합니다.
      • Visual Studio에서 경로를 인식하려면, 경로가 별도의 줄에 있어야 합니다.

      새 경로를 추가한 후, Visual Studio는 평가된 값 필드에 확인된 경로를 보여줍니다.

  7. 팝업 대화 상자를 종료하려면 확인 을 선택합니다.

  8. 속성 페이지 대화 상자에서, 추가 포함 디렉토리 속성의 값을 마우스로 가리키고 PyBind11 경로가 있는지 확인합니다.

  9. 속성 변화를 적용하려면 확인 을 클릭합니다.

module.cpp 파일 업데이트

마지막 단계는 PyBind11 헤더 파일 및 매크로 코드를 프로젝트 C++ 파일에 추가하는 것입니다.

  1. superfastcode2 C++ 프로젝트에 대해, 코드 편집기에서 module.cpp 파일을 엽니다.

  2. 문을 module.cpp 파일 맨 위에 추가하여 pybind11.h 헤더 파일을 포함합니다.

    #include <pybind11/pybind11.h>
    
  3. module.cpp 파일의 맨 뒤에서, PYBIND11_MODULE 매크로에 대한 코드를 추가하여 C++ 함수에 대한 진입점을 정의합니다.

    namespace py = pybind11;
    
    PYBIND11_MODULE(superfastcode2, m) {
        m.def("fast_tanh2", &tanh_impl, R"pbdoc(
            Compute a hyperbolic tangent of a single argument expressed in radians.
        )pbdoc");
    
    #ifdef VERSION_INFO
        m.attr("__version__") = VERSION_INFO;
    #else
        m.attr("__version__") = "dev";
    #endif
    }
    
  4. C++ 프로젝트를 빌드하고 코드를 확인합니다. 오류가 발생할 경우, 다음 섹션인 컴파일 오류 문제 해결 섹션을 참조하세요.

컴파일 오류 문제 해결

C++ 모듈 빌드의 실패를 초래할 가능성이 있는 문제의 경우 다음 섹션을 검토하세요.

오류: 헤더 파일을 찾을 수 없습니다.

Visual Studio는 E1696: 소스 파일 "Python.h"을 열 수 없습니다 또는 C1083: "Python.h" 파일을 열 수 없습니다: 해당 파일이나 디렉토리가 없습니다같은 에러 메시지를 반환합니다.

이 오류는 컴파일러가 프로젝트에 필요한 헤더(.h) 파일을 찾을 수 없음을 나타냅니다.

  • superfastcode 프로젝트의 경우, C/C++>일반>추가 포함 디렉토리 프로젝트 속성이 Python 설치에 필요한 include 폴더에 경로를 포함하고 있는지 확인합니다. 검토할 단계는 프로젝트 속성 구성에 있습니다.

  • superfastcode2 프로젝트의 경우, 동일한 프로젝트 속성에 PyBind11 설치에 대한 include 폴더를 경로에 포함하고 있는지 확인합니다. 검토할 단계는 프로젝트에 대한 Ad PyBind 경로에 있습니다.

Python 설치 구성 정보에 액세스하는 방법에 대한 자세한 내용은 Python 설명서를 참조하세요.

오류: Python 라이브러리를 찾을 수 없습니다.

Visual Studio는 프로젝트에 필요한 DLL(라이브러리) 파일을 컴파일러가 찾을 수 없음을 나타내는 오류를 반환합니다.

  • C++ 프로젝트(superfastcode 또는 superfastcode2)에 대해, 링커>일반>추가 라이브러리 디렉토리 속성이 Python 설치에 필요한 libs 폴더로 이어지는 경로를 포함하고 있는지 확인합니다. 검토할 단계는 프로젝트 속성 구성에 있습니다.

Python 설치 구성 정보에 액세스하는 방법에 대한 자세한 내용은 Python 설명서를 참조하세요.

Visual Studio는 x64 또는 Win32와 같은, 프로젝트의 대상 아키텍처 구성과 관련된 링커 오류를 보고합니다.

  • C++ 프로젝트(superfastcode 또는 superfastcode2)의 경우, Python 설치와 일치하도록 대상 구성을 변경합니다. 예를 들어, C++ 프로젝트에서 Win32를 대상 구성으로 지정하지만 Python 설치가 64비트인 경우, C++ 프로젝트 대상 구성을 x64로 변경합니다.

코드를 테스트하고 결과 비교

DLL을 Python 확장으로 구조화했으므로 Python 프로젝트에서 이를 참조하고, 모듈을 가져오고, 해당 메서드를 사용할 수 있습니다.

Python에서 DLL을 사용할 수 있도록 설정

여러 가지 방법으로 Python에서 DLL을 사용할 수 있도록 설정할 수 있습니다. 고려할 옵션 두 가지는 다음과 같습니다.

Python 프로젝트와 C++ 프로젝트가 동일한 솔루션에 있는 경우 다음 방법을 사용할 수 있습니다.

  1. 솔루션 탐색기에서, Python 프로젝트의 참조 노드를 마우스 우클릭한 후 참조 추가를 선택합니다.

    C++ 프로젝트가 아닌 Python 프로젝트에 대해 이 작업을 수행해야 합니다.

  2. 참조 추가 대화 상자에서 프로젝트 탭을 확장합니다.

  3. 체크박스를 superfastcodesuperfastcode2 양 프로젝트 모두에 대해 선택하고 확인을 선택합니다.

    Screenshot that shows how to add a reference to the super fast code project in Visual Studio.

다른 방법으로는 Python 환경에 C++ 확장 모듈을 설치하는 것이 있습니다. 이 메서드를 사용하면 다른 Python 프로젝트에서 모듈을 사용할 수 있습니다. 자세한 내용은 셋업툴 프로젝트 설명서를 참조하세요.

다음 단계를 완료하여 Python 환경에 C++ 확장 모듈을 설치합니다.

  1. 솔루션 탐색기에서, C++ 프로젝트를 마우스 우클릭한 후 추가>새 항목을 선택합니다.

  2. 파일 템플릿 목록에서 C++ 파일(.cpp)을 선택합니다.

  3. 파일의 이름을 바로 setup.py로 입력한 다음, 추가를 선택합니다.

    Python(.py) 확장을 사용하여 파일 이름을 입력해야 합니다. C++ 파일 템플릿을 사용했어도 Visual Studio는 해당 파일을 Python 코드로 인식합니다.

    코드 편집기에서 Visaul Studio로 새 파일이 열립니다.

  4. 새 파일에 다음 코드를 붙여 넣습니다. 확장 메서드에 해당하는 코드 버전을 선택합니다.

    • CPython 확장 (superfastcode 프로젝트).

      from setuptools import setup, Extension
      
      sfc_module = Extension('superfastcode', sources = ['module.cpp'])
      
      setup(
          name='superfastcode',
          version='1.0',
          description='Python Package with superfastcode C++ extension',
          ext_modules=[sfc_module]
      )
      
    • PyBind11 (superfastcode2 프로젝트).

      from setuptools import setup, Extension
      import pybind11
      
      cpp_args = ['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.7']
      
      sfc_module = Extension(
          'superfastcode2',
          sources=['module.cpp'],
          include_dirs=[pybind11.get_include()],
          language='c++',
          extra_compile_args=cpp_args,
      )
      
      setup(
          name='superfastcode2',
          version='1.0',
          description='Python package with superfastcode2 C++ extension (PyBind11)',
          ext_modules=[sfc_module],
      )
      
  5. C++ 프로젝트에서, pyproject.toml이라는 두 번째 파일을 만들고 다음의 코드를 붙여 넣습니다.

    [build-system]
    requires = ["setuptools", "wheel", "pybind11"]
    build-backend = "setuptools.build_meta"
    

    TOML (.toml) 파일은 구성 파일에 Tom's Obvious, Minimal Language 형식을 사용합니다.

  6. 확장을 빌드하려면, 코드 window 탭에 있는 pyproject.toml 파일 이름을 마우스 우클릭하고 전체 경로 복사를 선택합니다.

    Screenshot that shows how to copy the full path to the py project toml file in Visual Studio.

    경로에서 pyproject.toml 이름을 삭제한 후에 사용합니다.

  7. 솔루션 탐색기에서, 솔루션에 대한 Python 환경 노드를 확장합니다.

  8. (볼드체로 표시된) 활성 Python 환경을 마우스 우클릭한 후, Python 패키지 관리를 선택합니다.

    Python 환경 창이 열립니다.

    필요한 패키지가 이미 설치되어 있으면, 이 창에 나열됩니다.

    • 계속하기 전에, 패키지 이름 옆에 있는 X 를 선택하여 제거합니다.

    Screenshot that shows how to uninstall a package in the Python Environments pane.

  9. Python Environments 검색 창의 검색 상자에 복사한 경로를 붙여 넣고, 경로 끝에서부터 pyproject.toml 파일 이름을 삭제합니다.

    Screenshot that shows how to enter the path in the Python Environments pane to install the extension module.

  10. 복사한 경로의 위치에서 모듈을 설치하려면 입력 을 선택합니다.

    만약 권한 오류로 설치가 실패하는 경우, --user 인수를 명령 끝에 추가하고, 설치를 다시 시도합니다.

Python에서 DLL 호출

이전 섹션에서 설명한 대로 Python에서 DLL을 사용할 수 있도록 하면 Python에서 superfastcode.fast_tanhsuperfastcode2.fast_tanh2 함수를 호출할 준비가 된 것입니다. 그런 다음 함수 성능을 Python 구현과 비교할 수 있습니다.

다음 단계에 따라 Python에서 확장 모듈 DLL을 호출합니다.

  1. 코드 편집기에서 Python 프로젝트에 대한 .py 파일을 엽니다.

  2. 파일의 끝에, 다음 코드를 추가하여 DLL에서 가져온 메서드를 호출하고 출력을 표시합니다.

    from superfastcode import fast_tanh
    test(lambda d: [fast_tanh(x) for x in d], '[fast_tanh(x) for x in d] (CPython C++ extension)')
    
    from superfastcode2 import fast_tanh2
    test(lambda d: [fast_tanh2(x) for x in d], '[fast_tanh2(x) for x in d] (PyBind11 C++ extension)')
    
  3. Python 프로그램을 실행하려면 디버그>디버깅하지 않고 시작 을 선택하거나 또는 키보드 바로 가기 단축키 Ctrl+F5를 사용하면 됩니다.

    참고 항목

    만약 디버깅하지 않고 시작 명령이 사용 불가능한 경우 솔루션 탐색기에서 Python 프로젝트를 마우스 우클릭하고 시작 프로젝트로 설정을 선택합니다.

    프로그램이 실행되면, C++ 루틴이 Python 구현보다 약 5~20배 빠르게 실행됩니다.

    일반적인 프로그램 출력의 예는 다음과 같습니다.

    Running benchmarks with COUNT = 500000
    [tanh(x) for x in d] (Python implementation) took 0.758 seconds
    
    [fast_tanh(x) for x in d] (CPython C++ extension) took 0.076 seconds
    
    [fast_tanh2(x) for x in d] (PyBind11 C++ extension) took 0.204 seconds
    
  4. 시간 차이가 더 분명해지도록 COUNT 변수를 늘려 보세요.

    디버그 필드의 최적화 수준이 낮아지고 다양한 오류 검사를 포함하기 때문에 디버그 빌드의 C++ 모듈 또한 릴리스 빌드보다 느리게 실행됩니다. 비교를 위해 빌드 구성을 전환할 수 있지만 릴리스 구성의 경우 앞에서 설정한 속성으로 돌아가 업데이트해야 합니다.

주소 프로세스 속도 및 오버헤드

출력에서 보면, PyBind11 확장이 CPython 확장만큼 빠르지 않지만 순수 Python 구현보다는 더 빠른 점을 알 수 있습니다. 이런 차이의 주된 이유는 METH_O flag사용 때문입니다. 이 플래그는 여러 매개 변수, 매개 변수 이름 또는 키워드(keyword) 인수를 지원하지 않습니다. PyBind11은 약간 더 복잡한 코드를 생성하여 호출자에게 Python과 더 유사한 인터페이스를 제공합니다. 테스트 코드가 함수를 500,000번 호출하므로 결과적으로 오버헤드가 더 커질 수 있습니다.

네이티브 Python 코드로 for 루프를 이동시켜 오버헤드를 더 줄일 수 있습니다. 이 방법에서는 반복기 프로토콜(또는 py::iterable함수 매개 변수에 대한 PyBind11 형식)을 사용하여 각 요소를 처리합니다. Python과 C++ 사이에서 반복되는 전환을 제거하면 시퀀스를 처리하는 데 걸리는 시간을 효과적으로 줄일 수 있습니다.

가져오기 오류 문제 해결

모듈을 가져오려고 할 때 ImportError 메시지가 표시되면 다음 방법 중 하나로 해결할 수 있습니다.

  • 프로젝트 참조를 통해 빌드하는 경우, C++ 프로젝트 속성이 Python 프로젝트에 대해 활성화된 Python 환경과 일치하는지 확인합니다. 동일한 폴더 위치를 Include (.h) 및 라이브러리 (DLL) 파일이 사용하는지 확인합니다.

  • 출력 파일의 이름이 올바르게 지정되었는지 확인합니다(예: superfastcode.pyd). 잘못된 이름 또는 확장명을 사용하면 필요한 파일을 가져올 수 없습니다.

  • 모듈을 설치하려고 setup.py 파일을 사용하는 경우, Python 프로젝트가 활성화된 Python 환경에서 pip 명령을 실행하도록 합니다. 프로젝트에 대한 활성 Python 환경을 솔루션 탐색기에서 확장하면, superfastcode같이, C++ 프로젝트에 대한 항목이 표시됩니다.

C++ 코드 디버그

Visual Studio는 디버깅 Python 및 C++ 코드를 함께 지원합니다. 다음 단계에서는 superfastcode C++ 프로젝트에 대한 디버그 프로세스를 보여주지만, 그 프로세스는 superfastcode2 프로젝트에 대한 프로세스와 동일합니다.

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

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

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

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

  4. Visual Studio 툴바에서, 빌드 구성을 디버그로 설정합니다.

  5. 일반적으로 디버거에서 코드를 실행하는 데 더 많은 시간이 걸리기 때문에 COUNT Python 프로젝트 .py 파일에 있는 변수를 기본 값보다 약 5배 작은 값으로 변경하는 것이 좋습니다. 예를 들어 500000에서 100000으로 변경합니다.

  6. C++ 코드에서, tanh_impl 메서드의 첫 줄에 중단점을 설정합니다.

  7. 디버거를 시작하려면 디버그>디버깅 시작 을 선택하거나 키보드 바로 가기 키 F5를 사용합니다.

    디버거는 중단점 코드가 호출되면 중지합니다. 중단점이 적중되지 않으면, 구성이 디버그 로 설정되어 있는지, 프로젝트를 저장했는지 확인합니다. 이 작업은 디버거를 시작할 때 자동으로 수행되지 않습니다.

    Screenshot of C++ code that contains a breakpoint in Visual Studio.

  8. 중단점에서 C++ 코드를 단계별로 실행하고 변수를 검사하는 등의 작업을 수행할 수 있습니다. 이러한 기능에 대한 자세한 내용은 Python과 C++ 함께 디버그를 참조하세요.

대체 접근법

다음 표에 설명된 바와 같이 다양한 방법으로 Python 확장을 만들 수 있습니다. 이 문서에서는 처음 두 행인 CPythonPyBind11에 대해 설명합니다.

접근법 Vintage 대표적인 사용 대상
CPython용 C/C++ 확장 모듈 1991 표준 라이브러리
PyBind11(C++에 권장됨) 2015
Cython(C에 권장됨) 2007 gevent, kivy
HPy 2019
mypyc 2017
ctypes 2003 oscrypto
cffi 2013 cryptography, pypy
SWIG 1996 crfsuite
Boost.Python 2002
cppyy 2017