十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AWS SDK for C++ 1.11.4 x86平台源码编译与集成实践

AWS SDK for C++ 1.11.4 x86平台源码编译与集成实践 简介面向 Windows x86 架构的 AWS SDK for C 1.11.4 预编译二次开发包专供需要以 C 语言调用亚马逊云服务接口的桌面应用开发者使用。压缩包内已生成可直接引用的动态链接库、静态导入库和头文件目录接入 Visual Studio 工程即可开始开发省去从源码仓库拉取并自主编译的漫长等待。资源共含 758 个文件约 25.81MB其中 491 个头文件与 22 个内联文件完整描述接口32 个静态库和 34 个动态库负责链接与运行另配构建配置、调试符号、JSON 及文本说明便于集成和定位问题。当前已有 721 人学习下载包内还包含构建配置与外部依赖检测脚本可帮助开发者快速理清模块关系完成工程引入。拿到手即可跳过 SDK 构建阶段直接聚焦业务逻辑适合需要快速验证云端接口调用或搭建 C 云应用的开发者。 接到一项有点特殊的任务把AWS SDK for C 1.11.4编译成x86-windows平台的库给一个依赖32位原生组件的旧项目做S3上传功能。说实话刚看到这个组合时我心里是有预判的——版本锁在1.11.4平台锁在x86这两个限制叠加起来坑不会少。实际动工后确实如此编译、链接、运行时都有不少值得记下来的细节。如果你也在做同样的事这篇文章应该能帮你少走不少弯路。我最终用的是源码编译方式环境是Windows 10 Visual Studio 2019 CMake 3.24目标架构Win32也就是x86。整个过程中最花时间的不是写代码而是把编译参数、依赖库、运行库这几层关系理清楚。下面按我的实际操作顺序来写。1. 为什么是“1.11.4 x86”这个组合1.1 被生产环境锁定的版本aws-sdk-cpp的迭代速度不算慢每个季度都有新版本推进1.11.x系列是2022年前后的主流版本。很多团队不敢贸然升级SDK原因是内部代码已经基于某个特定版本的API接口开发牵扯到请求签名、网络栈、依赖库的ABI兼容性。升级一个minor版本都可能需要重新跑全量回归测试更不用说跨大版本了。1.11.4属于这个系列里相对稳定的tag很多项目的release分支就钉在这里。如果你用vcpkg直接安装aws-sdk-cpp默认拿到的是当前最新版本而不是1.11.4。一旦代码用了旧版API编译时就会出现接口不匹配比如某个枚举值被改名、某个Client构造函数签名变化、某个头文件路径调整。所以锁定版本这件事要从工具链层面解决不能等到编译报错了才回头查。1.2 x86在Windows生态里并没有消失很多人觉得现在随便一台电脑都是64位为什么还要出32位库。现实是金融、工控、医疗行业里有大量存量系统仍然跑在x86架构上。银行U盾、加密狗、某些老版ODBC驱动、第三方COM组件往往只有32位版本只要项目里存在一个这样的依赖整个进程就必须是x86。更麻烦的是这类依赖通常没有替代品也不是项目组能决定替换的。所以x86-windows并不是“过时的选择”而是这些场景里的硬性约束。你在64位机器上调试32位目标完全没问题Visual Studio支持的也很好运行时的WOW64机制会把32位进程跑在64位系统上。真正的难点在于32位进程能用的内存地址空间被限制在2GB或开启大地址后约4GB而且加载的DLL也必须是32位版本这一点在后面集成第三方依赖时会反复遇到。1.3 1.11.4和最新版的核心差异观察我之所以强调版本是因为实际踩过升级的坑。aws-sdk-cpp在1.11.x后期到1.12.xS3Client的构造方式、部分API的返回类型、错误处理的枚举定义都有调整。比如早期版本里直接用Aws::S3::S3Client client;就可以构造客户端后续版本有些场景需要显式传入ClientConfiguration否则可能拿到默认region导致请求失败。类似的细节在官方文档里不一定标注清楚只能靠编译期错误一个个试出来。做这次x86编译前我特意对比了一下1.11.4和当时最新版的CMakeLists.txt差异发现依赖库的版本基线、编译选项开关都有变化。如果你的项目已经锁定了老版本那么按最新版教程去编译大概率是行不通的。最好的做法就是跟着源码包里的README和CMake参数走别凭经验猜。2. 环境准备工具链版本直接影响编译成败2.1 Visual Studio与平台工具集的选择我用的Visual Studio 2019组件里勾选了“使用C的桌面开发”Windows SDK选的是10.0.19041.0。这套组合编译1.11.4没有遇到系统库缺失的问题。如果你的机器上只装了VS2022也没关系1.11.4的CMake脚本对VS2022生成器是兼容的但要注意Windows SDK版本别选太新。这里有个很容易忽略的点VS安装器里的“单个组件”页可以同时安装多个Windows SDK版本。1.11.4的构建脚本在检查Windows SDK时如果检测到过新的版本偶尔会触发ATL/MFC相关的校验错误而你的项目根本不需要ATL。遇到这种情况把CMake的-DCMAKE_SYSTEM_VERSION显式指定成旧版SDK号比如10.0.19041.0能绕过去。2.2 CMake与Ninja的版本坑1.11.4要求的CMake最低版本其实不高3.15以上就能跑但我在实际操作中推荐至少3.20。原因很简单新版CMake对VS生成器的匹配更稳定对BUILD_DEPS自动拉取依赖的缓存逻辑也更好用。不建议在Windows上单独装Ninja来配合这个老版本SDK。Ninja生成器需要你提前准备好所有编译环境变量不然很容易出现“找不到rc.exe”或者“无法启动MT.exe”这类CLion用户经常遇到的报错。直接用Visual Studio生成器CMake会在构建时自动加载环境的编译工具省去手动配置的麻烦。你只需要记住生成器类型和架构参数要同时指定缺一个后面就会构建出错误的平台产物。2.3 vcpkg还是源码编译我选了后者vcpkg确实方便一条vcpkg install aws-sdk-cpp[s3]:x86-windows就能装完还自动处理依赖。但问题有三点vcpkg默认安装的版本可能不是你想要的1.11.4而是当前vcpkg仓库里的最新版本除非你用manifest mode配合builtin-baseline锁版本。x86-windows triplet默认编译动态库如果你需要的是静态库要自己写triplet文件这对新手并不友好。vcpkg生成的CMake target路径比较特殊在老旧CMake工程里集成时需要调整CMAKE_TOOLCHAIN_FILE老项目常常不愿意改这个。所以当项目里必须精确使用1.11.4时我更推荐直接源码编译。整个过程不过多依赖包管理器的黑盒逻辑出了问题也容易排查。接下来的步骤全部基于源码编译。3. 从源码编译1.11.4的完整过程3.1 拉取源码与模块裁剪先拉源码指定taggit clone --branch 1.11.4 --depth 1 https://github.com/aws/aws-sdk-cpp.git cd aws-sdk-cpp这一步没有特别之处但要注意--depth 1会减少拉取量只保留这个tag的代码。如果你的网络环境不好GitHub访问慢可以考虑设置git代理或者用镜像仓库这一步取决于你的网络条件我就不展开说了。源码拉下来之后最关键的一步是裁剪模块。aws-sdk-cpp的源码默认包含几乎所有AWS服务模块如果全量编译在x86平台上会非常耗时。我只用了S3和核心模块通过BUILD_ONLY参数裁剪cmake -S . -B build \ -G Visual Studio 16 2019 \ -A Win32 \ -DBUILD_ONLYs3;core \ -DENABLE_TESTINGOFF \ -DBUILD_DEPSON \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_INSTALL_PREFIXC:/aws-sdk-cpp-1.11.4-x86BUILD_ONLY的意思是只构建s3和core模块这样CMake就不会为EC2、Lambda、DynamoDB等几十个模块生成工程文件编译时间可以从半小时缩短到几分钟。如果你的场景只用SQS就把BUILD_ONLY换成sqs;corecore永远要保留它是所有模块的基础。3.2 CMake配置参数逐个拆解上面命令里的几个参数每一个都值得解释清楚。-G Visual Studio 16 2019指定生成器VS2019对应的就是16VS2022对应17。-A Win32是重点它告诉CMake目标架构是32位x86而不是默认的x64。很多人在这一步出错因为只写了-G忘了写-A结果编译出来全是x64的库链接时一堆unresolved external symbol。-DBUILD_DEPSON是我强烈建议打开的选项。它的作用是让CMake自动拉取并编译aws-sdk-cpp的第三方依赖包括libcurl、OpenSSL、zlib等。Windows上手工配置这些依赖非常痛苦尤其是OpenSSL的32位版本如果你去官方下载安装包安装时还要手动指定DLL路径。打开BUILD_DEPS后这些依赖会跟着SDK一起编译生成的DLL也统一放在安装目录里省心很多。-DCMAKE_BUILD_TYPERelease在VS生成器下影响不大因为VS的配置是编译时通过--config Release指定的但保留这个参数可以让部分CMake脚本在生成阶段就采用Release优化选项。-DCMAKE_INSTALL_PREFIX指定安装目录后续编译好的头文件、库、DLL都会集中到这里方便集成时引用。3.3 编译、安装与产物验证配置成功后开始编译cmake --build build --config Release --parallel--parallel会启用多核编译我实测在8核机器上编s3core模块几分钟就完成了。编译过程中如果出现C4996这类安全警告不用管不影响产物。编译完成后安装cmake --install build --config Release安装完成后建议去C:/aws-sdk-cpp-1.11.4-x86目录检查一下。正常情况下会有三个子目录include放头文件lib放.lib导入库和CMake配置文件bin放.dll运行库。重点确认bin目录下有aws-cpp-sdk-core.dll和aws-cpp-sdk-s3.dll同时还有libcurl、openssl等第三方DLL。如果缺了某个DLL后面运行你的程序时会报“找不到DLL”所以这一步值得花十秒钟看一眼。4. 集成时最容易被绊倒的链接与运行问题4.1 需要链接哪些库SDK装好之后集成到你的项目里时要链接的库并不多。以S3为例aws-cpp-sdk-s3.libaws-cpp-sdk-core.lib如果是Debug版本库文件会带-d后缀也就是aws-cpp-sdk-s3-d.lib和aws-cpp-sdk-core-d.lib。注意Release和Debug库不要混用否则会出现运行时行为诡异的问题。我一般会建议项目里同时保留两种配置的安装目录比如aws-sdk-release和aws-sdk-debug互不干扰。在Visual Studio工程里除了在“附加依赖项”里加这两个.lib还要把include目录指向C:/aws-sdk-cpp-1.11.4-x86/include把库目录指向.../lib。如果你用的是CMake工程可以直接find_package安装目录里的lib/cmake/aws-cpp-sdk-core和lib/cmake/aws-cpp-sdk-s3提供了现成的target只要在CMakeLists.txt里设置CMAKE_PREFIX_PATH指向安装根目录即可。4.2 运行时库/MD vs /MT的矛盾这是我在集成过程中被绊倒最狠的一次也是网上问得最多的问题。链接阶段报错大概是这样的LNK2038: mismatch detected for RuntimeLibrary: value MDd_DynamicRelease doesnt match value MD_DynamicRelease这个错误的意思是SDK编译时用的是动态CRT运行时库/MD而你的项目设置的是静态CRT/MT或者Debug/Release混了。Windows下这种不匹配非常常见。解决方法很直接在集成项目的解决方案里把运行库统一设置为“多线程DLL/MD”。在VS2019里的路径是项目属性 - C/C - 代码生成 - 运行库选择/MDRelease或/MDdDebug。如果是CMake项目确保没有在CMakeLists里显式设置/MTCMAKE_MSVC_RUNTIME_LIBRARY保持默认即可。还有一种情况是你自己同时用vcpkg装了别的库那个库是用/MT编译的最后链接时也会冲突。碰到这种优先保证SDK相关的所有项目都用/MD这是AWS官方构建时用的默认值。4.3 依赖DLL的搬运链接成功之后运行程序时系统会提示0xc000007b错误这个错误码在x86程序里几乎是“DLL架构不匹配”的代名词。原因通常是某个依赖DLL是x64版而你的程序是x86Windows加载器直接拒绝。处理办法是把安装目录下bin文件夹里的所有DLL拷贝到exe所在目录包括aws-cpp-sdk-core.dllaws-cpp-sdk-s3.dlllibcrypto-1_1.dllOpenSSLlibssl-1_1.dlllibcurl-x86.dllzlib1.dll如果你用BUILD_DEPSON编译这些依赖DLL都会出现在同一个bin目录下直接一起拷走就行。如果你是自己手工配置的依赖一定要确认这些DLL都是32位版本可以用依赖查看工具右键属性看一眼“详细信息”里的版本号是x86还是x64或者用dumpbin /headers xxx.dll查看FILE HEADER VALUES里的machine字段是x86。5. 实测最小S3客户端跑起来5.1 最小代码骨架为了验证SDK是否真的可用我写了一个最小的S3客户端只做ListBuckets操作。这个操作不需要额外权限只要凭证有效就能跑通非常适合作为SDK集成后的冒烟测试。#include aws/core/Aws.h #include aws/s3/S3Client.h #include aws/s3/model/ListBucketsResult.h #include iostream int main() { Aws::SDKOptions options; Aws::InitAPI(options); { Aws::S3::S3Client client; auto outcome client.ListBuckets(); if (outcome.IsSuccess()) { const auto buckets outcome.GetResult().GetBuckets(); for (const auto bucket : buckets) { std::cout bucket.GetName() std::endl; } } else { std::cerr ListBuckets error: outcome.GetError().GetExceptionName() - outcome.GetError().GetMessage() std::endl; return -1; } } Aws::ShutdownAPI(options); return 0; }这段代码在1.11.4下可以直接编译运行S3Client默认使用默认凭证链会自动读取本地的AWS凭证文件~/.aws/credentials或环境变量。如果你在本地没有任何凭证程序会报Unable to find credentials这属于正常现象配置好凭证即可。5.2 常见运行时错误记录实际跑的时候我遇到过两个麻烦。第一个是Failed to connect to service: Unable to connect to endpoint。这通常不是网络问题而是region没有正确设置。S3Client默认构造时用的region是us-east-1如果桶不在这个区域访问时会报错。解决办法是构造ClientConfiguration并设置regionAws::Client::ClientConfiguration config; config.region cn-north-1; // 按你的实际region填 Aws::S3::S3Client client(config);第二个是程序启动后卡了几秒然后报AWS_EC2_METADATA_DISABLED相关的错误。这是因为SDK的默认凭证链会尝试访问EC2元数据服务本地环境下这个探测超时较慢。如果确定没有使用IAM Role可以设置环境变量AWS_EC2_METADATA_DISABLEDtrue来跳过这个探测程序启动会明显变快。5.3 几个容易被忽略的小事最后说几个我在x86编译和使用中积累的小细节都不是大问题但遇到了会折腾人。第一AWS SDK内部大量使用STL容器和智能指针在x86环境下内存占用比x64小但2GB地址空间依然有限。如果你的程序需要同时缓存大量数据建议在VS工程里开启“大地址”/LARGEADDRESSAWARENESS这样32位进程在64位系统上可以获得接近4GB的地址空间。第二千万不要在Aws::InitAPI之前创建任何SDK客户端。官方文档虽然强调了但很多人还是会把静态全局客户端写在main之前导致初始化顺序错误程序崩溃时栈信息还不清晰。第三如果后续要更新SDK版本不要直接在原来的安装目录上覆盖安装建议换一个全新的前缀路径把旧目录保留一段时间。这样一旦新版本有问题你可以快速切回旧版本重新编译而不是在代码里改一堆#ifdef来适配版本差异。我自己的习惯是在项目根目录放一个third_party/aws-sdk文件夹里面按版本号建子目录比如1.11.4-x86-release和1.11.4-x86-debug。修改CMake的CMAKE_PREFIX_PATH即可切换版本既干净又不容易出错。这种笨办法看起来没什么技术含量但确实帮我省了无数次来回切换环境的时间。本文还有配套的精品资源点击获取
返回列表