
简介这是一份面向 C 开发者的 AWS SDK for C 完整源码包适合需要在桌面端或服务端应用中集成亚马逊云服务的团队与个人。SDK 覆盖 EC2、S3、DynamoDB 等常用服务客户端也包含身份验证、HTTP 通信、线程与异步处理、错误调试等模块能够帮助开发者省去底层协议和鉴权细节快速构建云原生应用同时支持 IAM 角色、STS 临时凭证等安全机制满足不同部署环境下的凭据管理需求。压缩包共 2000 个文件其中 1022 个头文件与 965 个 C 源文件构成核心实现另有 11 个 txt 与 2 个 md 文档整体约 97.43MB目录结构清晰可按服务模块对照查阅。已有 316 人学习下载。通过源码可以深入理解 AWS 服务调用的封装方式、CMake 依赖管理和多线程设计也可作为二次开发、源码分析或构建自定义云 SDK 的参考基础尤其适合希望基于官方 SDK 做深度定制或研究其内部实现的中高级开发者。 说实话第一次从一个网盘链接里拿到aws-sdk-cpp.zip这种压缩包时大部分人心里是没底的。解压出来一堆文件夹里面有aws-cpp-sdk-core、aws-cpp-sdk-s3、aws-cpp-sdk-ec2看起来像源码又不完全是想直接编译又不知道从哪下手。这篇文章就围绕这个压缩包展开讲清楚 AWS SDK for C 到底怎么用、怎么编译、怎么接入自己的 CMake 工程以及 N 个我在实际项目中踩过的坑。内容适合两类人一是刚接触 AWS 但 C 基础不错的同学二是在已有 C 服务里想加云能力的后端开发。我会尽量把流程写细让读者照着做就能跑通。1. 解压之前先搞清 SDK 交付形态与服务范围1.1 源码包还是二进制包先判断拿到的是什么拿到AWS SDK for C.zip第一件事不是急着解压而是先看压缩包体积和顶层目录结构。如果压缩包里有大量.cmake文件、CMakeLists.txt和各个服务的源码目录那基本是源码包如果顶层目录直接是include/和lib/那大概率是预编译包。两者的使用方式完全不同源码包需要本机编译好处是能通过BUILD_ONLY参数只编自己用到的服务生成体积很小的静态库。预编译包适合快速验证但要特别注意编译器和运行库版本是否匹配尤其是 Windows 下 Debug/Release 不匹配的坑特别多。我建议大多数情况下自己编译源码包。AWS官方在 GitHub 上维护的aws-sdk-cpp仓库更新频率很高而且 CMake 已经把这些构建流程做得相当成熟不存在“必须依赖官方安装器”的说法。源码包本质上就是仓库某个版本的快照拿到之后先看根目录的README.md和CMakeLists.txt里的最低版本要求。1.2 AWS SDK for C 的核心模块结构与设计思路这个 SDK 不是一个大而全的单一库而是拆成了很多独立模块。最底层是aws-cpp-sdk-core所有服务模块都依赖它负责 HTTP 请求、签名、凭据管理、内存管理和日志。上面的服务模块则按照 AWS 服务划分比如aws-cpp-sdk-s3、aws-cpp-sdk-ec2、aws-cpp-sdk-dynamodb每个模块对应一组客户端类和请求/响应模型对象。这种模块化设计对 C 开发者来说非常关键。实际工程里十有八九只用到一两个服务比如只上传文件到 S3那完全没必要把 EC2、Lambda 这些模块编进来。CMake 里通过-DBUILD_ONLYs3;core就能把构建范围收缩到最小。我自己第一次编译时图省事全量构建结果在低配 Linux 机器上跑了一个多小时大量时间耗费在编译用不到的模块上。后来学乖了每次新增服务调用才重新跑一次 CMake增量编译非常快。模块化设计也直接决定了代码写法。S3Client、EC2Client这些类都是独立构造的它们共享Aws::SDKOptions这个全局配置。理解了这个结构写代码时就不会困惑“为什么每个 main 函数里都要先调用Aws::InitAPI”。因为 core 模块需要统一初始化全局的 HTTP 客户端、线程池和内存分配器这是 C SDK 的一个设计特点也经常被吐槽“重”但它换来的是一致的行为和可控的资源释放。2. 编译环境准备依赖库、CMake、编译器一个不少2.1 编译器版本与 CMake 配置要点AWS SDK for C 从较早的版本开始就要求 C 11 标准但实际使用中建议直接用 C 17 或更新版本。原因很简单这个 SDK 的异步回调接口和标准库容器交互非常频繁新的 C 标准能少写大量样板代码。在 GCC 上版本低于 7 的编译器基本没法编译新版 SDK因为模板特化能力和标准库支持都不够。Clang 的话建议 10 以上。Windows 上则避开老旧的 MSVC 2015老老实实用 2019 或 2022。CMake 建议 3.15 以上因为新版 SDK 的构建脚本用到了一些较新的target_link_options和FetchContent特性。如果系统自带 CMake 版本太低别再死磕了直接装新版。另外构建 Release 版时务必设置-DCMAKE_BUILD_TYPERelease否则 SDK 自身会带上大量调试符号编译慢、运行也慢最终链接出的二进制体积还会翻几倍。提示如果是在容器或者 CI 环境里编译记得先把基础依赖装齐避免编译到一半因为找不到头文件报错。Linux 上主要缺的是libcurl4-openssl-dev、libssl-dev、zlib1g-dev。2.2 依赖库curl、OpenSSL、zlib 的细节问题这个 SDK 的 HTTP 客户端默认基于 libcurl签名计算又依赖 OpenSSL压缩相关功能依赖 zlib。如果你只是做 S3 上传下载这三个依赖基本是绕不开的。版本方面OpenSSL 1.1.1 和 3.x 都支持但需要注意一个细节如果系统中同时存在多个 OpenSSL 版本CMake 可能找错路径最终链接出运行时 报libssl.so.1.1找不到的问题。我的经验是在 CMake 配置阶段就明确指定依赖路径比如-DCMAKE_PREFIX_PATH/usr/local/ssl或者直接把依赖装进/usr/local下让 CMake 查找时不产生歧义。zlib 一般不会出问题但 Windows 上如果用的预编译包要确认压缩包里的 zlib 是动态库还是静态库混用的话运行时会出现zlib1.dll缺失的经典报错。2.3 裁剪编译用 BUILD_ONLY 控制构建规模这个参数值得单独写。BUILD_ONLY是 AWS SDK 提供的一个 CMake 开关作用是只构建列出的服务模块不构建全部。命令形式是cmake -DBUILD_ONLYs3;core -DENABLE_TESTINGOFF -DCMAKE_BUILD_TYPERelease ..这里有几个隐藏细节。第一core必须带上因为所有模块都依赖它不写也没关系SDK 会自动依赖但写了更明确。第二ENABLE_TESTING一定要关掉否则它会尝试下载额外的测试依赖既浪费时间又容易失败。第三如果你用到 S3 的加密功能可能还需要追加kms模块否则某些带 KMS 加密的对象无法正常下载。编译单元的数量从几十个缩减到五六个之后整个编译时间能控制在一两分钟内。这个优化对后续迭代开发相当重要毕竟没人想在改一行代码后等待十几分钟的编译。3. 构建与集成从源码到可执行程序的完整链路3.1 Linux 下从源码编译 AWS SDK 的完整步骤这里以 Ubuntu 20.04 环境为例完整走一遍。首先要确保依赖装齐sudo apt update sudo apt install -y build-essential cmake libcurl4-openssl-dev libssl-dev zlib1g-dev然后解压源码包创建构建目录并执行 CMakeunzip aws-sdk-cpp.zip cd aws-sdk-cpp mkdir build cd build cmake -DCMAKE_BUILD_TYPERelease \ -DBUILD_ONLYs3;core \ -DENABLE_TESTINGOFF \ -DCMAKE_INSTALL_PREFIX/usr/local \ .. make -j$(nproc) sudo make install编译完成后头文件会安装到/usr/local/include/aws/库文件在/usr/local/lib/。这样系统里就有了可被 CMake 找到的 AWS SDK 库。make -j$(nproc)这里的nproc是获取 CPU 核心数用于并行编译但并行度过高可能内存暴涨8G 内存以下的机器建议-j2。注意如果遇到fatal error: aws/core/Aws.h: No such file or directory十有八九不是 SDK 没装好而是你工程里的 CMake 没有把/usr/local/include加到搜索路径。3.2 Windows 上用 vcpkg 或预编译包接入Windows 下最省心的方式是 vcpkg。也许你已经把 vcpkg 配置好了那么一条命令就能装好vcpkg install aws-sdk-cpp[s3]这个 triplet 默认是 x64-windows如果你需要静态链接可以指定x64-windows-static。安装完成后需要告诉 CMake 这个工具链文件cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE[vcpkg根目录]/scripts/buildsystems/vcpkg.cmake如果你拿到的是预编译的.zip里面的目录结构一般是include/和lib/。这时要手动在 CMakeLists.txt 里指定路径list(APPEND CMAKE_PREFIX_PATH D:/aws-sdk-cpp)只要压缩包的目录结构里带了cmake/配置目录find_package就能正确找到。另外Windows 上特别容易踩的一个坑是动态库和静态库的选择。用预编译包时一定要看它内置的AWS_SDK_LINKED_AS_SHARED_LIBRARY标记如果你在 CMake 里定义的宏和预编译包不一致链接会报一堆无法解析的外部符号。3.3 在 CMake 工程中链接 SDK 的正确姿势工程里配置 AWS SDK 链接最直观的方式是使用官方的 CMake 配置文件。在 CMakeLists.txt 里这么写find_package(aws-cpp-sdk-s3 REQUIRED) find_package(aws-cpp-sdk-core REQUIRED) add_executable(my_aws_app main.cpp) target_link_libraries(my_aws_app PRIVATE aws-cpp-sdk-s3 aws-cpp-sdk-core) target_compile_features(my_aws_app PRIVATE cxx_std_11)代码里直接#include aws/s3/S3Client.h即可。这里有个小细节如果 SDK 是动态编译的在 Windows 上需要定义AWS_S3_EXPORTS之类的宏吗不用那是编译 SDK 时用的使用方只需要链接正确的库即可。但如果是 Linux 上自己编译的静态库需要额外链接平台相关依赖比如pthread和curlCMake 里可以这样补全find_package(CURL REQUIRED) target_link_libraries(my_aws_app PRIVATE ${CURL_LIBRARIES}) target_link_libraries(my_aws_app PRIVATE Threads::Threads)如果嫌麻烦也可以直接用pkg-config来处理依赖。不过我用下来还是 CMake 的find_package最简单直接。4. 第一个 C AWS 程序S3 上传下载实战4.1 初始化与凭据配置S3 上传下载是 AWS SDK 最典型的入门场景。先放一个完整的可运行代码框架#include aws/core/Aws.h #include aws/s3/S3Client.h #include aws/s3/model/PutObjectRequest.h #include aws/s3/model/GetObjectRequest.h #include iostream #include fstream int main() { Aws::SDKOptions options; Aws::InitAPI(options); { Aws::S3::S3Client client; // 业务代码编写位置 } Aws::ShutdownAPI(options); return 0; }Aws::InitAPI和Aws::ShutdownAPI是必须成对出现的建议放在main函数最外层。这段代码背后做的事情很多初始化全局 HTTP 客户端、加载本地凭据、设置日志系统。如果你项目里用了多个线程同时调用 SDK所有线程必须在这个作用域之内运行。脱离InitAPI作用域的线程只要调用了 SDK 接口大概率会出现未定义行为。凭据配置方面SDK 按照固定的优先级查找环境变量AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY本地~/.aws/credentials文件IAM 角色挂载仅限 AWS 实例上运行时在本地开发时最常用的是前两种。S3Client默认区域是us-east-1如果你的 bucket 在其他区域必须显式指定否则会报PermanentRedirect错误Aws::Client::ClientConfiguration config; config.region cn-north-1; Aws::S3::S3Client client(config);4.2 上传文件与错误处理写一个简单的上传本地文件到 S3 bucket 的函数bool PutFile(const std::string bucket, const std::string key, const std::string file_path) { Aws::S3::S3Client client; Aws::S3::Model::PutObjectRequest request; request.SetBucket(bucket); request.SetKey(key); auto input_data Aws::MakeSharedAws::FStream(PutObject, file_path.c_str(), std::ios::binary | std::ios::in); if (!input_data-good()) { std::cerr Failed to open file: file_path std::endl; return false; } request.SetBody(input_data); auto outcome client.PutObject(request); if (outcome.IsSuccess()) { return true; } std::cerr PutObject error: outcome.GetError().GetExceptionName() : outcome.GetError().GetMessage() std::endl; return false; }关于内存管理这里特意用了Aws::FStream而不是标准库std::ifstream因为 SDK 内部要求 body 对象的类型必须满足它自己的内存分配规范。其实用std::make_sharedstd::ifstream也能编译通过但可能出现运行时行为不一致的问题我的经验是 SDK 例子里怎么写就怎么来别搞原创。4.3 异步接口的使用时机SDK 的异步接口是用回调方式实现的典型的下载场景如下void GetObjectAsync(const Aws::S3::S3Client client, const std::string bucket, const std::string key) { Aws::S3::Model::GetObjectRequest request; request.SetBucket(bucket); request.SetKey(key); auto callback [](const Aws::S3::S3Client*, const Aws::S3::Model::GetObjectRequest, const Aws::S3::Model::GetObjectOutcome outcome, const std::shared_ptrconst Aws::Client::AsyncCallerContext) { if (outcome.IsSuccess()) { auto result outcome.GetResult(); std::cout Download size: result.GetBody().rdbuf() std::endl; } else { std::cerr GET object error: outcome.GetError().GetMessage() std::endl; } }; client.GetObjectAsync(request, callback); }请注意异步接口的回调是在 SDK 内部线程池上调用的所以不要在回调里去操作已经销毁的变量。如果回调里涉及界面刷新或共享资源务必加锁或者把数据发到自己的消息队列里。这一点和任何 C 异步框架的习惯一样。5. 线上踩坑与性能调优经验5.1 常见编译/链接报错速查表我把这段时间维护 C 服务遇到的典型问题整理成了速查表报错现象根本原因解决方案fatal error: aws/core/Aws.h: No such file头文件路径未配置检查target_include_directories或 SDK 安装路径是否正确undefined reference to Aws::S3::S3Client::...链接库缺失或顺序错误在target_link_libraries中把 SDK 库放到被依赖库前面大量unresolved external symbol动态/静态链接方式不匹配检查AWS_SDK_LINKED_AS_SHARED_LIBRARY宏是否与链接库类型一致PermanentRedirect客户端区域和 bucket 区域不一致初始化S3Client时显式设置config.region证书校验失败本地 CA 证书缺失或过期更新系统的 ca-certificates 包链接顺序问题在 Linux 上特别妖如果aws-cpp-sdk-s3依赖aws-cpp-sdk-core但链接命令里写了aws-cpp-sdk-core在前、aws-cpp-sdk-s3在后就会出现一堆 undefined reference。我一般是把 SDK 库列表放在所有自定义库之前让链接器从右往左解析时能找到它们。5.2 运行时问题证书、超时与内存清理运行时最常见的坑就是证书问题。如果你在 Linux 服务器上遇到curlCode: 77之类的报错基本都是 CA 校验失败。最简单的解决方法是sudo apt install ca-certificates sudo update-ca-certificates如果是在内网访问自建 S3 兼容服务可以通过ClientConfiguration里的verifySSL开关来规避证书问题但生产环境不建议关掉校验。内存清理也是容易出问题的点。SDK 内部大量使用shared_ptr如果你把Aws::FStream对象赋给请求体后没保留引用可能在请求完成前被释放。之前我遇到过一次“上传文件偶尔损坏”的诡异问题最后排查下来就是 stream 对象被提前析构。另外如果你的程序会长时间运行记得定期调用Aws::ShutdownAPI和重新InitAPI不整个进程生命周期内只需要一次。SDK 的 HTTP 连接池会维持连接这个和 curl 的全局状态类似不要反复开关。5.3 性能与体积优化心得实际生产环境下大部分人不会只上传一个小文件。大文件上传要优先使用 S3 Multipart UploadSDK 的UploadPartRequest可以支持分片并行上传。我在一个项目里用 8 个并发分片上传 5GB 的大文件速度比单请求快了三倍多。当然分片大小和并发数的选择要结合带宽和内存来调整分片过小会导致请求数量暴涨网络往返成本反而上升。另外是二进制体积问题。静态链接 AWS SDK 后程序体积动辄增加几十 MB。如果项目对二进制体积有要求可以尝试三种优化思路使用BUILD_ONLY裁剪模块不用的服务不编译进来。编译时开启-ffunction-sections -fdata-sections链接时启用--gc-sections把未使用的函数和数据回收掉。如果真机上有对应动态库直接动态链接是最优解但要维护库的分发部署。结尾写了这么多最后分享一点个人的实际体会。AWS SDK for C 的官方文档更像是一本字典适合查阅不太适合当教程从头读到尾。我快速上手的方式还是找一个开源项目直接看它的 CMakeLists.txt 和核心调用代码然后照着结构改。这个 SDK 的学习曲线主要不在 API 本身而在 C 工程化那一整套东西——CMake 配置、依赖管理、链接策略、构建产物组织。只要把这几条理顺了后面换任何 AWS 服务模块写代码都只是照葫芦画瓢。最后再提一个容易被忽略的小细节如果你是在国内使用 AWS 服务记得把ClientConfiguration里的endpointOverride配置好某些情况下用官方默认 endpoint 会走绕路线路延迟高得离谱。这不是 SDK 的问题但属于实战里一定会遇到的优化点。希望这些经验能帮你少走几个弯路。本文还有配套的精品资源点击获取