non vorrei lavorare

昔はおもにプログラミングやガジェット系、今は?

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でエラーになる。

関連記事