[.NET Export] Improve .NET export process.
[macOS export] Fix incorrect file placement, search paths and architecture detection. [macOS export] Automatically detect executable files and set +x flag. [macOS export] Automatically apply "Disable Library Validation" entitlements when required. [macOS export] Remove old Mono export code. Fix folder tree creation for shared objects export. Add arch suffix to the exported .NET "data" folder name. Remove old Mono code from .NET "data" folder lookup.
This commit is contained in:
parent
58ca303141
commit
6daf4c6593
|
@ -144,6 +144,7 @@ public:
|
|||
};
|
||||
|
||||
virtual Ref<EditorExportPreset> create_preset();
|
||||
virtual bool is_executable(const String &p_path) const { return false; }
|
||||
|
||||
virtual void clear_messages() { messages.clear(); }
|
||||
virtual void add_message(ExportMessageType p_type, const String &p_category, const String &p_message) {
|
||||
|
|
|
@ -185,10 +185,12 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
|
|||
String src_path = ProjectSettings::get_singleton()->globalize_path(so_files[i].path);
|
||||
String target_path;
|
||||
if (so_files[i].target.is_empty()) {
|
||||
target_path = p_path.get_base_dir().path_join(src_path.get_file());
|
||||
target_path = p_path.get_base_dir();
|
||||
} else {
|
||||
target_path = p_path.get_base_dir().path_join(so_files[i].target).path_join(src_path.get_file());
|
||||
target_path = p_path.get_base_dir().path_join(so_files[i].target);
|
||||
da->make_dir_recursive(target_path);
|
||||
}
|
||||
target_path = target_path.path_join(src_path.get_file());
|
||||
|
||||
if (da->dir_exists(src_path)) {
|
||||
err = da->make_dir_recursive(target_path);
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace GodotTools.Export
|
|||
{
|
||||
public partial class ExportPlugin : EditorExportPlugin
|
||||
{
|
||||
private List<string> _tempFolders = new List<string>();
|
||||
|
||||
public void RegisterExportSettings()
|
||||
{
|
||||
// TODO: These would be better as export preset options, but that doesn't seem to be supported yet
|
||||
|
@ -111,18 +113,46 @@ namespace GodotTools.Export
|
|||
|
||||
string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
|
||||
|
||||
// TODO: This works for now, as we only implemented support for x86 family desktop so far, but it needs to be fixed
|
||||
string arch = features.Contains("x86_64") ? "x86_64" : "x86";
|
||||
var archs = new List<string>();
|
||||
if (features.Contains("x86_64"))
|
||||
{
|
||||
archs.Add("x86_64");
|
||||
}
|
||||
else if (features.Contains("x86_32"))
|
||||
{
|
||||
archs.Add("x86_32");
|
||||
}
|
||||
else if (features.Contains("arm64"))
|
||||
{
|
||||
archs.Add("arm64");
|
||||
}
|
||||
else if (features.Contains("universal"))
|
||||
{
|
||||
if (platform == OS.Platforms.MacOS)
|
||||
{
|
||||
archs.Add("x86_64");
|
||||
archs.Add("arm64");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var arch in archs)
|
||||
{
|
||||
string ridOS = DetermineRuntimeIdentifierOS(platform);
|
||||
string ridArch = DetermineRuntimeIdentifierArch(arch);
|
||||
string runtimeIdentifier = $"{ridOS}-{ridArch}";
|
||||
string projectDataDirName = $"{DetermineDataDirNameForProject()}_{arch}";
|
||||
if (platform == OS.Platforms.MacOS)
|
||||
{
|
||||
projectDataDirName = Path.Combine("Contents", "Resources", projectDataDirName);
|
||||
}
|
||||
|
||||
// Create temporary publish output directory
|
||||
|
||||
string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
|
||||
$"{Process.GetCurrentProcess().Id}-{buildConfig}-{runtimeIdentifier}");
|
||||
|
||||
_tempFolders.Add(publishOutputTempDir);
|
||||
|
||||
if (!Directory.Exists(publishOutputTempDir))
|
||||
Directory.CreateDirectory(publishOutputTempDir);
|
||||
|
||||
|
@ -149,24 +179,12 @@ namespace GodotTools.Export
|
|||
"Publish succeeded but project assembly not found in the output directory");
|
||||
}
|
||||
|
||||
// Copy all files from the dotnet publish output directory to
|
||||
// a data directory next to the Godot output executable.
|
||||
|
||||
string outputDataDir = Path.Combine(outputDir, DetermineDataDirNameForProject());
|
||||
|
||||
if (Directory.Exists(outputDataDir))
|
||||
Directory.Delete(outputDataDir, recursive: true); // Clean first
|
||||
|
||||
Directory.CreateDirectory(outputDataDir);
|
||||
|
||||
foreach (string dir in Directory.GetDirectories(publishOutputTempDir, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(publishOutputTempDir.Length + 1)));
|
||||
}
|
||||
// Add to the exported project shared object list.
|
||||
|
||||
foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
File.Copy(file, Path.Combine(outputDataDir, file.Substring(publishOutputTempDir.Length + 1)));
|
||||
AddSharedObject(file, tags: null, projectDataDirName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +216,12 @@ namespace GodotTools.Export
|
|||
if (Directory.Exists(aotTempDir))
|
||||
Directory.Delete(aotTempDir, recursive: true);
|
||||
|
||||
foreach (string folder in _tempFolders)
|
||||
{
|
||||
Directory.Delete(folder, recursive: true);
|
||||
}
|
||||
_tempFolders.Clear();
|
||||
|
||||
// TODO: The following is just a workaround until the export plugins can be made to abort with errors
|
||||
|
||||
// We check for empty as well, because it's set to empty after hot-reloading
|
||||
|
|
|
@ -94,138 +94,63 @@ String _get_mono_user_dir() {
|
|||
|
||||
class _GodotSharpDirs {
|
||||
public:
|
||||
String res_data_dir;
|
||||
String res_metadata_dir;
|
||||
String res_config_dir;
|
||||
String res_temp_dir;
|
||||
String res_temp_assemblies_base_dir;
|
||||
String res_temp_assemblies_dir;
|
||||
String mono_user_dir;
|
||||
String mono_logs_dir;
|
||||
|
||||
String api_assemblies_base_dir;
|
||||
String api_assemblies_dir;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String mono_solutions_dir;
|
||||
String build_logs_dir;
|
||||
|
||||
String data_editor_tools_dir;
|
||||
#else
|
||||
// Equivalent of res_assemblies_dir, but in the data directory rather than in 'res://'.
|
||||
// Only defined on export templates. Used when exporting assemblies outside of PCKs.
|
||||
String data_game_assemblies_dir;
|
||||
#endif
|
||||
|
||||
String data_mono_etc_dir;
|
||||
String data_mono_lib_dir;
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
String data_mono_bin_dir;
|
||||
#endif
|
||||
|
||||
private:
|
||||
_GodotSharpDirs() {
|
||||
res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().path_join("mono");
|
||||
String res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().path_join("mono");
|
||||
res_metadata_dir = res_data_dir.path_join("metadata");
|
||||
res_config_dir = res_data_dir.path_join("etc").path_join("mono");
|
||||
|
||||
// TODO use paths from csproj
|
||||
res_temp_dir = res_data_dir.path_join("temp");
|
||||
res_temp_assemblies_base_dir = res_temp_dir.path_join("bin");
|
||||
res_temp_assemblies_dir = res_temp_assemblies_base_dir.path_join(_get_expected_build_config());
|
||||
|
||||
api_assemblies_base_dir = res_data_dir.path_join("assemblies");
|
||||
res_temp_assemblies_dir = res_data_dir.path_join("temp").path_join("bin").path_join(_get_expected_build_config());
|
||||
|
||||
#ifdef WEB_ENABLED
|
||||
mono_user_dir = "user://";
|
||||
#else
|
||||
mono_user_dir = _get_mono_user_dir();
|
||||
#endif
|
||||
mono_logs_dir = mono_user_dir.path_join("mono_logs");
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
mono_solutions_dir = mono_user_dir.path_join("solutions");
|
||||
build_logs_dir = mono_user_dir.path_join("build_logs");
|
||||
|
||||
String base_path = ProjectSettings::get_singleton()->globalize_path("res://");
|
||||
#endif
|
||||
|
||||
String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
|
||||
String res_dir = OS::get_singleton()->get_bundle_resource_dir();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
String data_dir_root = exe_dir.path_join("GodotSharp");
|
||||
data_editor_tools_dir = data_dir_root.path_join("Tools");
|
||||
api_assemblies_base_dir = data_dir_root.path_join("Api");
|
||||
|
||||
String data_mono_root_dir = data_dir_root.path_join("Mono");
|
||||
data_mono_etc_dir = data_mono_root_dir.path_join("etc");
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
|
||||
#else
|
||||
data_mono_lib_dir = data_mono_root_dir.path_join("lib");
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
data_mono_bin_dir = data_mono_root_dir.path_join("bin");
|
||||
#endif
|
||||
|
||||
String api_assemblies_base_dir = data_dir_root.path_join("Api");
|
||||
build_logs_dir = mono_user_dir.path_join("build_logs");
|
||||
#ifdef MACOS_ENABLED
|
||||
if (!DirAccess::exists(data_editor_tools_dir)) {
|
||||
data_editor_tools_dir = exe_dir.path_join("../Resources/GodotSharp/Tools");
|
||||
data_editor_tools_dir = res_dir.path_join("GodotSharp").path_join("Tools");
|
||||
}
|
||||
|
||||
if (!DirAccess::exists(api_assemblies_base_dir)) {
|
||||
api_assemblies_base_dir = exe_dir.path_join("../Resources/GodotSharp/Api");
|
||||
}
|
||||
|
||||
if (!DirAccess::exists(data_mono_root_dir)) {
|
||||
data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
|
||||
data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
|
||||
api_assemblies_base_dir = res_dir.path_join("GodotSharp").path_join("Api");
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
|
||||
#else // TOOLS_ENABLED
|
||||
String arch = Engine::get_singleton()->get_architecture_name();
|
||||
String appname = ProjectSettings::get_singleton()->get("application/config/name");
|
||||
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
|
||||
String data_dir_root = exe_dir.path_join("data_" + appname_safe);
|
||||
String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
|
||||
if (!DirAccess::exists(data_dir_root)) {
|
||||
data_dir_root = exe_dir.path_join("data_Godot");
|
||||
data_dir_root = exe_dir.path_join("data_Godot_" + arch);
|
||||
}
|
||||
|
||||
String data_mono_root_dir = data_dir_root.path_join("Mono");
|
||||
data_mono_etc_dir = data_mono_root_dir.path_join("etc");
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
|
||||
#else
|
||||
data_mono_lib_dir = data_mono_root_dir.path_join("lib");
|
||||
data_game_assemblies_dir = data_dir_root.path_join("Assemblies");
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
data_mono_bin_dir = data_mono_root_dir.path_join("bin");
|
||||
#endif
|
||||
|
||||
#ifdef MACOS_ENABLED
|
||||
if (!DirAccess::exists(data_mono_root_dir)) {
|
||||
data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
|
||||
data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
|
||||
if (!DirAccess::exists(data_dir_root)) {
|
||||
data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
|
||||
}
|
||||
|
||||
if (!DirAccess::exists(data_game_assemblies_dir)) {
|
||||
data_game_assemblies_dir = exe_dir.path_join("../Resources/GodotSharp/Assemblies");
|
||||
if (!DirAccess::exists(data_dir_root)) {
|
||||
data_dir_root = res_dir.path_join("data_Godot_" + arch);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
|
||||
#else
|
||||
api_assemblies_dir = data_dir_root;
|
||||
#endif
|
||||
}
|
||||
|
@ -237,26 +162,10 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
String get_res_data_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_data_dir;
|
||||
}
|
||||
|
||||
String get_res_metadata_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_metadata_dir;
|
||||
}
|
||||
|
||||
String get_res_config_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_config_dir;
|
||||
}
|
||||
|
||||
String get_res_temp_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_temp_dir;
|
||||
}
|
||||
|
||||
String get_res_temp_assemblies_base_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_temp_assemblies_base_dir;
|
||||
}
|
||||
|
||||
String get_res_temp_assemblies_dir() {
|
||||
return _GodotSharpDirs::get_singleton().res_temp_assemblies_dir;
|
||||
}
|
||||
|
@ -265,23 +174,11 @@ String get_api_assemblies_dir() {
|
|||
return _GodotSharpDirs::get_singleton().api_assemblies_dir;
|
||||
}
|
||||
|
||||
String get_api_assemblies_base_dir() {
|
||||
return _GodotSharpDirs::get_singleton().api_assemblies_base_dir;
|
||||
}
|
||||
|
||||
String get_mono_user_dir() {
|
||||
return _GodotSharpDirs::get_singleton().mono_user_dir;
|
||||
}
|
||||
|
||||
String get_mono_logs_dir() {
|
||||
return _GodotSharpDirs::get_singleton().mono_logs_dir;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String get_mono_solutions_dir() {
|
||||
return _GodotSharpDirs::get_singleton().mono_solutions_dir;
|
||||
}
|
||||
|
||||
String get_build_logs_dir() {
|
||||
return _GodotSharpDirs::get_singleton().build_logs_dir;
|
||||
}
|
||||
|
@ -289,23 +186,6 @@ String get_build_logs_dir() {
|
|||
String get_data_editor_tools_dir() {
|
||||
return _GodotSharpDirs::get_singleton().data_editor_tools_dir;
|
||||
}
|
||||
#else
|
||||
String get_data_game_assemblies_dir() {
|
||||
return _GodotSharpDirs::get_singleton().data_game_assemblies_dir;
|
||||
}
|
||||
#endif
|
||||
|
||||
String get_data_mono_etc_dir() {
|
||||
return _GodotSharpDirs::get_singleton().data_mono_etc_dir;
|
||||
}
|
||||
|
||||
String get_data_mono_lib_dir() {
|
||||
return _GodotSharpDirs::get_singleton().data_mono_lib_dir;
|
||||
}
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
String get_data_mono_bin_dir() {
|
||||
return _GodotSharpDirs::get_singleton().data_mono_bin_dir;
|
||||
}
|
||||
#endif
|
||||
} // namespace GodotSharpDirs
|
||||
|
|
|
@ -35,34 +35,18 @@
|
|||
|
||||
namespace GodotSharpDirs {
|
||||
|
||||
String get_res_data_dir();
|
||||
String get_res_metadata_dir();
|
||||
String get_res_config_dir();
|
||||
String get_res_temp_dir();
|
||||
String get_res_temp_assemblies_base_dir();
|
||||
String get_res_temp_assemblies_dir();
|
||||
|
||||
String get_api_assemblies_dir();
|
||||
String get_api_assemblies_base_dir();
|
||||
|
||||
String get_mono_user_dir();
|
||||
String get_mono_logs_dir();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String get_mono_solutions_dir();
|
||||
String get_build_logs_dir();
|
||||
|
||||
String get_data_editor_tools_dir();
|
||||
#else
|
||||
String get_data_game_assemblies_dir();
|
||||
#endif
|
||||
|
||||
String get_data_mono_etc_dir();
|
||||
String get_data_mono_lib_dir();
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
String get_data_mono_bin_dir();
|
||||
#endif
|
||||
} // namespace GodotSharpDirs
|
||||
|
||||
#endif // GODOTSHARP_DIRS_H
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "export_plugin.h"
|
||||
|
||||
#include "codesign.h"
|
||||
#include "lipo.h"
|
||||
#include "macho.h"
|
||||
|
||||
#include "core/string/translation.h"
|
||||
#include "editor/editor_node.h"
|
||||
|
@ -754,6 +756,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
|
|||
if (extensions_to_sign.is_empty()) {
|
||||
extensions_to_sign.push_back("dylib");
|
||||
extensions_to_sign.push_back("framework");
|
||||
extensions_to_sign.push_back("");
|
||||
}
|
||||
|
||||
Error dir_access_error;
|
||||
|
@ -778,6 +781,10 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
|
|||
if (code_sign_error != OK) {
|
||||
return code_sign_error;
|
||||
}
|
||||
if (is_executable(current_file_path)) {
|
||||
// chmod with 0755 if the file is executable.
|
||||
FileAccess::set_unix_permissions(current_file_path, 0755);
|
||||
}
|
||||
} else if (dir_access->current_is_dir()) {
|
||||
Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_should_error_on_non_code) };
|
||||
if (code_sign_error != OK) {
|
||||
|
@ -799,6 +806,14 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
|
|||
const String &p_in_app_path, bool p_sign_enabled,
|
||||
const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
|
||||
bool p_should_error_on_non_code_sign) {
|
||||
static Vector<String> extensions_to_sign;
|
||||
|
||||
if (extensions_to_sign.is_empty()) {
|
||||
extensions_to_sign.push_back("dylib");
|
||||
extensions_to_sign.push_back("framework");
|
||||
extensions_to_sign.push_back("");
|
||||
}
|
||||
|
||||
Error err{ OK };
|
||||
if (dir_access->dir_exists(p_src_path)) {
|
||||
#ifndef UNIX_ENABLED
|
||||
|
@ -818,8 +833,14 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
|
|||
// If it is a directory, find and sign all dynamic libraries.
|
||||
err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign);
|
||||
} else {
|
||||
if (extensions_to_sign.find(p_in_app_path.get_extension()) > -1) {
|
||||
err = _code_sign(p_preset, p_in_app_path, p_ent_path, false);
|
||||
}
|
||||
if (is_executable(p_in_app_path)) {
|
||||
// chmod with 0755 if the file is executable.
|
||||
FileAccess::set_unix_permissions(p_in_app_path, 0755);
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@ -877,6 +898,17 @@ Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const Str
|
|||
return OK;
|
||||
}
|
||||
|
||||
bool EditorExportPlatformMacOS::is_shbang(const String &p_path) const {
|
||||
Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ);
|
||||
ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("Can't open file: \"%s\".", p_path));
|
||||
uint16_t magic = fb->get_16();
|
||||
return (magic == 0x2123);
|
||||
}
|
||||
|
||||
bool EditorExportPlatformMacOS::is_executable(const String &p_path) const {
|
||||
return MachO::is_macho(p_path) || LipO::is_lipo(p_path) || is_shbang(p_path);
|
||||
}
|
||||
|
||||
Error EditorExportPlatformMacOS::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
|
||||
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
|
||||
if (f.is_null()) {
|
||||
|
@ -1158,11 +1190,8 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
|
||||
// Now process our template.
|
||||
bool found_binary = false;
|
||||
Vector<String> dylibs_found;
|
||||
|
||||
while (ret == UNZ_OK && err == OK) {
|
||||
bool is_execute = false;
|
||||
|
||||
// Get filename.
|
||||
unz_file_info info;
|
||||
char fname[16384];
|
||||
|
@ -1219,7 +1248,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
continue; // skip
|
||||
}
|
||||
found_binary = true;
|
||||
is_execute = true;
|
||||
file = "Contents/MacOS/" + pkg_name;
|
||||
}
|
||||
|
||||
|
@ -1251,25 +1279,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
}
|
||||
|
||||
if (data.size() > 0) {
|
||||
if (file.find("/data.mono.macos.release_debug." + architecture + "/") != -1) {
|
||||
if (!p_debug) {
|
||||
ret = unzGoToNextFile(src_pkg_zip);
|
||||
continue; // skip
|
||||
}
|
||||
file = file.replace("/data.mono.macos.release_debug." + architecture + "/", "/GodotSharp/");
|
||||
}
|
||||
if (file.find("/data.mono.macos.release." + architecture + "/") != -1) {
|
||||
if (p_debug) {
|
||||
ret = unzGoToNextFile(src_pkg_zip);
|
||||
continue; // skip
|
||||
}
|
||||
file = file.replace("/data.mono.macos.release." + architecture + "/", "/GodotSharp/");
|
||||
}
|
||||
|
||||
if (file.ends_with(".dylib")) {
|
||||
dylibs_found.push_back(file);
|
||||
}
|
||||
|
||||
print_verbose("ADDING: " + file + " size: " + itos(data.size()));
|
||||
|
||||
// Write it into our application bundle.
|
||||
|
@ -1285,7 +1294,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
if (f.is_valid()) {
|
||||
f->store_buffer(data.ptr(), data.size());
|
||||
f.unref();
|
||||
if (is_execute) {
|
||||
if (is_executable(file)) {
|
||||
// chmod with 0755 if the file is executable.
|
||||
FileAccess::set_unix_permissions(file, 0755);
|
||||
}
|
||||
|
@ -1324,12 +1333,35 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
return ERR_SKIP;
|
||||
}
|
||||
|
||||
// See if we can code sign our new package.
|
||||
bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0);
|
||||
bool ad_hoc = false;
|
||||
int codesign_tool = p_preset->get("codesign/codesign");
|
||||
switch (codesign_tool) {
|
||||
case 1: { // built-in ad-hoc
|
||||
ad_hoc = true;
|
||||
} break;
|
||||
case 2: { // "rcodesign"
|
||||
ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
|
||||
} break;
|
||||
#ifdef MACOS_ENABLED
|
||||
case 3: { // "codesign"
|
||||
ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
|
||||
} break;
|
||||
#endif
|
||||
default: {
|
||||
};
|
||||
}
|
||||
|
||||
String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
|
||||
Vector<SharedObject> shared_objects;
|
||||
err = save_pack(p_preset, p_debug, pack_path, &shared_objects);
|
||||
|
||||
// See if we can code sign our new package.
|
||||
bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0);
|
||||
bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
|
||||
if (!shared_objects.is_empty() && sign_enabled && ad_hoc && !lib_validation) {
|
||||
add_message(EXPORT_MESSAGE_INFO, TTR("Entitlements Modified"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries."));
|
||||
lib_validation = true;
|
||||
}
|
||||
|
||||
String ent_path = p_preset->get("codesign/entitlements/custom_file");
|
||||
String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements");
|
||||
|
@ -1365,7 +1397,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
}
|
||||
}
|
||||
|
||||
if ((bool)p_preset->get("codesign/entitlements/disable_library_validation")) {
|
||||
if (lib_validation) {
|
||||
ent_f->store_line("<key>com.apple.security.cs.disable-library-validation</key>");
|
||||
ent_f->store_line("<true/>");
|
||||
}
|
||||
|
@ -1495,32 +1527,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
}
|
||||
}
|
||||
|
||||
bool ad_hoc = false;
|
||||
int codesign_tool = p_preset->get("codesign/codesign");
|
||||
switch (codesign_tool) {
|
||||
case 1: { // built-in ad-hoc
|
||||
ad_hoc = true;
|
||||
} break;
|
||||
case 2: { // "rcodesign"
|
||||
ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
|
||||
} break;
|
||||
#ifdef MACOS_ENABLED
|
||||
case 3: { // "codesign"
|
||||
ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
|
||||
} break;
|
||||
#endif
|
||||
default: {
|
||||
};
|
||||
}
|
||||
|
||||
if (err == OK) {
|
||||
bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
|
||||
if ((!dylibs_found.is_empty() || !shared_objects.is_empty()) && sign_enabled && ad_hoc && !lib_validation) {
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries."));
|
||||
err = ERR_CANT_CREATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (err == OK) {
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
for (int i = 0; i < shared_objects.size(); i++) {
|
||||
|
@ -1529,8 +1535,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file();
|
||||
err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
|
||||
} else {
|
||||
String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target).path_join(src_path.get_file());
|
||||
err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, false);
|
||||
String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target);
|
||||
tmp_app_dir->make_dir_recursive(path_in_app);
|
||||
err = _copy_and_sign_files(da, src_path, path_in_app.path_join(src_path.get_file()), sign_enabled, p_preset, ent_path, false);
|
||||
}
|
||||
if (err != OK) {
|
||||
break;
|
||||
|
@ -1546,14 +1553,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||
}
|
||||
}
|
||||
|
||||
if (sign_enabled) {
|
||||
for (int i = 0; i < dylibs_found.size(); i++) {
|
||||
if (err == OK) {
|
||||
err = _code_sign(p_preset, tmp_app_path_name + "/" + dylibs_found[i], ent_path, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (err == OK && sign_enabled) {
|
||||
if (ep.step(TTR("Code signing bundle"), 2)) {
|
||||
return ERR_SKIP;
|
||||
|
@ -1683,8 +1682,6 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
|
|||
} else if (da->current_is_dir()) {
|
||||
_zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name);
|
||||
} else {
|
||||
bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers") || f.ends_with(".command");
|
||||
|
||||
OS::DateTime dt = OS::get_singleton()->get_datetime();
|
||||
|
||||
zip_fileinfo zipfi;
|
||||
|
@ -1698,7 +1695,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
|
|||
// 0100000: regular file type
|
||||
// 0000755: permissions rwxr-xr-x
|
||||
// 0000644: permissions rw-r--r--
|
||||
uint32_t _mode = (is_executable ? 0100755 : 0100644);
|
||||
uint32_t _mode = (is_executable(dir.path_join(f)) ? 0100755 : 0100644);
|
||||
zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
|
||||
zipfi.internal_fa = 0;
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
|
|||
|
||||
return true;
|
||||
}
|
||||
bool is_shbang(const String &p_path) const;
|
||||
|
||||
protected:
|
||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
|
||||
|
@ -108,6 +109,7 @@ public:
|
|||
virtual String get_os_name() const override { return "macOS"; }
|
||||
virtual Ref<Texture2D> get_logo() const override { return logo; }
|
||||
|
||||
virtual bool is_executable(const String &p_path) const override;
|
||||
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
|
||||
List<String> list;
|
||||
if (use_dmg()) {
|
||||
|
|
Loading…
Reference in New Issue