nanopb - Protocol Buffers 編譯

關於Protocol Buffers

Protocol Buffers是Google開發的用於序列化數據的機制,它無關開發語言,無關使用平臺,且具備良好的可擴展性。
使用Protocol Buffers,你只須要把你的數據定義爲結構化的protocol buffer數據,而後使用編譯工具把它編譯成特定語言下的代碼,調用編譯後的代碼接口,你就能很方便地將你的結構數據寫成數據流(編碼),或是將數據流讀取爲你的結構數據(解碼)。
目前Protocol buffers可支持的生成語言有Java,Python, Object-c, 以及C++, proto3版本還新增了Dart,Go, Ruby, C#。

html

編譯工具安裝

這裏說的編譯工具是指編譯.proto文件,即protocol compiler(protoc)
首先,安裝並選擇默認python版本:
python

sudo apt-get install python//系統自帶的python腳本,18.04上自帶版本仍然是2.7.15~rc1-1)
//https://www.runoob.com/python3/python3-install.html 安裝python3
//使用update-alternatives修改系統默認配置python使用python3

update-alternatives --list python//列出全部可用的python版本
	#/usr/bin/python2.7
	#/usr/bin/python3.6
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.6 2
//將python3.6優先級設爲2,就會自動設置爲默認python版本
python --version
	#Python 3.6.9

update-alternatives --config python//也能夠經過此命令修改默認python版本
	有 2 個候選項可用於替換 python (提供 /usr/bin/python)。

  選擇       路徑              優先級  狀態
------------------------------------------------------------
* 0            /usr/bin/python3.6   2         自動模式
  1            /usr/bin/python2.7   1         手動模式
  2            /usr/bin/python3.6   2         手動模式

要維持當前值[*]請按<回車鍵>,或者鍵入選擇的編號:

再者,有了python,經過pip來安裝protobuf,protoclinux

sudo apt install python-pip//如未安裝,先安裝pip
pip install protobuf grpcio-tools

protoc是用C++語言編寫的,若是你使用的是C++語言,能夠參考C++安裝說明來安裝protoc
非C++語言也能夠參考protobuf來安裝
git

Nanopb

Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is especially suitable for use in microcontrollers, but fits any memory restricted system.github

使用nanopb庫編譯.proto文件和工程使用,只須要下面兩步便可:ubuntu

  1. 使用protoc編譯.protoc文件;
  2. 在你的工程中import pb_encode.c, pb_decode.c 和 pb_common.c

demo具體參考nanopb中example/simple工程,編譯.proto文件的命令可參考以下:session

protomk:
	mkdir -p $(OUT_DIR)
	$(PROTOC) $(PROTOC_OPTS) --proto_path=$(PROTO_DIR) --nanopb_out=$(OUT_DIR) $(PROTO_DIR)/*.proto
//OUT_DIR是%.proto文件編譯成功後,%.pb.c %.pb.h輸出的文件目錄
//PROTO_DIR是.proto文件所在的目錄位置
//PROTOC和PROTOC_OPTS的定義在../../extra/nanopb.mk
//extra/nanopb.mk
ifneq "$(wildcard $(NANOPB_DIR)/generator-bin)" ""
	# Binary package
	PROTOC = $(NANOPB_DIR)/generator-bin/protoc
	PROTOC_OPTS = 
else
	# Source only or git checkout
	PROTOC = protoc
	ifdef WINDOWS
		PROTOC_OPTS = --plugin=protoc-gen-nanopb=$(NANOPB_DIR)/generator/protoc-gen-nanopb.bat
	else
		PROTOC_OPTS = --plugin=protoc-gen-nanopb=$(NANOPB_DIR)/generator/protoc-gen-nanopb
	endif
endif

我本身的工程在ubuntu18.04上此命令打印出來以下:app

protoc --plugin=protoc-gen-nanopb=/media/pc-name/nanopb-nanopb-0.3.9.2/generator/protoc-gen-nanopb --proto_path=./proto --nanopb_out=./out ./proto/*.proto

遇到的問題

問題1:make失敗

Traceback (most recent call last):
  File "../../generator/nanopb_generator.py", line 2123, in <module>
    main_cli()
  File "../../generator/nanopb_generator.py", line 2019, in main_cli
    results = process_file(fdesc.name, fdesc, options, other_files)
  File "../../generator/nanopb_generator.py", line 1954, in process_file
    headerdata = ''.join(f.generate_header(includes, headerbasename, options))
  File "../../generator/nanopb_generator.py", line 1610, in generate_header
    yield msg.fields_declaration(self.dependencies) + '\n'
  File "../../generator/nanopb_generator.py", line 1169, in fields_declaration
    defval = self.default_value(dependencies)
  File "../../generator/nanopb_generator.py", line 1299, in default_value
    desc = google.protobuf.descriptor.MakeDescriptor(optional_only)
  File "/home/pc-name/.local/lib/python3.6/site-packages/google/protobuf/descriptor.py", line 1077, in MakeDescriptor
    _message.default_pool.Add(file_descriptor_proto)
TypeError: Couldn't build proto file into descriptor pool!
Invalid proto descriptor for file "a8332bcbde22f967a60b51afdddf1cd5.proto":
  NanoPBOptions.long_names: "NanoPBOptions.long_names" is already defined in file "nanopb.proto".
  NanoPBOptions.packed_struct: "NanoPBOptions.packed_struct" is already defined in file "nanopb.proto".
  NanoPBOptions.packed_enum: "NanoPBOptions.packed_enum" is already defined in file "nanopb.proto".
  NanoPBOptions.skip_message: "NanoPBOptions.skip_message" is already defined in file "nanopb.proto".
  NanoPBOptions.no_unions: "NanoPBOptions.no_unions" is already defined in file "nanopb.proto".
  NanoPBOptions.anonymous_oneof: "NanoPBOptions.anonymous_oneof" is already defined in file "nanopb.proto".
  NanoPBOptions.proto3: "NanoPBOptions.proto3" is already defined in file "nanopb.proto".
  NanoPBOptions.enum_to_string: "NanoPBOptions.enum_to_string" is already defined in file "nanopb.proto".
  NanoPBOptions.fixed_length: "NanoPBOptions.fixed_length" is already defined in file "nanopb.proto".
  NanoPBOptions.fixed_count: "NanoPBOptions.fixed_count" is already defined in file "nanopb.proto".
  NanoPBOptions: "NanoPBOptions" is already defined in file "nanopb.proto".

解決方案:python2.7

pip uninstall protobuf
pip install --no-binary=protobuf protobuf

問題2:grpcio-tools下載超時中斷

xiaoyanxia@xiaoyanxia-pc:/usr/bin$ pip3 install grpcio-tools
Collecting grpcio-tools
  Using cached https://files.pythonhosted.org/packages/7a/b3/532a19e668920d3e1c1c832b4365734ffe6f510c9dd5e1c81240d82535ea/grpcio-tools-1.31.0.tar.gz
Collecting protobuf<4.0dev,>=3.5.0.post1 (from grpcio-tools)
  Using cached https://files.pythonhosted.org/packages/30/79/510974552cebff2ba04038544799450defe75e96ea5f1675dbf72cc8744f/protobuf-3.13.0-cp36-cp36m-manylinux1_x86_64.whl
Collecting grpcio>=1.31.0 (from grpcio-tools)
  Downloading https://files.pythonhosted.org/packages/e3/0e/f56aa1f8200ae3c5d38305e69f5920caa480c7ff54ae4d8a5f57d1d69fa4/grpcio-1.31.0.tar.gz (20.0MB)
    1% |▌                               | 327kB 14kB/s eta 0:22:34^C
Operation cancelled by user
xiaoyanxia@xiaoyanxia-pc:/usr/bin$ pip3 install grpcio
Collecting grpcio
  Downloading https://files.pythonhosted.org/packages/e3/0e/f56aa1f8200ae3c5d38305e69f5920caa480c7ff54ae4d8a5f57d1d69fa4/grpcio-1.31.0.tar.gz (20.0MB)
    4% |█▌                              | 931kB 9.1kB/s eta 0:35:04Exception:
Traceback (most recent call last):
  File "/usr/share/python-wheels/urllib3-1.22-py2.py3-none-any.whl/urllib3/response.py", line 302, in _error_catcher
    yield
  File "/usr/share/python-wheels/urllib3-1.22-py2.py3-none-any.whl/urllib3/response.py", line 384, in read
    data = self._fp.read(amt)
  File "/usr/share/python-wheels/CacheControl-0.11.7-py2.py3-none-any.whl/cachecontrol/filewrapper.py", line 60, in read
    data = self.__fp.read(amt)
  File "/usr/lib/python3.6/http/client.py", line 459, in read
    n = self.readinto(b)
  File "/usr/lib/python3.6/http/client.py", line 503, in readinto
    n = self.fp.readinto(b)
  File "/usr/lib/python3.6/socket.py", line 586, in readinto
    return self._sock.recv_into(b)
  File "/usr/lib/python3.6/ssl.py", line 1012, in recv_into
    return self.read(nbytes, buffer)
  File "/usr/lib/python3.6/ssl.py", line 874, in read
    return self._sslobj.read(len, buffer)
  File "/usr/lib/python3.6/ssl.py", line 631, in read
    v = self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/basecommand.py", line 215, in main
    status = self.run(options, args)
  File "/usr/lib/python3/dist-packages/pip/commands/install.py", line 353, in run
    wb.build(autobuilding=True)
  File "/usr/lib/python3/dist-packages/pip/wheel.py", line 749, in build
    self.requirement_set.prepare_files(self.finder)
  File "/usr/lib/python3/dist-packages/pip/req/req_set.py", line 380, in prepare_files
    ignore_dependencies=self.ignore_dependencies))
  File "/usr/lib/python3/dist-packages/pip/req/req_set.py", line 620, in _prepare_file
    session=self.session, hashes=hashes)
  File "/usr/lib/python3/dist-packages/pip/download.py", line 821, in unpack_url
    hashes=hashes
  File "/usr/lib/python3/dist-packages/pip/download.py", line 659, in unpack_http_url
    hashes)
  File "/usr/lib/python3/dist-packages/pip/download.py", line 882, in _download_http_url
    _download_url(resp, link, content_file, hashes)
  File "/usr/lib/python3/dist-packages/pip/download.py", line 603, in _download_url
    hashes.check_against_chunks(downloaded_chunks)
  File "/usr/lib/python3/dist-packages/pip/utils/hashes.py", line 46, in check_against_chunks
    for chunk in chunks:
  File "/usr/lib/python3/dist-packages/pip/download.py", line 571, in written_chunks
    for chunk in chunks:
  File "/usr/lib/python3/dist-packages/pip/utils/ui.py", line 139, in iter
    for x in it:
  File "/usr/lib/python3/dist-packages/pip/download.py", line 560, in resp_read
    decode_content=False):
  File "/usr/share/python-wheels/urllib3-1.22-py2.py3-none-any.whl/urllib3/response.py", line 436, in stream
    data = self.read(amt=amt, decode_content=decode_content)
  File "/usr/share/python-wheels/urllib3-1.22-py2.py3-none-any.whl/urllib3/response.py", line 401, in read
    raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
  File "/usr/lib/python3.6/contextlib.py", line 99, in __exit__
    self.gen.throw(type, value, traceback)
  File "/usr/share/python-wheels/urllib3-1.22-py2.py3-none-any.whl/urllib3/response.py", line 307, in _error_catcher
    raise ReadTimeoutError(self._pool, None, 'Read timed out.')
urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.

解決方案:從新打開一個新的終端從新下載,就是這麼莫名奇妙,好幾回都是如此解決curl

問題3: make失敗

Traceback (most recent call last):
  File "../../generator/nanopb_generator.py", line 50, in <module>
    from .proto import nanopb_pb2
ModuleNotFoundError: No module named '__main__.proto'; '__main__' is not a package

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "../../generator/nanopb_generator.py", line 71, in <module>
    import proto.nanopb_pb2 as nanopb_pb2
ModuleNotFoundError: No module named 'proto.nanopb_pb2'

請進入generator/proto目錄下,執行***make all***命令

#nanopb-nanopb-0.3.9.2/generator/proto/Makefile

all: nanopb_pb2.py plugin_pb2.py

%_pb2.py: %.proto
        protoc --python_out=. $<

寫在最後:
很明顯能夠發現編譯.proto須要make 工具,請記得在編譯前要保證必要的工具安裝protocolbuffers

sudo apt-get install autoconf automake libtool curl make g++ unzip

參考來源 [1]: https://developers.google.com/protocol-buffers [2]: https://github.com/protocolbuffers/protobuf [3]: https://github.com/nanopb/nanopb

相關文章
相關標籤/搜索