C-如何快速生成Python的C擴充套件.md

我勒個去發表於2022-01-09

前言

真的好久沒有分享技術文章了,主要是因為自己寫的文章太過於小眾,沒想到自己竟然會分享這樣一篇文章。這麼一篇濃縮了自己多年來專案開發的實戰經驗。
不得不說,Python是一門很不錯的程式語言。有時候,為了專案程式碼安全考慮,會嘗試將一些原始碼使用Python提供的C API的方式進行編寫,再將其編譯為Python模組的方式,從而在Python中直接呼叫。

編譯的一些技巧

對於Python的C API編寫的程式碼,如果快速將其生成為Python對應的擴充套件庫,如Linux下的.so或Windows下的.pyd
主要有如下一些方法:

  • 使用setuptools模組
  • 使用scikit-build模組
  • 使用cmake

實際上這些方法經常是在一起使用的。
對於手動編寫setup.py檔案,指定對應的要引入的標頭檔案及連結庫,對於中大型專案是不推薦的。

setuptools方式

在此之前,先使用如下的方式先生成1個C原始檔:

pip install pyd-tpl
pyd-tpl hello

該模組是自己編寫用於快速生成Python的C擴充套件檔案的一個庫。安裝完成後,我們呼叫pyd-tpl命令會在當前目錄下生成1個hello.c原始檔及setup_hello.py檔案。
我們可以直接執行如下的方式進行編譯並生成1個hello模組:

python setup_hello.py

這是第1種使用setuptools生成模組的方式。下面主要介紹後面兩種方式。

scikit-build方式

首先我們執行下面的命令安裝對應的庫:

pip install scikit-build cmake

由於scikit-build依賴於cmake,我們可以直接使用pip的方式安裝該工具。
安裝完成後,接著我們在setup.py中編寫如下的程式碼:

from skbuild import setup

之後在專案目錄下新建1個CMakeLists.txt,其內容如下:

cmake_minimum_required(VERSION 3.11.0)
project(hello VERSION 0.1.0)
find_package(PythonExtensions REQUIRED)
add_library("${PROJECT_NAME}" MODULE hello.c)
python_extension_module("${PROJECT_NAME}")
install(TARGETS hello LIBRARY DESTINATION hello)

這裡我們設定我們專案的名稱為hello,通過使用cmake提供的find_package指令尋找Python的擴充套件。之後通過add_libraryhello.c檔案編譯,從而生成以專案名稱命名的模組。
接著還需要在專案目錄下創見1個pyproject.toml的檔案,其內容如下:

[build-system]
requires = ["setuptools", "wheel", "scikit-build", "cmake", "ninja"]

之後我們執行如下的命令即可實現整個過程的自動編譯:

python setup.py build

不過這種方式有個不好的地方在於,如果系統無法正常識別你的編譯器,比如在Windows下我使用的是Visual Studio 2015,它並沒有很好的識別出來。只能在Visual Studio 2015工具提供的選單視窗下執行才行。
其過程如下圖所示:

windows

cmake原生方式

在cmake版本3.12開始,提供了1個非常好用的Python_add_library命令,詳情可以參考。藉助該命令,我們可以快速生成Python的C擴充套件。
我們只需要在上述CMakeLists.txt中的內容進行如下的修改:

cmake_minimum_required(VERSION 3.12.0)
project(hello VERSION 0.1.0)
find_package (Python3 COMPONENTS Development)
include_directories(${Python3_INCLUDE_DIRS})
Python3_add_library(hello MODULE hello.c)

該命令語法與add_library命令一樣。在這裡,我們使用的是Python3,因此在find_package命令中指定的使用Python3。
之後在Windows下建立1個build目錄,並進入該目錄中再執行如下命令:

mkdir build
cd build
cmake -G "Visual Studio 14 2015" -A x64 ..
cmake --build . --config Release

而對於Linux將相應的命令修改為:

cmake ..
make

通過cmake工具,這樣我們就可以輕鬆地生成對應Python的hello.pydhello.so的C擴充套件。

後語

實際上,對於生成Python的C擴充套件還有1種方式就是將cmake與setup.py檔案結合,通過setup.py檔案中setup函式的cmdclass引數指定自定義1個cmake編譯類。
實際上,在實際專案開發中,真的沒必要搞得這麼複雜,將1個非常簡單的問題複雜化是得不償失的。
這裡就不展開介紹了,使用上述3種方法即可很輕鬆解決Python的C擴充套件編譯的問題。其中最推薦使用第3種方式。

相關文章