Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

Stella981
• 阅读 1712

目录

前言
Python源码以及VS2017的准备 Python源码 VS2017 Windows下编译Python源码 编译命令 编译步骤 编译后的配置 添加注册表 Win10中编译Python源码小结 Windows中C++调用Python代码绘制等高线图 CMakeLists.txt文件如下: Python代码如下: CPP文件: 运行结果 Linux中编译Python源码

前言

距离上次推送已经快一个月了,这段时间一直在准备开题。说起来我自己都不太相信,我竟然一个多学期没看过文献…….今年5月底才开始看文献,中间课题方向也被换了好几次。今天下午刚开完组会,又得改一堆。

前阵子我老师要我用C++做个软件(还没做完),其中需要有一项功能是显示一个等高线图,但是没找着可以画等高线的C++库,自己开发太麻烦了(主要自己不会)。画等高线用MATLAB很容易就能画出来,Python的matplotlib库画等高线图也很简单。所以就考虑C++调用MATLAB,或者C++调用Python。

  • 如果用C++调用MATLAB的话,打包后还需要MATLAB的运行时库才行,而且这个还很大,好像安装好后有几个G,而且美国又在对中国限制matlab,所以打算放弃C++调用MATLAB。

  • C++调用Python的话,坑会比较多,一般低级语言调用高级语言的坑都比较多。需要编译Python的源代码(Python的源码基本都是C文件),如果不编译的话可能会无法调用和Python有关的.dll文件或者.pyd文件以及相关的.lib库文件。这些都是经过编译器编译出来的,必须要保证编译器是一致的才能使用,还有需要明确是32位的还是64位的。

Note:本次推送中有部分内容是取自于我学习 夏曹俊 老师课程时所记的笔记,夏曹俊老师的课程质量还是很好的,有兴趣的可以上51cto或者网易云课堂搜索一下看看。

Python源码以及VS2017的准备

Python源码

可以直接去官网:www.python.org 上下载

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

解压后打开其中的目录结构如下:

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

VS2017

需要用VS2017来编译Python源码,VS2015得单独安装Win10开发工具,更高版本的就不清楚了,反正我还是建议使用VS2017,我这有一个企业版的2017:

链接:https://pan.baidu.com/s/1cLqLnEr9Apx5WUFqyllXBQ
提取码:46zw

具体的安装可以看看我之前写的VS2017编译Qt源码的那篇推送:搭建VS2017_QT_MATLAB开发环境

实际上我主要是需要VS2017的nmake这个编译器,这个VS2017的编译器可以直接被我的CLion检测到,但是我的CLion找不到VS2015编译器在哪,自己手动加了也不行。

Windows下编译Python源码

编译命令

build -c Release -p x64orbuild -c Release -p win32orbuild -c Debug -p x64orbuild -c Debug -p win32
  • 前两个都是用来编译Release版本的,一个是x64(amd64)平台的,一个是win32平台的。我编译的都是x64的。

  • 后两个都是用来编译Debug版本的,一个是x64(amd64)平台的,一个是win32平台的。我编译的都是x64的。

  • -c 表示编译模式,-p是指平台(platform)

下面仅以build -c Release -p x64为例。

编译步骤

  • 先把下面的这个目录添加到环境变量中,因为编译的过程中可能会用到Win10的开发工具,为了能让编译器找到它们,所以需要添加到路径中:

    C:\Program Files (x86)\Windows Kits\10\bin\10.0.17134.0\x64

上面的这个10.0.17134.0只是win10开发工具的一个版本,不一定要和我的一致,如果有多个版本,选择最新的就行。

  • 进入PCbuild文件夹中,这是Windows环境的源码目录,如下:

    可以看到这里面都是VS的项目文件

    Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

  • 在当前文件夹中打开WindowsPowerShell,或者打开CMD用cd命令切换到PCbuild文件夹下,在其中输入下面这行编译指令来编译64位的Python:

    ./build -c Release -p x64

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

编译过程的第一步是去下载编译依赖的库和文件,一般情况下下载都会出点错吧,毕竟是从国外的服务器上下载的。这个下载下来的东西都放在源码路径/externals文件夹下:

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

这个externals文件夹开始时是不存在的,执行编译指令后才会被创建

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

这个externals文件,我已经上传到云盘里了,如果有同学上面没下载下来的话可以下载我上传的这个,解压后放到下载的源码路径下,记得不要改externals这个名字:

链接:https://pan.baidu.com/s/1EgPjkcfFtTf1jCC\_geYF6g
提取码:depz

拷贝好后再重新编译就能成功了,如下图:

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

Note:build -c Release -p x64编译输出在./PCbulid/amd64文件夹中,这个文件夹中就有一个python.exe,如下图

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

编译后的配置

  • 添加一个PYTHONHOME系统变量,值为源码的家目录,如下图(我把源码拷贝到C盘了)

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

  • 在系统环境变量中把编译出来的python.exe的路径添加进去

    Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

  • 还有pip的路径也添加进去,你的pip可以用externals/pythonx86/tools/Scripts中的,所以还应该把这个路径添加到环境变量中

    Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

Note:如果有多个版本的Python的话,在用到Python.exe时,使用的是PATH环境变量中最上面的那个版本的Python。

添加注册表

在用Python做拓展库时,它拓展库可以打成一个安装包,这个安装包会通过注册表来判断你的系统有没有装这个版本的Python。

下面给出一段Python代码来添加注册表:

import sysfrom winreg import *version = sys.version[:3]installpath = sys.prefixregpath = "SOFTWARE\\Python\\Pythoncore\\%s-64\\" % (version)installkey = "InstallPath"pythonkey = "PythonPath"pythonpath = "%s;%s\\Lib\\;%s\\DLLs" % (installpath, installpath, installpath)print(version)def RegisterPy():    try:        reg = OpenKey(HKEY_CURRENT_USER, regpath)    except EnvironmentError as e:        try:            reg = CreateKey(HKEY_CURRENT_USER, regpath)            SetValue(reg, installkey, REG_SZ, installpath)            SetValue(reg, pythonkey, REG_SZ, pythonpath)            CloseKey(reg)        except:            print("---Python ", version, " is not registered!")            return    if (QueryValue(reg, installkey) == installpath) and (QueryValue(reg, pythonkey) == pythonpath):        CloseKey(reg)        print("---Python ", version, " is already registered!")        return    CloseKey(reg)if __name__ == "__main__":    RegisterPy()

Note: 一定要用你编译出来的那个版本的Python来运行这个代码!

Win10中编译Python源码小结

到此,在Win中的编译就算完事了,上面说了这老大一堆,实际总结下来也没多少

  • python官网下载源码,下载VS2017

  • 把Windows Kits中的那个x64目录添加到路径(具体路径往回翻一下看看)

  • 进入源码目录下的PCbuild目录中,在当前目录中打开Power Shell或者打开cmd然后cd到PCbuild目录中

  • 执行./build -c Release -p x64编译出64位Release版本的Python,python.exe在PCbuild目录中的amd64下面。(可以先下载我上传的那个externals文件夹,解压后放到源码根目录下)

  • 编译完成后添加PYTHONHOME系统变量,并把PCbuild/amd64这个目录添加到环境变量中

  • 添加注册表

如果想编译32位的只要把x64改成win32就行。过程都一样,那个Python代码中的64也改成32。

Windows中C++调用Python代码绘制等高线图

这部分不涉及C++与Python之间的参数传递,仅仅是C++调用py文件,py文件也没有编译。有关C++与Python之间的数据传递,后期会做一些推送来记录。

  • 把Python源码目录中的Include拷贝到程序目录中

  • 把Python源码目录中的PC/pyconfig.h拷贝到程序目录中(放到上面的Include里面)

  • 把PCbuild/amd64/python37.lib,还有相应的python37.dll也拷贝到程序目录中。除此之外还需要从这个amd64下面拷贝出:_bz2.lib、_contextvars.lib、_socket.lib、_tkinter.lib、select.lib、unicodedata.lib,以及对应的.pyd文件(pyd文件是Python编译的动态库也要和.exe放一起)。实际上你可以把amd64下的整个都拷贝走,这样更省事,就是打包后的文件大一点,事先我们也不知道需要哪些库,但是如果缺少库的话,运行结果会提示缺少那个,此时你再去amd64中找**(下同)**。

  • 把Python源码目录中的Lib目录也整个拷贝走,如果不怕麻烦可以挨个删掉用不上的库。

采用CLion创建的项目,项目文件结构如下:

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

我把python相关的lib库文件和头文件都放在Python子文件夹中,把pyd以及dll文件以及py源代码都和.exe文件放在一起。

CMakeLists.txt文件如下:

cmake_minimum_required(VERSION 3.15)project(demo8_2)set(CMAKE_CXX_STANDARD 14)set(CMAKE_INCLUDE_CURRENT_DIR ON)set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)# CLion这无法用相对路径# 把Armadillo的头文件的目录包括进来(固定的)include_directories("D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python/Include")# 把Python lib 目录路径 链接进来link_directories("D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python")# 链接 Python liblink_libraries(        "D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python/_bz2.lib"        "D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python/_contextvars.lib"        "D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python/_socket.lib"        "D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python/_tkinter.lib"        "D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python/python37.lib"        "D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python/select.lib"        "D:/PersonalAllAboutStudy/Programming/CLion_Python_Demo/demo8_2/Python/unicodedata.lib")add_executable(main main.cpp)

不可照搬,起码得改个路径啥的!

Python代码如下:

import numpy as npimport matplotlib.pyplot as pltimport matplotlib as mpl# 隐藏matplotlib的工具栏mpl.rcParams['toolbar'] = 'None'# 修改matplotlib窗口的图标thismanager = plt.get_current_fig_manager()# thismanager.window.wm_iconbitmap("could.png")  # 试了,看不到图标thismanager.window.wm_iconbitmap("")  # 换成Tkinter的羽毛把# 计算x,y坐标对应的高度值def f(x, y):    return (1-x/2+x**5+y**3) * np.exp(-x**2-y**2)def main():    # 生成x,y的数据    n = 256    x = np.linspace(-3, 3, n)    y = np.linspace(-3, 3, n)    # 把x,y数据生成mesh网格状的数据,因为等高线的显示是在网格的基础上添加上高度值    X, Y = np.meshgrid(x, y)    # 填充等高线    plt.contourf(X, Y, f(X, Y), 20, cmap=plt.cm.hot)    # 添加等高线    C = plt.contour(X, Y, f(X, Y), 20)    plt.clabel(C, inline=True, fontsize=12)    # 显示图表    plt.show()if __name__ == '__main__':    main()

CPP文件:

#include <iostream>#include <Python.h>#include <exception>using namespace std;int main(int argc, char *argv[]){    cout << "C++ call Python" << endl;    //设置Python的Home路径    Py_SetPythonHome(L"./");    //python解释器初始化    Py_Initialize();    try    {        int re = 0;        ////////////////////////////////////////////////////        // 执行python文件        char *filename = "a.py";        FILE *fp = fopen(filename,"r");        if (!fp)        {            throw exception("open file failed!");        }        re = PyRun_AnyFile(fp, filename);        if (re != 0)        {            PyErr_Print();            throw exception("PyRun_AnyFile failed!");        }        //清理python        Py_Finalize();    }    catch (exception &ex)    {        cout << ex.what() << endl;        Py_Finalize();    }    getchar();    getchar();    return 0;}

运行结果

Python源码在Win下和Linux下的编译,C++调用Python库绘制等高线

Linux中编译Python源码

这块我是直接用我的云服务器来演示的,就不写程序来演示了,直接给出编译步骤,也不截图了。

安装依赖项

命令行中分别输入以下几行

sudo apt-get install g++ make gitsudo apt-get install libbz2-dev libncurses5-dev  libgdbm-dev liblzma-dev libsqlite3-dev libssl-dev libreadline6-devsudo apt-get install libffi-dev zlib*

下载Python源码并解压
这部分同上面一样,略,下面只给出解压命令

tar -xvf xxxx.tar.xz

编译python

进入源码目录,分别执行下面几行指令

./configure -h./configure --enable-sharedmake -j2make install

其中,make -j2是采用2个线程编译

覆盖原来的Python

还是在Python源码目录中,

cp libpython3.7m.* /usr/libcp /usr/local/bin/python3.7 ./usr/bin/python

验证下Python的版本

命令行中输入:

python -V

本文分享自微信公众号 - MatlabGUI QtCPP等学习记录(ASparkleSubscription)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
3年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这