non vorrei lavorare

ブログ名の通りです。javascript three.js mruby rust OCaml golang julialang blender

RustでGoのライブラリを使うときのCargoのbuild.rsの書き方

こんにちは。長男の保育園最後の運動会は、雨天のため、室内でのダンスの発表のみになり、次男、長男とも曲に合わせて踊るのを見学できました。kjunichiです。

背景

gccなるクレートがあり、この使い方を知っているとC言語のライブラリを使う際はこれで便利に実現できそう。 C以外の言語をRustで使う際にどうすれば実現できるかをGoで試した。

build.rsの記述

GitHubからコードを持ってくる

以下のコードでGoのソースをgit clone出来た。

Command::new("git").args(&["clone","https://github.com/kjunichi/libimgtype.git"])
.status().unwrap();

持ってきたコードをgoでビルドして共有ライブラリを作成する

cloneしたディレクトリに入って、goのコマンドを実行する、という動作は 以下のコードで出来た。

let out_dir = env::var("OUT_DIR").unwrap();

Command::new("go").args(&["build","-buildmode=c-archive","-o"])
 .arg(&format!("{}/lib/libimgtype.a", out_dir))
 .current_dir(Path::new("libimgtype"))
 .status().unwrap();

以上、でGoでlibhoge.aを作ることのができるライブラリをソースからビルドしてCargo内で 扱うことができた。

まとめ

RustからGoの便利なライブラリを共有ライブラリ化して使う方法を編み出せた! LinuxMacではc-archiveでRustのプロジェクトに静的リンクしてしまっても 問題なさそうだが、Windowsの場合、c-archive形式だとMinGWのバイナリなのでMSVCな Rustだとリンクエラーになりそうな予感。

晴れてWindowsでのGoで共有ライブラリの出力出来れば、今回の方法で対応出来そうではある。

関連記事

Windows(MSVC)でplv8をビルドするまで

おはようございます。ちょっと前の事になりますが、休日になると体調を崩す次男でしたが、長男が習い事をしているのに、自分が何もしていないことに不満を覚え、そんな精神面からの体調不要だったのかと振り返ってみると思えます。そんな訳でで、昨日は次男も習い始めた習い事の教室へ長男とともに行きました。kjunichiです。

TL;DR

  • nugetコマンドを利用可能にする
  • CMakeコマンドを利用可能にする(choco install cmake)
  • plv8のMSVC版をクローン
git clone https://github.com/kjunichi/plv8.git
cd plv8
git checkout support-msvc
  • PostgreSQL本体のヘッダ(generic-msvc.h)を修正()
patch -u < generic-msvc.h.patch
  • MSVC環境下でcmakeでビルド
bootstrap.bat
cmake . -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX="C:\Program Files\PostgreSQL\9.6" -DPOSTGRESQL_VERSION=9.6
cmake --build . --config Release --target Package
  • 出来たZipを解凍して中身をPostgreSQLのインストール先にコピー

背景

MSVCでPostgreSQLのビルドまでは前回の記事で出来ている。 すっかり忘れていたが、思い抱いたのでやってみることにした。

調査

WinodwsのPostgreSQL向けにplv8のバイナリを配っているサイトで解説ページを発見。

概略

上記のサイトによると、MSVCで動かすのだが、PostgreSQL含めてMingw環境でビルドして、最終的に出来上がったDLLを使うというもの。 これは、主に、Unix系のPostgreSQL向けのエコシステムが前提となているビルドシステムPGXN上でビルドしている為の模様。

V8はDLLだけっぽいからMSVCでも行けそうな気がしてしまった。(これが後でダメだと分かるのだが。。)

make staticでエラー

とりあえず、手元のMsys2?環境で64ビット向けにビルドを試みた。

PostgreSQL9.6の最新版のソースをドキドキしながらビルドしたが、あっさり成功してしまった。

しかし、plv8の最新リリース版を

make static

とREADME通りにビルドしたら、エラー。

v8のコードをgithubからクローンした後のv8のビルドツールninja周りが、Windows固有のセットアップが必要な 模様で、その辺でエラーとなってしまった。

V8を自前でビル

それではということで、MSVC環境で、plv8が要求しているバージョンのV8をビルドすることにした。

plv8が要求しているV8のバージョンは以下。

 to build the later versions of PL/v8 you need a v8 minimum version of 4.4.63.31

V8をMSVCでビルドする作戦に

dllとヘッダしか資料によると必要なさそうだったので、MSVCでのビルドを試みた

色々、あったが、結果的には不要な作業なので、自分用のメモとして 書くだけにしておく。

set DEPOT_TOOLS_WIN_TOOLCHAIN=0
set GYP_MSVS_VERSION=2015

slnファイルが作られない

このページを参考になんとか進めた。

必要だったもの

plv8本体をビルド

plv8のMakefileを直接編集してビルドしたV8の各種パスを設定した。

V8_OUTDIR = /C/Users/kjunichi/Documents/work/build/v8/out/Default
V8_SRCDIR = /C/Users/kjw_j/Documents/work/build/v8  
make 

C++の構文エラー的なものがゾロゾロ出て来た。

謎のC++エラーとの戦い

これはそこそこ長かったので、前回の記事にまとめた。

原因はPostgreSQLの内部でopenを定義していたのが原因だった

残念!リンクでシンボル参照エラー

openの定義を途中でundefして遂にすべてのコードをコンパイルが通った! しかし、V8の関数のシンボルらしものが、軒並みシンボル参照未解決となってしまった。

そういえば、Cはstdcallとかccallを合わせる程度でABI互換だけど、C++は全く互換性がcl.exeとg++.exeにはないというような 話を思い出した。。。

C++なdllはそもそもMinGWと互換性ないのでは疑惑

上記の懸念を確認すべく、そもそもビルドしたV8が使えないのかどうかを、MSVCの処理系で確認することにした。

cl.exeでhello-worldはビルド出来た。

hello-world.ccが動かない!

ninjaでのビルドしたexeは動くが 自前でcl.exeコマンドでビルドするとだめ

原因?

環境変数LIBにV8のビルド結果のパスを指定していたのが原因っぽい。 必要な.dll.libファイルのみをフルパス指定することで解決した。

補足

にあるように、ちょっと前のNode.jsのセキュリティ問題に関連するのかもな スナップショットイメージファイルを2つカレントに置くこともお忘れなく。

ということで、V8自体は問題なさそうで、MSVCでビルドしている為に、gccでリンクが出来ない可能性が高まった。

ただ、このスナップショットイメージを使うV8は今回は動かしていない。。。 plv8がどこのカレントディレクトリで動いているかが分からず、PostgreSQL配下のbinやlibに置いては見たが、いずれもダメだった。

MSVCでplv8のビルドを試みる

もともと、MSVCでPostgresをビルドしたのも、MSVC環境で機能拡張をビルドする環境の 下準備をしていたわけで、MinGW作戦を諦め、当初の作戦にもどってさらに進めることにした。

contribフォルダに入れてビルドしてみた

前述のページによると、PostgreSQLのソースツリーがあれば、そこに置けば、ビルドできんじゃね?的な記述を見かけたので、 試してみたが、

plv8.sqlに必要なplv8.sql.inがないというエラーが出たので、 plv8.sql.commonをplv8.sqlにリネームしたら動き出した。

releaseフォルダ内にplv8フォルダができるが、 dllは作成されない。

ということで、早々に諦めて、明示的にCMakeでビルドする作戦に移った。

CMakeでのビルド

cmake . -G "Visual Studio 14 2015 Win64"  -DCMAKE_INSTALL_PREFIX="C:\Program Files\PostgreSQL\9.6" -DPOSTGRESQL_VERSION=9.6
cmake --build . --config Release

PostgreSQL本体のヘッダの修正

  • generic-msvc.h

手動インストール

sqlを以下のフォルダにコピー

C:\Program Files\PostgreSQL\9.6\share\extension

DLLの中身がない問題

どうやらエクスポートされていない

plv8のコードを修正

PG_FUNCTION_INFO_V1の手前に宣言文を移動して対応

PGDLLEXPORT Datum plv8_call_handler(PG_FUNCTION_ARGS);
PGDLLEXPORT Datum plv8_call_validator(PG_FUNCTION_ARGS);
PGDLLEXPORT Datum plcoffee_call_handler(PG_FUNCTION_ARGS);
PGDLLEXPORT Datum plcoffee_call_validator(PG_FUNCTION_ARGS);
PGDLLEXPORT Datum plls_call_handler(PG_FUNCTION_ARGS);
PGDLLEXPORT Datum plls_call_validator(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(plv8_call_handler);
PG_FUNCTION_INFO_V1(plv8_call_validator);
PG_FUNCTION_INFO_V1(plcoffee_call_handler);
PG_FUNCTION_INFO_V1(plcoffee_call_validator);
PG_FUNCTION_INFO_V1(plls_call_handler);
PG_FUNCTION_INFO_V1(plls_call_validator);

_PG_initも必要だった

PGDLLEXPORT void _PG_init(void);

スナップショットが不要な版を導入

自前でビルドしたV8だとスナップショットを使おうとして、そこで落ちてしまったので、 ダメもとで、NugetからV8をplv8で要求している版に合うものを選んで落とした。

nuget install v8-v140-x64 -Version 5.8.283.38

結果

動いた!

まとめ

PostgreSQL9.6向けのplv8をWindows環境でもビルド出来た。 バイナリ配布しているものは1系のモノなので、2系のものが出来たので、 それなりにこの記事の価値は高いのではと自己満足気味w。

一応、日本語で記事書くだけではもったいないので、本家へもプルリク出してます。

関連記事

PostgreSQLの機能拡張をWindowsでC++混在で作ろうとするとハマると分かった事2点

おはようございます。来年の4月からは小学生になる長男は、園の近所の小学校から学芸会に招待され、小学校を見学してきました。卒園生もその小学校には通っており、ひさしぶりに、小学生になったお兄さん、お姉さんにもあえた様でした。kjunichiです。

背景

WindowsPlv8を自前でビルドを試みていた。 諸事情によりMinGWとMSVCを行ったり来たりして作業していた。

stream関連を使おうとするとエラーが出る

1点目は、fstream関連を使おうとするとエラーが出る。

$ g++ -Wall -O2 -std=c++11 -fno-rtti  -I. -I./  -IC:/msys64/home/kjw_j/local/pg96/include/POSTGR~1/server  -IC:/msys64/home/kjw_j/local/pg96/include/POSTGR~1/internal  -IC:/msys64/home/kjw_j/local/pg96/include/POSTGR~1/server/port/win32  -I/C/Users/kjw_j/Documents/work/build/v8  -I/C/Users/kjw_j/Documents/work/build/v8/include -o ch1 ch1.cc
In file included from ch1.cc:9:0:
C:/msys64/mingw64/include/c++/7.2.0/fstream:297:54: error: macro "open" requires 3 arguments, but only 2 given
       open(const char* __s, ios_base::openmode __mode);
                                                      ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:307:61: error: macro "open" requires 3 arguments, but only 2 given
       open(const std::string& __s, ios_base::openmode __mode)
                                                             ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:308:40: error: macro "open" requires 3 arguments, but only 2 given
       { return open(__s.c_str(), __mode); }
                                        ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:499:24: error: macro "open" requires 3 arguments, but only 2 given
  this->open(__s, __mode);
                        ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:516:24: error: macro "open" requires 3 arguments, but only 2 given
  this->open(__s, __mode);
                        ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:595:69: error: macro "open" requires 3 arguments, but only 2 given
       open(const char* __s, ios_base::openmode __mode = ios_base::in)
                                                                     ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:597:49: error: macro "open" requires 3 arguments, but only 2 given
  if (!_M_filebuf.open(__s, __mode | ios_base::in))
                                                 ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:615:76: error: macro "open" requires 3 arguments, but only 2 given
       open(const std::string& __s, ios_base::openmode __mode = ios_base::in)
                                                                            ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:617:49: error: macro "open" requires 3 arguments, but only 2 given
  if (!_M_filebuf.open(__s, __mode | ios_base::in))
                                                 ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:702:24: error: macro "open" requires 3 arguments, but only 2 given
  this->open(__s, __mode);
                        ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:720:24: error: macro "open" requires 3 arguments, but only 2 given
  this->open(__s, __mode);
                        ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:800:64: error: macro "open" requires 3 arguments, but only 2 given
     ios_base::openmode __mode = ios_base::out | ios_base::trunc)
                                                                ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:802:50: error: macro "open" requires 3 arguments, but only 2 given
  if (!_M_filebuf.open(__s, __mode | ios_base::out))
                                                  ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:821:64: error: macro "open" requires 3 arguments, but only 2 given
     ios_base::openmode __mode = ios_base::out | ios_base::trunc)
                                                                ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:823:50: error: macro "open" requires 3 arguments, but only 2 given
  if (!_M_filebuf.open(__s, __mode | ios_base::out))
                                                  ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:907:24: error: macro "open" requires 3 arguments, but only 2 given
  this->open(__s, __mode);
                        ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:922:24: error: macro "open" requires 3 arguments, but only 2 given
  this->open(__s, __mode);
                        ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:1002:61: error: macro "open" requires 3 arguments, but only 2 given
     ios_base::openmode __mode = ios_base::in | ios_base::out)
                                                             ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:1004:34: error: macro "open" requires 3 arguments, but only 2 given
  if (!_M_filebuf.open(__s, __mode))
                                  ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:1023:61: error: macro "open" requires 3 arguments, but only 2 given
     ios_base::openmode __mode = ios_base::in | ios_base::out)
                                                             ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:1025:34: error: macro "open" requires 3 arguments, but only 2 given
  if (!_M_filebuf.open(__s, __mode))
                                  ^
In file included from C:/msys64/mingw64/include/c++/7.2.0/fstream:1081:0,
                 from ch1.cc:9:
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:179:52: error: macro "open" requires 3 arguments, but only 2 given
     open(const char* __s, ios_base::openmode __mode)
                                                    ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:184:28: error: macro "open" requires 3 arguments, but only 2 given
    _M_file.open(__s, __mode);
                            ^
In file included from ch1.cc:9:0:
C:/msys64/mingw64/include/c++/7.2.0/fstream:308:43: error: expected ';' at end of member declaration
       { return open(__s.c_str(), __mode); }
                                           ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:308:43: error: redeclaration of 'std::basic_filebuf<_CharT, _Traits>::__filebuf_type* std::basic_filebuf<_CharT, _Traits>::open'
C:/msys64/mingw64/include/c++/7.2.0/fstream:297:7: note: previous declaration 'std::basic_filebuf<_CharT, _Traits>::__filebuf_type* std::basic_filebuf<_CharT, _Traits>::open'
       open(const char* __s, ios_base::openmode __mode);
       ^~~~
C:/msys64/mingw64/include/c++/7.2.0/fstream:308:9: error: expected primary-expression before 'return'
       { return open(__s.c_str(), __mode); }
         ^~~~~~
C:/msys64/mingw64/include/c++/7.2.0/fstream:308:9: error: expected '}' before 'return'
C:/msys64/mingw64/include/c++/7.2.0/fstream:308:9: error: expected ';' before 'return'
C:/msys64/mingw64/include/c++/7.2.0/fstream:603:7: error: variable or field 'open' declared void
       }
       ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:603:7: error: expected ';' at end of member declaration
C:/msys64/mingw64/include/c++/7.2.0/fstream:623:7: error: variable or field 'open' declared void
       }
       ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:623:7: error: expected ';' at end of member declaration
C:/msys64/mingw64/include/c++/7.2.0/fstream:808:7: error: variable or field 'open' declared void
       }
       ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:808:7: error: expected ';' at end of member declaration
C:/msys64/mingw64/include/c++/7.2.0/fstream:829:7: error: variable or field 'open' declared void
       }
       ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:829:7: error: expected ';' at end of member declaration
C:/msys64/mingw64/include/c++/7.2.0/fstream:1010:7: error: variable or field 'open' declared void
       }
       ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:1010:7: error: expected ';' at end of member declaration
C:/msys64/mingw64/include/c++/7.2.0/fstream:1031:7: error: variable or field 'open' declared void
       }
       ^
C:/msys64/mingw64/include/c++/7.2.0/fstream:1031:7: error: expected ';' at end of member declaration
In file included from C:/msys64/mingw64/include/c++/7.2.0/fstream:1081:0,
                 from ch1.cc:9:
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:179:5: error: 'std::basic_filebuf<_CharT, _Traits>::__filebuf_type* std::basic_filebuf<_CharT, _Traits>::open' is not a static data member of 'class std::basic_filebuf<_CharT, _Traits>'
     open(const char* __s, ios_base::openmode __mode)
     ^~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:179:5: error: template definition of non-template 'std::basic_filebuf<_CharT, _Traits>::__filebuf_type* std::basic_filebuf<_CharT, _Traits>::open'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:181:22: error: expected primary-expression before '*' token
       __filebuf_type *__ret = 0;
                      ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:181:23: error: '__ret' was not declared in this scope
       __filebuf_type *__ret = 0;
                       ^~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:181:23: note: suggested alternative: '_creat'
       __filebuf_type *__ret = 0;
                       ^~~~~
                       _creat
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:181:32: error: expected '}' before ';' token
       __filebuf_type *__ret = 0;
                                ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:182:7: error: expected unqualified-id before 'if'
       if (!this->is_open())
       ^~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:207:7: error: expected unqualified-id before 'return'
       return __ret;
       ^~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:211:14: error: expected nested-name-specifier before 'basic_filebuf'
     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
              ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:211:27: error: expected initializer before '<' token
     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
                           ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:261:5: error: 'streamsize' does not name a type; did you mean 'HeapSize'?
     streamsize
     ^~~~~~~~~~
     HeapSize
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:287:14: error: expected nested-name-specifier before 'basic_filebuf'
     typename basic_filebuf<_CharT, _Traits>::int_type
              ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:287:27: error: expected initializer before '<' token
     typename basic_filebuf<_CharT, _Traits>::int_type
                           ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:446:14: error: expected nested-name-specifier before 'basic_filebuf'
     typename basic_filebuf<_CharT, _Traits>::int_type
              ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:446:27: error: expected initializer before '<' token
     typename basic_filebuf<_CharT, _Traits>::int_type
                           ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:505:14: error: expected nested-name-specifier before 'basic_filebuf'
     typename basic_filebuf<_CharT, _Traits>::int_type
              ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:505:27: error: expected initializer before '<' token
     typename basic_filebuf<_CharT, _Traits>::int_type
                           ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:571:18: error: expected initializer before '<' token
     basic_filebuf<_CharT, _Traits>::
                  ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:633:5: error: 'streamsize' does not name a type; did you mean 'HeapSize'?
     streamsize
     ^~~~~~~~~~
     HeapSize
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:721:5: error: 'streamsize' does not name a type; did you mean 'HeapSize'?
     streamsize
     ^~~~~~~~~~
     HeapSize
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:769:14: error: expected nested-name-specifier before 'basic_filebuf'
     typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
              ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:769:27: error: expected initializer before '<' token
     typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
                           ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:798:14: error: expected nested-name-specifier before 'basic_filebuf'
     typename basic_filebuf<_CharT, _Traits>::pos_type
              ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:798:27: error: expected initializer before '<' token
     typename basic_filebuf<_CharT, _Traits>::pos_type
                           ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:858:14: error: expected nested-name-specifier before 'basic_filebuf'
     typename basic_filebuf<_CharT, _Traits>::pos_type
              ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:858:27: error: expected initializer before '<' token
     typename basic_filebuf<_CharT, _Traits>::pos_type
                           ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:873:14: error: expected nested-name-specifier before 'basic_filebuf'
     typename basic_filebuf<_CharT, _Traits>::pos_type
              ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:873:27: error: expected initializer before '<' token
     typename basic_filebuf<_CharT, _Traits>::pos_type
                           ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:899:22: error: expected initializer before '<' token
     int basic_filebuf<_CharT, _Traits>::
                      ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:918:18: error: expected initializer before '<' token
     basic_filebuf<_CharT, _Traits>::
                  ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:979:18: error: expected initializer before '<' token
     basic_filebuf<_CharT, _Traits>::
                  ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:996:18: error: expected initializer before '<' token
     basic_filebuf<_CharT, _Traits>::
                  ^
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1053:25: error: 'basic_filebuf' is not a class template
   extern template class basic_filebuf<char>;
                         ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1053:25: error: explicit instantiation of non-template type 'basic_filebuf'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1054:25: error: 'basic_ifstream' is not a class template
   extern template class basic_ifstream<char>;
                         ^~~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1054:25: error: explicit instantiation of non-template type 'basic_ifstream'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1055:25: error: 'basic_ofstream' is not a class template
   extern template class basic_ofstream<char>;
                         ^~~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1055:25: error: explicit instantiation of non-template type 'basic_ofstream'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1056:25: error: 'basic_fstream' is not a class template
   extern template class basic_fstream<char>;
                         ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1056:25: error: explicit instantiation of non-template type 'basic_fstream'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1059:25: error: 'basic_filebuf' is not a class template
   extern template class basic_filebuf<wchar_t>;
                         ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1059:25: error: explicit instantiation of non-template type 'basic_filebuf'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1060:25: error: 'basic_ifstream' is not a class template
   extern template class basic_ifstream<wchar_t>;
                         ^~~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1060:25: error: explicit instantiation of non-template type 'basic_ifstream'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1061:25: error: 'basic_ofstream' is not a class template
   extern template class basic_ofstream<wchar_t>;
                         ^~~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1061:25: error: explicit instantiation of non-template type 'basic_ofstream'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1062:25: error: 'basic_fstream' is not a class template
   extern template class basic_fstream<wchar_t>;
                         ^~~~~~~~~~~~~
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1062:25: error: explicit instantiation of non-template type 'basic_fstream'
C:/msys64/mingw64/include/c++/7.2.0/bits/fstream.tcc:1067:1: error: expected declaration before '}' token
 } // namespace std
 ^

当初、Mingwのg++を疑い、pacmanコマンドをググって更新したが、エラーが出たまま。

仕方がないので、ミニマムケースを調査した。

#include <fstream>                                                                                                        
int main(){return 0;}

こちらはOK。g++がはずれ版という訳では無さそう。

次に、イマイチビルド方法も良く理解できずビルドしたV8が悪さしてないかを 確認。

#include <v8.h>                                                                                                           
#include <fstream>                                                                                                        
int main(){return 0;}

ビルドコマンドは

gcc -Wall -O2 -std=c++11 -fno-rtti  -I. -I./ \
 -I/C/Users/kjunichi/Documents/work/build/v8 \
 -I/C/Users/kjunichi/Documents/work/build/v8/include \
-v test2.cc

こちらもOK

#include <v8.h>                                                                                                           
#include <vector>                                                                                                         
#include <string>                                                                                                         
extern "C" {                                                                                                              
#include "postgres.h"                                                                                                     
}                                                                                                                         
#include <fstream>                                                                                                        
int main(){return 0;}

今度は、PostgreSQLのヘッダディレクトリもインクルードパスに追加して、 結構ゴツいコマンドにw

gcc -Wall -O2 -std=c++11 -fno-rtti  -I. -I./ \
 -IC:/msys64/home/kjw_j/local/pg96/include/POSTGR~1/server \
 -IC:/msys64/home/kjw_j/local/pg96/include/POSTGR~1/internal \
 -IC:/msys64/home/kjw_j/local/pg96/include/POSTGR~1/server/port/win32 \
 -I/C/Users/kjunichi/Documents/work/build/v8 \
 -I/C/Users/kjunichi/Documents/work/build/v8/include \
-v test3.cc

これがNGでした。

ということで、PostgreSQLが何かやってることが原因と分かりました。

さらに調査を進めると、postgres.h配下にopenが定義してあり、それが、今回のエラーの原因となっている ことが分かりました。

PostgreSQL/9.6/include/server/port.h
289:#define          open(a,b,c) pgwin32_open(a,b,c)                             

ここで、Windowsプラットフォームの場合、PostgreSQLが用意したopen関数をマクロで定義していおり、 これがビルドの通らない原因となっていました。

対処しては、PostgreSQLのヘッダ内でopenをマクロで定義しているから、これを出たところで、

undefするという方法をとりました。

#include "plv8_config.h"                                                                                                  
#include <v8.h>                                                                                                           
#include <vector>                                                                                                         
#include <string>                                                                                                         
extern "C" {                                                                                                              
#include "postgres.h"                                                                                                     
}                                                                                                                         
#undef open                                                                                                               
#include <fstream>                                                                                                        
int main(){return 0;}  

これで、g++から怒られなくなりました。

generic-msvc.hでエラーになる

  C:\Program Files\PostgreSQL\9.6\include\server\port/atomics/generic-msvc.h(79): error C2664: '__int64 _InterlockedCom pareExchange64(volatile __int64 *,__int64,__int64)': 引数 1 を 'volatile uint64 *' から 'volatile __int64 *' へ変換でき
ません。 [C:\U
sers\kjw_j\Documents\work\plv8msvccheck\libplv8.vcxproj]
  C:\Program Files\PostgreSQL\9.6\include\server\port/atomics/generic-msvc.h(93): error C2664: '__int64 _InterlockedExc hangeAdd64(volatile __int64 *,__int64)': 引数 1 を 'volatile uint64 *' から 'volatile __int64 *' へ変換できません。 [C:\
Users\kjw_j\D
ocuments\work\plv8msvccheck\libplv8.vcxproj]
  C:\Program Files\PostgreSQL\9.6\include\server\port/atomics/generic-msvc.h(79): error C2664: '__int64 _InterlockedCom pareExchange64(volatile __int64 *,__int64,__int64)': 引数 1 を 'volatile uint64 *' から 'volatile __int64 *' へ変換でき
ません。 [C:\U
sers\kjw_j\Documents\work\plv8msvccheck\libplv8.vcxproj]
  C:\Program Files\PostgreSQL\9.6\include\server\port/atomics/generic-msvc.h(93): error C2664: '__int64 _InterlockedExc hangeAdd64(volatile __int64 *,__int64)': 引数 1 を 'volatile uint64 *' から 'volatile __int64 *' へ変換できません。 [C:\
Users\kjw_j\D
ocuments\work\plv8msvccheck\libplv8.vcxproj]

これはgccだと通らないヘッダの為、MSVC環境で作業していて発生しました。

こちらは、cl.exeのエラーをよく読めば、書いてある通りだが、 Windows側のAPIへ渡すポインタがsingned int型なのに、PostgreSQL側からはunsigned int型を 渡している為、Cでは問題にならないが、C++では型の符号あり・なしも明確に区別しているようで、これに 抵触してコンパイラーがエラーを出していました。

以下の様の問題の箇所をキャストをつけて修正

static inline bool
pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
                                    uint64 *expected, uint64 newval) {
  bool ret;
  uint64 current;
  current =
      _InterlockedCompareExchange64((int64 *)&ptr->value, newval, *expected);
  ret = current == *expected;
  *expected = current;
  return ret;
}
#define PG_HAVE_ATOMIC_FETCH_ADD_U64
static inline uint64
pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_) {
  return _InterlockedExchangeAdd64((int64 *)&ptr->value, add_);
}

まとめ

PostgreSQLの機能拡張をWindowsC++も組み合わせると、

  • open関数をマクロでPostgreSQL独自のopen関数に置き換えているので、そのままでは、C++のfstream系の処理が利用できない。
  • 符号の有無のチェックが厳格になり、MSVCでは、generic-msvc.hでエラーになる。

関連記事