コーヒー飲みながら仕事したい

仕事で使う技術的なことの備忘録とか


Wordpress に引っ越しました!

EMQ で TLS 接続する

今回はEMQ(emqttd)を使用して、mqtt の TLS 接続をする方法。
EMQのインストール方法とかは割愛。

サーバーの公開鍵/暗号鍵の生成、それらのオレオレ認証

↓が参考になった。
基本的には前記事の mosquitto の場合と同じ。

medium.com

EMQ側の設定を変更

これも↑のサイトのまんまになるが、一つ気を付けないといけないのが、公開鍵の生成時に「CommonName」にブローカーの FQDN を設定する必要があること。
ここは mosquitto の場合と同じで、 CommonName とブローカーのホスト名が異なると、 TLS 接続できない。

mosquitto で OpenSSL を 用いて TLS 接続する

mosquitto をで TLS 接続する方法です。
OpenSSL を使用するのが簡単だと思うけど、ちょっと間が空くとすぐやり方を忘れてしまうので備忘録として残しておきます。

2018/03/11 追記/修正

いろいろ TLS について勉強してみると、言葉の使い方や理解が正しくない箇所が複数あったので修正しました。
そして、まだ勉強不足なので間違っている箇所がある可能性は十分あります・・・。

前提

  1. OS : Windows 10 64bit
  2. mqtt ブローカーもクライアントも mosquitto を使用する
  3. 秘密鍵/公開鍵やサーバー証明書の生成は、OpenSSL を使用して行う
  4. TLS するためのサーバー証明書は、自己認証局(オレオレ認証局)で実現する
  5. あらかじめ pfx 形式1のものが存在しており、それを使用して自己認証局の開局する
    (pfx ファイルのパスワードは把握しているものとする)

今回は 5. が特殊な条件ですが、現案件がこういう条件下なのでこれを前提で記述します。

pfx ファイルを秘密鍵/公開鍵情報とルート証明書に分離する

pfx ファイル(ca.pfx)を OpenSSL を使用して秘密鍵/公開鍵情報(ca.key)と自己認証局ルート証明書(ca.crt)に分離します。

# 秘密鍵/公開鍵の取り出し
$ openssl pkcs12 -in ca.pfx -nocerts -nodes -out ca.key
Enter Import Password: # ca.pfx ファイルのパスワードを入力
MAC verified OK # ca.key が出力される

# 自己認証局のルート証明書の取り出し
$ openssl pkcs12 -in ca.pfx -clcerts -nokeys -out ca.crt
Enter Import Password: # ca.pfx ファイルのパスワードを入力
MAC verified OK # ca.crt が出力される

mosquitto で TSL 接続を行う場合は、出来上がった crt ファイルをOSに「信頼できるルート証明書」として登録する必要はないので、事実上これで自己認証局の開局は済んだことになります。(mosquitto を起動する際に、ブローカーでもクライアントでも、起動引数にパスを付加することでこのルート証明書を使用します)

参考

blog.prophet.jp

サーバー(ブローカー)の秘密鍵/公開鍵を生成

ブローカーの TSL 接続用の秘密鍵/公開鍵として server.key を生成します。

# 秘密鍵/公開鍵生成
$ openssl genrsa -out server.key 2048

サーバー(ブローカー)のサーバー証明書署名要求の作成

「証明書署名要求」とは、公開鍵にコモンネーム(Common Name)等のサーバーの情報を付加したものです。

www.infraexpert.com

ブローカーの証明書署名要求として server.csr を生成します。

# 証明書署名要求の生成
$ openssl req -out server.csr -key server.key -new

いろいろ入力を促されますが、とりあえずはオレオレ認証なので Common Name (e.g. server FQDN or YOUR name) []: 以外は全て未入力(そのまま Enter )でよいです。
Common Name には、ブローカーの FQDN (ホスト名またはIPアドレス)を入力する必要があります。
もし正しく FQDN を入力しなかったら、Error: A TLS error occurred. と言われてブローカーと接続できません。

Common Name (コモンネーム)について追記

そもそも、SSL/TLS 接続を行う際に、クライアント側がサーバーを認証する(なりすましでないと特定する)手法が、サーバーへの接続文字列とコモンネームを比較することらしいです。
つまり、コモンネームが一致しないならば、相手が本物と特定できない(クライアントは相手がなりすましだと思わざるをえない)ので、それくらいコモンネームは重要です。

詳細は↓のサイトが非常に参考になります。

cspssl.jp

このサイトは SSL 接続の知識が体系的にまとめられていて、非常に勉強になります。

サーバー証明書の署名と発行

上記で生成したサーバー証明書署名要求を、自己認証局秘密鍵ca.key)でデジタル署名して、サーバー証明書を発行します。

# サーバー証明書の署名と発行
$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 36500

ここでは、有効期限を100年としています。(普通はこんなことしませんが、オレオレ認証なので・・・)

とりあえずここまでで、 OpenSSL を使用した TSL 接続用の鍵生成や署名は終了です。

参考

qiita.com

mosquitto.conf の設定

TSL 接続で使用する各証明書ファイルのパスを mosquitto.conf に追加します。
ファイルのどこに書いても良いそうです。

// C:\Program Files (x86)\mosquitto\mosquitto.conf
listener 8883
cafile   ./certs/ca.crt
certfile ./certs/server.crt
keyfile  ./certs/server.key

ここでは、上記で生成した鍵等を、 C:\Program Files (x86)\mosquitto\certs に入れているものとしています。

動作確認

# ブローカーの起動
$ mosquitto -v -c mosquitto.conf
1520414168: mosquitto version 1.4.12 (build date 29/05/2017 11:24:45.10) starting
1520414168: Config loaded from mosquitto.conf.
1520414168: Opening ipv6 listen socket on port 8883.
1520414168: Opening ipv4 listen socket on port 8883.
# mosquitto_sub の起動
$ mosquitto_sub -d -t test -h <BrokerのFQDN> -p 8883 --cafile ./certs/ca.crt
# mosquitto_pub の起動
$ mosquitto_pub -d -t test -m aaaaaa -h <BrokerのFQDN> -p 8883 --cafile ./certs/ca.crt

  1. 秘密鍵と公開鍵、サーバー証明書認証局の場合はルート証明書)をまとめて一つにし、パスワードにより暗号化されたもの

Protocol Buffers の C# 版で遊んでみる

Protocol Buffers のC#

有名どころでは、以下の2つがあるようです。

※ 追記:前者でも .proto ファイルを使用することができるみたいです。

今回の私が手掛ける案件では、後者のほうが適する(CのサービスとC#のサービスがやりとりする)ので、ここでは Google.Protobuf を主に取り上げます。

参考サイト

tnakamura.hatenablog.com

C# 版 protobuf (Google.Protobuf) の導入

githubのReadmeに書かれている手順で導入していきます。

条件

以下が条件です。

  • Visual Studio 2012 意向であること
  • .NET4.5 以降または .NET Core であること

Nuget

Google.Protobuf を使用するだけなら、 Google.Protobuf を Nuget すればよいです。
しかし、それに加えて .proto ファイルを使用してクラスファイルを生成するならば、 Google.Protobuf.Tools も Nuget する必要があります。

Google.Protobuf はライブラリなのだが、 Google.Protobuf.Tools はライブラリではなく、バイナリ(ptoroc.exe)が入っています。
ちなみに、 Nuget した際のダウンロード先は、私の場合はC:\Users\XXX\.nuget\packages\google.protobuf.tools\3.5.1\tools でした。
ソリューションファイル内にダウンロードされているものだと思っていたので、ちょっとはまってしまいました。

Google.Protobuf でチュートリアルする

とりあえず、公式のチュートリアルを実行してみます。
公式は英語なので、備忘録として意訳したやつを残しておきます。

.proto ファイルの用意

とりあえずチュートリアルで示されている addressbook.proto を使用します。これはgithubに掲載されているのだが、このまま使用するとエラーになる(import "google/protobuf/timestamp.proto" なんてねーよって言われる)ので、修正したのを↓に載せときます。

// [START declaration]
syntax = "proto3";
package tutorial;

// [END declaration]

// [START java_declaration]
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";
// [END java_declaration]

// [START csharp_declaration]
option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
// [END csharp_declaration]

// [START messages]
message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

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

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}
// [END messages]

.proto ファイルからクラスファイルを生成する

Nuget した Google.Protobuf.Tools 内に含まれる tools\windows_x64\protoc.exe を使用して、addressbook.protoシリアライズ/デシリアライズ用のクラスファイルを生成しあmす。

protoc -I=$SRC_DIR --csharp_out=$DST_DIR $SRC_DIR/addressbook.proto

上記を実行すると、Addressbook.cs$DST_DIR 内に生成されます。

Addressbook.cs の中身を見ると、なかなかキモくて焦るが、たぶん利用する側は中身を意識する必要はそんなになさそう)

生成されたクラスファイルと Google.Protobuf を使用して、シリアライズ/デシリアライズをやってみる

チュートリアルを参考に、以下のように動作確認用の Program.cs を作成して実行してみます。
実行結果、正しく動作していることが確認できました。

using System;
using System.IO;
using System.Text;
using Google.Protobuf;
using Google.Protobuf.Examples.AddressBook; // protoc.exeにより自動生成されたクラスの名前空間
using static Google.Protobuf.Examples.AddressBook.Person.Types; // C# 6 の書き方で、クラス内クラスを省略形式で記述することができるようになる(protobufとは関係なし)

namespace ProtobufCsharp
{
    class Program
    {
        static void Main(string[] args)
        {
            // AddressBook.csで定義されているPresonクラスを実体化する
            Person person = new Person
            {
                Id = 1234,
                Name = "Yamada Tarou",
                Email = "yamada@sample.com",
                Phones = { new PhoneNumber { Number = "555-4321", Type = PhoneType.Home },
                    new PhoneNumber { Number = "222-1111", Type = PhoneType.Work } }
            };

            // 文字列にシリアライズ
            var data = Serialize(person);

            // シリアライズした文字列を読み込んでデシリアライズする
            var someone = Deserialize<Person>(data);

            // 動作確認
            Console.WriteLine($"Id:{someone.Id}, Name:{someone.Name}, Email:{someone.Email}, " +
                $"Phones[0](Number:{someone.Phones[0].Number}, Type:{someone.Phones[0].Type}), " +
                $"Phones[1](Number:{someone.Phones[1].Number}, Type:{someone.Phones[1].Type})");

            Console.ReadKey();
        }

        static byte[] Serialize<T>(T obj) where T : IMessage<T>
        {
            using (var stream = new MemoryStream())
            {
                obj.WriteTo(stream);
                return stream.ToArray();
            }
        }

        static T Deserialize<T>(byte[] data) where T : IMessage<T>, new()
        {
            var parser = new MessageParser<T>(() => new T());
            return parser.ParseFrom(new MemoryStream(data));
        }
    }
}

解説

  • WriteTo(stream) メソッドで、Stream 型にシリアライズすることができる
  • Parser.ParseFrom(stream) メソッドで、Stream 型からデシリアライズすることができる
  • 実際、ネットワーク間でメッセージのやり取りをする場合は、文字列が都合がいい場合が多いので、その場合は MemoryStream 型を byte 配列に変換すればよい

とりあえず思ったより簡単に実行できました。
ただし、Stream 型を使用するシリアライズ/デシリアライズはちょっと面倒だ。直に byte 配列にできればいいのに。
ちょっと調査します。

直に byte 配列にシリアライズ/デシリアライズするようにサンプルを変更してみました。たぶんこれでいける。

Visual Studio 2017 で protobuf-c を試してみる

前回の続き。

tassi-yuzukko.hatenablog.com

もろもろの準備がやっとできたので、 Visual Studio 2017 で protobuf-c を試してみる。

前準備

あらかじめ下記内容で amessage.proto を用意しておく(前回生成済み)

syntax = "proto3";

message AMessage {
  int32 a=1; 
  int32 b=2;
}

そして、protoc-c --c_out=. amessage.proto で、以下のファイルを生成しておく(これも前回実施済み)

  • amessage.pb-c.c
  • amessage.pb-c.h

ソリューションの作成

上記のファイル2つと、 protobuf-c.c および protobuf-c.h をソリューションフォルダ内につっこむ。

この際、便宜上、以下を変更した。

amessage.pb-c.h

7:  --- #include <protobuf-c/protobuf-c.h>
7:  +++ #include "protobuf-c.h"    // protobuf-c.hをローカルに置いたため & <>の括弧ではアクセスできないため

protobuf-c.c

316:  --- return (-(uint32_t)v) * 2 - 1;
316:  +++ return ((uint32_t)(-v)) * 2 - 1;    // Visual Studio コンパイル時にエラーとなったため(符号なし型にマイナスをつけることができないみたい)

381:  --- return (-(uint64_t)v) * 2 - 1;
381:  +++ return ((uint64_t)(-v)) * 2 - 1;    // Visual Studio コンパイル時にエラーとなったため(符号なし型にマイナスをつけることができないみたい)

2413:  --- return -(v >> 1) - 1;
2413:  +++ return -1 * (v >> 1) - 1;    // Visual Studio コンパイル時にエラーとなったため(符号なし型にマイナスをつけることができないみたい)

2457:  --- return -(v >> 1) - 1;
2457:  +++ return -1 * (v >> 1) - 1;    // Visual Studio コンパイル時にエラーとなったため(符号なし型にマイナスをつけることができないみたい)

3147:  --- tmp.length_prefix_len = pref_len;
3147:  +++ tmp.length_prefix_len = (uint8_t)pref_len;    // 警告が出たので一応

注意

Visual Studio の環境では、これらのファイルをコンパイル対象とするために、明示的にソリューション(というかプロジェクト)構成配下に登録する必要がある。

Simple complete example チュートリアル実行

基本的に、Examples · protobuf-c/protobuf-c Wiki · GitHub を参照して、 protobuf-c の Simple complete example チュートリアルを実行してみる。

しかし以下を変更してやってみる。

結果、以下のようなファイルを用意した。

// AMessageSerialize.h

#pragma once
#include <windows.h>

BOOL AMessageSerialize(int argc, const char * argv[]);
// AMessageSerialize.c

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include "amessage.pb-c.h"
#include "AMessageSerialize.h"

static void MyWriteFile(void const * buf, size_t len, const char* filename);

BOOL AMessageSerialize(int argc, const char * argv[])
{
    AMessage msg = AMESSAGE__INIT; // AMessage
    void *buf;                     // Buffer to store serialized data
    unsigned len;                  // Length of serialized data

    if (argc != 2 && argc != 3)
    {   // Allow one or two integers
        fprintf(stderr, "usage: amessage a [b]\n");
        return FALSE;
    }

    msg.a = atoi(argv[1]);
    msg.b = atoi(argv[2]);
    len = amessage__get_packed_size(&msg);

    buf = malloc(len);
    amessage__pack(&msg, buf);

    fprintf(stderr, "Writing %d serialized bytes\n", len); // See the length of message
    MyWriteFile(buf, len, "test.txt"); // Write to stdout to allow direct command line piping

    free(buf); // Free the allocated serialized buffer
    return TRUE;
}

static void MyWriteFile(void const * buf, size_t len, const char* filename)
{
    FILE* fp;

    fopen_s(&fp, filename, "wb");
    if (fp == NULL) {
        fprintf(stderr, "failed to write file.");
        goto END;
    }

    fwrite(buf, len, 1, fp);

END:
    fclose(fp);

    return;
}
// AMessageDeserialize.h

#pragma once
#include <windows.h>

BOOL AMessageDeserialize();
// AMessageDeserialize.c

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include "amessage.pb-c.h"
#include "AMessageDeserialize.h"
#define MAX_MSG_SIZE 1024

static size_t
read_buffer(unsigned max_length, uint8_t *out, const char* filename)
{
    size_t cur_len = 0;
    size_t nread;
    FILE* fp;

    fopen_s(&fp, filename, "rb");
    if (fp == NULL) {
        fprintf(stderr, "failed to read file.");
        goto END;
    }

    while ((nread = fread(out + cur_len, 1, max_length - cur_len, fp)) != 0)
    {
        cur_len += nread;
        if (cur_len == max_length)
        {
            fprintf(stderr, "max message length exceeded\n");
            exit(1);
        }
    }

END:
    fclose(fp);

    return cur_len;
}


BOOL AMessageDeserialize()
{
    AMessage *msg;

    // Read packed message from standard-input.
    uint8_t buf[MAX_MSG_SIZE];
    size_t msg_len = read_buffer(MAX_MSG_SIZE, buf, "test.txt");

    // Unpack the message using protobuf-c.
    msg = amessage__unpack(NULL, msg_len, buf);
    if (msg == NULL)
    {
        fprintf(stderr, "error unpacking incoming message\n");
        return FALSE;
    }

    // display the message's fields.
    printf("Received: a=%d  b=%d \n", msg->a, msg->b);  // required field

    // Free the unpacked message
    amessage__free_unpacked(msg, NULL);
    return TRUE;
}
// main.c

#pragma once

#include <stdio.h>
#include "AMessageSerialize.h"
#include "AMessageDeserialize.h"

int main(int argc, const char * argv[])
{
    AMessageSerialize(argc, argv);
    AMessageDeserialize();

    system("pause");

    return 0;
}

実行結果

引数を 10 2 で実行してみると、以下になった。

Writing 4 serialized bytes
Received: a=10  b=2
続行するには何かキーを押してください . . .

んーたぶんできてるっぽい。
とりあえず目的達成。シリアライズとデシリアライズの方法も直感的だし、C言語でここまでできるのはかなり魅力的だなーと思いました。

ソースコード

一応、ソースコードを載せとく。

protobuf-c で今度こそ遊んでみる(proto2とproto3の違い編)

あらすじ

もともと軽い気持ちで Protocol Buffers のC言語版を遊んでみようと思っていたら、意図せず Docker を巻き込んだ一大イベントに発展した。

やっとこさ準備ができたので、楽しく遊ぼうとしていた。が、しかし・・・

protocol buffers のバージョン2とバージョン3は互換性がない件について

protobuf-c の wikiを読みながらチュートリアルに取り組んでみた。

amessage.proto という名前で以下の内容のファイルを作る。

message AMessage {
  required int32 a=1; 
  optional int32 b=2;
}

で、さっそく protobuf-c を実行させて AMessage 構造体のシリアライザーとデシリアライザーを作ろうと以下を実行した。

root@e834aae66aee:/work/ProtocolBuffersTest# protoc-c --c_out=. amessage.proto
[libprotobuf WARNING google/protobuf/compiler/parser.cc:546] No syntax specified for the proto file: amessage.proto. Please use 'syntax = "proto2";' or 'syntax = "proto3";' to specify a syntax version. (Defaulted to proto2 syntax.)

なんか警告が出る!
直訳すると、「 proto2 と proto3 のどっちで動作させるかちゃんと明記('syntax = "proto2";' か 'syntax = "proto3";')してくれ。じゃないと proto2 で動作するよ。」って感じだと思う。
なんとなくだけど、新しいほうがいいと思うので、amessage.proto を以下のように変更してみた。

syntax = "proto3";

message AMessage {
  required int32 a=1; 
  optional int32 b=2;
}

で、実行するとエラーになる・・・

root@e834aae66aee:/work/ProtocolBuffersTest# protoc-c --c_out=. amessage.proto
amessage.proto:5:12: Explicit 'optional' labels are disallowed in the Proto3 syntax. To define 'optional' fields in Proto3, simply remove the 'optional' label, as fields are 'optional' by default.

調べてみると、どうやら proto2 と proto3 で protoファイルの記法がかわったとのこと。
具体的には、proto3 では requiredoptional が削除されたらしい。
なんで?って感じだけど、以下の stackoverflow に質問と回答があったので、一応載せとく。よく読んでないけど、拡張性を考慮するとそれらを削除するという流れになったそうだ。

stackoverflow.com

protocol buffers バージョン3を選択する

ということで、再々度 amessage.proto を変更する。

syntax = "proto3";

message AMessage {
  int32 a=1; 
  int32 b=2;
}

これで、 protoc-c --c_out=. amessage.proto が正常に動作して、以下のファイルが出力された。

  • amessage.pb-c.c
  • amessage.pb-c.h

引き続き、wiki の Examples に従ってチュートリアルしてみるけど、まんま wiki の通りになるので割愛します。

Protobuf-c を Docker 上の Ubuntu 環境でインストールする

あらすじ

前回、 protobuf を Docker 上の Ubuntu 環境でインストールした。

tassi-yuzukko.hatenablog.com

今回は、いよいよ protobuf の C言語版である protobuf-c をインストールする。

protobuf-c をインストールするまでの手順

基本的には protobuf と同様に、以下の Readme に従う。

github.com

git hub からリポジトリをクローンする

こちらからクローン。詳細は省略します。

コンパイル/インストールする

Readme に書いてある通り、./autogen.sh && ./configure && make && make install を実行すればコンパイル&インストールができるらしい。

ちなみに、前提として以下の記事の通り、 protobuf-c をコンパイルするための Ubuntu の環境は構築済みとする。

tassi-yuzukko.hatenablog.com

tassi-yuzukko.hatenablog.com

補足

なんと、リリース版なのにコンパイルエラーになる。(protobuf-c ver1.30)

In file included from protoc-c/c_file.cc:64:0:
./protoc-c/c_file.h:107:3: error: 'vector' does not name a type
   vector<string> package_parts_;

調べてみると、既知の問題らしく、 issue に解決策が載っていた。
どうやら、 vectorstd::vector に、 pairstd::pair に置換すればよいとのこと。

github.com

理由は英語で解説してるっぽい人がいたけど、google先生に翻訳してもらってもよくわからん・・・

とりあえず言われた通り置換すると、一応コンパイル通りました。

動作確認

protoc-c --version を実行し、以下が出たたらOK。

root@e834aae66aee:/work/protobuf-c# protoc-c --version
protobuf-c 1.3.0
libprotoc 3.5.1

いやーしかし、リリース版がコンパイル通らないって・・・なんかこれ心配になってきたぞ・・・

次回はいよいよ、 protobuf-c を使って遊んでみる!

Protobuf を Docker 上の Ubuntu 環境でインストールする

あらすじ

前回の続き

tassi-yuzukko.hatenablog.com

今までの流れの概略

  • protobuf-c をコンパイルしようと思ったら Windows 上ではうまくいかなかった
  • Ubuntu 環境だったらうまくいくのではと思い、 Docker (Docker ToolBox)を導入してみた
  • Ubuntu のイメージを、 protobuf-c コンパイル用にカスタマイズするために Dockerfile を用意した
  • →protobuf-c をコンパイルするために、本家 Protobuf が必要なのだが、 Ubuntu 用のパッケージはバージョンが古い(protobuf ver2.6.1)。protobuf-c ver1.30 に互換性問題があり、 protobuf ver3.X 以降でないと、 protobuf-c をコンパイルできない
  • →protobuf ver3.X(最新版)を自分でコンパイル/インストールする

今回の目標

ということで、今回は本家 protobuf ver3.X をインストールする

protobuf をインストールするまでの手順

基本的には以下の Readme に従う。

github.com

git hub からリポジトリをクローンする

git hub のリポジトリからクローンする。

root@e834aae66aee:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  work
root@e834aae66aee:/# cd work
root@e834aae66aee:/work# git clone https://github.com/google/protobuf.git
Cloning into 'protobuf'...
remote: Counting objects: 50405, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 50405 (delta 5), reused 6 (delta 3), pack-reused 50392
Receiving objects: 100% (50405/50405), 44.17 MiB | 126.00 KiB/s, done.
Resolving deltas: 100% (33940/33940), done.
Checking connectivity... done.
Checking out files: 100% (1952/1952), done.

補足

一応、データ永続化用の共有フォルダにクローンすると、Windows であれば tortoise git とかの GUIで git 操作でき、ubuntuwindows のいいとこどりができる。
ちなみに、こういう永続化領域を Data Volume というらしい。

コンフィグスクリプトを生成する

クローンしたら、 ./autogen.sh を実行しなければいけないらしい。

root@e834aae66aee:/work# cd protobuf
root@e834aae66aee:/work/protobuf# ./autogen.sh

補足

Readme に You can skip this step if you are using a release package (which already contains gmock and the configure script). とあるので、もしかしたらコンパイルするだけなら上記コンフィグスクリプトは不要かもしれない。

コンパイルとインストール

Readmeによると、以下を実行するとのこと。

$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig

Readmeには、環境によっては追加でいろいろやらないとコンパイルが通らないことがあるとのことだけど、私の環境では上記コンパイル/インストールが成功したっぽい。

補足

make と make check は激遅です。無限ループしてるんじゃないかってくらい、同じようなビルドログが出力され続けて終わりません。私の環境でそれぞれ20分以上かかりました。

インストール確認

protoc --version が正常にできればとりあえずインストールはOKと思われる。

root@e834aae66aee:/work/protobuf# protoc --version
libprotoc 3.5.1

とりあえず protobuf のインストールまでできた。
次回は protobuf-c のインストールについてまとめる。


別のインストール方法

githububuntu で protobuf ver3.X をインストールすることを題材として issue を見つけた。

gist.github.com

これによると、 https://github.com/google/protobuf/releases/download/v3.4.0/protoc-3.4.0-linux-x86_64.zip でも入手してインストールできるみたい。
一応備忘録として残しておく。