h2oをraspberry pi用にcross compileする

HTTP/2に最適化されたhttpdのh2oは64bit環境前提に作られている(Raspbianは32bit)が、とりあえずやってみた

# 前提
* h2oはcmakeに対応しているので、cmakeを利用してcross compileを行う
* cross compile環境はdocker上に作ったCentOS7環境

cross compilerをインストールしておく
`/opt/rpi/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64`
環境変数CROSS_COMPILEをセットしておく
 `export CROSS_COMPILE=arm-linux-gnueabihf-`

# zlib

```build.sh
        ZLIB_VERSION=1.2.11
        if [ ! -d zlib-${ZLIB_VERSION} ]; then
                curl -L http://prdownloads.sourceforge.net/libpng/zlib-${ZLIB_VERSION}.tar.gz?download | tar zx
        fi

        cd zlib-${ZLIB_VERSION}
        CC=${CROSS_COMPILE}gcc ./configure --prefix=${SYSROOT} && make && make install
        cd ..
```

# libressl
libresslは--hostの指定と、CCなどを設定して対応した

```libressl_linux-arm.mk
$(DEST)/lib/libssl.a: $(ARCHIVE)
 	if [ ! -e "libressl-$(VERSION)" ] ; then tar xzf "$(ARCHIVE)" ; fi
-	if [ ! -e "libressl-$(VERSION)/Makefile" ] ; then (P=`pwd`/$(DEST); cd libressl-$(VERSION) && ./configure --prefix="$$P" --libdir="$$P/lib" --disable-shared `test "$(UNAME)" = "Darwin" && echo '--disable-asm'`) ; fi
+	if [ ! -e "libressl-$(VERSION)/Makefile" ] ; then (P=`pwd`/$(DEST); cd libressl-$(VERSION) && CC=${CROSS_COMPILE}gcc LD=${CROSS_COMPILE}ld CCLD=$LD AR=${CROSS_COMPILE}ar CXX=${CROSS_COMPILE}g++ CPP=${CROSS_COMPILE}cpp RANLIB=${CROSS_COMPILE}ranlib ./configure --host=arm-linux-gnueabi --prefix="$$P" --libdir="$$P/lib" --disable-shared `test "$(UNAME)" = "Darwin" && echo '--disable-asm'`) ; fi
 	(cd libressl-$(VERSION) && make && make install)
```

# mruby
mrubyのbuildにcrubyを使う。
mruby自体にcross compileの対応がしてあるため、rubyの設定ファイルを書く
mrubyルートディレクトリにあるbuild_conf.rbを参考にしながら`MRuby::CrossBuild.new`を使う


```mruby_config_linux-arm.rb
MRuby::CrossBuild.new('arm-linux-gnueabi') do |conf|
  toolchain :gcc

  conf.cc.command       = ENV['CROSS_COMPILE'] + 'gcc'
  conf.cxx.command      = ENV['CROSS_COMPILE'] + 'g++'
  conf.linker.command   = ENV['CROSS_COMPILE'] + 'gcc'
  conf.archiver.command = ENV['CROSS_COMPILE'] + 'ar'
#  conf.cc.flags << "-m32"
#  conf.linker.flags << "-m32"

  # use mrbgems
  Dir.glob("../mruby-*/mrbgem.rake") do |x|
    g = File.basename File.dirname x
    if g == 'mruby-onig-regexp'
      conf.gem "../deps/#{g}" do |c|
        c.bundle_onigmo
      end
    else
      conf.gem "../deps/#{g}"
    end
  end

  # include all the core GEMs
  conf.gembox 'full-core'

  conf.build_mrbtest_lib_only

  #conf.gem 'examples/mrbgems/c_and_ruby_extension_example'

  conf.test_runner.command = 'env'

end
```


mruby-file-statのクロスコンパイルに失敗するため、以下のパッチを適用する

```mruby-file-stat_cross.patch
diff --git a/deps/mruby-file-stat/mrbgem.rake b/deps/mruby-file-stat/mrbgem.rake
index ff7d076b..133aee1f 100644
--- a/deps/mruby-file-stat/mrbgem.rake
+++ b/deps/mruby-file-stat/mrbgem.rake
@@ -14,12 +14,16 @@ MRuby::Gem::Specification.new('mruby-file-stat') do |spec|
   file config do
     FileUtils.mkdir_p build_dir, :verbose => true
     Dir.chdir build_dir do
+      if build.kind_of? MRuby::CrossBuild
+        host = "--host=#{build.name}"
+      end
+
       if ENV['OS'] == 'Windows_NT'
         _pp 'on Windows', dir
         FileUtils.touch "#{build_dir}/config.h", :verbose => true
       else
         _pp './configure', dir
-        system env, "#{dir}/configure"
+        system env, "#{dir}/configure #{host}"
       end
     end
   end

```


# h2o
cmakeを利用したcross compile。
CMAKE_TOOLCHAIN_FILEを指定し、raspberry pi用のcmakeファイルを作る

```linux-arm.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_SYSROOT /opt/rpi/rootfs)
set(CMAKE_STAGING_PREFIX /home/data/target)

set(tools /opt/rpi/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64)
set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
#set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)

set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT} ${CMAKE_STAGING_PREFIX})

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
```

今まで諸々やってきたことをCMakeLists.txtへのpatchとして作る
アーカイブのパスがhostに依存しているため、cross compile時に切り替えられるようにしておく

```cross.patch
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e95190b..0dbf8384 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,7 +75,12 @@ OPTION(WITH_PICOTLS "whether or not to build with picotls" "ON")
 IF (WITH_BUNDLED_SSL)
     SET(BUNDLED_SSL_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/libressl-build/include")
     SET(BUNDLED_SSL_LIBRARIES "${CMAKE_CURRENT_BINARY_DIR}/libressl-build/lib/libssl.a" "${CMAKE_CURRENT_BINARY_DIR}/libressl-build/lib/libcrypto.a")
-    ADD_CUSTOM_TARGET(bundled-ssl make -f ${CMAKE_CURRENT_SOURCE_DIR}/misc/libressl.mk SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/misc
+    IF (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
+        SET(BUNDLED_SSL_CONFIG "libressl_linux-arm.mk")
+    ELSE ()
+        SET(BUNDLED_SSL_CONFIG "libressl.mk")
+    ENDIF ()
+    ADD_CUSTOM_TARGET(bundled-ssl make -f ${CMAKE_CURRENT_SOURCE_DIR}/misc/${BUNDLED_SSL_CONFIG} SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/misc
         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
 ELSE (WITH_BUNDLED_SSL)
     IF (NOT OPENSSL_FOUND)
@@ -445,7 +450,12 @@ IF (WITH_MRUBY)
     ELSE ()
         SET(MRUBY_TOOLCHAIN "gcc")
     ENDIF ()
-    ADD_CUSTOM_TARGET(mruby MRUBY_TOOLCHAIN=${MRUBY_TOOLCHAIN} MRUBY_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/misc/mruby_config.rb MRUBY_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}/mruby ruby minirake
+    IF (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
+        SET(CMAKE_MRUBY_CONFIG "mruby_config_linux-arm.rb")
+    ELSE ()
+        SET(CMAKE_MRUBY_CONFIG "mruby_config.rb")
+    ENDIF ()
+    ADD_CUSTOM_TARGET(mruby MRUBY_TOOLCHAIN=${MRUBY_TOOLCHAIN} MRUBY_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/misc/${CMAKE_MRUBY_CONFIG} MRUBY_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}/mruby ruby minirake
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/deps/mruby)
     LIST(APPEND STANDALONE_SOURCE_FILES
         lib/handler/mruby.c
@@ -473,10 +483,16 @@ ELSE (WITH_BUNDLED_SSL)
 ENDIF (WITH_BUNDLED_SSL)
 IF (WITH_MRUBY)
     TARGET_INCLUDE_DIRECTORIES(h2o BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/deps/mruby/include ${CMAKE_CURRENT_SOURCE_DIR}/deps/mruby-input-stream/src)
+    IF (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
+        SET(CMAKE_MRUBY_AR_DIR "arm-linux-gnueabi")
+    ELSE ()
+        SET(CMAKE_MRUBY_AR_DIR "host")
+    ENDIF ()
+
     # note: the paths need to be determined before libmruby.flags.mak is generated
     TARGET_LINK_LIBRARIES(h2o
-        "${CMAKE_CURRENT_BINARY_DIR}/mruby/host/lib/libmruby.a"
-        "${CMAKE_CURRENT_BINARY_DIR}/mruby/host/mrbgems/mruby-onig-regexp/onigmo-6.1.1/.libs/libonigmo.a"
+        "${CMAKE_CURRENT_BINARY_DIR}/mruby/${CMAKE_MRUBY_AR_DIR}/lib/libmruby.a"
+        "${CMAKE_CURRENT_BINARY_DIR}/mruby/${CMAKE_MRUBY_AR_DIR}/mrbgems/mruby-onig-regexp/onigmo-6.1.1/.libs/libonigmo.a"
         "m")
     ADD_DEPENDENCIES(h2o mruby)
 ENDIF (WITH_MRUBY)
```

ビルドスクリプトは以下の通り

```build.sh
        if [ ! -d h2o ]; then
                git clone https://github.com/h2o/h2o.git
        fi

        cd h2o
        cp ../libressl_linux-arm.mk misc
        cp ../mruby_config_linux-arm.rb misc
        patch --forward -p1 < ../mruby-file-stat_cross.patch
        patch --forward -p1 < ../cross.patch
        cmake -DWITH_MRUBY=on -DCMAKE_INSTALL_PREFIX=$SYSROOT -DCMAKE_TOOLCHAIN_FILE=`pwd`/../linux-arm.cmake .
        make
```


今まで書いてきたことは下記のリポジトリにある
[h2o cross compile build script](https://github.com/kawaway/h2o)
cloneしてmakeする

perlが必要ならyoctoのレシピを参考にすると