はじめに
この記事では AWS SDK for C++ を使い S3 互換ストレージである OCI Object Storage の操作をしている。
基本的には 公式の資料 にある通りです。
SDK のビルドについては こちら を参考にしています。
必要となるソフトウェア
関連するすべてのものは C:\cxx\ を起点として保存している。ダウンロードしたものは C:\cxx\tool\ に展開しパスを通す。
尚、Visual Studio 2022 はインストーラにより導入済である。
-
CMake
cmake-4.1.2-windows-x86_64.zip
情報収集
OCI ObjectStorage に接続するため、以下の情報が必要になる。
- リージョン
- ネームスペース
- ACCESS キー
- SECRET キー
リージョンの ID
ACCESS&SECRET キー
ネームスペース
プロジェクトの作成
C++ でコンソールアプリを作成する。
C:\cxx\project\01-oci-os\ をプロジェクト・ディレクトリとしている。
C++ のバージョンに 17 を指定(任意)。
aws-sdk-cpp のビルド
上記で作成したプロジェクトのディレクトリに AWS SDK for C++ のソースコードを取得してビルドする。
公式の資料 を参考に以下のコマンドを実行することで C:\cxx\project\01-oci-os\aws-sdk-cpp\dest\ 以下にヘッダとライブラリが作成される。
C:\cxx\project\01-oci-os>set PATH=C:\cxx\tool\cmake-4.1.2-windows-x86_64\bin;%PATH%
C:\cxx\project\01-oci-os>cmake --version
cmake version 4.1.2
CMake suite maintained and supported by Kitware (kitware.com/cmake).
C:\cxx\project\01-oci-os>git clone --recurse-submodules --branch 1.11.675 https://github.com/aws/aws-sdk-cpp.git aws-sdk-cpp\repo
...
C:\cxx\project\01-oci-os>cd aws-sdk-cpp\repo
C:\cxx\project\01-oci-os\aws-sdk-cpp\repo>cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=..\dest\Debug -DBUILD_ONLY="s3" -DCPP_STANDARD=17
...
C:\cxx\project\01-oci-os\aws-sdk-cpp\repo>cmake --build build --config=Debug
...
C:\cxx\project\01-oci-os\aws-sdk-cpp\repo>cmake --install build --config=Debug
...
ここでは C++17 を指定している(任意)。
ビルドした aws-sdk-cpp を参照
上記で生成されたヘッダとライブラリを参照するようにプロジェクトの設定を変更する。
追加のインクルード・ディレクトリ
aws-sdk-cpp の include を指定。
$(SolutionDir)aws-sdk-cpp\dest\$(Configuration)\include
追加のライブラリ・ディレクトリ
aws-sdk-cpp の bin を指定。
$(SolutionDir)aws-sdk-cpp\dest\$(Configuration)\bin
実行時 PATH 環境変数
aws-sdk-cpp の bin を指定。
PATH=$(SolutionDir)aws-sdk-cpp\dest\$(Configuration)\bin
プロジェクトのビルド
OCI_AWS_CPP_SDK_S3_Examples や AWS SDK Code Examples のソースコードを参考に、以下のファイルを配置した。
事前に準備した ACCESS&SECRET キーは環境変数から取得し、それ以外はハードコードしている。
#pragma comment(lib, "aws-cpp-sdk-core.lib")
#pragma comment(lib, "aws-cpp-sdk-s3.lib")
#include <iostream>
#include <cassert>
void listBuckets(const char* access_key, const char* secret_key);
void listObjects(const char* access_key, const char* secret_key);
void putObject(const char* access_key, const char* secret_key);
int main()
{
char* access_key = nullptr;
char* secret_key = nullptr;
size_t len = 0;
_dupenv_s(&access_key, &len, "ACCESS_KEY");
_dupenv_s(&secret_key, &len, "SECRET_KEY");
assert(access_key && secret_key);
std::cout << "== listBuckets ==" << std::endl;
listBuckets(access_key, secret_key);
std::cout << "== listObjects ==" << std::endl;
listObjects(access_key, secret_key);
std::cout << "== putObject ==" << std::endl;
putObject(access_key, secret_key);
free(access_key);
free(secret_key);
return 0;
}
バケットの一覧を取得。
#include <iostream>
#include <cassert>
#define USE_IMPORT_EXPORT
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
void listBuckets(const char* access_key, const char* secret_key)
{
const auto namespc = "**ke***g7**b";
const auto region = "ap-osaka-1";
Aws::SDKOptions sdkOptions;
Aws::InitAPI(sdkOptions);
Aws::Client::ClientConfiguration cfg;
cfg.endpointOverride = std::string("https://") + namespc + ".compat.objectstorage." + region + ".oraclecloud.com/";
cfg.scheme = Aws::Http::Scheme::HTTP;
cfg.verifySSL = true;
cfg.region = region;
Aws::S3::S3Client client(
Aws::Auth::AWSCredentials(access_key, secret_key), cfg,
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);
auto outcome = client.ListBuckets();
if (outcome.IsSuccess())
{
for (auto& bucket : outcome.GetResult().GetBuckets())
{
std::cout << bucket.GetName() << std::endl;
}
}
else
{
std::cerr << "ERROR: " << outcome.GetError() << std::endl;
}
Aws::ShutdownAPI(sdkOptions);
}
images/ に一致するオブジェクトの一覧を取得。
#include <iostream>
#include <cassert>
#define USE_IMPORT_EXPORT
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/s3/model/ListObjectsV2Request.h>
void listObjects(const char* access_key, const char* secret_key)
{
const auto namespc = "**ke***g7**b";
const auto region = "ap-osaka-1";
Aws::SDKOptions sdkOptions;
Aws::InitAPI(sdkOptions);
Aws::Client::ClientConfiguration cfg;
cfg.endpointOverride = std::string("https://") + namespc + ".compat.objectstorage." + region + ".oraclecloud.com/";
cfg.scheme = Aws::Http::Scheme::HTTP;
cfg.verifySSL = true;
cfg.region = region;
Aws::S3::S3Client client(
Aws::Auth::AWSCredentials(access_key, secret_key), cfg,
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);
Aws::S3::Model::ListObjectsV2Request request;
request.WithBucket("cxx-project").WithDelimiter("/").WithPrefix("images/");
auto outcome = client.ListObjectsV2(request);
if (outcome.IsSuccess())
{
for (auto& object : outcome.GetResult().GetContents())
{
std::cout << object.GetKey() << std::endl;
}
}
else
{
std::cerr << "ERROR: " << outcome.GetError() << std::endl;
}
Aws::ShutdownAPI(sdkOptions);
}
ファイルのアップロード。
#include <iostream>
#include <cassert>
#define USE_IMPORT_EXPORT
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/s3/model/PutObjectRequest.h>
#include <fstream>
#include <memory>
void putObject(const char* access_key, const char* secret_key)
{
const auto namespc = "**ke***g7**b";
const auto region = "ap-osaka-1";
Aws::SDKOptions sdkOptions;
Aws::InitAPI(sdkOptions);
Aws::Client::ClientConfiguration cfg;
cfg.endpointOverride = std::string("https://") + namespc + ".compat.objectstorage." + region + ".oraclecloud.com/";
cfg.scheme = Aws::Http::Scheme::HTTP;
cfg.verifySSL = true;
cfg.region = region;
//
// requestChecksumCalculation の指定は AWS のサンプルと異なる
// https://github.com/aws/aws-sdk-cpp/issues/3253
//
cfg.checksumConfig.requestChecksumCalculation = Aws::Client::RequestChecksumCalculation::WHEN_REQUIRED;
std::shared_ptr<Aws::IOStream> thisFile = Aws::MakeShared<Aws::FStream>(
"SampleAllocationTag", __FILE__, std::ios_base::in | std::ios_base::binary);
assert(*thisFile);
Aws::S3::S3Client client(
Aws::Auth::AWSCredentials(access_key, secret_key), cfg,
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);
Aws::S3::Model::PutObjectRequest request;
request.WithBucket("cxx-project").WithKey("putObject.cpp");
request.SetBody(thisFile);
auto outcome = client.PutObject(request);
if (outcome.IsSuccess())
{
std::cout << "success" << std::endl;
}
else
{
std::cerr << "ERROR: " << outcome.GetError() << std::endl;
}
Aws::ShutdownAPI(sdkOptions);
}
AWS S3 との違い
バケット、オブジェクトの一覧については参考したソースコードのままでも動作するので、わざわざ記事にする必要もなかった。
しかし、アップロードは 参考にしたコード のままでは以下のエラーが発生した。
ERROR: HTTP response code: 411
Resolved remote host IP address:
Request ID:
Exception name: MissingContentLength
Error message: Unable to parse ExceptionName: MissingContentLength Message: The Content-Length header is required
12 response headers:
access-control-allow-credentials : true
access-control-allow-methods : POST,PUT,GET,HEAD,DELETE,OPTIONS
access-control-allow-origin : *
access-control-expose-headers : access-control-allow-credentials,access-control-allow-methods,access-control-allow-origin,content-length,content-type,date,opc-client-info,opc-request-id,strict-transport-security,x-amz-request-id,x-api-id,x-content-type-options
content-length : 142
content-type : application/xml; charset=utf-8
date : Fri, 24 Oct 2025 21:56:35 GMT
opc-request-id : kix-1:taJ83YFjx5AvrYwvDRVZC8todi...
strict-transport-security : max-age=31536000; includeSubDomains
x-amz-request-id : kix-1:taJ83YFjx5AvrYwvDRVZC8todiNP6R2tccqaV3M...
x-api-id : s3-compatible
x-content-type-options : nosniff
Exception name: MissingContentLength というメッセージをヒントに SetContentLength() を試してみたり、他にも試行錯誤してみたが一向に解決せず、最終的には 公式の issue で案内され、解決方法 を教えてもらった。
おそらく、OCI OS ではリクエストの送信時にチェックサムの扱いが AWS S3 と異なることが原因だと思われる。
(ライブラリのデフォルト値が 2024年末に変更されている)
この結果、以下の一行を追加することで問題が解決した。
cfg.checksumConfig.requestChecksumCalculation = Aws::Client::RequestChecksumCalculation::WHEN_REQUIRED;
実行結果
プロジェクトを実行すると以下の出力が行われる。
== listBuckets ==
bucket-20251025-0453
cxx-project
hello-world
== listObjects ==
images/
images/6419115.png
images/6451979.png
== putObject ==
success
同じバケットに対し oci os コマンドで確認した結果。
(py312) ubuntu@vm1:~$ oci os bucket list | jq -r '.data[].name'
bucket-20251025-0453
cxx-project
hello-world
(py312) ubuntu@vm1:~$ oci os object list --bucket-name=cxx-project | jq -r '.data[].name'
images/
images/6419115.png
images/6451979.png
music/
putObject.cpp
(py312) ubuntu@vm1:~$ oci os object list --bucket-name=cxx-project | jq -r '.data[]|select(.name=="putObject.cpp").size'
1547
プログラムの出力と同じであることが確認できた。










