はじめに
AWS IoT SDKをデバイス向けにホスト環境からクロスコンパイルして利用するというようなユースケースが結構あるかと思いますが、あまり試してみたような記事がなかったため、試してみたいと思います
AWS IoT Device SDK for embedded CをARM向けにクロスコンパイル
今回はホスト環境としてAWSのCloud9を使用します。Cloud9ではUbuntu 18.04 LTSを使用しました。
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.6 LTS
Release: 18.04
Codename: bionic
まず、適当なディレクトリを作り、本家のGithubからSDKをCloneします。Git submoduleを使っているようなので、Clone時に--recurse-submodules
のオプションを付けます。
$ git clone --recurse-submodules https://github.com/aws/aws-iot-device-sdk-embedded-C.git
X86_64環境でのビルド
まずは普通にビルドしてみます。ビルドに必要となるcmakeやgccなどをインストールします。
$ sudo apt install build-essential cmake libssl-dev
あとはGithubのREADMEに従ってビルドします。
$ cmake -S . -Bbuild -DBUILD_DEMOS=0 -DBUILD_TESTS=0
cd build/
sudo make install
ビルドが成功し、インストールが成功すると、projectディテクトリの下にSDKのライブラリが作成されます。fileコマンドで確認すると、X86-64のShared Libraryができていることが確認できます。
$ file lib/libaws_iot_mqtt.so
lib/libaws_iot_mqtt.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=2e36b1b47f4ac1811fd8f73bdaace7673d4ed2ad, not stripped
ARM向けクロスコンパイル
次にARM向けのクロスコンパイルを行います。ARM向けのToolchainをインストールします。
$ sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
$ sudo apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
次のARM向けのツールチェーンファイルを作成します。arm-toolchain.cmake
という名前のファイルを作成し、以下のように記述します。
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc)
ビルド用のディレクトリを作成し、ツールチェーンファイルを指定してcmakeコマンドを実行します。
$ mkdir cross-build
$ cd cross-build/
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=../arm-toolchain.cmake -DBUILD_DEMOS=0 -DBULD_TESTS=0
ビルドを実行します。
$ sudo make install
[ 7%] Built target aws_iot_ota
[ 8%] Built target aws_iot_json
[ 9%] Built target aws_iot_ota_http
[ 10%] Built target aws_iot_jobs
==== 中略 ======
[ 83%] Building C object CMakeFiles/ota_posix.dir/platform/posix/ota_pal/source/ota_pal_posix.c.o
In file included from /home/ubuntu/environment/SDKs/aws-iot-device-sdk-embedded-C/platform/posix/ota_pal/source/ota_pal_posix.c:38:0:
/usr/include/openssl/evp.h:13:11: fatal error: openssl/opensslconf.h: No such file or directory
# include <openssl/opensslconf.h>
^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
opensslのヘッダが見つからないというエラーになってしまいました。OpenSSLをgitからダウンロードしてARM用にコンパイルしてインストールします。
git clone https://github.com/openssl/openssl
git checkout OpenSSL_1_0_2
export CROSS=arm-linux-gnueabi
export AR=${CROSS}-ar
export AS=${CROSS}-as
export CC=${CROSS}-gcc
export CXX=${CROSS}-g++
export LD=${CROSS}-ld
./Configure --prefix=/usr/${CROSS} os/compiler:${CC}
make
sudo make install
これで、/usr/arm-linux-gnueabi/include/openssl/opensslconf.h
にヘッダが格納されました。
再度ビルド実行。
$ cd cross-build
$ sudo make install
...
[ 95%] Linking C shared library ../../../lib/libopenssl_posix.so
/usr/lib/x86_64-linux-gnu/libssl.so: file not recognized: File format not recognized
collect2: error: ld returned 1 exit status
platform/posix/transport/CMakeFiles/openssl_posix.dir/build.make:97: recipe for target 'lib/libopenssl_posix.so' failed
make[2]: *** [lib/libopenssl_posix.so] Error 1
CMakeFiles/Makefile2:762: recipe for target 'platform/posix/transport/CMakeFiles/openssl_posix.dir/all' failed
make[1]: *** [platform/posix/transport/CMakeFiles/openssl_posix.dir/all] Error 2
Makefile:129: recipe for target 'all' failed
make: *** [all] Error 2
ARM用のlibssl.soがないようです。確認すると確かに、libssl.aしかありません。Shared libraryを作成するために以下のようにビルドします。
$ ./Configure linux-generic32 shared -DL_ENDIAN --prefix=/usr/${CROSS}
$ make
$ sudo make install
libssl.soがあることを確認します。
$ sudo find / -name libssl.so
/usr/lib/x86_64-linux-gnu/libssl.so
/usr/arm-linux-gnueabi/lib/libssl.so
再度、cross-buildのディレクトリに戻って、ビルド
$ cd aws-iot-device-sdk-embedded-C/cross-build
$ sudo make install
...
-- Up-to-date: /home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/include
-- Up-to-date: /home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/include/ota_os_posix.h
-- Up-to-date: /home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/include/ota_os_freertos.h
-- Installing: /home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/lib/libclock_posix.so
-- Installing: /home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/lib/libopenssl_posix.so
-- Set runtime path of "/home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/lib/libopenssl_posix.so" to ""
-- Installing: /home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/lib/libplaintext_posix.so
-- Set runtime path of "/home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/lib/libplaintext_posix.so" to ""
-- Installing: /home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/lib/libsockets_posix.so
-- Installing: /home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/lib/libtransport_mbedtls_pkcs11_posix.so
-- Set runtime path of "/home/ubuntu/SDKs/aws-iot-device-sdk-embedded-C/project/lib/libtransport_mbedtls_pkcs11_posix.so" to ""
今度はうまく行ったようです。fileコマンドで確認すると、ARM版のShared Libraryができていることが分かります。
$ file lib/libaws_iot_mqtt.so
lib/libaws_iot_mqtt.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=e817fb93764bd61324572026cdeae0367bcc3af0, not stripped
aws-iot-device-sdk-cpp-v2をARM向けにクロスコンパイル
次に、C++向けのAWS IoT Device SDKをARM向けにクロスコンパイルしてみます。まず、適当なディレクトリにCloneします。
$ git clone --recursive https://github.com/aws/aws-iot-device-sdk-cpp-v2.git
Readmeに記載の方法で通常のビルドを行います。
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/home/ubuntu/SDKs -DCMAKE_BUILD_TYPE=Debug ../aws-iot-device-sdk-cpp-v2
$ cmake --build . --target install
.
INSTALL_PREFIXで指定した場所にライブラリが作成されます。Shared Libraryを作成したい場合には -DSHARED_LIBS
を指定します。
$ cmake -DCMAKE_INSTALL_PREFIX=/home/ubuntu/SDKs -DCMAKE_BUILD_TYPE=Debug ../aws-iot-device-sdk-cpp-v2 -DSHARED_LIBS=ON
$ cmake --build . --target install
x86_64のライブラリが作成されます。
$ file lib/libIotJobs-cpp.so
lib/libIotJobs-cpp.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=eebf46c941b1c5d594dc5e4b3bf4d4ffb26fe243, with debug_info, not stripped
次にARMむけのクロスコンパイルを行います。以下のようにarm-toolchain.cmakeファイルを用意します。
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc)
SET(CMAKE_SYSTEM_PROCESSOR arm)
cross-buildディレクトリを作成し、以下のようにビルドします。
$ mkdir cross-build
$ cd cross-build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=../arm-toolchain.cmake -DCMAKE_INSTALL_PREFIX=/home/ubuntu/SDKs/cross-build -DCMAKE_BUILD_TYPE=Debug ../aws-iot-device-sdk-cpp-v2
$ cmake --build . --target install
...
[ 33%] Building C object crt/aws-crt-cpp/crt/aws-lc/crypto/CMakeFiles/crypto.dir/x509v3/v3_utl.c.o
[ 33%] Building ASM object crt/aws-crt-cpp/crt/aws-lc/crypto/CMakeFiles/crypto.dir/chacha/chacha-armv4.S.o
[ 33%] Building ASM object crt/aws-crt-cpp/crt/aws-lc/crypto/CMakeFiles/crypto.dir/curve25519/asm/x25519-asm-arm.S.o
/home/ubuntu/SDKs/aws-iot-device-sdk-cpp-v2/crt/aws-crt-cpp/crt/aws-lc/crypto/curve25519/asm/x25519-asm-arm.S: Assembler messages:
/home/ubuntu/SDKs/aws-iot-device-sdk-cpp-v2/crt/aws-crt-cpp/crt/aws-lc/crypto/curve25519/asm/x25519-asm-arm.S:44: Error: selected processor does not support `strd r4,[sp,#0]' in ARM mode
x25519-asm-arm.Sでエラーとなってしまいます。こちらによるとx25519-asm-arm.SはNEONでのコードしか含まれていないということなので、aws-iot-device-sdk-cpp-v2/crt/aws-crt-cpp/crt/aws-lc/crypto/CMakeLists.txt から外し、再度ビルド。
[ 85%] Building CXX object crt/aws-crt-cpp/crt/aws-lc/tool/CMakeFiles/bssl.dir/sign.cc.o
[ 85%] Building CXX object crt/aws-crt-cpp/crt/aws-lc/tool/CMakeFiles/bssl.dir/speed.cc.o
[ 86%] Building CXX object crt/aws-crt-cpp/crt/aws-lc/tool/CMakeFiles/bssl.dir/tool.cc.o
[ 86%] Building CXX object crt/aws-crt-cpp/crt/aws-lc/tool/CMakeFiles/bssl.dir/transport_common.cc.o
[ 86%] Linking CXX executable bssl
../crypto/libcrypto.a(curve25519.c.o): In function `x25519_scalar_mult':
/home/ubuntu/SDKs/aws-iot-device-sdk-cpp-v2/crt/aws-crt-cpp/crt/aws-lc/crypto/curve25519/curve25519.c:2092: undefined reference to `x25519_NEON'
../crypto/libcrypto.a(curve25519.c.o): In function `X25519_public_from_private':
/home/ubuntu/SDKs/aws-iot-device-sdk-cpp-v2/crt/aws-crt-cpp/crt/aws-lc/crypto/curve25519/curve25519.c:2136: undefined reference to `x25519_NEON'
collect2: error: ld returned 1 exit status
x25519_NEONのシンボルが見つからないと言っているので、aws-iot-device-sdk-cpp-v2/crt/aws-crt-cpp/crt/aws-lc/crypto/curve25519/internal.h から#define BORINGSSL_X25519_NEON をはずす。
これで、-DCMAKE_INSTALL_PREFIXに指定した場所にライブラリが作成されます。Shared Libraryを作成する場合は、-DBUILD_SHARED_LIBS
を指定します。
$cmake .. -DCMAKE_TOOLCHAIN_FILE=../arm-toolchain.cmake -DCMAKE_INSTALL_PREFIX=/home/ubuntu/SDKs/cross-shared-build -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON ../aws-iot-device-sdk-cpp-v2
...
-- Installing: /home/ubuntu/SDKs/cross-build/lib/libIotSecureTunneling-cpp.so
-- Set runtime path of "/home/ubuntu/SDKs/cross-build/lib/libIotSecureTunneling-cpp.so" to ""
-- Up-to-date: /home/ubuntu/SDKs/cross-build/include/aws/iotsecuretunneling/Exports.h
-- Up-to-date: /home/ubuntu/SDKs/cross-build/include/aws/iotsecuretunneling/IotSecureTunnelingClient.h
-- Up-to-date: /home/ubuntu/SDKs/cross-build/include/aws/iotsecuretunneling/SecureTunnel.h
-- Up-to-date: /home/ubuntu/SDKs/cross-build/include/aws/iotsecuretunneling/SecureTunnelingNotifyResponse.h
-- Up-to-date: /home/ubuntu/SDKs/cross-build/include/aws/iotsecuretunneling/SubscribeToTunnelsNotifyRequest.h
-- Installing: /home/ubuntu/SDKs/cross-build/lib/IotSecureTunneling-cpp/cmake/shared/IotSecureTunneling-cpp-targets.cmake
-- Installing: /home/ubuntu/SDKs/cross-build/lib/IotSecureTunneling-cpp/cmake/shared/IotSecureTunneling-cpp-targets-debug.cmake
-- Installing: /home/ubuntu/SDKs/cross-build/lib/IotSecureTunneling-cpp/cmake/iotsecuretunneling-cpp-config.cmake
$ file lib/libaws-c-mqtt.so.1.0.0
lib/libaws-c-mqtt.so.1.0.0: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=f5d0d9a425432a1e94f68ae5da3422edc4571d9f, with debug_info, not stripped
ARM用の共有ライブラリが作成されていることが確認できます。
まとめ
AWS IoT Device SDK for embedded C or C++をARM向けにクロスコンパイルしました。デバイスへの導入時に参考になれば幸いです。