1. 程式人生 > >Linux下安裝並使用protobuf

Linux下安裝並使用protobuf

Linux 下安裝protobuf 並使用

  • 下載protobuf 在此我使用的是protobuf2.5,解壓檔案之後
  • ./configure
  • make
  • make check
  • make install
    我本機上cenos 64位環境,這裡全都是選擇預設路徑安裝
  • user/local/bin
  • user/local/lib,
  • user/local/include
    都是系統預設路徑之一,到這已經都安裝好,但是在gcc 編譯還是會找不到protobuf.so庫檔案,原因因為在usr/local/lib,下的protobuf.so不能被gcc找到
    倆種解決方案,主要就是環境變數的設定問題
  • export LD_LIBRARY_PATH=/usr/local/lib 新增這句就可以通過了gcc編譯,不過只是臨時起效,重啟後不在生效。
  • 在/etc/ld.so.conf 檔案裡面新增路徑 /usr/local/lib ,因為linux系統執行庫會讀取這裡的目錄尋找so,之後記得ldconfig一下噢
    如圖
    在給出搜尋資料解答如下:

Linux 執行的時候,是如何管理共享庫(*.so)的?在 Linux 下面,共享庫的尋找和載入是由 /lib/ld.so 實現的。 ld.so 在標準路經(/lib, /usr/lib) 中尋找應用程式用到的共享庫。
但是,如果需要用到的共享庫在非標準路經,ld.so 怎麼找到它呢?
目前,Linux 通用的做法是將非標準路經加入 /etc/ld.so.conf,然後執行 ldconfig 生成 /etc/ld.so.cache。 ld.so 載入共享庫的時候,會從 ld.so.cache 查詢。
傳統上,Linux 的先輩 Unix 還有一個環境變數:LD_LIBRARY_PATH 來處理非標準路經的共享庫。ld.so 載入共享庫的時候,也會查詢這個變數所設定的路經。
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib
export LD_LIBRARY_PATH
但是,有不少聲音主張要避免使用 LD_LIBRARY_PATH 變數,尤其是作為全域性變數。這些聲音是:
* LD_LIBRARY_PATH is not the answer -

http://prefetch.net/articles/linkers.badldlibrary.html
* Why LD_LIBRARY_PATH is bad - /ldpath.html”>http://xahlee.org/UnixResource_dir//ldpath.html
* LD_LIBRARY_PATH - just say no - http://blogs.sun.com/rie/date/20040710
解決這一問題的另一方法是在編譯的時候通過 -R 選項指定 run-time path。
1. 往/lib和/usr/lib裡面加東西,是不用修改/etc/ld.so.conf的,但是完了之後要調一下ldconfig,不然這個library 會找不到
2. 想往上面兩個目錄以外加東西的時候,一定要修改/etc/ld.so.conf,然後再呼叫ldconfig,不然也會找不到。
比如安裝了一個mysql到/usr/local/mysql,mysql有一大堆library在/usr/local/mysql/lib下 面,這時就需要在/etc/ld.so.conf下面加一行/usr/local/mysql/lib,儲存過後ldconfig一下,新的 library才能在程式執行時被找到。
3. 如果想在這兩個目錄以外放lib,但是又不想在/etc/ld.so.conf中加東西(或者是沒有許可權加東西)。那也可以,就是export一個全域性變 量LD_LIBRARY_PATH,然後執行程式的時候就會去這個目錄中找library。一般來講這只是一種臨時的解決方案,在沒有許可權或臨時需要的時候使用。
4. ldconfig做的這些東西都與執行程式時有關,跟編譯時一點關係都沒有。編譯的時候還是該加-L就得加,不要混淆了。
5. 總之,就是不管做了什麼關於library的變動後,最好都ldconfig一下,不然會出現一些意想不到的結果。不會花太多的時間,但是會省很多的事。
LD_LIBRARY_PATH 這個環境變數是大家最為熟悉的,它告訴loader:在哪些目錄中可以找到共享庫。可以設定多個搜尋目錄,這些目錄之間用冒號分隔開。在linux下,還 提供了另外一種方式來完成同樣的功能,你可以把這些目錄加到/etc/ld.so.conf中,然後呼叫ldconfig。當然,這是系統範圍內全域性有效 的,而環境變數只對當前shell有效。按照慣例,除非你用上述方式指明,loader是不會在當前目錄下去找共享庫的,正如shell不會在當前目前找 可執行檔案一樣。

*另外,如果不想每次新啟一個shell都設定LD_LIBRARY_PATH,可以編輯~/.bash_profile檔案:
vim/.bashprofileLDLIBRARYPATH=/usr/local/libexportLDLIBRARYPATH source ~/.bash_profile 就行了。*

如圖

下面測試例子:
test.proto

package hello;

message Test
{
    optional uint32 name = 1;
    optional uint32 age  = 2;
}

執行protoc –cpp_out=./ test.proto
在當前目錄下生成test.pb.h 和test.pb.cc檔案
使用c++對Test資料進行讀寫,編寫write.cc寫資料到本地硬碟

#include<iostream>
#include<fstream>

#include "test.pb.h"
using namespace std;
using namespace hello;

int main()
{
    Test test;

    test.set_name(111);
    test.set_age(22);

    fstream output("./log",ios::out | ios::trunc | ios::binary);

    if (!test.SerializeToOstream(&output)){
        cerr << "Failed to write msg."<<endl;
        }   

    return 0;

}

編譯使用
g++ test.pb.h test.pb.cc write.cc -o write -lprotobuf -lpthread

如何編寫read.cc從本地讀取Test資料:

#include<iostream> 
#include<fstream>  
#include "test.pb.h"

using namespace std;
using namespace hello;

void PrintInfo(const Test &test){
    cout << test.name() <<endl;
    cout << test.age() <<endl;
}              


int main()     
{              
    cout<<"read Test"<<endl;
    Test test; 

    fstream input("./log",ios::in | ios::binary);

    if(!test.ParseFromIstream(&input)){
        cerr << "Failed to parse address book." << endl;
        return -1; 
    }          

    PrintInfo(test);
    return 0;      
}              

在此使用編譯
g++ test.pb.h test.pb.cc read.cc -o read -lprotobuf -lpthread
成功
這裡寫圖片描述

寫的有點糙,不過主要是編譯這下折騰了好幾天,終於通過了,記錄下,也希望有人看到能有所幫助。後面還會記錄protocbuf的動態編譯,好像還沒看到很多講這方面。