Как использовать autotools для создания интерфейса Python одновременно с библиотекой

В настоящее время у меня есть библиотека, написанная на C ++, построенная с использованием автоинструментов GNU, и я хотел бы добавить к ней интерфейс Python. Используя SWIG, я разработал интерфейс, но мне трудно понять, как интегрировать компиляцию модуля Python с остальной частью процесса.

Я просмотрел AM_PATH_PYTHON, но этот макрос, похоже, не устанавливает путь включения для Python.h, поэтому, когда я компилирую свой модуль, я получаю кучу ошибок об отсутствии включаемых файлов. Есть ли способ получить путь включения Python и ldflags из AM_PATH_PYTHON?

Просто для записи, я не думаю, что можно будет использовать метод distutils Python (setup.py), поскольку для этого требуется расположение библиотеки, чтобы связать новый модуль. Поскольку библиотека еще не была установлена ​​во время компиляции, мне пришлось бы использовать относительный путь (например, ../src/lib.so), который, конечно, сломался бы после установки модуля Python (поскольку библиотека тогда находится в / usr / lib или / usr / local / lib вместо этого.)

РЕДАКТИРОВАТЬ:

Теперь он может найти компилируемый файл .h, но после его установки (в правильном месте) Python не может загрузить модуль. Код создает foo.so, и когда я "импортирую foo", я получаю следующее:

ImportError: dynamic module does not define init function (initfoo)

Однако если я переименую его из foo.so в _foo.so, он загрузится и будет работать нормально, за исключением того, что мне придется «импортировать _foo», чего я бы предпочел не делать. Когда я следую инструкциям SWIG по созданию _foo.so в текущем каталоге, «import foo» работает, поэтому я не уверен, почему он ломается, когда библиотека устанавливается в каталог сайта.

РЕДАКТИРОВАТЬ2:

Оказывается, проблема заключалась в том, что я забыл скопировать foo.py, созданный SWIG, в каталог установки вместе с _foo.so. Как только я это сделал, все заработало, как ожидалось! Теперь мне просто нужно выяснить некоторые правила automake, чтобы скопировать файл в каталог установки ...


person Malvineous    schedule 20.02.2011    source источник
comment
Чтобы скопировать неисполняемый файл в каталог, вам, вероятно, понадобится что-то вроде pkgpythondir_DATA = foo.py.   -  person Jack Kelly    schedule 26.02.2011


Ответы (4)


Чтобы найти путь включения, я бы использовал python-config. Уловка состоит в том, чтобы использовать python-config, соответствующий питону, установленному в $PYTHON.

AM_PATH_PYTHON
AC_ARG_VAR([PYTHON_INCLUDE], [Include flags for python, bypassing python-config])
AC_ARG_VAR([PYTHON_CONFIG], [Path to python-config])
AS_IF([test -z "$PYTHON_INCLUDE"], [
  AS_IF([test -z "$PYTHON_CONFIG"], [
    AC_PATH_PROGS([PYTHON_CONFIG],
                  [python$PYTHON_VERSION-config python-config],
                  [no],
                  [`dirname $PYTHON`])
    AS_IF([test "$PYTHON_CONFIG" = no], [AC_MSG_ERROR([cannot find python-config for $PYTHON.])])
  ])
  AC_MSG_CHECKING([python include flags])
  PYTHON_INCLUDE=`$PYTHON_CONFIG --includes`
  AC_MSG_RESULT([$PYTHON_INCLUDE])
])

Другой альтернативой является поиск модуля distutils.sysconfig (это не имеет ничего общего с использованием distutils для сборки вашего кода). Запустите python -c "import distutils.sysconfig; help(distutils.sysconfig)" и посмотрите.

person Jack Kelly    schedule 24.02.2011
comment
Спасибо - это сработало, однако теперь у меня проблемы с окончательным двоичным файлом .so, я обновил исходный вопрос. - person Malvineous; 26.02.2011

Вот макрос autoconf, который я вызываю из своего «configure.ac», чтобы найти каталог включения Python (PYTHONINC) и каталог установки Python (через AM_PATH_PYTHON).

AC_DEFUN([adl_CHECK_PYTHON], 
 [AM_PATH_PYTHON([2.0])
  AC_CACHE_CHECK([for $am_display_PYTHON includes directory],
    [adl_cv_python_inc],
    [adl_cv_python_inc=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_inc()" 2>/dev/null`])
  AC_SUBST([PYTHONINC], [$adl_cv_python_inc])])

Затем мой wrap/python/Makefile.am создает два модуля Swig с помощью Libtool следующим образом:

SUBDIRS = . cgi-bin ajax tests

AM_CPPFLAGS = -I$(PYTHONINC) -I$(top_srcdir)/src $(BUDDY_CPPFLAGS) \
              -DSWIG_TYPE_TABLE=spot

EXTRA_DIST = spot.i buddy.i
python_PYTHON = $(srcdir)/spot.py $(srcdir)/buddy.py
pyexec_LTLIBRARIES = _spot.la _buddy.la

MAINTAINERCLEANFILES = \
  $(srcdir)/spot_wrap.cxx $(srcdir)/spot.py \
  $(srcdir)/buddy_wrap.cxx $(srcdir)/buddy.py

## spot

_spot_la_SOURCES = $(srcdir)/spot_wrap.cxx $(srcdir)/spot_wrap.h
_spot_la_LDFLAGS = -avoid-version -module
_spot_la_LIBADD = $(top_builddir)/src/libspot.la

$(srcdir)/spot_wrap.cxx: $(srcdir)/spot.i
        $(SWIG) -c++ -python -I$(srcdir) -I$(top_srcdir)/src $(srcdir)/spot.i


$(srcdir)/spot.py: $(srcdir)/spot.i
        $(MAKE) $(AM_MAKEFLAGS) spot_wrap.cxx

## buddy

_buddy_la_SOURCES = $(srcdir)/buddy_wrap.cxx
_buddy_la_LDFLAGS = -avoid-version -module $(BUDDY_LDFLAGS)

$(srcdir)/buddy_wrap.cxx: $(srcdir)/buddy.i
        $(SWIG) -c++ -python $(BUDDY_CPPFLAGS) $(srcdir)/buddy.i

$(srcdir)/buddy.py: $(srcdir)/buddy.i
        $(MAKE) $(AM_MAKEFLAGS) buddy_wrap.cxx

Вышеупомянутые правила таковы, что результат Swig рассматривается как исходный файл (т. Е. Распространяется в архиве) так же, как и синтаксический анализатор, созданный Bison. Таким образом, конечному пользователю не нужно устанавливать Swig.

Когда вы запускаете make, файлы *.so скрываются Libtool в каком-то .libs/ каталоге, но после make install они копируются в нужное место.

Единственная уловка - как использовать модули из исходного каталога перед запуском make install. Например. во время работы make check. В этом случае я генерирую (с configure) сценарий с именем run, который устанавливает PYTHONPATH перед запуском любого python сценария, и я выполняю все свои тестовые сценарии с помощью этого run сценария. Вот содержимое run.in до того, как configure заменит любое значение:

# Darwin needs some help in figuring out where non-installed libtool
# libraries are (on this platform libtool encodes the expected final
# path of dependent libraries in each library).
modpath='../.libs:@top_builddir@/src/.libs:@top_builddir@/buddy/src/.libs'

# .. is for the *.py files, and ../.libs for the *.so.  We used to
# rely on a module called ltihooks.py to teach the import function how
# to load a Libtool library, but it started to cause issues with
# Python 2.6.
pypath='..:../.libs:@srcdir@/..:@srcdir@/../.libs:$PYTHONPATH'

test -z "$1" &&
  PYTHONPATH=$pypath DYLD_LIBRARY_PATH=$modpath exec @PYTHON@

case $1 in
  *.py)
    PYTHONPATH=$pypath DYLD_LIBRARY_PATH=$modpath exec @PYTHON@ "$@";;
  *.test)
    exec sh -x "$@";;
  *)
    echo "Unknown extension" >&2
    exit 2;;
esac

Если вы хотите увидеть все это в действии в реальном проекте, вы можете получить это по адресу https://spot.lrde.epita.fr/install.html

person adl    schedule 26.02.2011

Сборка вручную из командной строки

Не добавляя шаги SWIG в ваши make-файлы, вы можете создать расширение SWIG, используя эти команды (если у вас есть source_file.cpp и your_extension.i для создания вашего модуля python):

  # creation of your_extension_wrap.cpp
  swig -c++ -python -o your_extension_wrap.cpp your_extension.i
  # creation of your_extension_wrap.o, source_file.o and your_extension.py
  g++ -fPIC -c your_extension_wrap.cpp source_file.cpp -I/usr/include/python2.7
  # creation of the library _your_extension.so
  g++ -shared your_extension_wrap.o source_file.o -o _your_extension.so

Примечание. Важно поставить перед именем общего объекта символ подчеркивания, иначе Python не сможет найти его при выполнении import your_extension.

Добавление SWIG в Autoconf

Я написал небольшую программу на Python, в которой мне нужен единственный файл, написанный на C ++ (например, метод округления).

Вам потребуются дополнительные макросы Autoconf для включения поддержки SWIG. Как отмечает johanvdw, будет проще использовать эти два макроса m4: ax_pck_swig и ax_swig_python. Я загрузил его из архива макросов Autoconf и поместил его в подкаталог m4 моего дерева проекта:

trunk
    ├── configure.ac
    ├── __init__.py
    ├── m4
    │   ├── ax_pkg_swig.m4
    │   ├── ax_swig_python.m4
    │   ├── libtool.m4
    │   ├── lt~obsolete.m4
    │   ├── ltoptions.m4
    │   ├── ltsugar.m4
    │   └── ltversion.m4
    ├── Makefile.am
    ├── rounding_swig
    │   ├── compile.txt
    │   ├── __init__.py
    │   ├── Makefile.am
    │   ├── rnd_C.cpp
    │   ├── rounding.i
    │   ├── rounding_wrap.cpp
    └── src
        ├── cadna_add.py
        ├── cadna_computedzero.py
        ├── cadna_convert.py
        ├── __init__.py
        └── Makefile.am

Когда вы помещаете два макроса m4 в подкаталог, вам нужно добавить эту строку в свой trunk / Makefile.am:

ACLOCAL_AMFLAGS = -I m4

Теперь посмотрим на trunk / configure.ac:

AC_PREREQ([2.69]) # Check autoconf version 
AC_INIT(CADNA_PY, 1.0.0, [email protected]) # Name of your software
AC_CONFIG_SRCDIR([rounding_swig/rnd_C.cpp]) # Name of the c++ source
AC_CONFIG_MACRO_DIR(m4)     # Indicate where are your m4 macro
AC_CONFIG_HEADERS(config.h)
AM_INIT_AUTOMAKE

AC_DISABLE_STATIC #enable shared libraries

# Checks for programs.
AC_PROG_LIBTOOL  # check libtool
AC_PROG_CXX  # check c++ compiler
AM_PATH_PYTHON(2.3) # check python version
AX_PKG_SWIG(1.3.21) # check swig version
AX_SWIG_ENABLE_CXX # fill some variable usefull later
AX_SWIG_PYTHON # same

# Checks for header files.
AC_CHECK_HEADERS([fenv.h stdlib.h string.h]) # any header needed by your c++ source
# Checks for typedefs, structures, and compiler characteristics.
AC_CHECK_HEADER_STDBOOL
AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_MALLOC
AC_CHECK_FUNCS([fesetround memset strstr])

AC_CONFIG_FILES([
        Makefile
    src/Makefile
    rounding_swig/Makefile
        ])

LIBPYTHON="python$PYTHON_VERSION" # define the python interpreter
LDFLAGS="$LDFLAGS -l$LIBPYTHON"
AC_OUTPUT

Добавление SWIG в Automake

В вашем транк / Makefile.am вам нужно сделать следующее:

ACLOCAL_AMFLAGS = -I m4

# Indicate the subdir of c++ file and python file
SUBDIRS = src rounding_swig

# Indicate a list of all the files that are part of the package, but
# are not installed by default and were not specified in any other way
EXTRA_DIST= \
rounding_swig/rounding.i \
rounding_swig/testrounding.py \
rounding_swig/testrounding.cpp

В вашем стволе / src / Makefile.am:

# Python source files that will be install in prefix/lib/name_of_your_python_interpreter/site-packages/name_of_your_project
pkgpython_PYTHON = cadna_add.py cadna_computedzero.py cadna_convert.py

Сложная часть находится в trunk / rounding_swig / Makefile.am. Он создает библиотеку .la и _your_extension.so и помещает их в prefix /lib64/python2.7/site-packages/name_of_the_project/.

# Name of the cpp source file
BUILT_SOURCES = rounding_wrap.cpp
# Name of the swig source file
SWIG_SOURCES = rounding.i
# Python source files that will be install in prefix/lib/name_of_your_python_interpreter/site-packages/name_of_your_project
pkgpython_PYTHON = rounding.py __init__.py
pkgpyexec_LTLIBRARIES = _rounding.la
_rounding_la_SOURCES = rounding_wrap.cpp $(SWIG_SOURCES) rnd_C.cpp
_rounding_la_CPPFLAGS = $(AX_SWIG_PYTHON_CPPFLAGS) -I$(top_srcdir)/rounding_swig -I/usr/include/python@PYTHON_VERSION@ -lpython@PYTHON_VERSION@
_rounding_la_LDFLAGS = -module

rounding_wrap.cpp: $(SWIG_SOURCES)
    $(SWIG) $(AX_SWIG_PYTHON_OPT) -I$(top_srcdir)/rounding_swig -I/usr/include/python@PYTHON_VERSION@ -o $@ $<

В конце, если у вас нет еще 5 макросов, вы можете получить его, набрав:

autoreconf -i

Наконец, чтобы установить ваш проект:

libtoolize && aclocal && autoheader && autoconf && automake -a -c
./configure --prefix=<install prefix>
make
make install

PS: Здесь это устаревшее, но простое руководство, которое помогло мне (устарело, потому что он использовал ac_pkg_swig.m4, который не работает с новой версией swig).

person Ben_LCDB    schedule 25.07.2016

Я знаю, что это старый пост, но поскольку я все равно сюда попал: есть несколько макросов m4, которые упрощают компиляцию привязок python с использованием swig:

http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html и http://www.gnu.org/software/autoconf-archive/ax_swig_python.html

person johanvdw    schedule 23.09.2011