Skip to main content

C++ of the Day #9 - Boost.Python 사용하기 #1

Python은 가장 인기있는 interpret 언어중의 하나입니다. Python의 장점 중 하나는 C/C++ 모듈과 쉽게 연동할 수 있다는 점입니다. 물론 손으로 일일히 wrapper를 만드는 것은 손이 많이 가고 에러를 만들수 있는 작업이나 SWIG등과 같은 도구를 사용하면 쉽게 python 모듈을 만들 수 있습니다.

Boost.Python은 이런 SWIG와 같이 python 모듈을 쉽게 만들 수 있도록 도와주는 라이브러리로 순수 C++만을 사용한다는 점이 SWIG와 다른 점입니다. 그리고 개인적으로는 Boost 라이브러리에 포함되어 있는 것들이 왠지 좀 더 믿음직스러워서... :-)

이번 글에서는 Boost.Python 문서에 나와 있는 예제를 가지고 간단하게 python 모듈을 만드는 방법에 대해서 알아보겠습니다.

Requirements

  1. 리눅스
    이 글에서는 리눅스 환경에서의 사용 방법을 설명한다.
  2. Boost.Python 라이브러리 (1.33.1)
    Boost 라이브러리를 다운로드받아 아래와 유사한 명령으로 라이브러리를 빌드한다.
    bjam -sTOOLS=gcc -with-python install

    bjam의 --prefix 옵션으로 라이브러리가 설치될 위치를 변경할 수 있다.
  3. Python 라이브러리 (2.4.3)
    Python을 다운로드 받아 빌드하여 설치한다.
    위의 경우와 유사하게 configure의 --prefix 옵션으로 설치될 위치를 변경할 수 있다.


Write C++ Code

다음과 같이 코드를 작성한다.

// greet.cpp
#include <stdexcept>

char const* greet(unsigned x)
{
  static char const* const msgs[] = { "hello", "Boost.Python", "world!" };
  if (x > 2) 
    throw std::range_error("greet: index out of range");
  return msgs[x];
}

#include <boost python.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(hello)
{
  def("greet", greet, "return one of 3 parts of a greeting");
}

일반적으로는 greet 함수 아래쪽의 wrapper와 같은 코드는 다른 파일에 작성하는 것이 보통이나 여기서는 편의를 위해 한 파일에 작성하였다.

Make Module

여기서는 python에서 제공하는 distutils를 사용하는 방법을 설명한다.
  1. 먼저 아래와 같이 setup.py를 작성한다.
    from distutils.core import setup, Extension
    
    module1 = Extension('hello',
        include_dirs = ['<your path="">/include/boost-1_33_1'],
        libraries = ['boost_python'],
        library_dirs = ['<your path="">/lib'],
        sources = ['greet.cpp'])
    
    setup (name = 'hello',
    version = '1.0',
    description = 'This is a demo package',
    ext_modules = [module1])
    
  2. 다음과 같이 setup.py를 실행시킨다.
    python setup.py build
    
  3. ./build/lib.linux-i686-2.2 와 같은 디렉토리에 만들어진 hello.so 파일을 적당한 디렉토리에 복사한다.

Use Module

이제 hello 모듈을 일반 python 모듈과 같은 방법으로 사용할 수 있다.

>>> import hello
>>> for x in range(3):
...     print hello.greet(x)
... 
hello
Boost.Python
world!
>>> hello.greet(4)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
RuntimeError: greet: index out of range

위의 예제에서 보듯이 C++에서 작성한 예외도 그대로 python 모듈에 적용되는 것을 알 수 있다.

Conclusion

이번에는 간단한 예제 코드를 가지고 Boost.Python의 사용 방법을 알아 보았습니다. 성능이 필요한 core 모듈은 C++로 작성하고 대부분의 glue 코드나 UI 코드는 python으로 작성하는 방법은 개발의 속도를 매우 높여줄 수 있을 것입니다.
저도 아직 이런 식으로 프로젝트를 해본적은 없지만 예전에 특정 라이브러리를 위한 python 모듈을 일일히 손으로 만들어본 적이 있었는데 이 라이브러리를 그때 알았더라면 하는 생각이 드네요. ;-)

Comments

  1. luabind(http://luabind.sourceforge.net)는 boost.python스타일로 lua를 C++에서 쉽게 쓸 수 있도록 해주는 라이브러리랍니다. :)

    이런 류의 시도가 많이 이루어 지는 듯.

    ps. SWIG와 비교해보면 boost.python이 훨씬 편한 것 같네요. :)

    ReplyDelete
  2. Lua라니요.. ㅠㅠ 요새 스크립트 언어가 유행하면서 python에 ruby에 개인적으로 요새는 또 lisp을 보고 있는데 또 lua라니요. 흑흑... 요놈은 그냥 모른척 할랍니다.
    이것저것 보다보니 인지도니 문법이니 따지다 보니까 개인적으로 사용할 메인 스크립트 언어는 역시 python인듯 합니다. Lisp은 한번쯤 공부해두어야 할 것 같은 언어인 것 같고 ruby도 재밌는 문법이 많은데 왠지 python이 RISC라면 ruby는 CISC같은 느낌이랄까요?
    그리고 Boost.Python을 이용한 pyste라는 프로젝트도 boost에 있습니다. 이건 export할 함수나 클래스 이름만 적어주면 알아서 Boost.Python 코드를 만들어주는 code generator랍니다. 이 프로젝트가 완성되면 진짜 SWIG보다 편하다고 말할 수 있게 되겠지요. ;-)

    ReplyDelete
  3. c++로 웹사이트를 scraping 하는 응용 프로그램을 개발중입니다.
    소스를 하나씩 뜯어서 하다..이건 아니다 싶어
    쓸만한 parser를 찾다가 pyhon의 BeautifulSoup 를 알게 되었습니다.
    BeautifulSoup을 c++ 에서 사용할려면 어떻게 해야 하나여?
    boost.python과의 관계는 어떻게 되는거져?
    도움 부탁드립니다.

    ReplyDelete
  4. boost.python은 애석하게도 C++에서의 python embedding은 지원하지 않습니다. 원하시는 내용은 아마 http://docs.python.org/ext/embedding.html 에서 찾을 수 있을 것 같습니다.

    웹사이트를 스크래핑하여 파일로 저장하는 코드를 python으로 작성하고 C++에서는 그 python 코드를 실행시켜 만들어진 파일을 사용하게 하는 방법 정도가 제일 간단하지 않을까 싶네요. :-)

    문법이 정확히 정의된 경우(BNF등으로) boost.spirit을 사용할 수도 있겠으나 html 같은 경우는 좀 힘들 것 같습니다. :-|

    ReplyDelete

Post a Comment

Popular posts from this blog

CodeHighlighter plugin test page.

This post is for testing CodeHighlighter plugin which uses GeSHi as a fontifier engine. ((Those code blocks are acquired from Google Code Search .)) ((For more supported languages, go CodeHighlighter plugin or GeSHi homepage.)) C++ (<pre lang="cpp" lineno="1">) class nsScannerBufferList { public: /** * Buffer objects are directly followed by a data segment. The start * of the data segment is determined by increment the |this| pointer * by 1 unit. */ class Buffer : public PRCList { public: Buffer() { ++index_; } PHP (<pre lang="php" lineno="4">) for ($i = 0; $i $value = ord( $utf8_string[ $i ] ); if ( $value < 128 ) { // ASCII $unicode .= chr($value); } else { if ( count( $values ) == 0 ) { $num_octets = ( $value } $values[] = $value; Lisp (<pre lang="lisp">) ;;; Assignment (define-caller-pattern setq ((:star var fo...

C++ of the Day #43 - SQLite3 C++ wrapper #1

The Definitive Guide to SQLite 를 읽다가 공부 겸 해서 C++ wrapper를 만들어 보았습니다. 최대한 C++ 냄새(?)가 나도록 만들어 보았습니다. :-) ((SQLite는 복잡한 관리가 필요없이 사용가능한, 파일이나 메모리 기반의, 라이브러리로 제공되는, 약 250kb 용량의, 대부분의 SQL92문을 지원하는, open source RDB입니다.)) 이 wrapper를 사용하기 위해서는 (당연하게도!) sqlite3 와 (당연하게도?) boost 라이브러리가 필요합니다. 사용 예들을 살펴보는 것으로 설명을 대신합니다. 이번 글에서는 다음과 같은 contacts 테이블이 test.db에 존재한다고 가정합니다. CREATE TABLE contacts ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, phone TEXT NOT NULL, UNIQUE(name, phone) ); Command 먼저 test.db 파일을 사용하기 위해 다음과 같이 파일 이름을 주어 connection 객체를 생성합니다. 생성과 동시에 test.db와 연결이 이루어집니다. ((생성자외에 open() 함수를 사용할 수도 있습니다.)) sqlite3pp::connection conn("test.db"); 다음은 contacts 테이블에 정보를 추가하는 가장 간단한 방법입니다. connection 클래스에서 제공하는 execute 함수를 사용합니다. ((executef 함수를 사용하면 printf와 같은 문법을 사용하여 query문을 작성할 수 있습니다.)) conn.execute("INSERT INTO contacts (name, phone) VALUES ('user', '1234')"); 위와 동일한 작업을 parameterized query를 사용하여 할 수도 있습니다. ((step()함수가 실제 query문을 수행하는 함수입니다. ...

Textiler plugin test page

This post is for testing Textiler plugin . This plugin uses Textile engine (version 2.0.0). The sample text is come from Textile test page. (Note that the result will be vary according to your CSS options.) Supported wiki syntax Rendering result h2{color:green}. This is a title h3. This is a subhead p{color:red}. This is some text of dubious character. Isn't the use of "quotes" just lazy writing -- and theft of 'intellectual property' besides? I think the time has come to see a block quote. bq[fr]. This is a block quote. I'll admit it's not the most exciting block quote ever devised. Simple list: #{color:blue} one # two # three Multi-level list: # one ## aye ## bee ## see # two ## x ## y # three Mixed list: * Point one * Point two ## Step 1 ## Step 2 ## Step 3 * Point three ** Sub point 1 ** Sub point 2 Well, that went well. How about we insert an <a href="/" title="watch out">old-fashioned hypertext link</a>? Will the quo...