4. C와 C++ 확장 빌드하기
************************

CPython의 C 확장은 *초기화 함수*를 내보내는 공유 라이브러리입니다 (예
를 들어, 리눅스는 ".so", 윈도우는 ".pyd").

임포트 할 수 있으려면, 공유 라이브러리가 "PYTHONPATH"에 있어야 하며,
모듈 이름을 따라 적절한 확장자를 붙여서 이름 지어야 합니다. distutils
를 사용하면, 올바른 파일 이름이 자동으로 생성됩니다.

초기화 함수는 다음과 같은 서명을 갖습니다:

PyObject* PyInit_modulename(void)

완전히 초기화된 모듈이나 "PyModuleDef" 인스턴스를 반환합니다. 자세한
내용은 C 모듈 초기화을 참조하십시오.

ASCII로만 이루어진 이름을 가진 모듈의 경우, 함수의 이름을
"PyInit_<modulename>"이어야 합니다. 여기서 "<modulename>"을 모듈의 이
름으로 치환합니다. 다단계 초기화를 사용할 때 ASCII가 아닌 모듈 이름이
허용됩니다. 이 경우, 초기화 함수 이름은 "PyInitU_<modulename>"이며
"<modulename>"은 파이썬의 *punycode* 인코딩으로 인코딩되고 하이픈을 밑
줄로 대체합니다. 파이썬에서:

   def initfunc_name(name):
       try:
           suffix = b'_' + name.encode('ascii')
       except UnicodeEncodeError:
           suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
       return b'PyInit' + suffix

여러 초기화 함수를 정의하여 단일 공유 라이브러리에서 여러 모듈을 내보
낼 수 있습니다. 그러나, 이들을 임포트 하려면 심볼릭 링크나 사용자 정의
임포터를 사용해야 합니다. 기본적으로 파일 이름에 해당하는 함수만 발견
되기 때문입니다. 자세한 내용은 **PEP 489**의 *"한 라이브러리에 여러 모
듈"* 절을 참조하십시오.


4.1. distutils로 C와 C++ 확장 빌드하기
======================================

확장 모듈은 파이썬에 포함된 distutils를 사용하여 빌드할 수 있습니다.
distutils가 바이너리 패키지의 생성을 지원하기 때문에, 사용자는 확장을
설치하기 위해 꼭 컴파일러와 distutils가 필요하지는 않습니다.

distutils 패키지에는 드라이버 스크립트인 "setup.py"가 들어 있습니다.
이것은 평범한 파이썬 파일인데, 대부분 간단한 경우에 이런 식입니다:

   from distutils.core import setup, Extension

   module1 = Extension('demo',
                       sources = ['demo.c'])

   setup (name = 'PackageName',
          version = '1.0',
          description = 'This is a demo package',
          ext_modules = [module1])

이 "setup.py"와 파일 "demo.c"로 다음을 실행하면

   python setup.py build

"demo.c"를 컴파일하고, "build" 디렉터리에 "demo"라는 확장 모듈을 생성
합니다. 시스템에 따라, 모듈 파일은 "build/lib.system" 하위 디렉터리에
들어가고, "demo.so"나 "demo.pyd"와 같은 이름을 가질 수 있습니다.

"setup.py"에서, 모든 실행은 "setup" 함수를 호출하여 수행됩니다. 이것은
다양한 키워드 인자를 받아들입니다. 위의 예에서는 일부만 사용합니다. 구
체적으로, 이 예는 패키지를 빌드하기 위한 메타 정보를 지정하고 패키지의
내용을 지정합니다. 일반적으로, 패키지는 파이썬 소스 모듈, 문서, 서브
패키지 등과 같은 추가 모듈이 포함됩니다. distutils의 기능에 대한 자세
한 내용은 파이썬 모듈 배포 (레거시 버전)의 distutils 설명서를 참조하십
시오; 이 절에서는 확장 모듈을 빌드하는 것만 설명합니다.

드라이버 스크립트를 더 잘 구조화하기 위해, "setup()"에 대한 인자를 미
리 계산하는 것이 일반적입니다. 위의 예에서, "setup()"에 대한
"ext_modules" 인자는 확장 모듈의 리스트며, 각 모듈은 "Extension"의 인
스턴스입니다. 이 예에서, 인스턴스는 단일 소스 파일 "demo.c"를 컴파일하
여 빌드하는 "demo"라는 확장을 정의합니다.

많은 경우, 확장을 빌드하는 것은 더 복잡합니다. 왜냐하면, 추가적인 전처
리기 정의와 라이브러리가 필요할 수 있기 때문입니다. 이는 아래에서 예시
합니다.

   from distutils.core import setup, Extension

   module1 = Extension('demo',
                       define_macros = [('MAJOR_VERSION', '1'),
                                        ('MINOR_VERSION', '0')],
                       include_dirs = ['/usr/local/include'],
                       libraries = ['tcl83'],
                       library_dirs = ['/usr/local/lib'],
                       sources = ['demo.c'])

   setup (name = 'PackageName',
          version = '1.0',
          description = 'This is a demo package',
          author = 'Martin v. Loewis',
          author_email = 'martin@v.loewis.de',
          url = 'https://docs.python.org/extending/building',
          long_description = '''
   This is really just a demo package.
   ''',
          ext_modules = [module1])

이 예에서, "setup()"는 추가 메타 정보로 호출되며, 배포 패키지를 빌드해
야 할 때 권장됩니다. 확장 자체에 대해서는, 전처리기 정의, 인클루드 디
렉터리, 라이브러리 디렉터리 및 라이브러리를 지정합니다. 컴파일러에 따
라, distutils는 이 정보를 다양한 방법으로 컴파일러에 전달합니다. 예를
들어, 유닉스에서는 다음과 같은 컴파일 명령으로 이어질 수 있습니다

   gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o

   gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so

이 줄은 예시 목적일 뿐입니다; distutils 사용자는 distutils가 올바르게
호출한다고 믿어야 합니다.


4.2. 확장 모듈 배포하기
=======================

확장이 성공적으로 빌드되면, 이를 사용하는 세 가지 방법이 있습니다.

최종 사용자는 보통 모듈을 설치하고 싶을 것이고, 다음을 실행합니다

   python setup.py install

모듈 관리자는 소스 패키지를 생성해야 합니다; 그러려면, 이렇게 실행합니
다

   python setup.py sdist

때에 따라, 추가 파일을 소스 배포에 포함해야 합니다; 이 작업은
"MANIFEST.in" 파일을 통해 수행됩니다; 자세한 내용은 배포할 파일 지정하
기를 참조하십시오.

소스 배포가 성공적으로 빌드되면, 관리자는 바이너리 배포도 만들 수 있습
니다. 플랫폼에 따라, 이를 위해 다음 명령 중 하나를 사용할 수 있습니다.

   python setup.py bdist_wininst
   python setup.py bdist_rpm
   python setup.py bdist_dumb
