突然Git Pushができなくなった時の一つの解

それはある日突然訪れた。

取引先と共有しているBitBucket上のリモートリポジトリに、ローカルでコミットしたソースコードがPushできなくなった。ソースコードはSails.jsサーバ上で組んでいるもので、クライアントはReactを使用してビルドしたものだ。

Sails.js | Realtime MVC Framework for Node.js

React – ユーザインターフェース構築のための JavaScript ライブラリ

これまで問題なく使えていたのだが、ある日突然次のようなログに見舞われPushできなくなった。

Enumerating objects: 47, done.
Counting objects: 100% (47/47), done.
Delta compression using up to 12 threads
Compressing objects: 100% (29/29), done.
fatal: the remote end hung up unexpectedly
Connection to bitbucket.org closed by remote host.
fatal: the remote end hung up unexpectedly

少量の変更なら問題なく使えたので、どう切り分ければいいのか皆目見当が付かない。

主眼を「大量データのPush」に絞り、 git push fatal hung up のようなキーワードでググり、.git/config上で ssh.postBuffer をいじってみたり、~/.ssh/config上に ServerAliveInterval を設定してみたりと手を尽くしたものの、一切変化がなかった。

もしやBitBucket特有のものかと思っていたら、別の取引先でGitHub上に共有していたソースコードも同様のログとともにPushできない事象に見舞われた。OMG

実は問題なく使えていた時と、問題が発生した時の環境で唯一違いがあった。それは「引越し」をしたことだ。プロバイダや回線は全く一緒なのだが、引っ越したことでネットワーク環境に何らかの差異が発生したのではと思った。

そこで自宅のLAN環境を無効にして、モバイルWi-Fiルーターで試してみた。が、問題は解決しなかった。なんやねん!

目の前が真っ暗になりかけたその時、検索画面に次の記事の検索結果が引っかかった。

GitLabとSSH接続 - Qiita

根本的な解決方法ではなさそうなものの、見出しが気になりリンクをたどると、内容は「ssh接続をhttpsポート(443)でつなぐ」というものだった。なるほど、22番以外でも接続することはできるのかと思い、失敗していたGitHub.comへの接続設定に適用してみた。

「こいつ・・・動くぞ!」

なんとこれまでウンともスンともPushできなかったコミットが、さらっと completed のメッセージとともにPushを完了した。そこで問題のBitbucketの方もやってみたところ、こちらも問題解決!見事に突破した。

22番ポートの何がダメになってしまったのか、そもそもの話はまるでわからないままだが、443番ポートを介することで、できなかったことができたことに違いはない。

参考にしたサイトに謝意を述べるとともに、リンクを掲載しておく。もし postBufferServerAliveInterval などで一切解決できなかった方はお試しあれ。

BitbucketにHTTPSポートでSSH接続する方法 – Memoteki

22 番ポートが通らない環境で GitHub / BitBucket / GitLab を SSH 経由で利用する方法 - Qiita

GitリポジトリサーバのSSH鍵を使い分け

自分用のメモ。

基本的には以下のページが非常に参考になる。

qiita.com

謝意を述べたい。

これに、私なりの理解や補足を加えておく。

結論

同一のリポジトリサーバ(GitHubやBitBucketのような)内を、目的やアカウントで、使用するSSH鍵を使い分けたい場合、SSHのホスト設定とGitのローカル設定を駆使すればできる。

Gitグローバル設定

まず、Gitのグローバル設定は空っぽが望ましい。Gitをインストールすると、大抵 git config --global user.email の設定を推奨されるが、アカウントの使い分けをする上では「うっかりミス」を誘発してしまう。もしEメールを使い分けるなら user.email をグローバル設定には置かないようにする。もしあるなら以下のようにする。

$ git config --global --unset user.email

SSH設定

例えば、A社用とB社用でGitHubで使うEメールアドレスやSSH鍵を使い分けなければならない場合、それぞれにSSH鍵を発行、登録していたとして、~/.ssh/configファイルに次のように設定する。

Host github_a_company
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa_github_a => これの公開鍵をA社アカウントでGitHubに登録
    IdentitiesOnly yes

Host github_b_company
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa_github _b => これの公開鍵をB社アカウントでGitHubに登録
    IdentitiesOnly yes

Gitローカル設定

あとはプロジェクトのディレクトリに移動し、Gitのローカル側設定を以下のようにする。

$ cd project_a
$ git init
$ git config user.name "My Name"
$ git config user.email myname@a.com
$ git config url.github_a_company.insteadof git@github.com
$ cd project_b
$ git init
$ git config user.name "My Name"
$ git config user.email myname@b.com
$ git config url.github_b_company.insteadof git@github.com

こうすると、例えばA社のプロジェクトでソースコードをPushすると、

$ cd project_a
$ git remote -v
origin  git@github.com:myaccount/myproject.git (fetch)
origin  git@github.com:myaccount/myproject.git (push)
$ git push origin master

Push時のホスト名は以下のように変化する。

git@github.com => github_a_company (.git/configを適用)
github_a_company => git@github.com (~/.ssh/configを適用)

?元に戻っただけ?

否!

github_a_company を適用した時点で、A社用の「SSH公開鍵」が使われるようになっている。

Gitクローン時

なお、 .git/config がまだ存在しない、例えば git clone 操作する場合はどうするか? その場合、ホスト名を ~/.ssh/config に設定した Host xxxxxx を代わりに使えばできる。

例えば、B社用のSSH鍵でsomeprojectのソースコードをクローンしたい場合は次のようにする。

$ git clone git@github_b_company:someaccout/someproject.git

あとは必要に応じてプロジェクト内でGitを初期化、ローカル設定すればいい。

DominoでGraphQL

DominoサーバでGraphQLを作れたらいいな・・・と思ったので、超簡単なプロトタイプを作ってみました。

GraphQL、ご存じない方のために簡単に説明すると、「つながり」でできたデータ構造に問い合わせてデータを取得したり、更新したりすることができる「クエリ仕様」と言えばいいだろうか。

Facebook社が開発したんだけど、Facebook内のデータっていろんなところに「つながり」を持っていて、それを捌くのに開発したんじゃねっていう理解。なので、ツリー構造になっているNotesデータベース構造って、GraphQLでも扱いやすいんじゃないかと思ったのがきっかけ。

GraphQLはスキーマを決めて、スキーマに沿って問い合わせればいい、至極簡単。でもそれって使う側の言い分。実際問題、提供する側は結構面倒。JSONっぽいQueryは似て非なり。なので改めてQueryを字句解析しないといけない。C++での実装はそこが骨の折れるところ。でも優秀なライブラリを見つけたので、今回はこれのおかげ。

github.com

Microsoftとあるけど、LinuxMacでもできるらしい。

ちなみに、試しに作ったスキーマはこれ。

schema {
  query: Query
}

type Query {
  dbDirectory(rootPath: String!): [DbNode!]!
}

interface DbNode {
  path: String!
  isDirectory: Boolean!
}

type DbDirectory implements DbNode {
  path: String!
  isDirectory: Boolean!
  dbDirectory: [DbNode!]!
}

type Database implements DbNode {
  path: String!
  isDirectory: Boolean!
  replicaId: String!
}

最初の schema はGraphQLの3つの機能、問い合わせ(Query)、変更(Mutation)、サブスクリプション(Subscription)のどれを使うかってことらしい。サブスクは基本的にWebSocketなどがないと動かない。Domino HTTPのアドイン(DSAPI)ではおそらくなんともしがたいと思う。

今回はデータの取得だけなので、Queryのみを定義する。

続く type Query は、その問い合わせの仕様について。 dbDirectory というキーワードに rootPath でどのディレクトリ内にあるデータベースやサブディレクトリを取得するかを特定する引数を定義している。後ろの [DbNode!]! は、 DbNode のリストを意味する戻り値の仕様。

interface DbNode は先の DbNode の仕様に他ならないが、先頭が type ではなく interface なのがミソ。Javaなどのインターフェースと同義で、仕様のみで実装はない。Notes C APIではNotesデータベースとディレクトリって扱いが似ていて、ディレクトリもデータベースと同じくデータベースハンドル(DBHANDLE)で扱う。なので、両社に共通のパス名と、ディレクトリであるか否かを判定できるブール値を仕様にしている。

type DbDirectory ではその DbNode を実装してディレクトリを定義している。データベースとの違いは、さらに別のデータベースやディレクトリを配下に持てるので、再帰的に dbDirectory を持っている。最初の Query との違いは、すでにパスを保持している点にある。

type DatabaseDbNode を実装しつつ、ディレクトリにはないものを実装する。今回レプリカIDを取得できるようにしてみた。

例えば、これを使って、 mail ディレクトリ内のデータベースを取得しようと思ったら、次のようなGraphQLを書けばよい。

query {
    dbDirectory(rootPath: "mail") {
        path
        isDirectory
        ...on Database {
            replicaId
        }
    }
}

これでDomino GraphQLに問い合わせると、

{
    "data": {
        "dbDirectory": [
            {
                "path": "mail\\admin.nsf",
                "isDirectory": false,
                "replicaId": "49257D76xxxxxxxx"
            },
            {
                "path": "mail\\hkobayas.nsf",
                "isDirectory": false,
                "replicaId": "492581B9xxxxxxxx"
            },
            {
                "path": "mail\\kshiden.nsf",
                "isDirectory": false,
                "replicaId": "492581B9xxxxxxxx"
            },
            {
                "path": "mail\\rhosei.nsf",
                "isDirectory": false,
                "replicaId": "492581B9xxxxxxxx"
            }
        ]
    }
}

のようなJSONデータが返ってくる。なお、 replicaId を付与すると、一つ一つDBをオープンしてレプリカIDを取得するような実装方法を取ったため、取得するDBやディレクトリが多いと途端に遅くなるので、改善の余地がある。

GraphQLがRESTなどに比べてすごいところは、取りたいデータをコントロールするすべを仕様が定義しているところ。例えば、先ほどのクエリを以下のように変えてみる。

query {
    dbDirectory(rootPath: "mail") {
        path
    }
}

すると、返ってくるデータは次のようになる。

{
    "data": {
        "dbDirectory": [
            {
                "path": "mail\\admin.nsf",
            },
            {
                "path": "mail\\hkobayas.nsf",
            },
            {
                "path": "mail\\kshiden.nsf",
            },
            {
                "path": "mail\\rhosei.nsf",
            }
        ]
    }
}

求めたいフィールドを変更すると、戻り値のフィールドも変更される。GraphQLはそれを仕様として定義している。RESTでももちろんできるが、仕様ではないので、手法は実装者に委ねられている。

今回は本当に序の口。まだまだ紹介できるレベルには達していない。でもなんか元旦早々嬉しくなったので、早出ししてみた。

W64API不具合レポート〜ExtMgr編

果たして、Lotus Notes C API ToolkitのHCL版はリリースされるのか?

今回のWindows 64ビット版コンパイル時の不具合については簡潔に報告します。

Extension Manager(通称ExtMgr)において、コールバック関数にはEMRecordという構造体へのポインタが渡されます。

typedef struct
  {
  EID           EId;                    /* identifier */
  WORD      NotificationType;       /* EM_BEFORE or EM_AFTER */
  STATUS        Status;                 /* core error code */
  VARARG_PTR    Ap;                     /* ptr to args */
  } EMRECORD;

このときの EID 型は、定義によると以下のようになります。

typedef WORD EID;

しかし、Windows 64では不十分で、このまま使うと以下のメンバ変数が2バイトずつズレてしまい、最後の Ap が指すポインタを操作すると、Dominoサーバがクラッシュします。

そのため、 EID の定義を以下のように修正する必要があります。

// extmgr.h
#if defined(NT) && defined(_AMD64_)
typedef DWORD EID;
#else
typedef WORD EID;
#endif

それでは、素敵なNotes C APIライフをお過ごしください。

Gitで共有しているコードをローカル固有環境で動かす

Gitリモートリポジトリ経由でWebサーバアプリケーションなどを開発している時、URL等の関係でどうしても自身のローカル環境に設定を合わせたい時がある。

今いちばんよい方法だと思っているのは、その設定ファイルをGitの対象ファイルから外す方法。

Node.jsのWebアプリケーションフレームワークSails.js | Realtime MVC Framework for Node.jsでは、ひな形を作ると config/local.js というファイル作成して、そのファイルを .gitignore 内に含めておいてくれるので、ローカルでの設定を他者とファイルを競合することなく開発することができる。

では、仕組みなどの理由でその方法が採れない時はどうすればいいか。

一時しのぎの感は否めないが、 git stash を使う方法もある。

クローンを作成し、自身のローカル用にURLを config.js に書くとする。 もちろん、このファイルは他者と共有するので、変更内容をアップロードすることは避けたい。 そんな場合に、以下の方法を取るといい。

# 変更内容をすべてステージング
git add .

# 特定のファイルをステージングから戻す
git reset HEAD config.js

# コミット
git commit -m HogeHoge

# プッシュ
git push origin master

リモートリポジトリの変更内容をローカルにプルするときは、以下の手順を取る。

# 現在の変更を退避(config.jsは変更前の状態になる)
git stash save

# リモートリポジトリから最新コードをプル
git pull origin master

# 直近の退避内容を戻す
git stash apply

退避内容の戻し方いろいろ

# 特定の退避内容を戻す(stash@{0}はスタッシュ名)
git stash apply stash@{0}

# 内容を戻すと同時に退避リストから削除したい場合(stash@{0}はスタッシュ名)
git stash pop stash@{0}

これで、はれて最新コードをローカル環境下で動かすことができる。 git stash は他にもいろいろコマンドがあるので、興味のある方はググってみてください。

NSFItemInfoNext対応の悪影響

1年半前の記事で、「NSFItemInfoNext」関数についての対応策について書いた。

chiburusystems.hatenablog.com

これについて、その後特に問題もなく順調にいっていたのだが、つい先日、とうとうこの対応が別の形で悪さをする事案に陥った。

以前の記事の概略

前回の対応をかいつまんで説明する

NSFItemInfoNext関数の第2引数はBLOCKIDという構造体を指定する。

typedef WORD BLOCK; /* pool block handle */

typedef struct /* Pointer to any block in any pool */
{
  DHANDLE pool; /* pool handle */
  BLOCK block; /* block handle */
} BLOCKID;

ところが、DominoサーバWindows64ビット版においては、この「BLOCK」は2バイトの「WORD」型ではなく、4バイトの「DWORD」型を指すという事実だ。

#ifdef W64
typedef DWORD BLOCK;
#else
typedef WORD BLOCK;
#endif

こうしないと、Win64においては必ずクラッシュする。幸い、Win32版、Mac版やLinux版ではこれを意識しなくてもいい。

今回発生した問題

このまま1年半使い続けてきたが、極めて限定的な条件の時にのみ、この対応がDominoサーバのクラッシュを生むらしい。私の認識している範囲で言えば、レプリカ直後の文書において、「特殊な」アクセスを試みたときに起こる(詳細は割愛する)。

NSFItemInfo関数は、文書内のアイテム情報(フィールド)を取得する。NSFItemInfoNext関数は、同一フィールド名の2番目以降を取得する。添付ファイルなどの特殊な場合を除き、1つのアイテムには64キロバイトの制限があるので、大きいサイズのフィールドはいくつかのブロックに分割して保存する。前出の「BLOCKID」はそれらを識別するための仕組みである。

ブロックからフィールドデータを得るためには、ブロックをロックして、ポインタを取得する。

void far * LNPUBLIC OSLockObject (DHANDLE Handle);

#define OSLock(blocktype,handle) ((blocktype far *) OSLockObject(handle))

#define    OSLockBlock(type,blockid) \
  ((type far *)(OSLock(char,(blockid).pool) + (blockid).block))

OSLockObject関数でハンドルからポインタを得る。

OSLockマクロは、単に得られたポインタを指定した型のポインタにキャストする。

OSLockBlockマクロは、BLOCKIDのpoolハンドルから得たcharポインタから、blockバイト分移動した場所を指すようにして返す。

一般的な使い方であればこれで問題がなかった。しかし、「特殊なアクセス」でこのOSLockBlockマクロを使ってポインタを得ると、とんでもないことになる。

問題の根本は、BLOCKID.blockの型を2バイトから4バイトにしたことにある。特殊なアクセスをすると、この4バイトの上位2バイトに得体の知れない値「0xc000」が含まれてしまうのである。元々blockは2バイトなので、OSLockBlockマクロが64キロバイト以上移動した場所を指すことはない。しかし、NSFItemInfoNext関数の「実装バグ」対応でBLOCKID.blockを4バイトにしたWin64 C APIプログラムでは、4バイトのblock値を受け取ってしまう。上位に「0xc000」という値が入ってしまえば、OSLockBlockマクロはとんでもない場所をポインタとして返してしまう。もちろんこのポインタでメモリアクセスすれば、保護違反でクラッシュする。幸い今まで上位2バイトに0以外が入ったことがなかっただけで、0以外が入らない保証はなく、この危険性は大いにあったわけである。

DBLOCK、DBLOCKIDの存在

この事案に直面した折、あらためてC APIヘッダファイルを確認したところ、BLOCK、BLOCKID以外に4バイト版とも言うべき以下の型を発見した。いずれもpool.hヘッダファイルである。

typedef DWORD DBLOCK; /* dpool block handle */

typedef struct /* Pointer to any block in any pool */
{
  DHANDLE pool; /* pool handle */
  DBLOCK block; /* block handle */
} DBLOCKID;

これらがWindows64ビット版で活用されてもいいところだが、残念ながら、APIツールキット9.0.1上では、これらは宣言されているだけで、NSFItemInfoNext関数などには全く利用されていない。

う〜む、またしても小手先で対応しなければならないではないか!

対応策

今回も、Windows64ビット版限定の対応とする。

// pool.hの54行目
#define    OSLockBlock(type,blockid) \
  ((type far *)(OSLock(char,(blockid).pool) + (blockid).block))

これを次のように書き換える。

#ifdef W64
#define    OSLockBlock(type,blockid) \
  ((type far *)(OSLock(char,(blockid).pool) + ((blockid).block & 0x0000ffff)))
#else
#define    OSLockBlock(type,blockid) \
  ((type far *)(OSLock(char,(blockid).pool) + (blockid).block))
#endif

BLOCKID.blockの値上位ビットをビットマスクでバッサリ切り捨てる。そもそもマクロやビットマスクの対応も、C++11以降のモダンC++の世界でどうかと思うが、まあこれはCのためのものなので、出しゃばったまねはしないようにする。

まとめ

クラッシュの原因特定まで時間を要した。「特殊なアクセス」という限定的な条件のときだけ起こるクラッシュ。その差分からとんちんかんな方向にも時間を費やした。最終的に、自分が書いた昔の記事に助けられた。こんな状況、海外も含めて同志がいないのもなかなかさみしいものだが、また一つ、自分の成長を実感できたことは嬉しい。

最後にもう一つ、HCLのNotes/Domino担当の皆さん、C APIのサポートってどうなっていますか?

mongodb c++ driver(windows 64)をビルド/インストールする。

目標

MongoDB C++ Driverをインストールして、C++からMongoDBを操作できるようにする。

公式ガイドはこちら。

mongocxx.org

日本語で参考にしたのはこちら。

qiita.com

環境

日本語で参考にした記事にはVS2017を使ったとあるが、後述するようにVS2017ではビルドできなかったので、VS2015を使う。

準備

Visual C++ 2015をインストール

visualstudio.microsoft.com

CMakeをインストール

VS用のMakefileを作成するために使用する。

cmake.org

Boostをインストール

MongoDB C++ DriverではC++17の機能を使用するため、対応していないコンパイラではC++17ポリフィルが必要になる。公式ガイドによると、MSVCではBoostが唯一の道だとある。Boost C++ Librariesは基本的にソースコードだけでいいはずだが、プリコンパイル版もあるので、そちらを使うことにする。

sourceforge.net

上記サイトから、最新版のboost_x_y_z-msvc-14.0-64.exeをダウンロードして、インストールしておく。デフォルトのままインストールすれば、C:/local/boost_x_y_xにインストールされる。

MongoDB C DriverとBSON libraryをインストールする。

2種類入れるような書き方だが、操作自体は単一。できあがるDLLが2つになるイメージ。

公式ガイドはこちら。

mongoc.org

ダウンロードサイトはこちら。

github.com

日本語で参考にしたのはこちら。

qiita.com

ダウンロードしたtar.gzファイルを、ここではC:¥tmp以下に展開する。 (Source codeリンクからダウンロードしたものは、中身は似ているが、cmakeでエラーとなってしまうので、必ずmongo-c-driver-x.y.z.tar.gzのリンクからダウンロードするように)

Visual Studio 2015のx64 Native Toolsコマンドプロンプトを起動して、以下のように進める。

cd /d C:\tmp\mongo-c-driver-1.15.1
mkdir cmake-build
cd cmake-build
"C:\Program Files\CMake\bin\cmake.exe" -G "Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=C:\mongo-c-driver" "-DCMAKE_PREFIX_PATH=C:\mongo-c-driver" ..

最後の .. が非常に重要なので、忘れないようにする。 C:\mongo-c-driverの部分は任意で変えられる。インストール先を変えたい場合は変更する。

  • 追記2020-1-15

このままだとデバッグビルドになる。リリースビルドにしたい場合は、以下のオプションを追加する。

-DCMAKE_BUILD_TYPE=Release

続いてビルドする。

msbuild.exe /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj

大量の警告が出てもエラーが0なら問題ない(と思う)。 続いてインストールする。インストールは、バイナリ(DLL)、インクルードファイル(ヘッダファイル)、ライブラリファイルを環境に配置する作業。

msbuild.exe INSTALL.vcxproj

これでC:\mongo-c-driverにMongoDB C Driverがインストールされた。

MongoDB C++ Driverをインストールする。

インストールの方法は、ほぼC Driverと同じ。下記リンクから最新版のSource codeリンクからをダウンロードして展開する。

github.com

Visual Studio 2015のx64 Native Toolsコマンドプロンプトを起動して、以下のように進める。

cd /d C:\tmp\mongo-cxx-driver-r3.4.0\build
"C:\Program Files\CMake\bin\cmake.exe" -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=C:\mongo-cxx-driver -DCMAKE_PREFIX_PATH=C:\mongo-c-driver -DBOOST_ROOT=C:\local\boost_1_71_0 ..

C Driverインストール時にC:\mongo-c-driverを変更していたら、こちらでもそれに対応しておくこと。 また、C:\mongo-cxx-driverの部分は任意で変更可能。 実行すると、最終行で-- Build files have been written to: C:/tmp/mongo-cxx-driver-r3.4.0/buildのような出力が表示されるはず。

  • 追記2020-1-15

こちらも同様。このままだとデバッグビルドになる。リリースビルドにしたい場合は、以下のオプションを追加する。

-DCMAKE_BUILD_TYPE=Release

続いてビルド、インストールする。

msbuild.exe ALL_BUILD.vcxproj
msbuild.exe INSTALL.vcxproj

VS2017

Visual Studio 2017で一連の作業を進めたところ、C++ Driverのビルドmsbuild.exe ALL_BUILD.vcxprojでエラーが出力されて、全く進めなくなった。ENABLE_EXTENDED_ALIGNED_STORAGEに関するエラーが出ているが、Boostをやめてもムダで、結局VS2015を使ってみたらエラーが出なくなった。バイナリさえできてしまえば、あとはVS2017で開発できるが、この疑問は解消されないまま。まあ、公式ガイドにVS2017のことは書いていないので、正しいといえば正しいのかな。

初めてのMongoDB C++によるレコードの作成。

私のC++開発環境はQt Creatorなので、Qt寄りで説明する。

公式ガイドのサンプルコードをアレンジして、次のようなコードを作成する。

#include <iostream>

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>

#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>

int main(int, char**) {
  try {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{}};

    bsoncxx::builder::stream::document document{};

    auto collection = conn["mydb"]["mycollection"];
    document << "say" << "Hello, MongoDB C++ Driver!";

    collection.insert_one(document.view());
    auto cursor = collection.find({});

    for (auto&& doc : cursor) {
        std::cout << bsoncxx::to_json(doc) << std::endl;
    }
  }
  catch (std::exception &ex) {
    std::cerr << ex.what() << std::endl;
  }
}

mongocxx::uri{}のところで接続したいMongoDBへのURIを書くが、ローカルに接続したいときは空で構わない。

Qtプロジェクトファイルには、インクルードパスとライブラリパスを定義しておく。Boostにもインクルードパスを通す。

INCLUDEPATH += C:/mongo-cxx-driver/include/bsoncxx/v_noabi C:/mongo-cxx-driver/include/mongocxx/v_noabi C:/local/boost_1_71_0
LIBS += -LC:/mongo-cxx-driver/lib -lmongocxx -lbsoncxx

実行時のPATH環境変数には、C++ DriverとC DriverのDLLがあるbinパスを通しておく。C++のDLLがCのDLLを参照しているため。

...;C:\mongo-cxx-driver\bin;C:\mongo-c-driver\bin

実行すると、次のように書き込まれたレコードが表示される。何回も実行すれば、IDだけ違うレコードが複数表示される。

f:id:takahide-kondoh:20191010154833p:plain

MongoDBクライアントCompassで見るとご覧の通り。

f:id:takahide-kondoh:20191010154941p:plain