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 зв’язування з бібліотекою більше схоже на імпорт спаму *; він створює окрему копію.

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

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

Під час створення DLL у Windows ви повинні передати pythonXY.lib до компонувальника. Щоб створити дві бібліотеки DLL, spam і ni (яка використовує функції C, знайдені в спамі), ви можете використати такі команди:

cl /LD /I/python/include spam.c ../libs/pythonXY.lib
cl /LD /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.