Apache Arrow の Issue を watch していたら、Gandiva が Windows 環境でも動くようになっていたので、開発環境を構築しました。

C++ Development Setup

Gandiva は C++ で開発されているので、まず C++ の開発環境が必要になります。Windows の C++ の開発環境の構築に関しては、以下に記載されています。

今回は Visual Studio 2017 の Community をインストールしました。

Compile

Apache Arrow は 様々な言語に対応していますが、それらを1つの git リポジトリで管理しています。

$ git clone https://github.com/apache/arrow.git

Developing on Windows に記載されている内容に沿って、ビルドできる状態にします。

$ activate arrow-dev
$ set ARROW_BUILD_TOOLCHAIN=%CONDA_PREFIX%\Library
$ "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=amd64

ビルドは以下のとおりです。

$ cd arrow\cpp
$ mkdir build
$ cd build
$ cmake -G "NMake Makefiles" -DARROW_GANDIVA=ON -DARROW_GANDIVA_JAVA=ON -DCMAKE_BUILD_TYPE=Release ..
$ cmake --build . --config Release

Errors

error: expected function body after function declarator

D:/development/repository/git/arrow/cpp/src/gandiva/precompiled/../../arrow/vendored/datetime/date.h:229:81: error: expected function body after function declarator
CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int          m) NOEXCEPT;
                                                                                ^
D:/development/repository/git/arrow/cpp/src/gandiva/precompiled/../../arrow/vendored/datetime/date.h:101:22: note: expanded from macro 'NOEXCEPT'
#    define NOEXCEPT _NOEXCEPT

関数の最後に付いている NOEXCEPT を認識することができず、コンパイルエラー。これは以下の変更をすることで回避しています。

(arrow-dev) D:\development\repository\git\arrow\cpp\build>git diff
diff --git a/cpp/src/gandiva/precompiled/CMakeLists.txt b/cpp/src/gandiva/precompiled/CMakeLists.txt
index 6d3daf2..c98c020 100644
--- a/cpp/src/gandiva/precompiled/CMakeLists.txt
+++ b/cpp/src/gandiva/precompiled/CMakeLists.txt
@@ -35,7 +35,7 @@ if(MSVC)
   # Visual Studio 2015, and the standard library uses C++14 features,
   # so we have to use that -std version to get the IR compilation to
   # work
-  set(PLATFORM_CLANG_OPTIONS -std=c++14 -fms-compatibility -fms-compatibility-version=19)
+  set(PLATFORM_CLANG_OPTIONS -std=c++14 -fms-compatibility -fms-compatibility-version=19.10)
 else()
   set(PLATFORM_CLANG_OPTIONS -std=c++11)
 endif()

以下のページを見ると noexcept は MSVC 19.0 (VS2015) でサポートされていることになっているので、変更前の設定で合っています。Clang のバージョンに依るのかな。

https://ja.cppreference.com/w/cpp/compiler_support

Clang のバージョンは以下のとおり。

(arrow-dev) C:\development\cmder\cmder_mini_1.3.4>clang --version
clang version 7.0.0 (tags/RELEASE_700/final)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\development\python\Miniconda3\envs\arrow-dev\Library\bin

error LNK2001

   ライブラリ ..\..\..\release\gandiva_jni.lib とオブジェクト ..\..\..\release\gandiva_jni.exp を作成中
expression_registry_helper.cc.obj : error LNK2001: 外部シンボル ""class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char
> > > google::protobuf::internal::fixed_address_empty_string" (?fixed_address_empty_string@internal@protobuf@google@@3V?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@A)" は未解決です。
Types.pb.cc.obj : error LNK2001: 外部シンボル ""class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > google::prot
obuf::internal::fixed_address_empty_string" (?fixed_address_empty_string@internal@protobuf@google@@3V?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@A)" は未解決で
す。
jni_common.cc.obj : error LNK2001: 外部シンボル ""private: static int google::protobuf::io::CodedInputStream::default_recursion_limit_" (?default_recursion_limit_@CodedInputStream@io@protobuf@google@@0HA)"
は未解決です。
..\..\..\release\gandiva_jni.dll : fatal error LNK1120: 2 件の未解決の外部参照

libprotobuf の関数をリンクするあたりでエラーがでます。

以下のコマンドで libprotobuf.lib に含まれている関数を確認すると、エラーになっている関数のシグネチャが出力されるので問題ないように見えるのですが…。

link /dump /exports C:\development\python\Miniconda3\envs\arrow-dev\Library\lib\libprotobuf.lib
?fixed_address_empty_string@internal@protobuf@google@@3V?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@A (class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > google::protobuf::internal::fixed_address_empty_string)

もうちょっと調べてみると、問題はヘッダ側でした。

// Default empty string object. Don't use this directly. Instead, call
// GetEmptyString() to get the reference.
PROTOBUF_EXPORT extern ExplicitlyConstructed<::std::string>
    fixed_address_empty_string;
#if defined(_MSC_VER) && defined(PROTOBUF_USE_DLLS)
#ifdef LIBPROTOBUF_EXPORTS
#define PROTOBUF_EXPORT __declspec(dllexport)
#else
#define PROTOBUF_EXPORT __declspec(dllimport)
#endif
#ifdef LIBPROTOC_EXPORTS
#define PROTOC_EXPORT __declspec(dllexport)
#else
#define PROTOC_EXPORT __declspec(dllimport)
#endif
#else
#define PROTOBUF_EXPORT
#define PROTOC_EXPORT
#endif

以上より、以下の設定を加えています。

diff --git a/cpp/src/gandiva/jni/CMakeLists.txt b/cpp/src/gandiva/jni/CMakeLists.txt
index 680b6e5..33a7e96 100644
--- a/cpp/src/gandiva/jni/CMakeLists.txt
+++ b/cpp/src/gandiva/jni/CMakeLists.txt
@@ -19,6 +19,8 @@ if(CMAKE_VERSION VERSION_LESS 3.11)
   message(FATAL_ERROR "Building the Gandiva JNI bindings requires CMake version >= 3.11")
 endif()

+add_definitions(-DPROTOBUF_USE_DLLS)
+
 # Find JNI
 find_package(JNI REQUIRED)

Java

現時点での Java の parent の pom.xml では Gandiva がビルド対象になっていないので、Java の parent で Gandiva もビルドする場合には、以下のように pom.xml に追加する必要があります。

diff --git a/java/pom.xml b/java/pom.xml
index 9e4afcf..cdb8885 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -652,6 +652,7 @@
     <module>adapter/jdbc</module>
     <module>plasma</module>
     <module>flight</module>
+    <module>gandiva</module>
   </modules>

   <profiles>

Gandiva の test を実行する際に、C++ のビルドで生成した gandiva_jni.dll が必要になります。以下のコマンドで実行します。

mvn install -Dcheckstyle.skip -Dflatc.download.skip=true -Dgandiva.cpp.build.dir=<path to gandiva_jni.dll dir> 

また、以下の Erros で記載していますが、Windows で Arrow の Java モジュールをビルドする際に必要な flatc.exe はMaven から取得することができないので、自分でダウンロードして配置し、-Dflatc.download.skip=true をつけてビルドする必要があります。

Errors

Could not find artifact com.github.icexelloss:flatc-windows-x86_64:exe:1.9.0 in central (https://repo.maven.apache.org/maven2)

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 47.503 s
[INFO] Finished at: 2019-04-06T21:54:03+09:00
[INFO] Final Memory: 72M/464M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-dependency-plugin:3.0.1:copy (copy-flatc) on project arrow-format: Unable to find/resolve artifact.: Could not find artifact com.github.icexelloss:flatc-windows-x86_64:exe:1.9.0 in central (https://repo.maven.apache.org/maven2) -> [Help 1]

これは com.github.icexelloss:flatc-windows-x86_64:exe:1.9.0 が Maven Central Repository に無いことに起因しています。以下に対応方法が記載されています。

Conclusion

以上の手順で Windows / Java の環境で Gandiva を動かすことができました。Arrow は Windows ビルドも積極的にサポートしているので、興味がある人はぜひトライしてください。今回の変更内容は、適用する条件を整理して PR を投げるつもりです。