2019年6月1日 星期六

Protocol Buffers - for C++


Protocol buffers基本上我把他想成是一個資料庫應用的延伸, 這話該如何說呢? 基本上他就是透過名為proto的meta file, 用以描述資料形態與內容(做encode/decode).

How does the Protocol Buffers work?

先定義你的message結構, 如
message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

再用protoc將該檔案轉成code, 目前支援(C++, Java and Python), 如下例子, 將brook.proto轉成C++(brook.pb.cc與brook.pb.h).
brook@vista:~/protobuf/CPP$ protoc --cpp_out=. brook.proto
brook@vista:~/protobuf/CPP$ ls
brook.pb.cc  brook.pb.h  brook.proto

這些code會包含存取每一個欄位的API(如下由doxygen產生的圖), 如email()與set_email(), 用以serialize/parse資料,

接著我們就可以用這些API寫一段code, 做serialize/parse資料
#include <iostream>
#include <fstream>
#include "brook.pb.h"
using namespace std;

static void _Serialize(void)
{
        Person person;
        person.set_name("John Doe");
        person.set_id(1234);
        person.set_email("jdoe@example.com");
        fstream output("myfile", ios::out | ios::binary);
        person.SerializeToOstream(&output);
}

static void _Parse(void)
{
        Person person;
        fstream input("myfile", ios::in | ios::binary);
        person.ParseFromIstream(&input);
        cout << "Name: " << person.name() << endl;
        cout << "E-mail: " << person.email() << endl;
}

int main(int argc, char *argv[])
{
        _Serialize();
        _Parse();
        return 0;
}

brook@vista:~/protobuf/CPP$ g++ main.c brook.pb.cc -lprotobuf
brook@vista:~/protobuf/CPP$ ./a.out
Name: John Doe
E-mail: jdoe@example.com


    參考資料:
  • protocol buffer簡介, https://developers.google.com/protocol-buffers/docs/overview





2019年1月13日 星期日

Note for SCons 3.0.3 User Guide, CH5 Node Objects


所有的檔案與目錄在SCons中都被視為"Nodes",善用"Node"可以使您的SConscript文件可移植且易於閱讀。

5.1. Builder Methods Return Lists of Target Nodes

所有builder methods都回傳一個Node list,用於辨識要構建的目標文件。這Node list可作為參數傳遞給其他builder methods。
brook@vista:~/scons/04.7$ cat SConstruct
a_list = Object('a.c', CCFLAGS='-DHELLO')
b_list = Object('b.c', CCFLAGS='-DWORLD')
Program(a_list + b_list)
 
brook@vista:~/scons/04.7$ scons -Q
gcc -o a.o -c -DHELLO a.c
gcc -o b.o -c -DWORLD b.c
gcc -o a a.o b.o


5.2. Explicitly Creating File and Directory Nodes

SCons的File()與Dir()可回傳file或directory Node,而Entry()可回傳file或directory Node。
hello_c = File('hello.c')
Program(hello_c)
 
classes = Dir('classes')
Java(classes, 'src')
 
xyzzy = Entry('xyzzy')


5.3. Printing Node File Names

您可以對Node執行print,打Node所代表的檔名。
brook@vista:~/scons/05.3$ cat SConstruct
object_list = Object(['a.c', 'b.c'])
program_list = Program(object_list)
print("The object file is: %s"%object_list)
print("The program file is: %s"%program_list[0])

brook@vista:~/scons/05.3$ scons -Q
The object file is: ['a.o', 'b.o']
The program file is: a
scons: `.' is up to date.


5.4. Using a Node's File Name as a String

您可以使用Python的str函數將Node轉成字串加以處理。
brook@vista:~/scons/05.5$ cat SConstruct
import os
object_list = Object(['a.c', 'b.c'])
obj_str = str(object_list[0])
print("The object file is: %s"% obj_str)
if not os.path.exists(obj_str):
    print("%s does not exist!"% obj_str)
else:
    print("%s exist!"% obj_str)
brook@vista:~/scons/05.5$ scons -Q
The object file is: a.o
a.o exist!
scons: `.' is up to date.


5.5. GetBuildPath: Getting the Path From a Node or String

env.GetBuildPath(file_or_list)可以用來取得file/Node的路徑。
brook@vista:~/scons/05.6$ cat SConstruct
object_list = Object(['a.c', 'b.c'])
env=Environment(VAR="value")
n=File("foo.c")
print(env.GetBuildPath([n, "sub/dir/$VAR", '/tmp'] + object_list))
brook@vista:~/scons/05.6$ scons -Q
['foo.c', 'sub/dir/value', '/tmp', 'a.o', 'b.o']
scons: `.' is up to date.





Note for SCons 3.0.3 User Guide, CH4 Building and Linking with Libraries


4.1. Building Libraries

在軟體開發過程中,將軟體切成數個library是很常見的,build成library在SCons中也是很容易完成的。
如果是要build成library,只需將builder method從Program換成Library即可。
Library('foo', ['f1.c', 'f2.c', 'f3.c'])

SCons會根據當前的系統,build出該Library,如Linux
% scons -Q
cc -o f1.o -c f1.c
cc -o f2.o -c f2.c
cc -o f3.o -c f3.c
ar rc libfoo.a f1.o f2.o f3.o
ranlib libfoo.a

Windows
C:\>scons -Q
cl /Fof1.obj /c f1.c /nologo
cl /Fof2.obj /c f2.c /nologo
cl /Fof3.obj /c f3.c /nologo
lib /nologo /OUT:foo.lib f1.obj f2.obj f3.obj

Library會build成static library,你也可以使用StaticLibrary來build static library
brook@vista:~/scons/04.2$ cat SConstruct
StaticLibrary('foo',['a.c', 'b.c'])

brook@vista:~/scons/04.2$ scons -Q
gcc -o a.o -c a.c
gcc -o b.o -c b.c
ar rc libfoo.a a.o b.o
ranlib libfoo.a

你也可以使用SharedLibrary 來build shared library
brook@vista:~/scons/04.3$ cat SConstruct
SharedLibrary('foo',['a.c', 'b.c'])

brook@vista:~/scons/04.3$ scons -Q
gcc -o a.os -c -fPIC a.c
gcc -o b.os -c -fPIC b.c
gcc -o libfoo.so -shared a.os b.os


4.2. Linking with Libraries

如果你的Program需要link某個Library,你只需在Program中指定$LIBS與$LIBPATH
brook@vista:~/scons/04.5$ cat SConstruct
SharedLibrary('foo',['a.c'])
StaticLibrary('bar',['b.c'])
Program('prog', 'prog.c', LIBS=['foo', 'bar'], LIBPATH='.')

brook@vista:~/scons/04.5$ scons -Q
gcc -o a.os -c -fPIC a.c
gcc -o b.o -c b.c
ar rc libbar.a b.o
ranlib libbar.a
gcc -o libfoo.so -shared a.os
gcc -o prog.o -c prog.c
gcc -o prog prog.o -L. -lfoo -lbar


4.3. Finding Libraries: the $LIBPATH Construction Variable

如果你要SCons尋找系統以外的library目錄,你指定$LIBPATH
brook@vista:~/scons/04.5$ cat SConstruct
SharedLibrary('foo',['a.c'])
StaticLibrary('bar',['b.c'])
Program('prog', 'prog.c', LIBS=['foo', 'bar'], LIBPATH=['/brook/lib', '.'])

brook@vista:~/scons/04.5$ scons -Q
gcc -o a.os -c -fPIC a.c
gcc -o b.o -c b.c
ar rc libbar.a b.o
ranlib libbar.a
gcc -o libfoo.so -shared a.os
gcc -o prog.o -c prog.c
gcc -o prog prog.o -L/brook/lib -L. -lfoo -lbar





熱門文章