Установить только заголовочную библиотеку с Python - PullRequest
0 голосов
/ 30 апреля 2018

У меня есть библиотека C ++ только для заголовков, которую я использую в своих расширениях Python. Я хотел бы иметь возможность установить их по пути включения Python, так что я могу очень легко скомпилировать расширения с помощью python3 setup.py build. Я частично могу, но есть две вещи, с которыми я не могу работать (см. Ниже):

  1. Как я могу использовать python3 setup.py install для установки файлов заголовков? В настоящее время я получаю только некоторые файлы *.egg, но заголовки не установлены.

  2. Как сохранить файловую структуру модуля? В настоящее время файловая структура ошибочно сглажена.

Что работает

со следующим setup.py

from setuptools import setup

setup(
   name        = 'so',
   description = 'Example',
   headers     = [
      'so.h',
   ],
)

Я могу загрузить модуль в PyPi:

python3 setup.py bdist_wheel --universal
twine upload dist/*

и затем установите его, используя pip:

pip3 install so

В моей системе я нахожу заголовок здесь

/usr/local/include/python3.6m/so/so.h

, которая доступна, когда я компилирую расширения с помощью Python.

Как я могу использовать 'python3 setup.py install'?

Используя эту стратегию, я не могу просто запустить

python3 setup.py install

В этом случае устанавливается so*.egg, но заголовки не хранятся где-то там, где они доступны для компилятора.

Как сохранить файловую структуру?

Когда модуль немного сложнее и существует некоторая иерархия каталогов, я также сталкиваюсь с проблемами. Для следующих setup.py

from setuptools import setup

setup(
  name        = 'so',
  description = 'Example',
  headers     = [
    'so.h',
    'so/implementation.h',
  ],
)

Проблема в том, что заголовки установлены на

/usr/local/include/python3.6m/so/so.h
/usr/local/include/python3.6m/so/implementation.h

, тем самым выравнивая исходную файловую структуру.

Как я могу исправить обе проблемы?

1 Ответ

0 голосов
/ 01 мая 2018

Как я могу использовать python3 setup.py install для установки файлов заголовков?

К сожалению, вы не можете так долго, как используете setuptools. Что происходит под капотом, когда вы звоните setuptools.setup()? Инсталлятор egg строится (команда bdist_egg) и устанавливается (через easy_install), и ни bdist_egg, ни easy_install поддержка, включая / установку заголовков, не поддерживается. Хотя объект distribution содержит информацию заголовков, он никогда не запрашивается во время команды install. Это старая хорошо известная проблема, которая никогда не решалась, потому что, очевидно, установка заголовочных файлов не вписывается в процедуру сборки / установки egg.

Таким образом, у вас есть три варианта (или, по крайней мере, три варианта, которые я знаю). Два из них (оба вызывают переключение на distutils) не рекомендуются и предоставляются только для полноты:

Голый distutils установка (не рекомендуется)

$ sed 's/from setuptools import setup/from distutils.core import setup/' setup.py

Таким образом, добрый старик distutils позаботится об установке при выполнении python setup.py install, установщик яиц не будет собран и будет вызван install_headers. Однако это также включает отказ от всех функций setuptools, включая дополнительные аргументы ключевых слов в setup() и все другие полезные вещи, само собой разумеется, что пакеты, установленные через distutils, не могут быть удалены с помощью pip.

old-and-unmanageable установка (не рекомендуется)

Запустите установку с

$ python setup.py install --old-and-unmanageable

Это ключ, который setuptools предоставляет, если вы явно хотите запустить distutils установку. Установщик яиц не создан, вместо этого вызывается distutils.command.install.install. Таким образом, установка такая же, как и при простой установке distutils.

Недостатки этого подхода: так же, как с distutils install plus: setuptools осуждает использование коммутатора; если вы забудете предоставить его, вы закончите установку яиц и вам придется повторить установку.

Заменить python setup.py install на pip install (рекомендуется)

pip способен устанавливать пакеты из исходных каталогов; просто выдать

$ pip install dir/

при условии, что dir содержит setup.py. Таким образом, файл wheel создается из исходных текстов (как в bdist_wheel; на самом деле эта команда запускается первой) и устанавливается, отлично управляя установкой заголовочных файлов.

Как сохранить файловую структуру модуля?

Вам придется немного подправить команду install_headers:

import os
from distutils.command.install_headers import install_headers as install_headers_orig
from setuptools import setup

class install_headers(install_headers_orig):

    def run(self):
        headers = self.distribution.headers or []
        for header in headers:
            dst = os.path.join(self.install_dir, os.path.dirname(header))
            self.mkpath(dst)
            (out, _) = self.copy_file(header, dst)
            self.outfiles.append(out)

setup(
    name='so',
    headers=['h1.h', 'subtree/h2.h'],
    cmdclass={'install_headers': install_headers},
    ...
)

Что здесь важно, так это строка

dst = os.path.join(self.install_dir, os.path.dirname(header))

Ваниль install_headers копирует заголовочные файлы напрямую в install_dir; вышеприведенная строка в перегруженной команде install_headers дополнительно заботится о возможных подкаталогах в именах заголовков. При установке пакета, подкаталоги должны быть сохранены:

$ pip show -f so | grep include
  ../../../include/site/python3.6/so/h1.h
  ../../../include/site/python3.6/so/subtree/h2.h
...