环境:
起初,我是在 M1 通过 brew 安装的 openssl。通过安装命令
$ brew install openssl
最新版本的openssl。安装后的目录为
- /opt/homebrew/opt/openssl
- /opt/homebrew/opt/openssl/lib
- /opt/homebrew/opt/openssl/include/
发现不行,需要自己编译 x86_64 版本。
从 https://www.openssl.org/source/ 下载 openssl-1.1.1g.tar.gz。解压后将文件夹修改为 openssl-1.1.1g-x86_64
,在此文件夹下生成 x86_64 版本的 openssl。终端进入该目录,开始编译。
export MACOSX_DEPLOYMENT_TARGET=10.15
cd openssl-1.1.1g-x86_64
./Configure darwin64-x86_64-cc shared
make
成功的话,就可以在文件夹下看到生成的动态库和静态库文件:
通过生成多个架构的 openssl,可以参考:How to build openssl for M1 and for Intel?。
CMake 是一个跨平台的编译工具,可以用简单的语句来描述所有平台的编译过程。到 CMake 的下载页面,下载并安装 CMake。
在 Mac 中自带了 CMake,可以通过命令行的方式编译阿里 OSS sdk,也可以安装 CMake,生成 Xcode 项目编译阿里 OSS sdk。
首先查看阿里文档。根据提示,下载 c++ SDK 的安装包并解压:
打开终端,进入目录aliyun-oss-cpp-sdk-master
。创建 build 文件夹,并进入。
mkdir build
cd build
配置 cmake:
cmake -DOPENSSL_ROOT_DIR=/Users/...../openssl-1.1.1g-x86_64 \
-DOPENSSL_INCLUDE_DIRS=/Users/...../openssl-1.1.1g-x86_64/include/ \
-DCMAKE_OSX_ARCHITECTURES=x86_64 ..
其中:
arm64;x86_64
。经过测试 DOPENSSL_LIBRARIES 并不需要指定。
打开 build/CMakeCache.txt
的文件,找到下面的内容:
//Minimum OS X version to target for deployment (at runtime); newer
// APIs weak linked. Set to empty string for default value.
CMAKE_OSX_DEPLOYMENT_TARGET:STRING=
设置 CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.15
系统版本,因为 UE 的支持的最低版本为 10.15。如果不设置的话,在之后的使用当中,会报如下的错误:
libalibabacloud-oss-cpp-sdk.a(OssClient.cc.o)) was built for newer macOS version (12.0) than being linked (10.15)
这个值应该怎么通过命令进行设置呢?我暂时没有找到。
设置之后,开始编译:
make
结果报错了
/Users/fuyoufang/Desktop/UE_OSS/aliyun-oss-cpp-sdk-master/sample/src/bucket/BucketSample.cc:440:25: error: loop variable 'rule' creates a copy from type 'const AlibabaCloud::OSS::LifecycleRule' [-Werror,-Wrange-loop-construct]
for (auto const rule : outcome.result().LifecycleRules()) {
^
/Users/fuyoufang/Desktop/UE_OSS/aliyun-oss-cpp-sdk-master/sample/src/bucket/BucketSample.cc:440:14: note: use reference type 'const AlibabaCloud::OSS::LifecycleRule &' to prevent copying
for (auto const rule : outcome.result().LifecycleRules()) {
^~~~~~~~~~~~~~~~~
&
/Users/fuyoufang/Desktop/UE_OSS/aliyun-oss-cpp-sdk-master/sample/src/bucket/BucketSample.cc:473:29: error: loop variable 'origin' creates a copy from type 'const std::string' [-Werror,-Wrange-loop-construct]
for (auto const origin : rule.AllowedOrigins()) {
^
/Users/fuyoufang/Desktop/UE_OSS/aliyun-oss-cpp-sdk-master/sample/src/bucket/BucketSample.cc:473:18: note: use reference type 'const std::string &' to prevent copying
for (auto const origin : rule.AllowedOrigins()) {
^~~~~~~~~~~~~~~~~~~
&
/Users/fuyoufang/Desktop/UE_OSS/aliyun-oss-cpp-sdk-master/sample/src/bucket/BucketSample.cc:471:25: error: loop variable 'rule' creates a copy from type 'const AlibabaCloud::OSS::CORSRule' [-Werror,-Wrange-loop-construct]
for (auto const rule : outcome.result().CORSRules()) {
^
/Users/fuyoufang/Desktop/UE_OSS/aliyun-oss-cpp-sdk-master/sample/src/bucket/BucketSample.cc:471:14: note: use reference type 'const AlibabaCloud::OSS::CORSRule &' to prevent copying
for (auto const rule : outcome.result().CORSRules()) {
^~~~~~~~~~~~~~~~~
&
3 errors generated.
make[2]: *** [sample/CMakeFiles/cpp-sdk-sample.dir/src/bucket/BucketSample.cc.o] Error 1
make[1]: *** [sample/CMakeFiles/cpp-sdk-sample.dir/all] Error 2
make: *** [all] Error 2
应该是编辑条件比较严格,for (auto const rule : outcome.result().LifecycleRules()) { }
,会进行拷贝操作,应该使用引用。打开 aliyun-oss-cpp-sdk-master/sample/src/bucket/BucketSample.cc 文件,在 440,471,473 行,修一下报错的地方,修改为引用
使用,即在变量前加 &
。重新编译。
make
此时,应该编译成功,就可以看到编译好的 build/lib/libalibabacloud-oss-cpp-sdk.a
文件了。
创建一个 C++ 类型的 UE 项目 TestAliOSS
,来测试编译好的库文件。
给 UE 项目 TestAliOSS
,创建一个插件 AliOSS
,用于封装阿里 OSS sdk。
此处创建一个空白的插件,命名为 AliOSS
。
在 AliOSS
的源码路径 Source
下,新建文件 OSSThirdParty
文件,然后做以下操作:
OSSThirdParty/Lib
文件下;OSSThirdParty/include
文件下,即阿里 OSS 相关的头文件OSSThirdParty/include/
文件下,即 curl 相关的头文件( 我发现复制过来的 openssl 头文件不行)OSSThirdParty/include
文件下,即 openssl 相关的头文件;~~OSSThirdParty/lib/Mac_x86_64~~
第 6 步中的 libcurl.tbd
文件是什么?
libcurl 是 mac 的一个库文件。我是在阿里源码中,通过 Cmake 生成的项目文件中,看到需要 link 这样一个文件。拷贝这个文件到插件当中,感觉有点奇怪,但是暂时没办通过其他方式不依赖这个文件。
现在目录结构为
修改 AliOSS.Build.cs
文件为下面的内容:
// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.IO;
using UnrealBuildTool;
public class AliOSS : ModuleRules
{
private string OSSThirdPartyPath
{
get
{
// ModuleDirectory 为插件的 项目路径/Plugins/SimpleOSS/Source/SimpleOSS/ 目录
return Path.GetFullPath(Path.Combine(ModuleDirectory, "../OSSThirdParty/"));
}
}
public AliOSS(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
string OssincludePath = Path.Combine(OSSThirdPartyPath, "include");
PublicIncludePaths.Add(OssincludePath);
string AlibabacloudPath = Path.Combine(OssincludePath, "alibabacloud/oss");
PublicIncludePaths.Add(AlibabacloudPath);
PublicIncludePaths.Add(Path.Combine(AlibabacloudPath, "auth"));
PublicIncludePaths.Add(Path.Combine(AlibabacloudPath, "client"));
PublicIncludePaths.Add(Path.Combine(AlibabacloudPath, "encryption"));
PublicIncludePaths.Add(Path.Combine(AlibabacloudPath, "http"));
PublicIncludePaths.Add(Path.Combine(AlibabacloudPath, "model"));
PublicIncludePaths.Add(Path.Combine(AlibabacloudPath, "utils"));
// PublicIncludePaths.Add(Path.Combine(OssincludePath, "curl"));
PublicIncludePaths.Add(Path.Combine(OssincludePath, "openssl"));
string LibPath = Path.Combine(OSSThirdPartyPath, "lib");
PublicIncludePaths.Add(LibPath);
PublicAdditionalLibraries.Add(Path.Combine(LibPath, "libalibabacloud-oss-cpp-sdk.a"));
// 被注释掉的两个,可以使用下面的替换
//PublicAdditionalLibraries.Add(Path.Combine(LibPath, "Mac_x86_64", "libcrypto.a"));
//PublicAdditionalLibraries.Add(Path.Combine(LibPath, "Mac_x86_64", "libssl.a"));
AddEngineThirdPartyPrivateStaticDependencies(Target, "libcurl");
AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenSSL");
PublicAdditionalLibraries.Add(Path.Combine(LibPath, "Mac_x86_64", "libcurl.4.tbd"));
}
}
注意添加头文件:
using System;
using System.IO;
在插件中添加测试程序,新建 Test.h 和 Test.cpp,创建一个 OSSTest 类,内容分别如下:
#pragma once
#include "CoreMinimal.h"
namespace OSSTest
{
// 加上导出宏,否则其他模块无法使用
// 导出宏的格式为,`插件名字的大写_API`
ALIOSS_API int32 MainOSS();
}
#include "Test.h"
#include "alibabacloud/oss/OssClient.h"
using namespace AlibabaCloud::OSS;
int32 OSSTest::MainOSS()
{
std::string AccessKeyId = "";
std::string AccessKeySecret = "";
std::string Endpoint = "";
std::string BucketName = "";
/* 初始化网络等资源 */
InitializeSdk();
return 0;
}
注意,插件中的方法要在其他模块中使用时,需要加上导出宏,否则其他模块无法使用。导出宏的格式为,插件名字的大写_API
。比如插件的名字为AliOSS
时,导出宏为:ALIOSS_API
。
在 UE 工程中的 TestAliOSS.Build.cs 中添加依赖 AliOSS
。
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "AliOSS" });
在 ATestOSSGameModeBase 的 BeginPlay() 方法中调用测试方法 MainOSS
。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "TestOSSGameModeBase.generated.h"
/**
*
*/
UCLASS()
class TESTOSS2_API ATestOSSGameModeBase : public AGameModeBase
{
GENERATED_BODY()
public:
virtual void BeginPlay() override;
};
#include "TestOSSGameModeBase.h"
#include "Test.h"
void ATestOSSGameModeBase::BeginPlay()
{
Super::BeginPlay();
OSSTest::MainOSS();
}
结果编译错误:
Declaration shadows a variable in namespace ‘AlibabaCloud::OSS’
不知道具体原始是什么,暂时直接将 URL 改成 URL1
。
enumType
{
URL1 = 0,
JSON
};
发现可以通过编译了。
不知道为什么在 Mac M1 下,UE5 经常遇到下面的问题:
CodeSign /Volumes/devfang/App/UE_5.0/Engine/Binaries/Mac/UnrealEditor.app
cd /Volumes/devfang/com/Test/TestAliOSS/Intermediate/ProjectFiles
export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
Signing Identity: "-"
/usr/bin/codesign --force --sign - --generate-entitlement-der --entitlements /Volumes/devfang/com/Test/TestAliOSS/Intermediate/ProjectFiles/build/TestAliOSS.build/Development\ Editor/TestAliOSS.build/UnrealEditor.app.xcent --timestamp=none /Volumes/devfang/App/UE_5.0/Engine/Binaries/Mac/UnrealEditor.app
/Volumes/devfang/App/UE_5.0/Engine/Binaries/Mac/UnrealEditor.app: No such file or directory
Command /usr/bin/codesign failed with exit code 1
解决方案为:重新校验 UE5 。