Chapter 3
在学习的过程中总结的关于python路径的一些问题
ubuntu中自带了python,我的ubuntu版本是20.04,python版本是3.8,但是不像自己编译安装一样,ubuntu把这个python安装到了很多的地方。
首先,默认是没有安装pip
的,可以通过sudo apt install python3-pip
来安装。
然后,再使用pip
来安装python的一些模块的时候,这些模块被安装到的路径是由USER_SITE
变量来决定的。可以通过python3 -m site
来查看这些信息。比如我的就是
1 | ~ ❯ python3 -m site |
因此,如果使用pip install numpy
的话,numpy包会被安装在/home/lushuangning/.local/lib/python3.8/site-packages
下面,而不是安装在python自带的模块/usr/lib/python3/dist-packages
下,想要更改可以参考ubuntu下更改pip安装的模块路径
另外,python的include目录在/usr/include/python3.8
,这也是下面PYTHON_INCLUDE_DIR
指向的目录,而PYTHON_LIBRARY
指向的是/usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.so
chpater 3.1 检测 Python 解释器
CMakeLists.txt
1 | cmake_minimum_required(VERSION 3.5 FATAL_ERROR) |
find_package
是用于发现和设置包的CMake模块的命令。这些模块包含CMake命令,用于标识系统标准位置中的包。CMake模块文件称为 Find<name>.cmake
,当调用find_package(<name>)
时,模块中的命令将会运行。
除了在系统上实际查找包模块之外,查找模块还会设置了一些有用的变量,反映实际找到了什么,也可以在自己的CMakeLists.txt
中使用这些变量。对于Python解释器,相关模块为FindPythonInterp.cmake附带的设置了一些CMake变量:
- PYTHONINTERP_FOUND:是否找到解释器
- PYTHON_EXECUTABLE:Python解释器到可执行文件的路径
- PYTHON_VERSION_STRING:Python解释器的完整版本信息
- PYTHON_VERSION_MAJOR:Python解释器的主要版本号
- PYTHON_VERSION_MINOR :Python解释器的次要版本号
- PYTHON_VERSION_PATCH:Python解释器的补丁版本号
可以强制CMake,查找特定版本的包。例如,要求Python解释器的版本大于或等于2.7:find_package(PythonInterp 2.7)
可以强制满足依赖关系:
1 | find_package(PythonInterp REQUIRED) |
TIPS:CMake有很多查找软件包的模块。我们建议在CMake在线文档中查询Find<package>.cmake
模块,并在使用它们之前详细阅读它们的文档。find_package
命令的文档可以参考 https://cmake.org/cmake/help/latest/command/find_package.html 另外一个方法是浏览 https://github.com/Kitware/CMake/tree/master/Modules 中的CMake模块源代码——它们记录了模块使用的变量,以及模块可以在CMakeLists.txt
中使用的变量。
软件包没有安装在标准位置时,CMake无法正确定位它们。尤其是,对于Python解释器来说,使用Anaconda的用户可能创建了多个Python环境。用户可以使用CLI的-D
参数传递相应的选项,告诉CMake查看特定的位置。Python解释器可以使用以下配置:
1 | cmake -D PYTHON_EXECUTABLE=/media/lushuangning/mount_disk/software/anaconda3/envs/detectron2/bin/python .. |
chapter 3.2 检测python库
勘误
首先是hello-embedded-python.c
里,有一行代码是
1 | PyRun_SimpleString("from time import time,ctime\n" |
这样在python3下会报错的,应该修改为
1 | PyRun_SimpleString("from time import time,ctime\n" |
个人猜测原书和翻译上可能用的是python2中的print方法,一时没有改过来。完整的代码是
hello-embedded-python.c
1 |
|
其次,如果是用的Anaconda,那么直接cmake --build .
也是会报错的,需要先指定PYTHONHOME
和PYTHON_EXECUTABLE
的路径,正确的流程是
1 | mkdir build && cd build |
完整的CmakeLists.txt
代码如下:
1 | cmake_minimum_required(VERSION 3.12 FATAL_ERROR) |
注:find_package(PythonInterp REQUIRED)
已在Cmake 3.12以后的版本中废弃,替代的方式为find_package(Python COMPONENTS Interpreter Development)
chapter 3.3 检测Python模块和包
本示例演示如何通过Cmake找到Python的Numpy模块
1 | execute_process( |
新命令:execute_process
将作为子进程执行一个或多个命令。最后,子进程返回值将作为参数,传递给RESULT_VARIABLE
,而管道标准输出和标准错误的内容将被保存到变量作为参数传递给OUTPUT_VARIABLE
和ERROR_VARIABLE
。execute_process
可以执行任何操作,并使用它们的结果来推断系统配置。本例中,用它来确保NumPy可用,然后获得模块版本。
1 | include(FindPackageHandleStandardArgs) |
新命令:find_package_handle_standard_args
提供了用于处理与查找相关程序和库的标准工具。引用此命令时,可以正确的处理与版本相关的选项(REQUIRED
和EXACT
),而无需更多的CMake代码。稍后将介绍QUIET
和COMPONENTS
选项。
所有必需的变量都设置为有效的文件路径(NumPy)后,发送到模块(NumPy_FOUND
)。它还将版本保存在可传递的版本变量(_numpy_version
)中并打印:
1 | -- Found NumPy: /usr/lib/python3.6/site-packages/numpy (found version "1.14.3") |
1 | add_custom_command( |
新命令:add_custom_command
,将在第5章详细讨论。
完整的执行命令及结果为:
1 | ~/CodeHub/CMake/MyCmakeExample/chapter3/3.3/build main ?1 |
chapter 3.4 检测BLAS和LAPACK数学库
这篇示例需要提前安装gfortran,BLAS库,LAPACK库,安装命令为sudo apt install gfortran libblas-dev liblapack-dev liblapack-doc
我们首先明确,这个系列的博客是在学习CMake的用法,而不是Python、Fortran或者其他什么语言的用法,注意不要本末倒置。 这里我们把用到的文件从对应的github上下载下来即可,重点关注的是CMakeLists.txt
文件,而这其中,构建过程的重点代码又如下所示:
1 | add_library(math "") |
理清楚这个顺序很重要。首先,add_library
生成一个math
的链接文件,该文件依赖的cpp文件由target_sources
指定,包含的头文件由target_include_directories
指定,需要用到的库由target_link_libraries
指定。
然后,可执行文件linear-algebra
需要的cpp文件由target_sources
指定,需要用到的库即是上一步生成的链接文件math,由target_link_libraries
指定。
chapter 3.5-3.6
chapter 3.5和3.6需要用到OpenMP,但是其安装较为繁琐,而且我目前的技术栈用不到它。还是那句话,我们当前的目的是学习CMake,这两节的CMakeLists.txt
很简单,并且没有出现新的CMake命令,因此选择跳过这两节。
chapter 3.7-3.8
这两节里面出现了一个很重要的知识点,即find_package
查找的两种方式。CMake的官方文档中也给出了这两种方式的说明:https://cmake.org/cmake/help/latest/command/find_package.html
为此,不惜直接将官网上的这两段重点复制过来
Module mode
In this mode, CMake searches for a file called Find<PackageName>.cmake
, looking first in the locations listed in the CMAKE_MODULE_PATH, then among the Find Modules provided by the CMake installation. If the file is found, it is read and processed by CMake. It is responsible for finding the package, checking the version, and producing any needed messages. Some Find modules provide limited or no support for versioning; check the Find module’s documentation.
The Find<PackageName>.cmake
file is not typically provided by the package itself. Rather, it is normally provided by something external to the package, such as the operating system, CMake itself, or even the project from which the find_package()
command was called. Being externally provided, Find Modules tend to be heuristic in nature and are susceptible to becoming out-of-date. They typically search for certain libraries, files and other package artifacts.
Module mode is only supported by the basic command signature.
Config mode
In this mode, CMake searches for a file called <lowercasePackageName>-config.cmake
or <PackageName>Config.cmake
. It will also look for <lowercasePackageName>-config-version.cmake
or <PackageName>ConfigVersion.cmake
if version details were specified (see Config Mode Version Selection for an explanation of how these separate version files are used).
In config mode, the command can be given a list of names to search for as package names. The locations where CMake searches for the config and version files is considerably more complicated than for Module mode (see Config Mode Search Procedure).
The config and version files are typically installed as part of the package, so they tend to be more reliable than Find modules. They usually contain direct knowledge of the package contents, so no searching or heuristics are needed within the config or version files themselves.
Config mode is supported by both the basic and full command signatures.
找不到依赖是CMake报错的重灾区,了解CMake如何找到依赖是非常重要的,可参考深入理解CMake(3):find_package()的使用对这两种模式有一个大致的了解。