PostgreSQLの機能拡張をWindowsでC++混在で作ろうとするとハマると分かった事2点
おはようございます。来年の4月からは小学生になる長男は、園の近所の小学校から学芸会に招待され、小学校を見学してきました。卒園生もその小学校には通っており、ひさしぶりに、小学生になったお兄さん、お姉さんにもあえた様でした。@kjunichiです。
背景
WindowsでPlv8を自前でビルドを試みていた。 諸事情により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の機能拡張をWindowsでC++も組み合わせると、
- open関数をマクロでPostgreSQL独自のopen関数に置き換えているので、そのままでは、C++のfstream系の処理が利用できない。
- 符号の有無のチェックが厳格になり、MSVCでは、generic-msvc.hでエラーになる。