DLL延迟加载
递归搜索指定后缀集合的文件
// Fill out your copyright notice in the Description page of Project Settings. using System.IO; using System.Collections.Generic; using UnrealBuildTool; namespace UnrealBuildTool.Rules { #if WITH_FORWARDED_MODULE_RULES_CTOR using zTargetInfo = ReadOnlyTargetRules; #else using zTargetInfo = TargetInfo; #endif public class HeXrTransceiverLib : ModuleRules { public HeXrTransceiverLib(zTargetInfo Target) #if WITH_FORWARDED_MODULE_RULES_CTOR : base(Target) #endif { Type = ModuleType.External; PublicIncludePaths.AddRange( new string[] { // ... add public include paths required here ... Path.Combine(ModuleDirectory, "include"), } ); // Add the import library //PublicLibraryPaths.Add(Path.Combine(ModuleDirectory, "lib")); PublicAdditionalLibraries.Add(Path.Combine(ModuleDirectory, "lib", "HeXrTransceiver.lib")); // Delay-load the DLL, so we can load it from the right place first PublicDelayLoadDLLs.Add("HeXrTransceiver.dll"); string dll_folder_path = Path.Combine(ModuleDirectory, "dll"); string[] dlls_fullpath = DFS_GetFilesRecursively(dll_folder_path, new string[] { ".dll" }); // Runtime Dependencies for Project Package foreach(string dll in dlls_fullpath) { string target_output_path = "$(TargetOutputDir)/dll".Replace("dll", Path.GetFileName(dll)); RuntimeDependencies.Add(target_output_path, dll); // copy // PublicDelayLoadDLLs.Add(Path.GetFileName(dll)); RuntimeDependencies.Add(target_output_path, StagedFileType.NonUFS); } } /* * Root: folder full path * FileExts: dll,jpg,txt,etc. * Return full path of files. */ public string[] DFS_GetFilesRecursively(string Root, string[] FileExts) { List<string> Ret = new List<string>(); DirectoryInfo DI = new DirectoryInfo(Root); foreach(FileInfo FI in DI.GetFiles()) { //System.Console.WriteLine("FI.Extension={0} FI.FullName={1}", FI.Extension, FI.FullName); foreach(string Ext in FileExts) { if (Ext.Equals(FI.Extension, System.StringComparison.OrdinalIgnoreCase)) { Ret.Add(FI.FullName); break; } } } foreach(DirectoryInfo SubDI in DI.GetDirectories()) { Ret.AddRange(DFS_GetFilesRecursively(SubDI.FullName, FileExts)); } return Ret.ToArray(); } /** * Root: folder full path * FileExts: dll,jpg,txt,etc. * Return full path of files. */ public string[] GetFiles_NoRecur(string Root, string[] FileExts) { List<string> Ret = new List<string>(); DirectoryInfo DI = new DirectoryInfo(Root); foreach (FileInfo FI in DI.GetFiles()) { //System.Console.WriteLine("FI.Extension={0} FI.FullName={1}", FI.Extension, FI.FullName); foreach (string Ext in FileExts) { if (Ext.Equals(FI.Extension, System.StringComparison.OrdinalIgnoreCase)) { Ret.Add(FI.FullName); break; } } } return Ret.ToArray(); } } }
UE4插件简单正确加载插件的方法
#include "Interfaces/IPluginManager.h" #include "HAL/FileManager.h" bool FSURAPluginRuntimeModule::LoadHeXrDependency( ) { // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module // Get the base directory of this plugin FString BaseDir = IPluginManager::Get( ).FindPlugin( "SURAPlugin" )->GetBaseDir( ); // Add on the relative location of the third party dll and load it FString DllFolder(FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/HeXrTransceiverLib/dll"))); FPlatformProcess::AddDllDirectory(*DllFolder); IFileManager::Get().IterateDirectoryRecursively(*DllFolder, [&](const TCHAR* Node, bool IsDir) -> bool { if (IsDir) { FPlatformProcess::AddDllDirectory(Node); } return true; }); FString LibraryPath; #if PLATFORM_WINDOWS LibraryPath = FPaths::Combine(*DllFolder, TEXT("HeXrTransceiver.dll")); #endif // PLATFORM_WINDOWS HeXr_LIB_HANDLE = !LibraryPath.IsEmpty( ) ? FPlatformProcess::GetDllHandle( *LibraryPath ) : nullptr; return HeXr_LIB_HANDLE != nullptr; }
RuntimeDependencies
If you want to have the DLL copied to the same output directory as the executable at build time, you do so via an overload of the RuntimeDependencies.Add method:
RuntimeDependencies.Add("$(TargetOutputDir)/Foo.dll", Path.Combine(PluginDirectory, "Source/ThirdParty/bin/Foo.dll"));
Other variables can be used for output paths of the DLL:
$(EngineDir) | The engine directory |
$(ProjectDir) | Directory containing the project file |
$(ModuleDir) | Directory containing the .build.cs file |
$(PluginDir) | Directory containing the .uplugin file |
$(BinaryOutputDir) | Directory containing the binary that this module is compiled into (for example, the path to the DLL for editor builds, and path to the executable (EXE) for packaged builds) |
$(TargetOutputDir) | Directory containing the executable (including in editor builds) |
module.build.cs文件常见字段
string path = Path.Combile(p1, p2, p3);
string absolutePath = Path.GetFullPath(path);
string absolutePath = Path.GetFullPath(path);
//https://docs.unrealengine.com/4.27/en-US/ProductionPipelines/BuildTools/UnrealBuildTool/ThirdPartyLibraries/
RuntimeDependencies.Add(Path.GetFullPath(absolutePath), StagedFileType.NonUFS);
RuntimeDependencies.Add(Path.GetFullPath(absolutePath), StagedFileType.NonUFS);
Public/PrivateDependencyModuleNames属于静态链接,通常其Public/PrivateIncludePaths会自行处理正确。
Public/PrivateIncludePathModuleNames与DynamicallyLoadedModuleNames配合属于动态链接,因此如果你使用了非抽象函数,则会提示无法找到链接符号。这一对配置的典型用法参考 #474,一般就是LoadModuleChecked,然后调用接口的抽象函数。
Public/PrivateIncludePathModuleNames与DynamicallyLoadedModuleNames配合属于动态链接,因此如果你使用了非抽象函数,则会提示无法找到链接符号。这一对配置的典型用法参考 #474,一般就是LoadModuleChecked,然后调用接口的抽象函数。
关于PublicSystemLibraryPaths,PublicAdditionalLibraries,PublicLibraryPaths的问题
在(<)UE4.24的版本中,指定lib文件的方法跟visual studio里使用的方式一致:
- PublicLibraryPaths用于添加lib文件所在的目录
- PublicAdditionalLibraries用于添加lib文件,不包括路径信息
- 忽略PublicLibraryPaths字段,且PublicAdditionalLibraries字段直接添加lib文件绝对路径。
如果仍坚持老的使用方式,则会报Warning,用以下方式可以消除这个Warning,但并不能消除老的方式的效率低下的问题:
- 用PublicSystemLibraryPaths取代PublicLibraryPaths,用于添加lib文件所在的目录
- 用PublicSystemLibraries来添加库文件,但只需要库的名字即可,不需要后缀。或者直接在cpp中用#pragma comment(lib,"avcodec.lib")这种写法,会从PublicSystemLibraryPaths指定的目录下去寻找