Table of contents
1. Brief introduction
1.1 Clear goals
Because it needs to be run on an embedded Linux development board, the x86_64 platform files need to be cross-compiled into arm architecture files through cross-compilation. The main thing here is to cross-compile the python source code and its dependent libraries, and then cross-compile on the QT platform of ubuntu to build an executable file that uses the python language and can run on the embedded Linux platform.
1.2 python version and its background
- Cross-compilation tool chain: gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf
- ubuntu platform:ubuntu18.04.1 64bit
- python version: python3.6.9
- Embedded linux development board kernel: NXP CORTEX-A7 IMX6ULL
1.3 Steps
- First cross-compile the python source code and its dependent libraries
- Ported to linux development board
- Writing demo verification on ubuntu's Qt platform
2. Cross-compile python source code and its dependent libraries
2.1 Compilation steps
- Cross-compile the openssl library, which is likely to be used by most other libraries
- Cross-compile the zlib library, which is a necessary dependent library for python source code installation
- Cross compile libffi library
- Cross-compile python source code.
Here is a Baidu network disk link. You can download the relevant libraries from the official website, or you can get them directly from here:
Link: https://pan.baidu.com/s/1mui3Vw8FfxnMUFSjFZhItA
Extraction code: pwev
2.2 Cross-compile openssl
- Download openssl, https://www.openssl.org/source/ . The version I am using here is openssl1.1.1.
(Note: For the convenience of management, all downloaded source codes are placed in /home/book/pyarm/zlibarm/) - Unzip: tar -xzvf openssl-1.1.1.tar.gz
- cd openssl-1.1.1
- Configure the compilation environment: ./Configure no-asm shared no-async linux-generic32 --prefix=/home/book/pyarm/opensslarm --cross-compile-prefix=arm-linux-gnueabihf- no-asm in the cross-compilation
process Assembly code is not used to speed up the compilation process;
shared generates a dynamic link library.
no-async The cross-compilation tool chain does not provide the GNU C ucontext library
–prefix= installation path (after make and make install, openssl-related include and lib files are in this directory. You can choose the installation directory by yourself) –cross-
compile -prefix= cross-compilation tool
linux-generic32 means cross-compiling to a 32-bit operating system - make
- make install
2.3 Cross-compile zlib
- Download zlib, http://zlib.net/ . The version I am using here is 1.2.11.
- Unzip: tar -xzvf zlib-1.2.11.tar.gz
- cd zlib-1.2.11
- Set the compiler: export CC=arm-linux-gnueabihf-gcc (because there is no option to configure the compiler in zlib's configure, so set the environment variable here)
- Configure the compilation environment: ./configure --prefix=/home/book/pyarm/zlibarm --enable-shared
- make
- make install
2.4 Cross-compile libffi
- Download libffi, https://sourceware.org/libffi/ . The version I am using here is 3.2.1
- Unzip: tar xvzf libffi-3.2.1.tar.gz
- cd libffi-3.2.1
- 配置编译环境:./configure CC=arm-linux-gnueabihf-gcc --host=arm-linux-gnueabihf --build=x86_64-linux-gnu target=arm-linux-gnueabihf --enable-shared --prefix=/home/book/pyarm/libffiarm
- make
- make install
2.5 Cross-compile python
-
Download python, https://www.python.org/downloads/source/ . The version I am using here is 3.6.9
-
Unzip: tar xvf Python-3.6.9.tgz
-
cd Python-3.6.9
-
mkdir /home/book/arm-python (because python compilation depends on the above library, so add a directory here, and the include and lib compiled above are moved to this directory)
-
Copy the header files and link libraries of the relevant libraries compiled above to /home/book/arm-python cp -rfp /
home/book/pyarm/zlibarm/* /home/book/arm-python cp
-rfp /home/ book/pyarm/libffiarm/* /home/book/arm-python
cp -rfp /home/book/pyarm/opensslarm/* /home/book/arm-python -
设置CFLAGS:CFLAGS=“-I /home/book/arm-python -I /home/book/arm-python/include/python3.6m -L /home/book/arm-python/lib”
-
Set LDFLAGS: LDFLAGS="-L /home/book/arm-python/lib"
-
vi Modules/Setup.dist, modify the header files and library files of the relevant libraries inside.
Note: As you can see from the picture above, the path to the library we set is an absolute path, so when we package the compiled files to the development board later, they must also be placed in /home/book/arm-python of the development board. directory (if not, you can create it yourself)
(The reason is: The Python virtual environment will record the absolute path of the Python compiler ; therefore, when running the Python virtual environment on other hosts, the virtual environment will still look for the Python compiler under this absolute path. .So the same directory must be created on the development board, otherwise errors such as files and modules not found will occur) -
./configure CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ AR=arm-linux-gnueabihf-ar RANLIB=arm-linux-gnueabihf-ranlib --host=arm-linux-gnueabihf --build=x86_64-linux-gnu --target=arm-linux-gnueabihf --disable-ipv6 ac_cv_file__dev_ptmx=yes ac_cv_file__dev_ptc=yes --prefix=/home/book/arm-python --enable-shared --without-ensurepip
-
make
-
make install
3. Transplant to linux development board
- Compress the arm-python directory: cd /home/book tar cvf arm-python.tar arm-python
- Transfer arm-python.tar to the /home/book directory of the development board through tools such as FileZilla
- Unzip: tar xvf arm-python.tar
Summary: After the above steps, the python transplant has been completed. You can also cd /home/book/arm-python/bin here, and then ./python3 to enter the python interface programming, and use exit() to exit. Python interface, return to the command line.
4. Write demo verification on ubuntu’s Qt platform
- Create a new project in Qt-----The template I chose here is Application (Qt)-----name: py_test, and the creation path is /home/book/QT/my_qt/qt_python------behind Several steps are defaulted -----Finally check the cross-compilation tool chain----finished.
- Create a new file—select Python, Python File----name: test_pyfile.py, the path does not need to be modified----complete. (After creation, you can see the test_pyfile.py file in Other files of the project)
- Add the following code to the test_pyfile.py file: (The main function is to pass in a string through parameter a, and then return a concatenated string b)
def testpyfile(a):
b = a+'jiayou'
return b
# 这里必须空两行:
# python编码规范:类与类,类与函数,函数与函数之间空两行)
print(testpyfile("111"))
- Import python-related library files and header files in the .pro file
INCLUDEPATH += \
-I /home/book/arm-python/include/python3.6m/ \
-I /home/book/arm-python/include \
-I /home/book/arm-python/include/openssl
LIBS += \
-L /home/book/arm-python/lib/ -lpython3.6m \
-L /home/book/arm-python/lib/ -lssl \
-L /home/book/arm-python/lib/ -lcrypto \
-L /home/book/arm-python/lib/ -lz \
- Add the following code in the main function:
#include "mainwindow.h"
#include <QApplication>
#include "Python.h" //引入python头文件
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
Py_Initialize(); // 初始化Python
PyObject *pModule = nullptr;
PyObject *pLoadFunc = nullptr;
PyObject *pArgs = nullptr;
PyObject *pReturn = nullptr;
PyObject *str = nullptr;
const char *bytes = nullptr;
if(!Py_IsInitialized())
{
qDebug()<<"inititalize failed";
return -1;
}
else
qDebug()<<"inititalize success";
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('/home/book/QT/my_qt/qt_python/py_test')");
pModule = PyImport_ImportModule("test_pyfile");
if(!pModule)
{
PyErr_Print();
qDebug()<<"not loaded module";
return -1;
}
else
qDebug()<<"load module success";
pLoadFunc = PyObject_GetAttrString(pModule, "testpyfile");
if(!pLoadFunc)
{
PyErr_Print();
qDebug()<<"not loaded pLoadFunc";
return -1;
}
else
qDebug()<<"load pLoadFunc success";
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0 , Py_BuildValue("s", "xuheqing"));
pReturn = PyObject_CallObject(pLoadFunc, pArgs);
if(!pReturn)
{
qDebug()<<"no return value";
return -1;
}
str = PyObject_Str(pReturn);
bytes = PyUnicode_AsUTF8(str);
qDebug()<<bytes;
Py_Finalize();// 关闭 Python 脚本解释器
return a.exec();
}
Note: The absolute path is used in PyRun_SimpleString("sys.path.append('/home/book/QT/my_qt/qt_python/py_test')") to add the .py file we wrote ourselves, so we need to put the file in In the /home/book/QT/my_qt/qt_python/py_test directory of the development board (if not, you can create it yourself). Otherwise, when the development board is running, there will be an error that the file module cannot be found! ! !
-
Before building, sudo vi /home/book/arm-python/include/python3.6m/object.h and modify it as shown below. (Because slots are defined as keys in QT, and slots are used as variables in python3, there will be conflicts during compilation.)
-
Select the cross-compilation tool, then right-click the py_test project and click Build to get the program py_test that can run on the arm architecture.
-
Transfer the py_test file to the /mnt directory of the development board through tools such as FileZilla. First chmod +x py_test, add executable operations to py_test, and then ./py_test. At this time, you will find an error:
./py_test: error while loading shared libraries: libpython3.6m.so.1.0: cannot open shared object file: Norectory
Solution :
① First use the commandecho $PATH
to display the current PATH environment variable. My environment variable is / bin:/sbin:/usr/bin:usr/sbin. When we execute the program, the shell automatically searches these paths for the program based on the value of the PATH variable. So you canexport LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/arm-python/lib
add the path to the python related library and you can execute it.
(Note: This is only one of the methods, and it is only a temporary modification. After restarting the development board, the environment variable needs to be reset)
② vi /etc/profile. Added at the end of the fileexport LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/arm-python/lib
. Then restart the development board . The environment variables in /etc/profile are valid for all users and are run when the system starts. This is a way for environment variables to be permanently valid. -
operation result