\ 跳到主要內容

Write a module in C++ and use it in python

 做這個小實驗的當天看到這個梗圖,相當呼應這個主題:

「其它的程式語言對你作力學是沒用的,作計算就三本柱 Python、C++、Fortran 足矣,連 C 都沒什麼用處。」Python在計算的速度上相較於C++非常的緩慢,這個demo很清楚地呈現了這件事。

以計算力學為題,python在tool的開發,input的整合上具有優勢,但是在計算效能上的表現不佳,於是就有了許多與python互相支援的foreign function interface(FFI),如 swig, cython, pybind11。

截python所長,補C++所短 (or vice versa) ,似乎是做出更好的力學程式不可或缺的元素,pybind扮演的角色於是顯現。接下來就簡單用C++寫一個python的module:

1. 寫 .cpp/.h file。
#include <pybind11/pybind11.h>
double square(double i){
	return i*i;
}

PYBIND11_MODULE(test, handle){ //Module 的attributes 會在這裡做定義
        handle.doc()="This is my doc";
        handle.def("sqrt", &square);
}

2. 寫 CMakeList.txt。
cmake_minimum_required(VERSION 3.4)
PROJECT(pybind_vid)
add_subdirectory(pybind11)
pybind11_add_module(test test.cpp) //test為建構的module的名稱 test.cpp是它所依據的檔案

3. Build the module。
mkdir build
cd build/
cmake ..
make

4. 在python中使用前面所建立的module。
~/git-repo/importation/test$ python3
>>> import test
>>> dir(test)
['doc', 'file', 'loader', 'name', 'package', 'spec', 'sqrt']
>>> test.sqrt(3.145)
9.891025
>>> test.__doc__
"This is my doc"
  • dir(test)中可以看我們define的function以及attributes。
  • What's the cause of success within ~/git-repo/importation/test but not ~/git-repo/importation?
>>> import test
>>> dir(test)
['builtins', 'cached', 'doc', 'file', 'loader', 'name', 'package', 'path', 'spec']

留言

這個網誌中的熱門文章

Command Line 與 Makefile

在認識到Linux以前,我鮮少接觸到CLI(Command Line Interface),也花了些許時間去熟悉。一開始看它也許會感到有些震懾,但並沒有想像中的複雜,單純是將我們習慣使用的GUI(Graphical User Interface)改成CLI,滑鼠改成鍵盤,簡單做了轉換。 sudo apt-get install qt6-default //以superuser身份安裝qt6-default mkdir build/install -p //新增資料夾 cd build/install //切換目錄到build/install rm –rf build //remove文件, recursively. makefile make 以及 makefile讓我們得以自動化我們想執行的command line。比如說modmesh裡面中clean這個target,若是藉由一行一行的command line我們會需要輸入以下的指令, rm -f $(MODMESH_ROOT)/modmesh/_modmesh$(pyextsuffix) make -C $(BUILD_PATH) clean 但如果已經在Makefile中寫好了clean這個target,將一行行的command line寫成了shell script。 .PHONY: clean clean: rm -f $(MODMESH_ROOT)/modmesh/_modmesh$(pyextsuffix) make -C $(BUILD_PATH) clean 我們就可以去藉由make,直接輸入 make clean 去執行我們想要去執行的內容,不用逐步命令。 make clean

Compile behind-the-scene

習慣使用了具備強大功能的整合工具-- IDE(e.g Visual Studio),執行source code(e.g .cpp)僅需點下  建置(Build)   然後  ▷  ,有時是只點下   ▷  ,就完成了許多希望程式去做的事,很方便,但也因此缺乏對於幕後工程的認識。離開了IDE,使用terminal則可以透過下面的指令完成同樣的事情: $ g++ main.cpp -o main.out #編譯 $ ./main.out #執行 helloworld 編譯透過以上一行簡單的指令,將我們寫的source code編譯成執行檔(在Linux上是.out,在Windows上則是.exe),然後可以直接被電腦執行。簡單的一句指令,過程則可以分為四個步驟,分別是1. 前編譯Preprocessing, 2. 編譯compilation, 3. 組譯assembly 以及 4. 連結linking。 以下用一支比helloworld更簡單的程式來呈現: main.cpp #define N 81 int main(){ return 0;//this is the end } 1. Preprocessing: .cpp -> .ii,處理#,刪除註解(//, /**/),加以編號。 $ g++ -E main.cpp -o main.ii main.ii: # 1 "main.cpp" # 1 "<built-in>" # 1 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 1 "<command-line>" 2 # 1 "main.cpp" int main(){ return 0; } 2. Compilation: .ii -> .s,將 .ii檔進行分析以及最佳化,將高階語言翻譯成assembly code。屬於程式建構過程最複雜的環節。 main.s $ g++ -S main.ii -o main.s .file "main.cpp" ...

Python importation

In a well-organized C++ code base, the hpp files should always be included using the full path like: #include <modmesh/base.hpp> #include <modmesh/profile.hpp> #include <modmesh/buffer/buffer.hpp> Python import 的module 並不必然要用python撰寫,也可以藉由C++。然而我誤解了這番話的意思,進而混用了 header files 與 modules,以為以下的實驗會成功: import importation #succeed import layer1.importation #succeed import header #failed 以下是python importation 整理過後的資訊: 1. import modmesh 以 modmesh 作為例子 , import modmesh 我原先同樣是誤會 modmesh.hpp 才是被 python import的對象;但這個對象其實是library(or python package):$(MODMESH_ROOT)/modmesh。如果它已經被 built, 那麼目錄裡頭就會有 __init__.py 以及 .so 。 2. python importation python importation 的機制在於編輯 sys.path. e,g  del sys.path[0] sys.path儲存的是尋找python module的路徑。在這個動作之後,原先若是被import的對象被列在sys.path[0]所儲存的路徑之下,那麼import就會失敗。 3. Module written in C++ 如前所述,Python import 的module 並不必然要用python撰寫,e.g. C++, 它們是透過 import shared library(.so)來被python支援。 C++ and python 的連結可透過 swig, cython, pybind11 等等。在modmesh 中則是使用 py...