この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX事業本部のうらわです。
aws-sdk-cppのビルドにおいて、Apple Clangではエラーがなかったのですがbrew install llvm
で入手したClang(以降、LLVM/Clangと表記します)では同じコマンドでもエラーがありビルドに失敗してしまいました。
本記事では失敗した点とビルドに成功した対応策をご紹介します。なお、失敗した点は本記事の執筆時点の内容ですので、今後のaws-sdk-cppのアップデートで改善・解消する可能性があります。
作業環境
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.7
BuildVersion: 19H15
# cmakeはbrewでインストールしておきます
$ cmake --version
cmake version 3.18.4
$ brew info llvm
llvm: stable 11.1.0 (bottled), HEAD [keg-only]
Next-gen compiler infrastructure
https://llvm.org/
/usr/local/Cellar/llvm/11.0.0 (7,910 files, 1.2GB)
aws-sdk-cppのビルドコマンド
以下のコマンドでaws-sdk-cppをクローンしてcmakeでDynamoDBのSDKのコードのみをビルドします。全てビルドするとかなり時間がかかります。
CMAKE_INSTALL_PREFIX
を指定して任意のディレクトリにSDKをインストールします。
git clone https://github.com/aws/aws-sdk-cpp.git
cd aws-sdk-cpp
mkdir build
cd build
cmake .. -DBUILD_ONLY="dynamodb" \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX=/path/to/sdk-install-dir
make
make install
LLVM/Clangを使用する設定
MacではCommand Line Tools for XcodeをインストールするとC/C++のデフォルトのコンパイラにApple Clangが設定されます。
$ clang++ --version
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
brew install llvm
で入手したLLVM/Clangを使用するにはパスを通す必要があります。
$ export PATH="/usr/local/opt/llvm/bin:$PATH"
$ clang++ --version
clang version 11.0.0
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
ただし、パスを通しただけではaws-sdk-cppのビルド時は依然としてApple Clangが使用されます。
$ cmake .. -DBUILD_ONLY="dynamodb" \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX=/path/to/sdk-install-dir
-- Found Git: /usr/local/bin/git (found version "2.30.2")
-- TARGET_ARCH not specified; inferring host OS to be platform compilation target
-- Building AWS libraries as shared objects
-- Building project version: 1.8.160
-- The C compiler identification is AppleClang 12.0.0.12000032
-- The CXX compiler identification is AppleClang 12.0.0.12000032
...
LLVM/Clangを使うためには環境変数CC
とCXX
を以下のように設定しておきます。
$ export CC="clang"
$ export CXX="clang++"
$ cmake .. -DBUILD_ONLY="dynamodb" \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX=~/install
-- Found Git: /usr/local/bin/git (found version "2.30.2")
-- TARGET_ARCH not specified; inferring host OS to be platform compilation target
-- Building AWS libraries as shared objects
-- Building project version: 1.8.160
-- The C compiler identification is Clang 11.0.0
-- The CXX compiler identification is Clang 11.0.0
...
これでApple ClangではなくLLVM/Clangでビルドする準備ができました。
aws-c-commonビルド時のエラー
cmakeコマンド実行時に以下のエラーでビルドに失敗しました。
/path/to/aws-sdk-cpp/build/.deps/build/src/AwsCCommon/source/posix/system_info.c:136:34: error: this old-style function definition is not preceded by a prototype [-Werror,-Wstrict-prototypes]
const char *s_get_executable_path() {
^
1 error generated.
make[5]: *** [CMakeFiles/aws-c-common.dir/source/posix/system_info.c.o] Error 1
make[4]: *** [CMakeFiles/aws-c-common.dir/all] Error 2
make[3]: *** [all] Error 2
make[2]: *** [build/src/AwsCCommon-stamp/AwsCCommon-build] Error 2
make[1]: *** [CMakeFiles/AwsCCommon.dir/all] Error 2
make: *** [all] Error 2
CMake Error at CMakeLists.txt:224 (message):
Failed to build third-party libraries.
-- Configuring incomplete, errors occurred!
これはaws-c-commonリポジトリにissueがありました。issueを参考にダウンロードされたコードを直接修正することで解消しました。
/path/to/aws-sdk-cpp/build/.deps/build/src/AwsCCommon/source/posix/system_info.c
- const char *s_get_executable_path() {
+ static const char *s_get_executable_path() {
static const char *s_exe = NULL;
if (AWS_LIKELY(s_exe)) {
return s_exe;
}
uint32_t len = sizeof(s_exe_path);
if (!_NSGetExecutablePath(s_exe_path, &len)) {
s_exe = s_exe_path;
}
return s_exe;
}
make時のエラー
makeコマンド実行時、コンパイラオプションに-Werror
が設定されているため警告がエラーとなりビルドに失敗しました。
[ 41%] Building CXX object testing-resources/CMakeFiles/testing-resources.dir/source/MemoryTesting.cpp.o
In file included from /path/to/aws-sdk-cpp/testing-resources/source/MemoryTesting.cpp:9:
/path/to/aws-sdk-cpp/testing-resources/include/aws/external/gtest.h:11886:8: error: definition of implicit copy constructor for 'ValueArray2<bool, bool>' is deprecated because it has a user-declared copy assignment operator [-Werror,-Wdeprecated-copy]
void operator=(const ValueArray2& other);
^
/path/to/aws-sdk-cpp/testing-resources/include/aws/external/gtest.h:17082:10: note: in implicit copy constructor for 'testing::internal::ValueArray2<bool, bool>' first required here
return internal::ValueArray2<T1, T2>(v1, v2);
^
/path/to/aws-sdk-cpp/testing-resources/include/aws/external/gtest.h:17949:10: note: in instantiation of function template specialization 'testing::Values<bool, bool>' requested here
return Values(false, true);
^
1 error generated.
make[2]: *** [testing-resources/CMakeFiles/testing-resources.dir/source/MemoryTesting.cpp.o] Error 1
make[1]: *** [testing-resources/CMakeFiles/testing-resources.dir/all] Error 2
make: *** [all] Error 2
これは、コンパイラオプションを変更して回避します。aws-sdk-cpp/cmake/compiler_setting.cmake
のコンパイラオプションを設定している箇所で-Werror
をはずします。
macro(set_gcc_warnings)
- list(APPEND AWS_COMPILER_WARNINGS "-Wall" "-Werror" "-pedantic" "-Wextra")
+ list(APPEND AWS_COMPILER_WARNINGS "-Wall" "-pedantic" "-Wextra")
if(COMPILER_CLANG)
if(PLATFORM_ANDROID)
# when using clang with libc and API lower than 21 we need to include Android support headers and ignore the gnu-include-next warning.
if(ANDROID_STL MATCHES "libc" AND ANDROID_NATIVE_API_LEVEL_NUM LESS "21")
# NDK lower than 12 doesn't support ignoring the gnu-include-next warning so we need to disable pedantic mode.
if(NDK_RELEASE_NUMBER LESS "12000")
string(REGEX REPLACE "-pedantic" "" AWS_COMPILER_WARNINGS "${AWS_COMPILER_WARNINGS}")
else()
list(APPEND AWS_COMPILER_WARNINGS "-Wno-gnu-include-next")
endif()
endif()
endif()
endif()
endmacro()
または、cmakeコマンド実行時にENABLE_TESTING=OFF
を設定するとテストコードは無視されるため上記のようなエラーは発生しません。
$ cmake .. -DBUILD_ONLY="dynamodb" \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX=/path/to/sdk-install-dir
-DENABLE_TESTING=OFF
$ make
最善策がわからずこれで良いのか…という気がしています。コンパイラオプションの細かな調整はまだまだ勉強不足です。
DynamoDBを試す
無事ビルド・インストールが完了したら、あとは利用するだけです。今回はawslabs/aws-lambda-cppのコード例を参考に、DynamoDBテーブルの作成を試してみます。
create_table.cpp
とCMakeLists.txt
を作成します。
mkdir dynamodb_test
cd dynamodb_test
touch create_table.cpp
touch CMakeLists.txt
create_table.cpp
#include <aws/core/Aws.h>
#include <aws/core/utils/Outcome.h>
#include <aws/dynamodb/DynamoDBClient.h>
#include <aws/dynamodb/model/AttributeDefinition.h>
#include <aws/dynamodb/model/CreateTableRequest.h>
#include <aws/dynamodb/model/KeySchemaElement.h>
#include <aws/dynamodb/model/ProvisionedThroughput.h>
#include <aws/dynamodb/model/ScalarAttributeType.h>
#include <iostream>
int main()
{
Aws::SDKOptions options;
Aws::InitAPI(options);
{
const Aws::String table("SampleTable");
const Aws::String region("ap-northeast-1");
Aws::Client::ClientConfiguration clientConfig;
if (!region.empty())
clientConfig.region = region;
Aws::DynamoDB::DynamoDBClient dynamoClient(clientConfig);
Aws::DynamoDB::Model::CreateTableRequest req;
Aws::DynamoDB::Model::AttributeDefinition haskKey;
haskKey.SetAttributeName("Name");
haskKey.SetAttributeType(Aws::DynamoDB::Model::ScalarAttributeType::S);
req.AddAttributeDefinitions(haskKey);
Aws::DynamoDB::Model::KeySchemaElement keyscelt;
keyscelt.WithAttributeName("Name").WithKeyType(Aws::DynamoDB::Model::KeyType::HASH);
req.AddKeySchema(keyscelt);
Aws::DynamoDB::Model::ProvisionedThroughput thruput;
thruput.WithReadCapacityUnits(5).WithWriteCapacityUnits(5);
req.SetProvisionedThroughput(thruput);
req.SetTableName(table);
const Aws::DynamoDB::Model::CreateTableOutcome& result = dynamoClient.CreateTable(req);
if (result.IsSuccess())
{
std::cout << "Table " << result.GetResult().GetTableDescription().GetTableName() <<
" created!" << std::endl;
}
else
{
std::cout << "Failed to create table: " << result.GetError().GetMessage();
}
}
Aws::ShutdownAPI(options);
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(dynamodb-examples)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
find_package(AWSSDK REQUIRED COMPONENTS dynamodb)
add_executable(create_table create_table.cpp)
target_link_libraries(create_table ${AWSSDK_LINK_LIBRARIES})
ビルドします。CMAKE_INSTALL_PREFIX
でさきほどビルドしたaws-sdk-cppのインストールディレクトリを指定します。
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/path/to/sdk-install-dir
make
実行してみます。事前にassume-roleしているため環境変数にクレデンシャルが設定されています。
$ ./create_table
Table SampleTable created!
* Closing connection 0
おわりに
Apple Clangでは一切エラーが出なかったのですがLLVM/Clangを使用するように変更したら色々つまずいてビルドするのに苦戦しました。
本記事の対応策は正攻法ではないかもしれませんが、LLVM/Clangを利用してaws-sdk-cppをビルドしたい場合の参考になれば幸いです。