驭风万里无垠

用Boost.Python + CMake + wxPython构建跨语言GUI程序<一>

单纯用C/C++做UI程序的盛况已经成为过去时,如果要做跨平台的UI程序,那么可供选择的更是为数不多。如果不考虑跨平台的因素,那么Windows上边,c#绝对是最佳的选择,因为微软的.NET投资大部分在这个上头,而且有WPF的支持,至少比Java的Swing/SWT/FlashFX要高效和漂亮很多。 如果想跨Posix系统和Windows这两个平台,不嫌麻烦的话可以选择Java (MONO的法律协议还是个问题);但是动态语言的特性决定了它来做界面更有优势,譬如函数可以随便做参数传递,变量类型可以随便变换等。

最近在关注这个方面的东东,恰好就发现了和自己的经验、兴趣很相合的一个选择:wxWidgets + Python = wxPython.这个项目底层部分是用c++来实现的,基本架构据说和MFC很像,我的那一点可怜的UI经验都来源于MFC,因此必要的时候查下代码应该没大的难度。上层的部分有很多语言的bingding,最成熟的部分则是python绑定的wxPython. 找到了切合点,另外一个问题又随之而来,UI毕竟只是负责来做用户交互的,底层的逻辑(网络、业务)大多还是要c++来写,或者已经有的C++代码最好能少改动就可以重复利用。

突然灵机一动想起来,Boost库里边刚还有这么一个东东来处理跨c++ 和 Python 的,可以导出或者内嵌, 于是翻出来体验一番:

 

  • 编译Boost.Python

不经意发现Boost已经有了1.39版本了,我机器上的还是1.37,向来乐于追新的我对于这种自我学习的东西更是不会吝惜时间了,马上将其7z包拖了下来,居然惊奇的发现里边已经有了我很喜欢的CMakeLists.txt文件了,原来可以用CMake编译,boost里边我最讨厌的就是那个bjam了,学了几次都没有完全琢磨明白,这次就下定决心也要把CMake版本的编出来。

这里需要编译的是libboost_python.so,其它的东西,出于更新的目的,还是把常用的几个也编一下好了。

7z x boost_1_39_0.7z
cd boost_1_39_0/
mkdir mybuild
cd mybuild
cmake ../

居然报错了:

-- ##########################################################################
--
--               Only Boost.Build is officially supported.
--
--                       This is not Boost.Build.
--
--  This is an alternate, cmake-based build system that is currently under development.
--  To try it out, invoke CMake with the argument
--         -DCMAKE_IS_EXPERIMENTAL=YES_I_KNOW
--  Or use the gui to set the variable CMAKE_IS_EXPERIMENTAL to some value.
--  This will only be necessary the first time.
--
--  For more information on boost-cmake see the wiki:
--      https://svn.boost.org/trac/boost/wiki/CMake
--
--  Subscribe to the mailing list:
--      http://lists.boost.org/mailman/listinfo.cgi/boost-cmake
--
--  NOTE:  Please ask questions about this build system on the boost-cmake list,
--         not on other boost lists.
--
--  And/or check the archives:
--      http://news.gmane.org/gmane.comp.lib.boost.cmake
--
-- ##########################################################################

 

还好问题不大,顶多加上那个选项就是了,有问题自己搞定:

cmake -DCMAKE_IS_EXPERIMENTAL=YES_I_KNOW ../

接下来OK了,看看那些选项可以改动,于是ccmake .  , 去掉不需要的variants,将动态库标上版本号,就是这么几个:

BUILD_DEBUG        OFF
BUILD_STATIC       OFF
BUILD_VERSIONED    ON

然后,c/g重新生成cache就可以了。接下来是make,不过照例看一下有哪些可以编, make help之后好大的一堆,这里就选需要的吧:

make help | grep boost
... boost_date_time
... boost_date_time-mt-shared
... boost_regex
... boost_regex-mt-shared
... boost_serialization
... boost_serialization-mt-shared
... boost_wserialization
... boost_wserialization-mt-shared
... boost_graph
... boost_graph-mt-shared
... boost_python
... boost_python-mt-shared
... boost_system
... boost_system-mt-shared
... boost_prg_exec_monitor
... boost_prg_exec_monitor-mt-shared
... boost_test_exec_monitor
... boost_unit_test_framework
... boost_unit_test_framework-mt-shared
... boost_filesystem
... boost_filesystem-mt-shared
... boost_iostreams
... boost_iostreams-mt-shared
... boost_program_options
... boost_program_options-mt-shared
... boost_signals
... boost_signals-mt-shared
... boost_thread
... boost_thread-mt-shared
... boost_wave
... boost_wave-mt-shared

需要的就是这么几个了:

make boost_date_time  boost_regex  boost_python boost_system boost_unit_test_framework boost_filesystem boost_thread  boost_signals

编译的过程中,发现有些不对,因为有:

Linking CXX shared library ../../../lib/libboost_date_time-gcc44-mt-1_38.so

不是1.39吗,怎么版本号不对?赶紧查一下 ../CMakeLists.txt,发现:

grep BOOST_VERSION ../CMakeLists.txt
set(BOOST_VERSION_MAJOR 1)
set(BOOST_VERSION_MINOR 38)
set(BOOST_VERSION_SUBMINOR 0)
set(BOOST_VERSION "${BOOST_VERSION_MAJOR}.${BOOST_VERSION_MINOR}.${BOOST_VERSION_SUBMINOR}")
if(BOOST_VERSION_SUBMINOR GREATER 0)
"include/boost-${BOOST_VERSION_MAJOR}_${BOOST_VERSION_MINOR}_${BOOST_VERSION_SUBMINOR}")
else(BOOST_VERSION_SUBMINOR GREATER 0)
"include/boost-${BOOST_VERSION_MAJOR}_${BOOST_VERSION_MINOR}")
endif(BOOST_VERSION_SUBMINOR GREATER 0)
#  install(EXPORT boost-targets DESTINATION "lib/Boost${BOOST_VERSION}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Boost ${BOOST_VERSION}")
set(CPACK_PACKAGE_VERSION "${BOOST_VERSION}")
set(CPACK_PACKAGE_VERSION_MAJOR "${BOOST_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${BOOST_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${BOOST_VERSION_SUBMINOR}")
set(CPACK_NSIS_DISPLAY_NAME "Boost ${BOOST_VERSION_MAJOR}.${BOOST_VERSION_MINOR}.${BOOST_VERSION_SUBMINOR}")
set(CPACK_PACKAGE_FILE_NAME "Boost-${BOOST_VERSION}-vc6")
set(CPACK_PACKAGE_FILE_NAME "Boost-${BOOST_VERSION}-vc7")
set(CPACK_PACKAGE_FILE_NAME "Boost-${BOOST_VERSION}-vc71")
set(CPACK_PACKAGE_FILE_NAME "Boost-${BOOST_VERSION}-vc8")
set(CPACK_PACKAGE_FILE_NAME "Boost-${BOOST_VERSION}-vc9")
set(CPACK_PACKAGE_FILE_NAME "Boost-${BOOST_VERSION}-borland")
"http://www.osl.iu.edu/~dgregor/Boost-CMake/${BOOST_VERSION}/"

将那个38改正成为39就可以了。重复make,生成的库全在lib目录下了。

 

编译完了之后,才发现make install并不能将这些安装到系统里边去,因为它有开始编译没有选择的库了,真浪费时间,也许这个是它们要坚持其为Experimental Support的缘故吧,而且accumulators库的编译还有个问题导致编译不通过。

到这里只能再用bjam投机一下,让它的install命令把头文件拷贝过去,然后自己手工拷贝库文件了:

cd ../
./bootstrap
./bjam --with-system --libdir=/usr/local/lib threading=multi variant=release link=shared runtime-link=shared toolset=gcc install 
这里之所以指定libdir是因为默认bjam会将库文件安装到/lib/下边,不知道是不是个bug。好处是只需要指定一个库的编译,bjam就可以在install的时间将所有的头文件准备就绪了。
查看一下:
ls -l /usr/local/include/boost-1_39/boost/python

文件已经在了,再次回到cmake的临时目录:

cd mybuild/lib
su
xxxxx
cp libboost*  /usr/local/lib/
ls -lh /usr/local/lib/libboost_python-gcc*
-rwxr-xr-x 1 root root 5.2M 2009-08-09 09:57 /usr/local/lib/libboost_python-gcc44-mt-1_39.so

OK,boost.python环境准备妥当了,下一步体验一下其Helloworld。

 

  • 初试Boost.Python<CMake项目>

新建一个目录,并用CMake搭建项目环境:

cd
mkdir study
cd study
mkdir boost.python
cd boost.python
mkdir build
touch CMakeLists.txt
mkdir HelloWorld

这里的boost.python作为一个根目录,build目录用于编译和测试,CMakeLists.txt用于组织各个子项目,剩下的就是每个项目一个子目录了,起步的这个就是boost.python文档提供的HelloWorld了。根目录下的CMakeLists.txt如下:

cmake_minimum_required(VERSION 2.6)
set(BOOST_INCLUDEDIR /usr/local/include/boost-1_39)
set(BOOST_LIBRARYDIR /usr/local/lib)
set(Boost_FIND_VERSION_EXACT TRUE)
set(Boost_Debug TRUE)
set(Boost_ADDITIONAL_VERSIONS "1.39" "1.39.0")
include(FindBoost)
find_package(Boost 1.39.0 COMPONENTS python thread unit_test_framework)
if (NOT Boost_FOUND)
message(FATAL " Boost library not found!")
endif()
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
include_directories(${Boost_INCLUDE_DIRS} /usr/local/include/python2.6/)
add_subdirectory(HelloWorld)

中间的一大堆是用于保证能够找到1.39版本的库的,因为cmake 2.6.4并不能很好的找到,默认总是找到1.38的,如果没有安装多个版本的boost,可能没有这么麻烦。接下来就是把HelloWorld那个子目录包进来。

cd HelloWorld
cat CMakeLists.txt
具体内容如下(这里将默认CMake生成的动态库的lib前缀去掉,因为python不喜欢这个,:-)):
project(HelloWorld)
include_directories(${Boost_INCLUDE_DIRS})
add_library(hello SHARED test.cpp)
set_target_properties(hello PROPERTIES PREFIX "")
target_link_libraries(hello ${Boost_LIBRARIES})
编辑test.cpp,将测试代码拿进来
#include <string>
#include <boost/python.hpp>
using namespace boost::python;
struct World
{
void set(std::string msg) { this->msg = msg; }
std::string greet() { return msg; }
std::string msg;
};
//Wrapper
BOOST_PYTHON_MODULE(hello)
{
class_<World>("World")
.def("greet", &World::greet)
.def("set", &World::set)
;
}
 
编译之:
cd ../build
cmake ../
make
输出如下:
Scanning dependencies of target hello
[100%] Building CXX object HelloWorld/CMakeFiles/hello.dir/test.cpp.o
Linking CXX shared library ../lib/hello.so
[100%] Built target hello
查看生成的库文件:
cd lib
ls -lh hello.so
file hello.so

接下来用测试一番,启动python:

python
...............
>>> import hello
>>> help(hello.World.set)
Help on method set:
set(...) unbound hello.World method
set( (World)arg1, (str)arg2) -> None :
C++ signature :
void set(World {lvalue},std::string)
>>> obj = hello.World()
>>> obj.set("hello world!")
>>> obj.greet()
'hello world!'
>>> obj.set("Another string")
>>> obj.greet()
'Another string'
>>> del obj
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'hello', 'readline', 'rlcompleter']
>>> quit()

这里尝试的几个方法都已经凑效:构造、析构、greet/set,刚好就是前边expose的那些了:

class_<World>("World") .def("greet", &World::greet) .def("set", &World::set) ;

 

下一步再尝试一些复杂的东东。

posted on 2009-08-09 11:34 skyscribe 阅读(4448) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2021年4月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

导航

统计

常用链接

留言簿(3)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜