AWS for Games Blog
How to build and integrate the AWS SDK for C++ games on Windows
Following on from our first post ‘Game developer’s guide to setting up the AWS SDK’, we’re now going to show you how to integrate the SDK for C++, the language used in major game engines like Unreal and Lumberyard.
To help you get up and running even faster, we’ve created a sample code package that is available for you to download from GitHub.
Setting up the client
Using the sample code above, you’re now ready to run the code demo client. However, it doesn’t show you how to add the AWS C++ SDK in to your own game, so we’ll explain that here.
With Windows, using Visual Studio 2017 or higher, the easiest way to add the necessary libraries is with the NuGet package manager. This demo uses the AWSSDKCPP-IdentityManagent and AWSSDKCPP-Lambda packages. NuGet is helpful because it will pull in any other packages that your top level packages depend on, it adds all the libraries, includes the paths needed to build, and will copy any DLL’s needed to the output folder.
However, due to limitations of NuGet, it’s no longer officially supported by AWS and the last version of the AWS C++ SDK available from NuGet is 1.6. If you need features not found in the NuGet SDK, you can build the libraries yourself. You will also need to do this if using other operating systems. You can find more info in the developer guide.
Building the SDK
Here we’ll focus on building the source from GitHub using the CMake/msbuild tools.
Note: this guide assumes you are using Visual Studio 2017 and you want to build 64-bit libraries.
- Go to the SDK source for C++
- To get the source, either download the zip file from GitHub or, if you have Git installed, run the command:
git clone https://github.com/aws/aws-sdk-cpp.git
We encourage cloning the SDK as it will make it easier for you to update in the future.
- If you don’t already have it, get a copy of CMake and install it.If you have Visual Studio 2017 or higher, there’s a good chance you already have CMake installed! To check, open the Developer Command Prompt for VS2017 (found in your Start Menu’s Visual Studio folder) and type
cmake
. If you see the usage info, it’s installed. Be aware that you’ll need the command line version of git installed and in your path for the later CMake step to work. Visual Studio 2017 comes with a git client installed, however it’s not in your path by default. This can be found in the Visual Studio installation path, for example in the community version it would usually be in
C:\Program Files(x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\TeamExplorer\Git\cmd
Add that to your path and you should be good to go.
- Once you have CMake installed, you’ll need to run a command line to perform the build itself. From your Start Menu, find the icon for “Developer Command Prompt for VS 2017” in your Visual Studio folder.Be sure to right click on the console icon to run as administrator or you will get errors at the end of the build.
- Go to folder
/<path>/aws-sdk-cpp-master/
and call
cmake
on it as below to create the make files for msbuild to operate on:
cmake -G "Visual Studio 15 2017 Win64"
If you remove the Win64 part, it will build 32 bit. You can find more info on build options here: https://cmake.org/cmake/help/v3.7/manual/cmake-generators.7.html
- You can switch out versions and release types with option flags like:
-DCMAKE_BUILD_TYPE=Release
Or
-DCMAKE_BUILD_TYPE=Debug
- If you want to make specific pieces, you can specify them with the following flags (make sure to use semi-colons to separate the targets):
-DBUILD_ONLY="aws-cpp-sdk-core;aws-cpp-sdk-lambda"
- Next, build the libraries by calling:
msbuild INSTALL.vcxproj /p:Configuration=Release
Which will build the libs in each folder.
Adding the AWS C++ SDK in to your game
Now that the AWS C++ SDK is built, you’ll need to add it to your project. The following instructions are for adding the libraries and including files to an existing project.
If you’re starting a new project, consider using CMake, and the export functionality to create your Visual Studio project with all the correct paths and libraries already set up. You can learn more in this article.
For this example we will use
AWSSDK\aws-sdk-cpp-master
as the path that we unpacked and compiled the SDK with.
Set the correct configuration (Debug or Release) and Platform (x86 or x64) as required using Visual Studio’s project properties dialog box.
At this point you’ll have the libraries build in to locations like this:
AWSSDK\aws-sdk-cpp-master\aws-cpp-sdk-core\Release\aws-cpp-sdk-core.lib
The include directories will look like:
AWSSDK\aws-sdk-cpp-master\aws-cpp-sdk-core\include
You’ll also need to use the following preprocessor defines:
USE_IMPORT_EXPORT USE_WINDOWS_DLL_SEMANTICS
If you don’t, you may experience this error when linking:
error: LNK2001: unresolved external symbol "char const * const Aws::Http::CONTENT_TYPE_HEADER"
As a last note, be sure to copy the DLLs to the folder with the executable.
Once you have all of that, you are ready to integrate the services you wish to use.
For more information, read the AWS C++ SDK documentation.
The code
First, grab the sample package from GitHub.
Any time you use the AWS SDK for C++ you need to initialize it and then shut it down when you’re done, after you’ve ran your last AWS command.
Aws::SDKOptions options;
Aws::Utils::Logging::LogLevel logLevel{ Aws::Utils::Logging::LogLevel::Error };
options.loggingOptions.logger_create_fn = [logLevel] {return make_shared<Aws::Utils::Logging::ConsoleLogSystem>(logLevel); };
Aws::InitAPI(options);
...
Aws::ShutdownAPI(options);
One little extra, we’ve also set the log level. Though it’s set to the default level right now (Error), if you want to see what the SDK is doing behind the scenes, set this to Trace. It’s great for learning a bit about how the SDK operates, as well as finding the occasional tricky error. For example, we used it to find why a token wasn’t being accepted and we were able to see what was being transmitted to AWS. It turned out the format was slightly inconsistent, and we’d never had spotted that from the debugger.
The next step is the code to allow your anonymous (unauthenticated) users to make calls to AWS resources we’ve authorized access for via IAM:
auto credentialsProvider = Aws::MakeShared<Aws::Auth::CognitoCachingAnonymousCredentialsProvider>("CredentialsProvider", ACCT_ID, POOL_ID);
The anonymous credential API in the SDK for C++ requires you to put in your account ID, along with the Amazon Cognito Pool ID. You can find the account ID in the AWS console by clicking “My Account” from the popup menu at the top right. Just paste it in to the settings.h file along with the pool ID from the steps above.
The credentialsProvider
can now be passed in whenever you create a “client” for a particular AWS service.
static shared_ptr<Aws::Lambda::LambdaClient> s_LambdaClient = Aws::MakeShared<Aws::Lambda::LambdaClient>("LambdaClient", credentialsProvider);
This is a pattern used throughout the AWS SDK for C++. For every major system like Lambda, S3, Amazon Cognito, etc, you create a client. The client will be responsible for making calls to AWS and typically contains most of the AWS controlling methods. For example, the code for invoking an AWS Lambda looks like this:
Aws::Lambda::Model::InvokeRequest invokeRequest;
invokeRequest.SetFunctionName("GetMOTD");
invokeRequest.SetInvocationType(Aws::Lambda::Model::InvocationType::RequestResponse);
std::shared_ptr<Aws::IOStream> payload = Aws::MakeShared<Aws::StringStream>("LambdaFunctionRequest");
Aws::Utils::Json::JsonValue jsonPayload;
jsonPayload.WithString("param1", param1);
jsonPayload.WithInteger("param2", param2);
jsonPayload.WithInteger("param3", param3);
*payload << jsonPayload.View().WriteReadable();
invokeRequest.SetBody(payload);
invokeRequest.SetContentType("application/javascript");
auto outcome = s_LambdaClient->Invoke(invokeRequest);
if (outcome.IsSuccess())
{
auto& result = outcome.GetResult();
Aws::Utils::Json::JsonValue resultPayload{ result.GetPayload() };
auto jsonView = resultPayload.View();
if (jsonView.ValueExists("body"))
{
cout << "Response body: " << jsonView.GetString("body") << endl << endl;
}
else
{
cout << "Unable to parse response body!" << endl << endl;
}
}
else
{
auto error = outcome.GetError();
cout << "Error invoking lambda: " << error.GetMessage() << endl << endl;
}
Again, throughout the AWS C++ SDK, this is the pattern you’ll use to make the calls. You’ll create a “request” specific to the method you’re going to call. In this case we want to invoke a Lambda function, so we’ll call the Invoke function on the Lambda client. The actual parameters are stored in an InvokeRequest()
, which has various accessors and methods to make it easy to form the request.
Once the method is called, it returns an “outcome” which is specific to the method we invoked, in this case, InvokeOutcome()
(but you can use auto to make your life easier by not having to remember all this.)
The outcome tells you if the call was successful or not, containing error information if not. If it’s successful you can then grab a “response” from the outcome, which is also specific to the method called InvokeRequest()
. The outcome, much like the request, will contain accessors and methods to make it easy to figure out what the method returned.
It’s worth noting, AWS stands for “Amazon Web Services” which is why JSON is so prevalent here. The AWS SDK for C++ is pretty much a wrapper around a bunch of HTTP service calls. Fortunately, the SDK for C++ has a JSON library built in so you don’t need to find one.
That’s it!
For extra help setting up Amazon Cognito, read this post on ‘How to Set Up Player Authentication with Amazon Cognito’.
If you need more information on using the AWS C++ SDK read the documentation.
As always, we want to hear from you. If you have any questions or feedback on our learning resources, head over to the Amazon GameDev forums.