Tag: cmake


Developer Experience of the AWS SDK for C++ Now Simplified by CMake

by Andrew Tang | on | in C++, C++ | Permalink | Comments |  Share

Building a cross-platform C or C++ project is tedious and time consuming. You often have to manage build files for each platform’s build system. On Unix-like systems, you might use Make, while on Windows you would have to use MSBuild. To make matters worse, in each of these build systems you have to manually maintain and configure compiler flags and linker flags.

We’re very pleased to announce that starting with version 1.0.109 of the AWS SDK for C++, you can more easily use CMake to build your project against the SDK. In addition, it’s easier to uninstall the SDK.

Here’s a simple example script that uses CMake to build a project against the SDK.

cmake_minimum_required(VERSION 2.8)
project(s3Encryption)
find_package(AWSSDK REQUIRED)
set(SERVICE s3-encryption)
AWSSDK_DETERMINE_LIBS_TO_LINK(SERVICE OUTPUT)
link_directories("${AWSSDK_LIB_DIR}")
add_executable(s3Encryption s3Encryption.cpp)
target_link_libraries(s3Encryption ${OUTPUT})
target_include_directories(s3Encryption PRIVATE ${AWSSDK_INCLUDE_DIR})

To uninstall the SDK, just run make uninstall inside your build directory.

In earlier versions, each SDK had its own CMake scripts. However, the functionality only told you that the SDK existed. Now when you run sudo make install, this latest version installs a new directory named AWSSDK.

On a Unix-like system, this is the default installation path:
“/usr/local/lib/cmake/AWSSDK”

On Windows, this is the default installation path:
“C:/Program Files/aws-cpp-sdk-all/lib/cmake/AWSSDK”

Several CMake scripts are created in this directory. The most important one is AWSSDKConfig.cmake. CMake can use it to find the AWSSDK module and load the script. For information about naming of this specific file name, see CMake Find Package Config Mode.

Calling find_package(AWSSDK) makes several useful variables and macros available to you, as follows.

Variables:

AWSSDK_LIB_DIR
AWSSDK_BIN_DIR
AWSSDK_INCLUDE_DIR

Macros:

AWSSDK_CPY_DYN_LIBS(SERVICE_LIST CONFIG DESTDIR)
AWSSDK_LIB_DEPS(SERVICE DEPS)
AWSSDK_DETERMINE_LIBS_TO_LINK(SERVICE_LIST OUTPUT)

You can use the AWSSDK_CPY_DYN_LIBS macro to copy all the SDKs that are specified in the SERVICE_LIST. In addition, it copies all their dependent libraries (including recursive dependencies) and the core library to DESTDIR. You use CONFIG to specify the compile time binary configuration of the SDKs. You don’t have to set it, or you can set it to Debug, Release, and others.

For example, S3 encryption depends on Core, Amazon S3, and AWS KMS. Both S3 and KMS depend on Core. So, the following script copies libaws-cpp-sdk-core.so, libaws-cpp-sdk-s3.so, libaws-cpp-sdk-kms.so and libaws-cpp-sdk-s3-encryption.so to the current directory.

Set(SERVICE_LIST s3 s3-encryption)
AWSSDK_CPY_DYN_LIBS(SERVICE_LIST “” “./”)

You could use the AWSSDK_LIB_DEPS macro to output dependent libraries of SERVICE to DEPS. However, remember that SERVICE is just a single SDK’s name instead of a list of all the SDK names, and DEPS is a list of names of simplified libraries such as “core; s3; kms; s3-encryption”.

The AWSSDK_DETERMINE_LIBS_TO_LINK macro is similar to AWSSDK_CPY_DYN_LIBS. However, it doesn’t copy but does output the library names to OUTPUT. Notice that OUTPUT is a complete list of library names, which you could use as arguments of find_library(). For example, “aws-cpp-sdk-core; aws-cpp-sdk-s3;”.

The PkgConfig metadata file of each SDK is installed on all platforms under the same directory as CMake scripts. On Unix-like systems, we can use the PkgConfig module in CMake to simplify this, as we did in the previous example script. But if you want to try a command line build or a simple Makefile build, you can use a command like the following to generate all the flags, libs, and paths you want.

pkg_config –libs –cflags aws-cpp-sdk-s3-encryption

Try this sample project on your own platform. Before you begin, be sure to do the following:

  • Install the latest version of the AWS SDK for C++.
  • Create and set up AWS credentials on your test machine.
  • Create an Amazon S3 bucket under your account. The region must be the same as the region used in your AWS client configuration.
  • Create an AWS KMS master key.
  • Apply changes to main.cpp in this project, such as master key ID, bucket name, key you wanted to use, and so on.

Please reach out to us with questions and improvements. As always, pull requests are welcome!

Using CMake Exports with the AWS SDK for C++

by Jonathan Henson | on | in C++, C++ | Permalink | Comments |  Share

This is our very first C++ blog post for the AWS Developer blog. There will be more to come. We are excited to receive and share feedback with the C++ community. This first post will start where most projects start, with the building of a simple program.

Building an application in C++ can be a daunting task—especially when dependencies are involved. Even after you have figured out what you want to do and which libraries you need to use, you encounter seemingly endless, painful tasks to compile, link, and distribute your application.

AWS SDK for C++ users most frequently report the difficulty of compiling and linking against the SDK. This involves building the SDK, installing the header files and libraries somewhere, updating the build system of the application with the include and linker paths, and passing definitions to the compiler. This is an error-prone– and now unnecessary– process. CMake has built-in functionality that will handle this scenario. We have now updated the CMake build scripts to handle this complexity for you.

The example we will use in this post assumes you are familiar with Amazon Simple Storage Service (Amazon S3), and know how to download and build the SDK. For more information, see our readme on github. If we want to write a simple program to upload and retrieve objects from Amazon S3. The code would look something like this:


#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-cpp-sample-bucket";

int main()
{
    Aws::SDKOptions options;
    Aws::InitAPI(options);
	{
		S3Client client;

		//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;  
}

Here, we have a direct dependency on aws-cpp-sdk-s3 and an indirect dependency on aws-cpp-sdk-core. Furthermore, we have several platform-specific dependencies that are required to make this work. On Windows, this involves WinHttp and BCrypt. On Linux, curl and OpenSSL. On OSX, curl and CommonCrypto. Other platforms, such as mobile, have their own dependencies. Traditionally, you would need to update your build system to detect each of these platforms and inject the right properties for each target.

However, the build process for the SDK already has access to this information from its configuration step. Why should you have to worry about this mess? Enter CMake export(). What would a CMakeLists.txt look like to build this program? This file generates our build artifacts for each platform we need to support—Visual Studio, XCode, AutoMake, and so on.


cmake_minimum_required(VERSION 2.8)
project(s3-sample)

#this will locate the aws sdk for c++ package so that we can use its targets
find_package(aws-sdk-cpp)

add_executable(s3-sample main.cpp)

#since we called find_package(), this will resolve all dependencies, header files, and cflags necessary
#to build and link your executable. 
target_link_libraries(s3-sample aws-cpp-sdk-s3)

That’s all you need to build your program. When we run this script for Visual Studio, CMake will determine that aws-cpp-sdk-s3 has dependencies on aws-cpp-sdk-core, WinHttp, and BCrypt. Also, the CMake configuration for the aws-sdk-cpp package knows whether the SDK was built using custom memory management. It will make sure the –DAWS_CUSTOM_MEMORY_MANAGEMENT flag is passed to your compiler if needed. The resulting Visual Studio projects will already have the include and linker arguments set and will contain compile definitions that need to be passed to your compiler. On GCC and Clang, we will also go ahead and pass you the –std=c++11 flag.

To configure your project, simply run the following:


cmake –Daws-sdk-cpp_DIR=<path to your SDK build> <path to your source>

You can pass additional CMake arguments , such as –G “Visual Studio 12 2013 Win64” too.

Now you are ready to build with msbuild, make, or whatever other build system you are using.

Obviously, not everyone uses or even wants to use CMake. The aws-sdk-cpp-config.cmake file will contain all of the information required to update your build script to use the SDK.

We’d like to extend a special thanks to our GitHub users for requesting this feature, especially Rico Huijbers who shared a blog post on the topic. His original post can be found here

We are excited to be offering better support to the C++ community. We invite you to try this feature and leave feedback here or on GitHub.