MACにAWS SDK for C++を導入して簡単なサンプルコードを動かしてみる

はじめに

サーバーレス開発部@大阪の岩田です。 PythonでLambdaをゴリゴリ書いていたと思ったら最近はIoTおじさんと化しており、C++の勉強を始めました。 とりあえずAWS SDK for C++を使った簡単なサンプルプログラムが実装できたので手順をご紹介します。

環境

今回利用した開発環境です。

  • OS: Mac OS X 10.14.2
  • CMake: 3.13.4
  • AWS SDK for C++: 1.7.60
  • Xcode: 10.1 Build version 10B61

AWS SDK for C++の導入

それでは実際にSDKを導入していきます。 SDKのビルドにCMakeが必要になるので、brewでインストールしておきます。

brew install cmake

CMakeがインストールできたらSDKを導入していきます。 AWS SDK for C++の1.7.0からいくつかサードパーティーのライブラリへの依存関係が追加されているので、まずは依存しているライブラリを順番に導入していきます。

aws-c-commonの導入

まずaws-c-commonを導入します。

$ git clone https://github.com/awslabs/aws-c-common
$ cd aws-c-common
$ mkdir build && cd build
$ cmake ..
-- The C compiler identification is AppleClang 10.0.0.10001145
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
...略
-- Build files have been written to: /Users/xxxxx/aws-c-common/build


$ make
[ 46%] Built target aws-c-common
[ 96%] Built target aws-c-common-tests
[100%] Built target aws-c-common-assert-tests


$ make install
[ 46%] Built target aws-c-common
[ 96%] Built target aws-c-common-tests
[100%] Built target aws-c-common-assert-tests
Install the project...
-- Install configuration: ""
...略

aws-checksumsの導入

次はaws-checksumsです。

$ git clone https://github.com/awslabs/aws-checksums
$ cd aws-checksums
$ mkdir build && cd build
$ cmake ..
-- The C compiler identification is AppleClang 10.0.0.10001145
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/xxxxxx/aws-checksums/build


$ make
Scanning dependencies of target aws-checksums
[ 72%] Built target aws-checksums
Scanning dependencies of target aws-checksums-tests
[100%] Built target aws-checksums-tests


$ make install
[ 72%] Built target aws-checksums
[100%] Built target aws-checksums-tests
Install the project...
-- Install configuration: ""
-- Up-to-date: /usr/local/include/aws/checksums/crc.h
-- Up-to-date: /usr/local/include/aws/checksums/crc_jni.h
-- Up-to-date: /usr/local/include/aws/checksums/exports.h
-- Installing: /usr/local/lib/libaws-checksums.a
...略

aws-c-event-streamの導入

次はaws-c-event-streamです。

$ git clone https://github.com/awslabs/aws-c-event-stream
$ cd aws-c-event-stream
$ mkdir build && cd build
$ cmake ..
-- The C compiler identification is AppleClang 10.0.0.10001145
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
...略
-- Build files have been written to: /Users/xxxxxx/aws-c-event-stream/build


$ make
Scanning dependencies of target aws-c-event-stream
[ 18%] Built target aws-c-event-stream
[ 27%] Linking C executable aws-c-event-stream-tests
[ 63%] Built target aws-c-event-stream-tests
[ 72%] Linking C executable aws-c-event-stream-write-test-case
[ 81%] Built target aws-c-event-stream-write-test-case
[ 90%] Linking C executable aws-c-event-stream-pipe
[100%] Built target aws-c-event-stream-pipe


$ make install
[ 18%] Built target aws-c-event-stream
[ 63%] Built target aws-c-event-stream-tests
[ 81%] Built target aws-c-event-stream-write-test-case
[100%] Built target aws-c-event-stream-pipe
Install the project...
-- Install configuration: ""
...略
-- Up-to-date: /usr/local/lib/aws-c-event-stream/cmake/aws-c-event-stream-config.cmake]

AWS SDK for C++本体の導入

依存ライブラリの準備ができたのでAWS SDK for C++の本体を導入します。 なお、今回はS3関連のライブラリのみ導入するため、CMakeの引数に-DBUILD_ONLY="s3"を渡しています。

$ git clone https://github.com/aws/aws-sdk-cpp
$ cd aws-sdk-cpp
$ mkdir build && cd build
$ cmake .. -DBUILD_ONLY="s3" -DBUILD_DEPS=OFF
-- Found Git: /usr/local/Cellar/git/2.17.0/bin/git (found version "2.17.0")
-- TARGET_ARCH not specified; inferring host OS to be platform compilation target
-- Building AWS libraries as shared objects
-- Building project version: 1.7.60
-- The CXX compiler identification is AppleClang 10.0.0.10001145
...略
-- Build files have been written to: /Users/xxxxxx/aws-sdk-cpp/build


$ make
[  0%] Linking CXX shared library libaws-cpp-sdk-core.dylib
[ 19%] Built target aws-cpp-sdk-core
[ 20%] Linking CXX shared library libaws-cpp-sdk-s3.dylib
[ 89%] Built target aws-cpp-sdk-s3
[ 90%] Linking CXX shared library libtesting-resources.dylib
[ 91%] Built target testing-resources
[ 91%] Linking CXX executable aws-cpp-sdk-s3-integration-tests
[ 91%] Built target aws-cpp-sdk-s3-integration-tests
[ 91%] Linking CXX executable aws-cpp-sdk-core-tests
[==========] Running 305 tests from 49 test cases.
[----------] Global test environment set-up.
[----------] 2 tests from VersionTest
[ RUN      ] VersionTest.TestMajorMinorPatch
...略
[  PASSED  ] 305 tests.
[100%] Built target aws-cpp-sdk-core-tests


$ make install
[ 19%] Built target aws-cpp-sdk-core
[ 89%] Built target aws-cpp-sdk-s3
[ 91%] Built target testing-resources
[ 91%] Built target aws-cpp-sdk-s3-integration-tests
[100%] Built target aws-cpp-sdk-core-tests
Install the project...
...略
-- Installing: /usr/local/lib/cmake/testing-resources/testing-resources-config-version.cmake

これで準備完了です!!

SDKを使ってみる

SDKを利用してS3にオブジェクトをPUTする簡単なプログラムを作成してみます。 まずはソースコードです。 ほぼAWSのブログで紹介されているコードそのままです。 バケットとリージョンの指定だけ修正しています。

Using CMake Exports with the AWS SDK for C++

#include <aws/s3/S3Client.h>
#include <aws/s3/model/PutObjectRequest.h>
#include <aws/s3/model/GetObjectRequest.h>
#include <aws/core/Aws.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h> 

using namespace Aws::S3;
using namespace Aws::S3::Model;

static const char* KEY = "s3_cpp_sample_key";
static const char* BUCKET = "<適当なS3バケット>";

int main()
{
    Aws::SDKOptions options;
    Aws::InitAPI(options);
	{
                Aws::Client::ClientConfiguration clientConfig;
                clientConfig.region = "ap-northeast-1";
		S3Client client(clientConfig);

		//first put an object into s3
		PutObjectRequest putObjectRequest;
		putObjectRequest.WithKey(KEY)
			   .WithBucket(BUCKET);

		//this can be any arbitrary stream (e.g. fstream, stringstream etc...)
		auto requestStream = Aws::MakeShared<Aws::StringStream>("s3-sample");
		*requestStream << "Hello World!";

		//set the stream that will be put to s3
		putObjectRequest.SetBody(requestStream);

		auto putObjectOutcome = client.PutObject(putObjectRequest);

		if(putObjectOutcome.IsSuccess())
		{
			std::cout << "Put object succeeded" << std::endl;
		}
		else
		{
			std::cout << "Error while putting Object " << putObjectOutcome.GetError().GetExceptionName() << 
				   " " << putObjectOutcome.GetError().GetMessage() << std::endl;
		}

		//now get the object back out of s3. The response stream can be overridden here if you want it to go directly to 
		// a file. In this case the default string buf is exactly what we want.
		GetObjectRequest getObjectRequest;
		getObjectRequest.WithBucket(BUCKET)
			.WithKey(KEY);

		auto getObjectOutcome = client.GetObject(getObjectRequest);

		if(getObjectOutcome.IsSuccess())
		{
			std::cout << "Successfully retrieved object from s3 with value: " << std::endl;
			std::cout << getObjectOutcome.GetResult().GetBody().rdbuf() << std::endl << std::endl;;  
		}
		else
		{
			std::cout << "Error while getting object " << getObjectOutcome.GetError().GetExceptionName() <<
				 " " << getObjectOutcome.GetError().GetMessage() << std::endl;
		}
	}
    Aws::ShutdownAPI(options);
    return 0;  
}

ビルドするためにCMakeLists.txtを作成します。今回一番苦労した部分です。前述のAWSブログやこちらのブログを参考にしたのですが、なかなかうまくいきませんでした。最終系は下記の通りです。

cmake_minimum_required(VERSION 2.8)
project(s3-sample)
set (CMAKE_CXX_STANDARD 11)

find_package(AWSSDK REQUIRED COMPONENTS s3)
add_executable(s3-sample main.cpp)
target_link_libraries(s3-sample ${AWSSDK_LINK_LIBRARIES})

set (CMAKE_CXX_STANDARD 11)しているのがポイントで、この記述がないとビルドできません。また、今回は依存ライブラリ含めて全てインストール済みなので、単にtarget_link_libraries(s3-sample ${AWSSDK_LINK_LIBRARIES})と指定するだけで諸々のライブラリをリンクする事ができます。

ビルドします。

$ cmake .
-- The C compiler identification is AppleClang 10.0.0.10001145
-- The CXX compiler identification is AppleClang 10.0.0.10001145
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found AWS SDK for C++, Version: 1.7.60, Install Root:/usr/local, Platform Prefix:, Platform Dependent Libraries: pthread;curl
-- Components specified for AWSSDK: s3
-- Try finding aws-cpp-sdk-core
-- Found aws-cpp-sdk-core
-- Try finding aws-cpp-sdk-s3
-- Found aws-cpp-sdk-s3
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/xxxxxx/sample

$ make
Scanning dependencies of target s3-sample
[ 50%] Linking CXX executable s3-sample
[100%] Built target s3-sample

ビルドできたので実行します。

$ ./s3-sample
Put object succeeded
Successfully retrieved object from s3 with value:
Hello World!

うまく実行できてそうです。

S3バケットを確認してみます。

ちゃんとPUTできていますね!

まとめ

AWS SDK for C++の導入手順についてご紹介しました。AWSのブログを初めとして色々と情報は転がっていたのですが、バージョン1.7.0以後で依存関係周りの仕様変更があったり、set (CMAKE_CXX_STANDARD 11)が必要だったりと色々と詰まりどころが多かったです。とりあえず動くようにはなったので、これから実用的なアプリを作っていきたいと思います。