当前位置: 首页 > news >正文

CMake 学习笔记(访问Python)

CMake 学习笔记(访问Python)

利用Python可以做很多事情。比如:

  1. 利用 Python 自动生成一些代码。

  2. 在我们的程序中植入一个 Python 解释器。

为了做这些事情。就需要 CMake 能够知道 python 装在哪里,装的是什么版本的 python,装了哪些包。是否安装了Python 相关的库。

下面就依次介绍如何实现这些功能。最核心的知识就是学会如何使用 find_package( ) 命令。

检测 Python 解释器

下面是个简单的例子。

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-01 LANGUAGES NONE)
find_package(PythonInterp REQUIRED)
execute_process(COMMAND${PYTHON_EXECUTABLE} "-c" "print('Hello, world!')"RESULT_VARIABLE _statusOUTPUT_VARIABLE _hello_worldERROR_QUIETOUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "RESULT_VARIABLE is: ${_status}")
message(STATUS "OUTPUT_VARIABLE is: ${_hello_world}")# compare the "manual" messages with the following handy helper
include(CMakePrintHelpers)
cmake_print_variables(_status _hello_world)

上面的代码最核心的有两句。find_package 用来查找 python。

find_package(PythonInterp REQUIRED)

如果需要指定 python 版本。可以像下面这样,下面的代码要求Python 版本不低于 3.5:

find_package(PythonInterp 3.5 REQUIRED)

如果要求Python 版本必须是某一个特定版本。可以像下面这样写:

find_package(PythonLibs 3.11.5 EXACT REQUIRED)

上面的代码要求python 的版本必须是3.11.5。find_package() 执行完后会自动生成一系列的变量,我们可以在后面的代码中使用这些变量。

  • PYTHONINTERP_FOUND, 布尔变量,记录是否找到 python 解释器
  • PYTHON_EXECUTABLE, python 解释器的路径
  • PYTHON_VERSION_STRING, python 的版本
  • PYTHON_VERSION_MAJOR, python 的主版本号
  • PYTHON_VERSION_MINOR, python 的副版本号
  • PYTHON_VERSION_PATCH, python 的版本修订号

另外需要掌握的是 execute_process()。 用这个命令可以调用 python ,执行一段特殊的程序。通常我们是利用 python 生成一段源代码。之所以用 python 生成代码。是因为可以利用 python 对当前系统做很多探测,根据系统的情况生成最适合的代码。或者我们的代码里有很多重复的地方。用python可以快速生成这些重复的代码。

总之,用上面的类似的方法,我们可以调用任意一段 python 程序,做我们想做的任意事情。

如果python 安装到了 cmake 无法自动检测到的位置,我们可以通过命令行告诉cmake 去哪里找 python:

cmake -D PYTHON_EXECUTABLE=/custom/location/python

检测 Python 库

第二种使用 python 的方法是在我们的程序中直接调用 python 。下面是一个简单的程序:

#include <Python.h>
int main(int argc, char *argv[]) 
{Py_SetProgramName(argv[0]); /* optional but recommended */Py_Initialize();PyRun_SimpleString("from time import time,ctime\n""print 'Today is',ctime(time())\n");Py_Finalize();return 0;
}

我们要编译这个程序。

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-02 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_C_STANDARD_REQUIRED ON)
find_package(PythonInterp REQUIRED)
find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)
add_executable(hello-embedded-python hello-embedded-python.c)target_include_directories(hello-embedded-python
PRIVATE
${PYTHON_INCLUDE_DIRS}
)target_link_libraries(hello-embedded-python
PRIVATE
${PYTHON_LIBRARIES}
)

在我的电脑上运行的结果是这样的:

Could not find platform independent libraries <prefix>
Today is Tue May  7 08:51:16 2024

第一行是因为我没有设置环境变量,这个程序找不到我电脑里的python。但是这个并不影响程序运行。

检测 Python 包

下面是个更复杂的代码。里面调用了 Python 的包。为了能编译运行这个代码,需要cmake 检测我们的 python 是否安装了对应的包。

/** Code example from:*    https://docs.python.org/3.5/extending/embedding.html#pure-embedding*/#include <Python.h>int main(int argc, char *argv[]) {PyObject *pName, *pModule, *pDict, *pFunc;PyObject *pArgs, *pValue;int i;if (argc < 3) {fprintf(stderr, "Usage: pure-embedding pythonfile funcname [args]\n");return 1;}Py_Initialize();PyRun_SimpleString("import sys");PyRun_SimpleString("sys.path.append(\".\")");pName = PyUnicode_DecodeFSDefault(argv[1]);/* Error checking of pName left out */pModule = PyImport_Import(pName);Py_DECREF(pName);if (pModule != NULL) {pFunc = PyObject_GetAttrString(pModule, argv[2]);/* pFunc is a new reference */if (pFunc && PyCallable_Check(pFunc)) {pArgs = PyTuple_New(argc - 3);for (i = 0; i < argc - 3; ++i) {pValue = PyLong_FromLong(atoi(argv[i + 3]));if (!pValue) {Py_DECREF(pArgs);Py_DECREF(pModule);fprintf(stderr, "Cannot convert argument\n");return 1;}/* pValue reference stolen here: */PyTuple_SetItem(pArgs, i, pValue);}pValue = PyObject_CallObject(pFunc, pArgs);Py_DECREF(pArgs);if (pValue != NULL) {printf("Result of call: %ld\n", PyLong_AsLong(pValue));Py_DECREF(pValue);} else {Py_DECREF(pFunc);Py_DECREF(pModule);PyErr_Print();fprintf(stderr, "Call failed\n");return 1;}} else {if (PyErr_Occurred())PyErr_Print();fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);}Py_XDECREF(pFunc);Py_DECREF(pModule);} else {PyErr_Print();fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);return 1;}Py_Finalize();return 0;
}

我们的这个程序还要调用一段 python 代码:

import numpy as np
def print_ones(rows, cols):
A = np.ones(shape=(rows, cols), dtype=float)
print(A)
# we return the number of elements to verify
# that the C++ code is able to receive return values
num_elements = rows*cols
return(num_elements)

cmake 文件前部分还是一样的:

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-03 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(PythonInterp REQUIRED)
find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)

后面的部分就不同了。首先要检测有没有安装 numpy:


# Find NumPy location
execute_process(COMMAND${PYTHON_EXECUTABLE} "-c" "import re, numpy; print(re.compile('/__init__.py.*').sub('',numpy.__file__))"RESULT_VARIABLE _numpy_statusOUTPUT_VARIABLE _numpy_locationERROR_QUIETOUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT _numpy_status)set(NumPy ${_numpy_location} CACHE STRING "Location of NumPy")
endif()# Find NumPy version
execute_process(COMMAND${PYTHON_EXECUTABLE} "-c" "import numpy; print(numpy.__version__)"OUTPUT_VARIABLE _numpy_versionERROR_QUIETOUTPUT_STRIP_TRAILING_WHITESPACE)include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(NumPyFOUND_VAR NumPy_FOUNDREQUIRED_VARS NumPyVERSION_VAR _numpy_version)

这一段代码主要有2部分组成。首先是判断有没有安装 numpy,代码如下。

execute_process(COMMAND${PYTHON_EXECUTABLE} "-c" "import re, numpy; print(re.compile('/__init__.py.*').sub('',numpy.__file__))"RESULT_VARIABLE _numpy_statusOUTPUT_VARIABLE _numpy_locationERROR_QUIETOUTPUT_STRIP_TRAILING_WHITESPACE)if(NOT _numpy_status)set(NumPy ${_numpy_location} CACHE STRING "Location of NumPy")
endif()

如果找到了numpy, _numpy_status = 0。 所以后面的判断条件是 if(NOT _numpy_status) 。

找到 numpy 后,将numpy 的位置保存到一个变量 NumPy 中,并且这个 变量是 CACHE 的,也就是后面用户可以自己编辑这个变量的值。

然后是检测 numpy 的版本:

# Find NumPy version
execute_process(COMMAND${PYTHON_EXECUTABLE} "-c" "import numpy; print(numpy.__version__)"OUTPUT_VARIABLE _numpy_versionERROR_QUIETOUTPUT_STRIP_TRAILING_WHITESPACE)

版本号保存到 _numpy_version 这个变量中。然后用 FindPackageHandleStandardArgs 这个包的功能设置 NumPy_FOUND 变量。这里使用FindPackageHandleStandardArgs 的目的其实只有一个,就是当 NumPy 没找到时,cmake 可以抱错并停下来。

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(NumPy
FOUND_VAR NumPy_FOUND
REQUIRED_VARS NumPy
VERSION_VAR _numpy_version
)

后面如何编译exe文件,这里也用了些技巧,比如用到了 PYTHON_VERSION_MAJOR:

add_executable(pure-embedding "")
target_sources(pure-embedding
PRIVATE
Py${PYTHON_VERSION_MAJOR}-pure-embedding.cpp
)
target_include_directories(pure-embedding
PRIVATE
${PYTHON_INCLUDE_DIRS}
)
target_link_libraries(pure-embedding
PRIVATE
${PYTHON_LIBRARIES}
)

还有最后一部分,我们要把 use_numpy.py 文件拷贝到 exe 所在目录,因为我们的程序要调用这个文件:


add_custom_command(OUTPUT${CMAKE_CURRENT_BINARY_DIR}/use_numpy.pyCOMMAND${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/use_numpy.py${CMAKE_CURRENT_BINARY_DIR}/use_numpy.pyDEPENDS${CMAKE_CURRENT_SOURCE_DIR}/use_numpy.py)# make sure building pure-embedding triggers the above
# custom command
target_sources(pure-embeddingPRIVATE${CMAKE_CURRENT_BINARY_DIR}/use_numpy.py)

编译生成 pure-embedding.exe 后可以试着运行一下。

./pure-embedding use_numpy print_ones 2 3

结果如下:

[[1. 1. 1.]
[1. 1. 1.]]
Result of call: 6

相关文章:

CMake 学习笔记(访问Python)

CMake 学习笔记&#xff08;访问Python&#xff09; 利用Python可以做很多事情。比如&#xff1a; 利用 Python 自动生成一些代码。 在我们的程序中植入一个 Python 解释器。 为了做这些事情。就需要 CMake 能够知道 python 装在哪里&#xff0c;装的是什么版本的 python&a…...

【ruoyi】docker部署 captchaImage接口 FontConfiguration空指针异常

后台服务报错captchaImage接口空指针异常&#xff0c;无法启动项目&#xff1a; [http-nio-4431-exec-27] ERROR c.r.f.w.e.GlobalExceptionHandler - [handleRuntimeException,93] - 请求地址/captchaImage,发生未知异常.java.lang.NullPointerException: nullat sun.awt.Font…...

P1443 马的遍历

题目描述: 有一个 &#x1d45b;&#x1d45a;nm 的棋盘&#xff0c;在某个点 (&#x1d465;,&#x1d466;)(x,y) 上有一个马&#xff0c;要求你计算出马到达棋盘上任意一个点最少要走几步。 代码: package lanqiao;import java.util.*;public class Main {static int n,m…...

AI学习指南概率论篇-贝叶斯推断

AI学习指南概率论篇-贝叶斯推断 概述 在人工智能中&#xff0c;贝叶斯推断是一种基于贝叶斯统计理论的推理方法。它通过使用概率论的知识&#xff0c;结合先验信息和观测数据&#xff0c;来更新对未知变量的推断。贝叶斯推断提供了一种合理的方法来处理不确定性&#xff0c;并…...

大数据测试

1、前言 大数据测试是对大数据应用程序的测试过程&#xff0c;以确保大数据应用程序的所有功能按预期工作。大数据测试的目标是确保大数据系统在保持性能和安全性的同时&#xff0c;平稳无差错地运行。 大数据是无法使用传统计算技术处理的大型数据集的集合。这些数据集的测试涉…...

金融业开源软件应用 管理指南

金融业开源软件应用 管理指南 1 范围 本文件提供了金融机构在应用开源软件时的全流程管理指南&#xff0c;对开源软件的使用和管理提供了配套 组织架构、配套管理规章制度、生命周期流程管理、风险管理、存量管理、工具化管理等方面的指导。 本文件适用于金融机构规范自身对开…...

SolidWorks 齿轮配合

SolidWorks 齿轮配合 在SolidWorks中&#xff0c;齿轮配合是一种特殊的配合类型&#xff0c;用于模拟两个或多个齿轮之间的旋转关系。这种配合确保当一个齿轮旋转时&#xff0c;其他齿轮按照特定的比例旋转&#xff0c;非常适合模拟机械传动系统。以下是使用齿轮配合的详细步骤…...

鸿蒙开发-ArkTS语言-XML

鸿蒙开发-UI-web 鸿蒙开发-UI-web-页面 鸿蒙开发-ArkTS语言-基础类库 鸿蒙开发-ArkTS语言-并发 鸿蒙开发-ArkTS语言-并发-案例 鸿蒙开发-ArkTS语言-容器 鸿蒙开发-ArkTS语言-非线性容器 文章目录 前言 一、XML概述 二、XML生成 三、XML解析 1.解析XML标签和标签值 2.解析XML属性…...

网安面经之文件上传漏洞

一、文件上传漏洞 1、文件上传漏洞的原理&#xff1f;危害&#xff1f;修复&#xff1f; 原理&#xff1a;⽂件上传漏洞是发⽣在有上传功能的应⽤中&#xff0c;如果应⽤程序对⽤户上传的⽂件没有控制或者存在缺陷&#xff0c;攻击者可以利⽤应⽤上传功能存在的缺陷&#xff…...

如何使用 WavLM音频合成模型

微软亚洲研究院与 Azure 语音组的研究员们提出了通用语音预训练模型 WavLM。通过 Denoising Masked Speech Modeling 框架&#xff08;核心思想是通过预测被掩蔽&#xff08;即遮蔽或删除&#xff09;的语音部分来训练模型&#xff0c;同时还包括去噪的过程&#xff09;&#x…...

学习java第六十七天

注入 Bean 的注解有哪些&#xff1f; 答&#xff1a; Autowired&#xff1a;根据类型进行注入&#xff0c;如果匹配到多个Bean&#xff0c;则会爆出异常。可以和Qualifier搭配使用&#xff0c;指定使用哪个名称的Bean Resource&#xff1a;首先根据名称注入&#xff0c;如果…...

Linux(Ubuntu24.04) 安装 MinIO

本文所使用的 Ubuntu 系统版本是 Ubuntu 24.04 ! # 1、下载 MinIO wget https://dl.min.io/server/minio/release/linux-amd64/minio# 2、添加可执行权限 chmod x minio# 3、导出环境变量&#xff0c;用于设置账号密码&#xff0c;我设置的账号和密码都是 minioadmin export MI…...

视频汇聚边缘网关EasyCVR硬件设备无法访问域名,解析失败该如何处理?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚融合管理平台EasyCVR既具备传统安防视…...

差速机器人模型LQR 控制仿真(c++ opencv显示)

1 差速机器人状态方程构建 1.1差速机器人运动学模型 1.2模型线性化 1.3模型离散化 2离散LQR迭代计算 注意1&#xff1a;P值的初值为Q。见链接中的&#xff1a; 注意2&#xff1a;Q, R参数调节 注意3&#xff1a;LQR一般只做横向控制&#xff0c;不做纵向控制。LQR输出的速度…...

探索设计模式的魅力:权力集中,效率提升,中心化模式的优势与挑战

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索中心化模式之旅✨ 大家好啊&#xff01;&#x1f44b; 这次我们要聊的是IT界一…...

uniapp0基础编写安卓原生插件之编写安卓页面在uniapp上显示(摄像头调用)

前言 如果你对安卓插件开发部分不熟悉你可以先看uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之零基础编写安卓插件 效果 开始 dcloud_uniplugins.json {"nativePlugins": [{"hooksClass": "","plugins": [{&…...

fastapi数据库连接池的模版

在FastAPI中,数据库连接池通常通过使用SQLAlchemy来实现。以下是一些基于官方文档和其他可靠资源的数据库连接池模板示例。 1. 使用SQLAlchemy创建异步数据库引擎 首先,你需要创建一个异步数据库引擎,这将作为数据库连接的来源。以下是使用sqlalchemy.ext.asyncio模块创建…...

如何批量将十六进制数据转成bin文件

最近在做新项目遇到一个问题&#xff0c;我们要通过上位机把一堆数据通过串口发送给下位机存储&#xff0c;而上位机需要Bin文件。 解决办法&#xff1a; 1)创建一个记事本文件&#xff0c;然后将其后缀修改成.bin 2)然后打开notepad,新建一个文件&#xff0c;随便写下数据 我…...

知识付费程序源码_30秒轻松搭建知识付费小程序_免费试用,知识付费工具有哪些?哪个比较好用?

继2016年知识付费大火之后&#xff0c;衍生出很多关于知识付费的平台或工具。除了得到APP、荔枝微课、千聊等需要用户作为“客”家申请入驻的流量型平台&#xff0c;还有一些其他的知识付费工具&#xff0c;那么有哪些呢? 知识付费工具&#xff0c;推荐使用系统。 自2016年知识…...

【系统架构师】-案例篇(九)容器化、CDN与微服务

某汽车制造企业提出开发一个车联网系统。该系统釆用微服务架构&#xff0c;将系统功能分解为多个松散耦合且可独立部署的较小组件或服务。最终设计的系统包括了车辆信息服务、车辆监控服务、车辆控制服务、人车授权服务、资源聚合服务、车机互联服务等。 在系统上线之后&#…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...