Неустранимая ошибка Python при использовании динамической версии Python для выполнения встроенного кода python
SPOILER: частично разрешен (см. в конце).
Вот пример кода с использованием встроенного Python:
#include <Python.h>
int main(int argc, char** argv)
{
Py_SetPythonHome(argv[1]);
Py_Initialize();
PyRun_SimpleString("print \"Hello !\"");
Py_Finalize();
return 0;
}
Я работаю под Linux openSUSE 42.2 с gcc 4.8.5 (но у меня также такая же проблема для openSUSE 13.2 с gcc 4.8.3 или RedHat 6.4 с gcc 4.4.7).
Я собрал статическую и динамическую версию Python 2.7.9 (но у меня тоже такая же проблема с Python 2.7.13).
Я компилирую свой пример, ссылаясь на статическую версию Python с помощью следующей команды:
g++ hello.cpp -o hello \
-I /home/caduchon/softs/python/2.7.9/64/gcc/4.8.5/static/include/python2.7 \
-L /home/caduchon/softs/python/2.7.9/64/gcc/4.8.5/static/lib \
-l python2.7 -l pthread -l util -l dl
Если я выполнил свой пример со статической версией Python в аргументе, он работает.
Если я выполнил его в динамической версии Python в аргументе, я получаю следующую ошибку (это происходит в Py_Initialize()
):
> ./hello /home/caduchon/softs/python/2.7.9/64/gcc/4.8.5/dynamic
Fatal Python error: PyThreadState_Get: no current thread
Aborted (core dumped)
Я понятия не имею, почему он работает со статической версией, а не с динамической. Как я могу решить эту проблему?
EDIT: my script установка Python:
#!/bin/bash
WORKDIR=/home/caduchon/tmp/install_python_2_7_13
ARCHIVEDIR=/home/caduchon/downloads/python
PYTHON_VERSION='2.7.13'
EZ_SETUP_VERSION='0.9'
SETUPTOOLS_VERSION='34.1.0'
CYTHON_VERSION='0.25.2'
NUMPY_VERSION='1.12.0'
SCIPY_VERSION='0.18.1'
MATPLOTLIB_VERSION='2.0.0'
INSTALLDIR=/home/caduchon/softs/python/$PYTHON_VERSION/64/gcc/4.8.5
LAPACKDIR=/home/caduchon/softs/lapack/3.6.1/64/gcc/4.8.5
### Tkinter ###
echo "Install Tkinter"
sudo apt-get install tk-dev
### Workdir ###
echo "Create workdir"
mkdir -p $WORKDIR/static
mkdir -p $WORKDIR/dynamic
### Python
for x in static dynamic
do
echo "Install Python ($x)"
cd $WORKDIR/$x
echo " extract archive"
cp $ARCHIVEDIR/Python-$PYTHON_VERSION.tgz .
tar -xzf ./Python-$PYTHON_VERSION.tgz &> archive.log
cd ./Python-$PYTHON_VERSION
echo " configure"
if [ "$x" = "static" ]
then
./configure --prefix=$INSTALLDIR/$x --libdir=$INSTALLDIR/$x/lib &> configure.log
else
export LD_RUN_PATH=$INSTALLDIR/$x/lib
./configure --enable-shared --prefix=$INSTALLDIR/$x --exec-prefix=$INSTALLDIR/$x --libdir=$INSTALLDIR/$x/lib &> configure.log
fi
echo " build"
make &> make.log
echo " install"
make install &> make_install.log
echo " done"
done
### setuptools
for x in static dynamic
do
echo "Install setuptools ($x)"
cd $WORKDIR/$x
echo " extract archives"
cp $ARCHIVEDIR/ez_setup-$EZ_SETUP_VERSION.tar.gz .
tar -xzf ./ez_setup-$EZ_SETUP_VERSION.tar.gz &> archive.log
cp $ARCHIVEDIR/setuptools-$SETUPTOOLS_VERSION.zip .
unzip ./setuptools-$SETUPTOOLS_VERSION.zip &> archive.log
cp ./ez_setup-$EZ_SETUP_VERSION/ez_setup.py ./setuptools-$SETUPTOOLS_VERSION/.
cd ./setuptools-$SETUPTOOLS_VERSION
echo " install"
$INSTALLDIR/$x/bin/python ./ez_setup.py &> setup.log
echo " done"
done
### Cython
for x in static dynamic
do
echo "Install Cython ($x)"
cd $WORKDIR/$x
echo " extract archive"
cp $ARCHIVEDIR/Cython-$CYTHON_VERSION.tar.gz .
tar -xzf ./Cython-$CYTHON_VERSION.tar.gz &> archive.log
cd ./Cython-$CYTHON_VERSION
echo " install"
$INSTALLDIR/$x/bin/python ./setup.py install &> install.log
echo " done"
done
### NumPy
for x in static dynamic
do
echo "Install NumPy ($x)"
cd $WORKDIR/$x
echo " extract archive"
cp $ARCHIVEDIR/numpy-$NUMPY_VERSION.zip .
unzip ./numpy-$NUMPY_VERSION.zip &> archive.log
cd ./numpy-$NUMPY_VERSION
echo " build"
$INSTALLDIR/$x/bin/python ./setup.py build --fcompiler=gfortran &> build.log
echo " install"
$INSTALLDIR/$x/bin/python ./setup.py install &> install.log
echo " done"
done
### SciPy
for x in static dynamic
do
echo "Install SciPy ($x)"
cd $WORKDIR/$x
echo " extract archive"
cp $ARCHIVEDIR/scipy-$SCIPY_VERSION.tar.gz .
tar -xzf ./scipy-$SCIPY_VERSION.tar.gz &> archive.log
cd ./scipy-$SCIPY_VERSION
echo " configure"
echo "[DEFAULT]" > ./site.cfg
echo "library_dirs = $LAPACKDIR/lib64" >> ./site.cfg
echo "search_static_first = true" >> ./site.cfg
echo " build"
$INSTALLDIR/$x/bin/python ./setup.py build --fcompiler=gfortran &> build.log
echo " install"
$INSTALLDIR/$x/bin/python ./setup.py install &> install.log
echo " done"
done
### MatPlotLib
for x in static dynamic
do
echo "Install MatPlotLib ($x)"
cd $WORKDIR/$x
echo " extract archive"
cp $ARCHIVEDIR/matplotlib-$MATPLOTLIB_VERSION.tar.gz .
tar -xzf ./matplotlib-$MATPLOTLIB_VERSION.tar.gz &> archive.log
cd ./matplotlib-$MATPLOTLIB_VERSION
echo " build"
$INSTALLDIR/$x/bin/python ./setup.py build &> build.log
echo " install"
$INSTALLDIR/$x/bin/python ./setup.py install &> install.log
echo " done"
done
EDIT: Я определил возможную причину проблемы. Если я удаляю строку export LD_RUN_PATH=$INSTALLDIR/$x/lib
при установке динамического Python, мой встроенный код работает. Я напечатал sys.path
через встроенный код и указал на правильную установку. НО... таким образом я не могу использовать установку напрямую: он загружает неправильную версию, найденную в системе (когда я печатаю sys.path
, я вижу, что она указывает на /usr/...). Кроме того, я не хочу устанавливать переменные среды для запуска Python, потому что я использую несколько версий Python на одной машине.
EDIT: Сохраняя мою установку по умолчанию script Python, я решаю проблему, добавляя -rdynamic в параметрах при компиляции примера С++. Но я не совсем понимаю, что это за вариант, и какое бедствие оно может вызвать...
Ответы
Ответ 1
Если я правильно понимаю, вы хотите запустить статически связанную версию, установив дом Python в динамически связанную версию. Это не работает.
Вот что происходит: когда вы запускаете Py_Initialize()
статически связанной библиотеки, в какой-то момент попытайтесь импортировать модуль _locale
. Поскольку вы устанавливаете дом Python в динамически связанную версию, он загружает $INSTALLDIR/dynamic/lib/python2.7/lib-dynload/_locale.so
. Эта библиотека динамически связана с $INSTALLDIR/dynamic/lib/libpython2.7.so.1.0
. Теперь вы получаете две копии переводчика. Первая копия - статически связанная, которая инициализируется. Вторая копия неинициализирована. Когда механизм импорта динамического модуля пытается инициализировать модуль _locale
, он терпит неудачу, потому что функция _locale
init ссылается на второй, полностью неинициализированный интерпретатор.
В чем причина, по которой вы это пробовали? Если вы сообщите нам, какую проблему вы хотели бы решить в первую очередь, мы могли бы вам помочь.
РЕДАКТИРОВАТЬ: (я написал это после первого редактирования, я не пробовал до сих пор, что происходит с -rdynamic
):
Если вы не установите LD_RUN_PATH
, $INSTALLDIR/dynamic/lib/python2.7/lib-dynload/_locale.so
динамически связана с системой libpython2.7.so
. Причина, по которой вы не видите ошибку, заключается в том, что импорт модуля _locale
завершается с помощью ImportError (вместо segfaulting), но этот ImportError улавливается во время инициализации интерпретатора (в то время как ранее segfault не удалось поймать). Но если вы попробуете встроенный интерпретатор импортировать _locale
(или любой другой модуль расширения, например, например, _struct
), вы получите такую ошибку:
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: $INSTALLDIR/dynamic/lib/python2.7/lib-dynload/_locale.so: undefined symbol: PyUnicodeUCS2_FromObject
EDIT: При компиляции hello.cpp
в отношении статической версии Python обычно большинство символов, таких как _PyThreadState_Current
, не входят в таблицу динамических символов. Вот почему вы получаете "две копии интерпретатора", как описано выше, и segfault. Однако при передаче -rdynamic
эти символы заканчиваются в таблице динамических символов, поэтому теперь функция init модуля из llocale.so "динамической" сборки ссылается на _PyThreadState_Current
"статической" сборки. Я все еще не убежден, что то, что вы пытаетесь сделать (используя программу, связанную с "статической" сборкой с домом Python из "динамической" сборки), является хорошей идеей.;)