I haven’t written any C++ since 2009, or cross-platform C++ since the 90s. Working with the language in 2020 continues to require a lot of paper and glue (a.k.a. autoconf and make). The scissors, however, have become dramatically sharper as the community seems to have adopted CMake.
And so, having found a spare half hour, I decided to build a “hello world” C++ sample for AWS Data Exchange. It was more challenging than I would have liked.
Building the AWS SDK for C++
I began with Getting Started Using the AWS SDK for C++ which links to Setting Up the AWS SDK for C++. Since I’m using a Mac, I had to build the SDK from source.
> git clone git@github.com:aws/aws-sdk-cpp.git
> cd aws-sdk-cpp
aws-sdk-cpp>
I generally recommend using a released version of the SDK to ensure that you’ve checked out something stable.
aws-sdk-cpp> git checkout 1.7.278
The immediately confusing part of building the SDK was the idea that the build
directory, i.e. the directory from which one runs make
, is separate from the source. All my past projects required checking out the source, and typing make
, or something similar. The sharp scissors, aka cmake
generates a Makefile
and is something you run from an empty build
(sub)directory that you create.
aws-sdk-cpp> mkdir build
aws-sdk-cpp> cd build
aws-sdk-cpp/build> cmake .. -DCMAKE_BUILD_TYPE=Debug
aws-sdk-cpp/build> make
You don’t have to create a build
directory inside the source directory, but it is even more confusing if you have to keep the source and the build in separate hierarchies.
Installing the AWS SDK for C++
You must install the SDK with make install
. I used the defaults, which is to copy the output to /usr/local
on *nix systems, including MacOS.
This destination is configured with DCMAKE_INSTALL_PREFIX
. For example, the following builds the Release
flavor and installs the SDK into $HOME/bin/aws-sdk
.
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/bin/aws-sdk
make install
If you made a mistake, and want to change the destination, you can also uninstall the SDK with make uninstall
, but it will leave a bunch of folders and some files behind, which is now aws-sdk-cpp#1335.
It wasn’t immediately clear whether installing the SDK was required, rather than just building it, because the documentation always referenced sdk_build_dir
. It is required and the docs really meant sdk_install_dir
.
Using the AWS SDK for C++
I then tried to build a very simple “hello world” sample using the C++ SDK. This, of course, didn’t just work.
Minimal Code
A minimum example that uses the AWS SDK for C++ creates Aws::SDKOptions
, calls Aws::InitAPI
, does a bunch of work against one the many AWS services and calls Aws::ShutdownAPI
to cleanup.
#include <iostream>
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/Bucket.h>
int main(int argc, char** argv)
{
Aws::SDKOptions options;
Aws::InitAPI(options);
// Do something with S3 ...
// Aws::S3::S3Client s3_client;
// etc.
Aws::ShutdownAPI(options);
}
CMakeLists.txt
A working CMakeLists.txt
for version 1.7.278 of the SDK looks like this.
cmake_minimum_required(VERSION 3.2)
project(project-name)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
find_package(AWSSDK REQUIRED COMPONENTS s3)
add_executable(project-name main.cpp)
target_compile_features(project-name PUBLIC cxx_std_11)
target_link_libraries(project-name ${AWSSDK_LINK_LIBRARIES})
I had started from an example in this blog post from 2016 and from the docs, both of which were obsolete. I ran into a number of issues and have opened aws-sdk-cpp#1334 to get help. This is the complete list of changes I had to make.
- The
find_package
arguments changed toAWSSDK
(looks forAWSSDKConfig.cmake
),REQUIRED
(generates a fatal error ifAWSSDK
is not found), andCOMPONENTS
, followed by a list of components (e.g.s3 dataexchange
). - The
BUILD_SHARED_LIBS
option changed to being on, because the SDK recently started defaulting to building shared vs. static libraries. - The
target_compile_features(my-example PUBLIC cxx_std_11)
was added to default to the C++ 11 standard required by the SDK code. This is potentially avoidable, see aws-sdk-cpp#1338. - When installed into a custom location, any reference to
-Daws-sdk-cpp_DIR
needed to become-DAWSSDK_DIR
because of the new name forAWSSDKConfig.cmake
. - The
target_link_libraries
arguments changed to include${AWSSDK_LINK_LIBRARIES}
to avoid having to list all dependencies manually.
The minimal CMakeLists.txt
example has been corrected in aws-doc-sdk-examples#1022, and the documentation in aws-cpp-developer-guide#37.
Listing S3 Buckets in C++
Now that I was able to build C++ code against the AWS SDK for C++, I wrote a demo that lists S3 buckets.
#include <iostream>
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/Bucket.h>
int main(int argc, char** argv)
{
Aws::SDKOptions options;
Aws::InitAPI(options);
{
Aws::S3::S3Client s3_client;
auto outcome = s3_client.ListBuckets();
if (outcome.IsSuccess()) {
std::cout << "Your Amazon S3 buckets:" << std::endl;
Aws::Vector<Aws::S3::Model::Bucket> bucket_list =
outcome.GetResult().GetBuckets();
for (auto const &bucket: bucket_list) {
std::cout << " * " << bucket.GetName() << std::endl;
}
} else {
std::cout << "ListBuckets error: "
<< outcome.GetError().GetExceptionName() << " - "
<< outcome.GetError().GetMessage() << std::endl;
}
}
Aws::ShutdownAPI(options);
}
The complete project can be found in aws-samples/aws-sdk-cpp-list-s3-buckets.
Listing Entitled Data Sets in AWS Data Exchange in C++
Finally, I wrote a sample for AWS Data Exchange. In the following example we list all the data sets that our current account is entitled to.
Aws::DataExchange::DataExchangeClient client;
Aws::DataExchange::Model::ListDataSetsRequest list_data_sets_options;
list_data_sets_options.SetOrigin("ENTITLED");
auto outcome = client.ListDataSets(list_data_sets_options);
Aws::Vector<Aws::DataExchange::Model::DataSetEntry> data_sets_list = outcome.GetResult().GetDataSets();
for (auto const &data_set: data_sets_list) {
std::cout
<< data_set.GetOriginDetails().GetProductId() << "/"
<< data_set.GetId() << ": "
<< data_set.GetName() << std::endl
<< " " << data_set.GetDescription()
<< std::endl;
}
See aws-dataexchange-api-samples/subscribers/cpp/all-entitled-datasets, via aws-dataexchange-api-samples#33 for complete working code and a working CMakeFile.txt
.