顯示具有 Boost 標籤的文章。 顯示所有文章
顯示具有 Boost 標籤的文章。 顯示所有文章

python call C++ API by Boost~初體驗

沒有留言:
原則上,是將c++編譯成dll檔。
只是這個dll檔,是要給python用的

建立專案檔

建立一個Win32 Console的dll檔專案

原本的C++程式碼

先來看看一個cpp原本的code

.h檔

#include <string>
#include <map>

class Persion
{
    std::string m_Name;
    std::string m_HomeNumber;
public:
    Persion();
    explicit Persion(const std::string &name);
    virtual ~Persion();
    void SetName(const std::string &name);
    std::string GetName() const;
    void SetHomeNumber(const std::string &number);
    std::string GetHomeNumber() const;
};

class PersionWithCell : public Persion
{
    std::string m_CellNumber;
public:
    PersionWithCell();
    explicit PersionWithCell(const std::string &name);
    void SetCellNumber(const std::string &number);
    std::string GetCellNumber() const;
};

class PhoneBook
{
    std::map<std::string, Persion*> m_PhoneBook;
public:
    int GetSize() const;
    void AddPerson(Persion *p);
    void RemovePersion(const std::string &name);
    Persion *FindPerison(const std::string &name);
};

.cpp檔

#include "phonebook.h"

Persion::Persion():
m_Name(""), m_HomeNumber("")
{}

Persion::Persion(const std::string &name):
m_Name(name), m_HomeNumber("")
{}

void Persion::SetName(const std::string &name)
{
    m_Name = name;
}

std::string Persion::GetName() const
{
    return m_Name;
}

void Persion::SetHomeNumber(const std::string &number)
{
    m_HomeNumber = number;
}

std::string Persion::GetHomeNumber() const
{
    return m_HomeNumber;
}

Persion::~Persion()
{}

int PhoneBook::GetSize() const
{
    return (int)m_PhoneBook.size();
}

void PhoneBook::AddPerson(Persion *p)
{
    m_PhoneBook[p->GetName()] = p;
}

void PhoneBook::RemovePersion(const std::string &name)
{
    m_PhoneBook.erase(name);
}

Persion *PhoneBook::FindPerison(const std::string &name)
{
    return m_PhoneBook[name];
}

void PersionWithCell::SetCellNumber(const std::string &number)
{
    m_CellNumber = number;
}

std::string PersionWithCell::GetCellNumber() const
{
    return m_CellNumber;
}

PersionWithCell::PersionWithCell():m_CellNumber(""), Persion()
{}

PersionWithCell::PersionWithCell(const std::string &name):m_CellNumber(""), Persion(name)
{}

為C++ code 建立表皮

再來我們為了這一個cpp程式,建立一份「皮」
在此可以注意的是,如果你要為屬性設定get/set,使用.add_property(),如果是只有get或只有set,就如同新增一個function一樣,用.def()
#include "phonebook.h"
#include <boost/python.hpp>

using namespace boost::python;

static std::string PrintPersion(const Persion &p)
{
    std::ostringstream stream;
    stream << p.GetName() << ": " << p.GetHomeNumber();
    return stream.str();
}

std::ostream &operator<<(std::ostream &os, const Persion &p)
{
    os << p.GetName() << ": " << p.GetHomeNumber();
    return os;
}

BOOST_PYTHON_MODULE(phonebook)
{
    class_<Persion>("Persion", init<>())
        .def(init<std::string>())
        .add_property("name", &Persion::GetName, &Persion::SetName)
        .add_property("home_number", &Persion::GetHomeNumber, &Persion::SetHomeNumber)
        .def("__str__", &PrintPersion)
        .def(self_ns::str(self))
        ;

    class_<PhoneBook>("PhoneBook")
        .def("size", &PhoneBook::GetSize)
        .def("add_persion", &PhoneBook::AddPerson)
        .def("remove_persion", &PhoneBook::RemovePersion)
        .def("find_persion", &PhoneBook::FindPerison,
            return_value_policy<reference_existing_object>())
            ;
}


編譯

編譯成.dll檔!

用python呼叫之前


  1. 將.dll改成.pyd
  2. 將.pyd檔的檔名設定成BOOST_PYTHON_MODULE()裡定義的名字
  3. 將Boost的boost_python-vc80-mt-gd-1_60.dll copy 到和.py檔同目錄
    (這一步如果有人知道怎麼不移動檔案,還麻煩請告訴我呢!)

寫python

import debug.phonebook as phonebook

book = phonebook.PhoneBook()
p = phonebook.Persion()
p.name = "Chris"
p.home_number = '(123) 456-7890'
book.add_persion(p)
p = phonebook.Persion('Mary')
#p.name = 'Mary'
p.home_number = '(123) 456-7890'
book.add_persion(p)
print('No. of contacts =', book.size())
print(book.find_persion('Mary').home_number)
print(p)
print('--------')
import debug.phonebook as phonebook
p = phonebook.Persion('Mary')
print(p)
p.home_number = '(123) 456-7890'
print(p)

def persion_str(self):
    return "Name: %s\nHome: %s" % (self.name, self.home_number)

phonebook.Persion.__str__ = persion_str
p = phonebook.Persion()
p.name = "Chris"
p.home_number = "(123) 456-7890"
print (p)

book = phonebook.PhoneBook()

class PyPersionWithCell(phonebook.Persion):
    def get_cell_number(self):
        return self.cell
    def set_cell_number(self, n):
        cell = n
    celll_number = property(get_cell_number, set_cell_number)

p = PyPersionWithCell()
p.name = 'Martin'
p.home_number = '(123) 456-7890'
p.celll_number = '(123) 097-2134'
p2 = book.find_persion('Martin')
print(p2)

執行pythony就可以看見結果啦!

Boost C++ Libraries 哈囉~World

沒有留言:

測試環境

python 版本: python 3
visual studio版本: 2013

步驟

原則上,是依照一篇簡單明瞭的教學進行。[1]

不過因為我太嫩了,遇到一些問題無法排解。
所以,在此只記錄問題與排解的過程。有空再來把步驟補齊。

成功了就會這樣

可能會遇到的問題

  1. 問題:錯誤 1 error LNK1104: 無法開啟檔案 'python34.lib'
    解法:添加專案 lib檔路徑 C:\Python34\libs
  2. 問題:錯誤 1 error C1083: 無法開啟包含檔案: 'pyconfig.h':
    解法:添加專案 include路徑 C:\Python34\include
  3. 問題:錯誤 1 error C1083: 無法開啟包含檔案: 'stdafx.h'
    解法:註解掉教學裡,這一行程式碼「#include "stdafx.h"」,即可。

參考資料

Boost C++ Libraries 初次見面

沒有留言:
會接觸的原因是:它可以讓python用C++的code

一開始

Boost官方網站下載最新版(當下是Version 1.59.0) [1]

再來

解壓縮後,放在永久的參考目錄。(我是放在C:\BoostLib)
執行bootstrap.bat,就會出現bjam.exe

編譯release版

在command line模式,執行
bjam --build-dir=".\build" --toolset=msvc stage

編譯debug版

在command line模式,執行
bjam --build-dir=".\build" --build-type=complete --toolset=msvc stage 

hello world試看看

在visual studio,建立Win32 主控台應用程式的空專案。[2]

專案設定

專案屬性>組態屬性>C/C++>其它Include目錄: 輸入C:\BoostLib
專案屬性>組態屬性>連結器>其它程式庫目錄: 輸入C:\BoostLib\stage\lib

貼上主程式的code

#include < boost/thread/thread.hpp >  
#include < boost/bind.hpp >  
#include < iostream >  

void helloworld(const char* who)
{
    std::cout << who << ": Hello World!" << std::endl;
}

void main()
{
    boost::thread thrd(boost::bind(&helloworld, "Darkblack"));
    thrd.join();
}

編譯

若成功會顯示
Darkblack: Hello World!

參考資料

[1] boost官網
[2] 登泰山而小天下:Boost C++ Libraries 初體驗