5. Створення розширень C і C++ у Windows

У цій главі коротко пояснюється, як створити модуль розширення Windows для Python за допомогою Microsoft Visual C++, а далі надається більш детальна довідкова інформація про те, як це працює. Пояснювальний матеріал корисний як для Windows-програміста, який навчається створювати розширення Python, так і для Unix-програміста, зацікавленого у створенні програмного забезпечення, яке можна успішно створювати як на Unix, так і на Windows.

Авторам модулів рекомендується використовувати підхід distutils для створення модулів розширення замість описаного в цьому розділі. Вам все одно знадобиться компілятор C, який використовувався для створення Python; зазвичай Microsoft Visual C++.

Примітка

У цьому розділі згадується кілька імен файлів, які включають закодований номер версії Python. Ці назви файлів представлені номером версії, показаним як XY; на практиці 'X' буде номером основної версії, а 'Y'' буде номером другорядної версії випуску Python, з яким ви працюєте. Наприклад, якщо ви використовуєте Python 2.2.1, XY насправді буде 22.

5.1. Підхід з кулінарної книги

There are two approaches to building extension modules on Windows, just as there are on Unix: use the setuptools package to control the build process, or do things manually. The setuptools approach works well for most extensions; documentation on using setuptools to build and package extension modules is available in Building C and C++ Extensions with setuptools. If you find you really need to do things manually, it may be instructive to study the project file for the winsound standard library module.

5.2. Відмінності між Unix і Windows

Unix і Windows використовують абсолютно різні парадигми для завантаження коду під час виконання. Перш ніж спробувати створити модуль, який можна динамічно завантажувати, ознайомтеся з тим, як працює ваша система.

В Unix файл спільного об’єкта (.so) містить код, який буде використовуватися програмою, а також назви функцій і даних, які вона очікує знайти в програмі. Коли файл приєднується до програми, усі посилання на ці функції та дані в коді файлу змінюються, щоб вказувати на фактичні місця в програмі, де функції та дані розміщені в пам’яті. По суті, це операція посилання.

У Windows файл бібліотеки динамічного компонування (.dll) не має висячих посилань. Натомість доступ до функцій або даних відбувається через таблицю пошуку. Тому код DLL не потрібно виправляти під час виконання, щоб посилатися на пам’ять програми; замість цього код уже використовує таблицю пошуку DLL, і таблиця пошуку змінюється під час виконання, щоб вказувати на функції та дані.

В Unix існує лише один тип файлу бібліотеки (.a), який містить код із кількох об’єктних файлів (.o). Під час етапу зв’язування для створення файлу спільного об’єкта (.so) компонувальник може виявити, що він не знає, де визначено ідентифікатор. Компонувальник шукатиме його в об’єктних файлах у бібліотеках; якщо він знайде його, він включить увесь код із цього об’єктного файлу.

У Windows існує два типи бібліотек: статична та імпортована (обидві називаються .lib). Статична бібліотека схожа на файл Unix .a; він містить код, який слід включити за необхідності. Бібліотека імпорту в основному використовується лише для того, щоб переконати компонувальник у тому, що певний ідентифікатор є законним і буде присутній у програмі, коли DLL завантажується. Таким чином, компонувальник використовує інформацію з бібліотеки імпорту для створення таблиці пошуку для використання ідентифікаторів, які не включені в DLL. Коли програму або DLL пов’язано, може бути створена бібліотека імпорту, яку потрібно буде використовувати для всіх майбутніх DLL, які залежать від символів у програмі чи DLL.

Припустімо, ви створюєте два модулі динамічного завантаження, B і C, які мають спільно використовувати ще один блок коду A. В Unix ви не передаєте A.a компонувальнику для B.so і C.so; це призвело б до того, що його було б включено двічі, так що B і C мали б кожен свою копію. У Windows збірка A.dll також створить A.lib. Ви передаєте A.lib компонувальнику для B і C. A.lib не містить коду; він просто містить інформацію, яка буде використана під час виконання для доступу до коду A.

У Windows використання бібліотеки імпорту схоже на використання import spam; він надає вам доступ до імен спаму, але не створює окремої копії. В Unix зв’язування з бібліотекою більше схоже на імпорт спаму *; він створює окрему копію.

Turn off the implicit, #pragma-based linkage with the Python library, performed inside CPython header files.

Added in version 3.14.

5.3. Використання DLL на практиці

Windows Python побудовано на Microsoft Visual C++; використання інших компіляторів може працювати, а може і не працювати. Решта цього розділу стосується MSVC++.

When creating DLLs in Windows, you can use the CPython library in two ways:

  1. By default, inclusion of PC/pyconfig.h directly or via Python.h triggers an implicit, configure-aware link with the library. The header file chooses pythonXY_d.lib for Debug, pythonXY.lib for Release, and pythonX.lib for Release with the Limited API enabled.

    To build two DLLs, spam and ni (which uses C functions found in spam), you could use these commands:

    cl /LD /I/python/include spam.c
    cl /LD /I/python/include ni.c spam.lib
    

    The first command created three files: spam.obj, spam.dll and spam.lib. Spam.dll does not contain any Python functions (such as PyArg_ParseTuple()), but it does know how to find the Python code thanks to the implicitly linked pythonXY.lib.

    Друга команда створила ni.dll.obj і .lib), який вміє знаходити потрібні функції в спамі, а також у виконуваному файлі Python.

  2. Manually by defining Py_NO_LINK_LIB macro before including Python.h. You must pass pythonXY.lib to the linker.

    To build two DLLs, spam and ni (which uses C functions found in spam), you could use these commands:

    cl /LD /DPy_NO_LINK_LIB /I/python/include spam.c ../libs/pythonXY.lib
    cl /LD /DPy_NO_LINK_LIB /I/python/include ni.c spam.lib ../libs/pythonXY.lib
    

    Перша команда створила три файли: spam.obj, spam.dll і spam.lib. Spam.dll не містить жодних функцій Python (таких як PyArg_ParseTuple()), але він знає, як знайти код Python завдяки pythonXY.lib.

    Друга команда створила ni.dll.obj і .lib), який вміє знаходити потрібні функції в спамі, а також у виконуваному файлі Python.

Не кожен ідентифікатор експортується до таблиці пошуку. Якщо ви хочете, щоб будь-які інші модулі (включно з Python) могли бачити ваші ідентифікатори, вам потрібно сказати _declspec(dllexport), як у void _declspec(dllexport) initspam(void) або PyObject _declspec(dllexport) *NiGetSpamData(void).

Developer Studio will throw in a lot of import libraries that you do not really need, adding about 100K to your executable. To get rid of them, use the Project Settings dialog, Link tab, to specify ignore default libraries. Add the correct msvcrtxx.lib to the list of libraries.