1. 程式人生 > >c++ 呼叫Python指令碼或者動態庫——環境Ubuntu 16.04下用codeblocks

c++ 呼叫Python指令碼或者動態庫——環境Ubuntu 16.04下用codeblocks

背景:因為使用的是python版本的程式,最終要整合到C++環境的架構中,也就是說架構是c++的,交付使用者為c++的介面,但是呼叫的是python的庫,因此需要學習在c++環境下呼叫python。因為對python不熟悉,可以說有點一抹黑,因此從簡到難逐步探索。首先在c++的工程中實現呼叫單個簡單的python指令碼(.py指令碼檔案),然後再呼叫python編譯成的庫(.so),最後將複雜的python“工程”編譯成庫,用c++寫好介面被總工程可呼叫。使用的IDE是codeblocks。

翻看了很多部落格,都是假設我們已經知道了設定操作,對我這種操作小白來說及其痛苦。翻牆的油管視訊實在是太慢,國內的優酷實在沒什麼乾貨。。。遂這樣拆解任務由簡到難,也可以為不同的需求提供不同的方式。

1. C++呼叫python指令碼檔案

(1)配置環境

用codeblocks(後面簡稱CB)建立一個console的c++工程,取名叫consoleUseSo,裡面只有一個main.cpp檔案。

配置好Python的環境,具體配置方法請見:

總結起來基本就是:右鍵工程,點選build options,左欄選擇最上面的工程名(不要選Debug或者Release否則得設定兩遍)。我預設的編譯器是GNU GCC Compiler,這個不用去管。需要設定的是:點選linker settings選項卡,在Link Libraries裡面選擇python的庫檔案路徑,一般是usr/lib/python2.7/config-x86_64-linux-gnu/libpython2.7.so,CB可以選擇設為相對路徑。完成後點選search directories選項卡,在下面的complier選項卡下,選擇Python的include路徑,一般為:usr/include/python2.7;然後在Linker選項卡中,選擇lib路徑,一般為:usr/lib/python2.7。這樣編譯環境就設定好了。在main.cpp中,需要加上:

#include <python2.7/Python.h>
或者
#include <Python.h>

(2)簡單的python指令碼檔案

寫一個簡單的Python指令碼檔案,叫做:your_file.py

#-* -coding: UTF-8 -* -

def display(name):
    print "hi",name  

class test:
    def say(self):
        print 'hello'

裡面有簡單的螢幕列印函式。

將此your_file.py檔案放置在consoUseSo工程的目錄裡面,即和main.cpp在同一路徑下

(3)main.cpp中呼叫python指令碼

在main.cpp中新增如下程式碼:

#include <iostream>
#include "stdio.h"
#include <python2.7/Python.h> //只寫<Python.h>也可以

int main()
{
    // 初始化Python
    //在使用Python系統前,必須使用Py_Initialize對其
    //進行初始化。它會載入Python的內建模組並新增系統路
    //徑到模組搜尋路徑中。這個函式沒有返回值,檢查系統
    //是否初始化成功需要使用Py_IsInitialized。
    Py_Initialize();

    // 檢查初始化是否成功
    if ( !Py_IsInitialized() ) {
        return -1;
    }

    // 添加當前路徑。這裡注意下面三句都不可少,
    //新增的是當前路徑。但是我列印了sys.path,
    //出來了好多路徑,有點類似環境變數路徑的東西。這點不太懂怎麼就成當前路徑了
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("print '---import sys---'");
    PyRun_SimpleString("print sys.path.append('./')");

    PyObject *pName,*pModule,*pDict,*pFunc,*pArgs;

    // 載入名為your_file的指令碼
    pName = PyString_FromString("your_file");
    pModule = PyImport_Import(pName);
    if ( !pModule ) {
        printf("can't find your_file.py");
        getchar();
        return -1;
    }

    pDict = PyModule_GetDict(pModule);
    if ( !pDict ) {
        return -1;
    }
    printf("----------------------\n");

    // 找出函式名為display的函式
    pFunc = PyDict_GetItemString(pDict, "display");
    if ( !pFunc || !PyCallable_Check(pFunc) ) {
        printf("can't find function [display]");
        getchar();
        return -1;
     }

    //將引數傳進去。1代表一個引數。
    pArgs = PyTuple_New(1);

    //  PyObject* Py_BuildValue(char *format, ...)
    //  把C++的變數轉換成一個Python物件。當需要從
    //  C++傳遞變數到Python時,就會使用這個函式。此函式
    //  有點類似C的printf,但格式不同。常用的格式有
    //  s 表示字串,
    //  i 表示整型變數,
    //  f 表示浮點數,
    //  O 表示一個Python物件。
    //這裡我要傳的是字串所以用s,注意字串需要雙引號!
    PyTuple_SetItem(pArgs, 0, Py_BuildValue("s"," python in C++"));
    // 呼叫Python函式
    PyObject_CallObject(pFunc, pArgs);

    // 關閉Python
    Py_Finalize();
    return 0;
}

點選build,然後執行,如下:

不知道為什麼打印出來的sys.path.append就成了None,我只列印sys.path出來了好多類似環境變數的路徑。此處不懂。

這個小節寫的用c++呼叫指令碼,只能將main.cpp和py指令碼放在同一路徑下,除非設定好路徑,然而是不認

2. C++工程呼叫python生成的so庫

更進一步。