thrift在windows的編譯/安裝--c++版


前言:
  thrift是出於Facebook的rpc網絡編程框架, 其對跨平台和多語言的支持優於google protobuf, 但thrift在java/c#語言上應用比較多, 資料也豐富, 在windows平台的c++這塊, 資料相對較少, 而且編譯也麻煩. 這篇博客主要記錄對thrift在windows上的編譯和使用過程, 不涉及原理, 也不具體涉及應用.如有不足, 請各位指正.

執行過程
1. 下載並安裝Visual Studio
notice: visual studio 有windows版本限制, 比如visual studio 2013在windows 7就安裝不了
參考網址: http://www.visualstudio.com/zh-cn/visual-studio-2013-compatibility-vs
系統: windows7 + visual studio 2012

2. boost安裝/編譯/鏈接
  具體步驟如下:
  *) 下載boost
    1. 下載 boost_1_55_0.zip
  *) 編譯boost
    1. 執行 bootstrap.bat
    2. 執行 b2.exe (編譯的時間較長, 請耐心等待)
  *) 驗證boost
    在virtual studio的window console工程屬性中添加如下:
    1. 附加包含目錄: $BOOST_HOME
    2. 附加庫目錄: $BOOST_HOME\stage\lib
    3. 編寫如下代碼進行編譯/運行認證

 1 #include <iostream>
 2 #include <string>
 3 #include <boost/regex.hpp>
 4 int main()
 5 {
 6  boost::regex pattern("\\w+@\\w+(\\.\\w+)*");
 7  std::string mail("xxx@gmail.com");
 8  
 9  if ( boost::regex_match(mail, pattern) ) {
10   std::cout << mail << " is a valid mail address!" << std::endl;
11  } else {
12   std::cout << mail << " is not a valid mail address!" << std::endl;
13  }
14 }

  安裝boost和配置visual studio的參考網址如下所示:
  http://blog.csdn.net/stanfordzhang/article/details/8587282
  http://www.cnblogs.com/me115/archive/2010/10/08/1845825.html
  http://www.cnblogs.com/chuncn/archive/2012/09/10/2679026.html

3. libevent的編譯/安裝/鏈接
  *) 參考的編譯/安裝過程網頁
  http://blog.s135.com/libevent_windows/
  *) 下載libevent
  http://libevent.org/
  *) 編譯libevent
  遇到的編譯錯誤處理方案
  http://10305101ivy.blog.163.com/blog/static/584765892012227322607/

  http://blog.csdn.net/boyxiaolong/article/details/17057063
  evutil.c添加如下行:

 1 #ifdef WIN32
 2 #include <winsock2.h>
 3 #include <ws2tcpip.h>
 4 #pragma comment(lib,"ws2_32.lib") 
 5 #define WIN32_LEAN_AND_MEAN
 6 #include <windows.h>
 7 #undef WIN32_LEAN_AND_MEAN
 8 #include <io.h>
 9 #include <tchar.h>
10 #endif

  nmake /f Makefile.nmake
  生成libevent_core.lib libevent_extras.lib libevent.lib
  若遇到頭文件找不到的問題, 需要手動修改Makefile.nmake文件, 添加相關的頭文件路徑

CFLAGS=/IWIN32-Code /Iinclude /Icompat /DWIN32 /DHAVE_CONFIG_H /I.  /I"C:\Program Files (x86)\Windows Kits\8.0\Include\um" /I"C:\Program Files (x86)\Windows Kits\8.0\Include\shared" /I"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include"
    具體添加的原則是編譯缺那個頭文件, 就去添加相關的系統頭文件目錄   
    編寫libevent代碼編譯/運行成功
1 #include <event.h>
2 #include <stdio.h>
3 
4 int main()
5 {
6     const char *version = event_get_version();
7     printf("%s\n",version);
8     return 0;
9 }
    附加依賴項: ws2_32.lib ,  libevent_core.lib , libevent.lib,  libevent_extras.lib

4. thrift的編譯/鏈接
  *)下載thrift 0.9.0源碼
  下載網址: http://archive.apache.org/dist/thrift
  *)thrift依賴的庫
  http://www.coder4.com/archives/3777
  thrift 依賴 boost庫(1.4.7), thriftnb 依賴 boost/libevent庫
  http://www.iteye.com/problems/87958
  thrift在編譯過程中, 會遇到二義性
  “_wassert”: 對重載函數的調用不明確
  void _wassert(const wchar_t *,const wchar_t *,unsigned int)
  void apache::thrift::protocol::_wassert(const wchar_t *,const wchar_t *,unsigned int)
  解決方案:
  這算命令空間污染的問題, 添加::, 使得對_wassert的調用采用全局聲明的那個函數

1 assert.h
2  
3 #define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
4  
5 #define assert(_Expression) (void)( (!!(_Expression)) || (::_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
6      
    測試驗證:
    編寫 hello.thrift 文件
1 namespace cpp test
2  
3 service HelloService {
4     string hello(1: string username); 
5 }
   thrift.exe -gen cpp hello.thrift 
1 2014/05/07 11:35 9,215 HelloService.cpp
2 2014/05/07 11:26 7,117 HelloService.h
3 2014/05/07 11:26 1,422 HelloService_server.skeleton.cpp
4 2014/05/07 11:35 268 hello_constants.cpp
5 2014/05/07 11:35 357 hello_constants.h
6 2014/05/07 11:35 202 hello_types.cpp
7 2014/05/07 11:35 367 hello_types.h 
    編譯執行, 遇到10093錯誤, 如何去解決?
    WSANOTINITIALISED,  which means WSAStartup() has not been called yet.
     編譯完成后運行時會報 WSAStartup 錯誤    
    解決方案:
     http://hi.baidu.com/fsx92/item/9f7a96efd33f9f1b585dd88c                  
    編寫測試case
  服務端代碼:
 1 class HelloServiceHandler : virtual public HelloServiceIf {
 2  public:
 3   HelloServiceHandler() {
 4     // Your initialization goes here
 5   }
 6  
 7   void hello(std::string& _return, const std::string& username) {
 8  _return = "hello " + username;
 9   }
10  
11 };
12  
13 int main(int argc, char **argv) {
14   int port = 9090;
15  
16   TWinsockSingleton::create();      // 需要用戶自己添加, 進行WSAStartup的初始化, 算是windows 版的thrift的一個疏忽
17  
18   shared_ptr<HelloServiceHandler> handler(new HelloServiceHandler());
19   shared_ptr<TProcessor> processor(new HelloServiceProcessor(handler));
20   shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
21   shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
22   shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
23  
24   TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
25   server.serve();
26   return 0;
27 }
    客戶端代碼 
 1  
 2 #include "HelloService.h"
 3 #include <thrift/protocol/TBinaryProtocol.h>
 4 #include <thrift/server/TSimpleServer.h>
 5 #include <thrift/transport/TBufferTransports.h>
 6 #include <thrift/transport/TSocket.h>
 7  
 8 using namespace ::apache::thrift;
 9 using namespace ::apache::thrift::protocol;
10 using namespace ::apache::thrift::transport;
11 using namespace ::apache::thrift::server;
12  
13 using boost::shared_ptr;
14  
15 using namespace ::test;
16  
17 int main()
18 {
19  
20  shared_ptr<TTransport> socket(new TSocket("127.0.0.1", 9090));
21  shared_ptr<TTransport> transport(new TBufferedTransport(socket));
22  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
23  
24  HelloServiceClient client(protocol);
25  
26  try {
27   transport->open();
28   std::string res;
29   client.hello(res, "lilei");
30   std::cout << res << std::endl;
31  } catch(TException &e) {
32   std::cout << e.what() << std::endl;
33  }
34  
35  return 0;
36 }
37  
    推薦做法:
    對依賴庫的整理, 這是一個好的習慣
    每個庫單獨創建一個頭文件目錄, 和庫文件目錄, 所有的庫統一在同一個庫倉庫下,  c++的庫管理不如java的maven那么方便, 又進入一個石器時代, 庫的維護需要開發者手動去支持, 但這是種很好的工程實踐.     
    
    repository目錄為頂級的倉庫目錄, 以boost為例, boost表示庫名, 之下boost/1.55.0為boost的具體的某一版本, 而boost/0.55.0/include為這個版本的頭文件目錄, boost/0.55.0/lib為這個版本的lib庫目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM