You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-26 15:46:23 +00:00
[.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:
@@ -144,6 +144,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtual Ref<EditorExportPreset> create_preset();
|
virtual Ref<EditorExportPreset> create_preset();
|
||||||
|
virtual bool is_executable(const String &p_path) const { return false; }
|
||||||
|
|
||||||
virtual void clear_messages() { messages.clear(); }
|
virtual void clear_messages() { messages.clear(); }
|
||||||
virtual void add_message(ExportMessageType p_type, const String &p_category, const String &p_message) {
|
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 src_path = ProjectSettings::get_singleton()->globalize_path(so_files[i].path);
|
||||||
String target_path;
|
String target_path;
|
||||||
if (so_files[i].target.is_empty()) {
|
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 {
|
} 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)) {
|
if (da->dir_exists(src_path)) {
|
||||||
err = da->make_dir_recursive(target_path);
|
err = da->make_dir_recursive(target_path);
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ namespace GodotTools.Export
|
|||||||
{
|
{
|
||||||
public partial class ExportPlugin : EditorExportPlugin
|
public partial class ExportPlugin : EditorExportPlugin
|
||||||
{
|
{
|
||||||
|
private List<string> _tempFolders = new List<string>();
|
||||||
|
|
||||||
public void RegisterExportSettings()
|
public void RegisterExportSettings()
|
||||||
{
|
{
|
||||||
// TODO: These would be better as export preset options, but that doesn't seem to be supported yet
|
// 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";
|
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
|
var archs = new List<string>();
|
||||||
string arch = features.Contains("x86_64") ? "x86_64" : "x86";
|
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 ridOS = DetermineRuntimeIdentifierOS(platform);
|
||||||
string ridArch = DetermineRuntimeIdentifierArch(arch);
|
string ridArch = DetermineRuntimeIdentifierArch(arch);
|
||||||
string runtimeIdentifier = $"{ridOS}-{ridArch}";
|
string runtimeIdentifier = $"{ridOS}-{ridArch}";
|
||||||
|
string projectDataDirName = $"{DetermineDataDirNameForProject()}_{arch}";
|
||||||
|
if (platform == OS.Platforms.MacOS)
|
||||||
|
{
|
||||||
|
projectDataDirName = Path.Combine("Contents", "Resources", projectDataDirName);
|
||||||
|
}
|
||||||
|
|
||||||
// Create temporary publish output directory
|
// Create temporary publish output directory
|
||||||
|
|
||||||
string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
|
string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
|
||||||
$"{Process.GetCurrentProcess().Id}-{buildConfig}-{runtimeIdentifier}");
|
$"{Process.GetCurrentProcess().Id}-{buildConfig}-{runtimeIdentifier}");
|
||||||
|
|
||||||
|
_tempFolders.Add(publishOutputTempDir);
|
||||||
|
|
||||||
if (!Directory.Exists(publishOutputTempDir))
|
if (!Directory.Exists(publishOutputTempDir))
|
||||||
Directory.CreateDirectory(publishOutputTempDir);
|
Directory.CreateDirectory(publishOutputTempDir);
|
||||||
|
|
||||||
@@ -149,24 +179,12 @@ namespace GodotTools.Export
|
|||||||
"Publish succeeded but project assembly not found in the output directory");
|
"Publish succeeded but project assembly not found in the output directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy all files from the dotnet publish output directory to
|
// Add to the exported project shared object list.
|
||||||
// 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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
|
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))
|
if (Directory.Exists(aotTempDir))
|
||||||
Directory.Delete(aotTempDir, recursive: true);
|
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
|
// 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
|
// 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 {
|
class _GodotSharpDirs {
|
||||||
public:
|
public:
|
||||||
String res_data_dir;
|
|
||||||
String res_metadata_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 res_temp_assemblies_dir;
|
||||||
String mono_user_dir;
|
String mono_user_dir;
|
||||||
String mono_logs_dir;
|
|
||||||
|
|
||||||
String api_assemblies_base_dir;
|
|
||||||
String api_assemblies_dir;
|
String api_assemblies_dir;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
String mono_solutions_dir;
|
|
||||||
String build_logs_dir;
|
String build_logs_dir;
|
||||||
|
|
||||||
String data_editor_tools_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
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
_GodotSharpDirs() {
|
_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_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
|
// TODO use paths from csproj
|
||||||
res_temp_dir = res_data_dir.path_join("temp");
|
res_temp_assemblies_dir = res_data_dir.path_join("temp").path_join("bin").path_join(_get_expected_build_config());
|
||||||
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");
|
|
||||||
|
|
||||||
#ifdef WEB_ENABLED
|
#ifdef WEB_ENABLED
|
||||||
mono_user_dir = "user://";
|
mono_user_dir = "user://";
|
||||||
#else
|
#else
|
||||||
mono_user_dir = _get_mono_user_dir();
|
mono_user_dir = _get_mono_user_dir();
|
||||||
#endif
|
#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 exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
|
||||||
|
String res_dir = OS::get_singleton()->get_bundle_resource_dir();
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
||||||
String data_dir_root = exe_dir.path_join("GodotSharp");
|
String data_dir_root = exe_dir.path_join("GodotSharp");
|
||||||
data_editor_tools_dir = data_dir_root.path_join("Tools");
|
data_editor_tools_dir = data_dir_root.path_join("Tools");
|
||||||
api_assemblies_base_dir = data_dir_root.path_join("Api");
|
String api_assemblies_base_dir = data_dir_root.path_join("Api");
|
||||||
|
build_logs_dir = mono_user_dir.path_join("build_logs");
|
||||||
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
|
|
||||||
|
|
||||||
#ifdef MACOS_ENABLED
|
#ifdef MACOS_ENABLED
|
||||||
if (!DirAccess::exists(data_editor_tools_dir)) {
|
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)) {
|
if (!DirAccess::exists(api_assemblies_base_dir)) {
|
||||||
api_assemblies_base_dir = exe_dir.path_join("../Resources/GodotSharp/Api");
|
api_assemblies_base_dir = res_dir.path_join("GodotSharp").path_join("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");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
|
||||||
#else
|
#else // TOOLS_ENABLED
|
||||||
|
String arch = Engine::get_singleton()->get_architecture_name();
|
||||||
String appname = ProjectSettings::get_singleton()->get("application/config/name");
|
String appname = ProjectSettings::get_singleton()->get("application/config/name");
|
||||||
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
|
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)) {
|
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
|
#ifdef MACOS_ENABLED
|
||||||
if (!DirAccess::exists(data_mono_root_dir)) {
|
if (!DirAccess::exists(data_dir_root)) {
|
||||||
data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
|
data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
|
||||||
data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
|
|
||||||
}
|
}
|
||||||
|
if (!DirAccess::exists(data_dir_root)) {
|
||||||
if (!DirAccess::exists(data_game_assemblies_dir)) {
|
data_dir_root = res_dir.path_join("data_Godot_" + arch);
|
||||||
data_game_assemblies_dir = exe_dir.path_join("../Resources/GodotSharp/Assemblies");
|
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
api_assemblies_dir = data_dir_root;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -237,26 +162,10 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
String get_res_data_dir() {
|
|
||||||
return _GodotSharpDirs::get_singleton().res_data_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
String get_res_metadata_dir() {
|
String get_res_metadata_dir() {
|
||||||
return _GodotSharpDirs::get_singleton().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() {
|
String get_res_temp_assemblies_dir() {
|
||||||
return _GodotSharpDirs::get_singleton().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;
|
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() {
|
String get_mono_user_dir() {
|
||||||
return _GodotSharpDirs::get_singleton().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
|
#ifdef TOOLS_ENABLED
|
||||||
String get_mono_solutions_dir() {
|
|
||||||
return _GodotSharpDirs::get_singleton().mono_solutions_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
String get_build_logs_dir() {
|
String get_build_logs_dir() {
|
||||||
return _GodotSharpDirs::get_singleton().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() {
|
String get_data_editor_tools_dir() {
|
||||||
return _GodotSharpDirs::get_singleton().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
|
#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
|
} // namespace GodotSharpDirs
|
||||||
|
|||||||
@@ -35,34 +35,18 @@
|
|||||||
|
|
||||||
namespace GodotSharpDirs {
|
namespace GodotSharpDirs {
|
||||||
|
|
||||||
String get_res_data_dir();
|
|
||||||
String get_res_metadata_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_res_temp_assemblies_dir();
|
||||||
|
|
||||||
String get_api_assemblies_dir();
|
String get_api_assemblies_dir();
|
||||||
String get_api_assemblies_base_dir();
|
|
||||||
|
|
||||||
String get_mono_user_dir();
|
String get_mono_user_dir();
|
||||||
String get_mono_logs_dir();
|
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
String get_mono_solutions_dir();
|
|
||||||
String get_build_logs_dir();
|
String get_build_logs_dir();
|
||||||
|
|
||||||
String get_data_editor_tools_dir();
|
String get_data_editor_tools_dir();
|
||||||
#else
|
|
||||||
String get_data_game_assemblies_dir();
|
|
||||||
#endif
|
#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
|
} // namespace GodotSharpDirs
|
||||||
|
|
||||||
#endif // GODOTSHARP_DIRS_H
|
#endif // GODOTSHARP_DIRS_H
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
#include "export_plugin.h"
|
#include "export_plugin.h"
|
||||||
|
|
||||||
#include "codesign.h"
|
#include "codesign.h"
|
||||||
|
#include "lipo.h"
|
||||||
|
#include "macho.h"
|
||||||
|
|
||||||
#include "core/string/translation.h"
|
#include "core/string/translation.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
@@ -754,6 +756,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
|
|||||||
if (extensions_to_sign.is_empty()) {
|
if (extensions_to_sign.is_empty()) {
|
||||||
extensions_to_sign.push_back("dylib");
|
extensions_to_sign.push_back("dylib");
|
||||||
extensions_to_sign.push_back("framework");
|
extensions_to_sign.push_back("framework");
|
||||||
|
extensions_to_sign.push_back("");
|
||||||
}
|
}
|
||||||
|
|
||||||
Error dir_access_error;
|
Error dir_access_error;
|
||||||
@@ -778,6 +781,10 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
|
|||||||
if (code_sign_error != OK) {
|
if (code_sign_error != OK) {
|
||||||
return code_sign_error;
|
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()) {
|
} 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) };
|
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) {
|
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 String &p_in_app_path, bool p_sign_enabled,
|
||||||
const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
|
const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
|
||||||
bool p_should_error_on_non_code_sign) {
|
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 };
|
Error err{ OK };
|
||||||
if (dir_access->dir_exists(p_src_path)) {
|
if (dir_access->dir_exists(p_src_path)) {
|
||||||
#ifndef UNIX_ENABLED
|
#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.
|
// 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);
|
err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign);
|
||||||
} else {
|
} 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);
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -877,6 +898,17 @@ Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const Str
|
|||||||
return OK;
|
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) {
|
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);
|
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
|
||||||
if (f.is_null()) {
|
if (f.is_null()) {
|
||||||
@@ -1158,11 +1190,8 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||||||
|
|
||||||
// Now process our template.
|
// Now process our template.
|
||||||
bool found_binary = false;
|
bool found_binary = false;
|
||||||
Vector<String> dylibs_found;
|
|
||||||
|
|
||||||
while (ret == UNZ_OK && err == OK) {
|
while (ret == UNZ_OK && err == OK) {
|
||||||
bool is_execute = false;
|
|
||||||
|
|
||||||
// Get filename.
|
// Get filename.
|
||||||
unz_file_info info;
|
unz_file_info info;
|
||||||
char fname[16384];
|
char fname[16384];
|
||||||
@@ -1219,7 +1248,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||||||
continue; // skip
|
continue; // skip
|
||||||
}
|
}
|
||||||
found_binary = true;
|
found_binary = true;
|
||||||
is_execute = true;
|
|
||||||
file = "Contents/MacOS/" + pkg_name;
|
file = "Contents/MacOS/" + pkg_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1251,25 +1279,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.size() > 0) {
|
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()));
|
print_verbose("ADDING: " + file + " size: " + itos(data.size()));
|
||||||
|
|
||||||
// Write it into our application bundle.
|
// Write it into our application bundle.
|
||||||
@@ -1285,7 +1294,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||||||
if (f.is_valid()) {
|
if (f.is_valid()) {
|
||||||
f->store_buffer(data.ptr(), data.size());
|
f->store_buffer(data.ptr(), data.size());
|
||||||
f.unref();
|
f.unref();
|
||||||
if (is_execute) {
|
if (is_executable(file)) {
|
||||||
// chmod with 0755 if the file is executable.
|
// chmod with 0755 if the file is executable.
|
||||||
FileAccess::set_unix_permissions(file, 0755);
|
FileAccess::set_unix_permissions(file, 0755);
|
||||||
}
|
}
|
||||||
@@ -1324,12 +1333,35 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
|||||||
return ERR_SKIP;
|
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";
|
String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
|
||||||
Vector<SharedObject> shared_objects;
|
Vector<SharedObject> shared_objects;
|
||||||
err = save_pack(p_preset, p_debug, pack_path, &shared_objects);
|
err = save_pack(p_preset, p_debug, pack_path, &shared_objects);
|
||||||
|
|
||||||
// See if we can code sign our new package.
|
bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
|
||||||
bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0);
|
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 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");
|
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("<key>com.apple.security.cs.disable-library-validation</key>");
|
||||||
ent_f->store_line("<true/>");
|
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) {
|
if (err == OK) {
|
||||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
for (int i = 0; i < shared_objects.size(); i++) {
|
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();
|
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);
|
err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
|
||||||
} else {
|
} else {
|
||||||
String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target).path_join(src_path.get_file());
|
String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target);
|
||||||
err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, false);
|
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) {
|
if (err != OK) {
|
||||||
break;
|
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 (err == OK && sign_enabled) {
|
||||||
if (ep.step(TTR("Code signing bundle"), 2)) {
|
if (ep.step(TTR("Code signing bundle"), 2)) {
|
||||||
return ERR_SKIP;
|
return ERR_SKIP;
|
||||||
@@ -1683,8 +1682,6 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
|
|||||||
} else if (da->current_is_dir()) {
|
} else if (da->current_is_dir()) {
|
||||||
_zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name);
|
_zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name);
|
||||||
} else {
|
} 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();
|
OS::DateTime dt = OS::get_singleton()->get_datetime();
|
||||||
|
|
||||||
zip_fileinfo zipfi;
|
zip_fileinfo zipfi;
|
||||||
@@ -1698,7 +1695,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
|
|||||||
// 0100000: regular file type
|
// 0100000: regular file type
|
||||||
// 0000755: permissions rwxr-xr-x
|
// 0000755: permissions rwxr-xr-x
|
||||||
// 0000644: permissions rw-r--r--
|
// 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.external_fa = (_mode << 16L) | !(_mode & 0200);
|
||||||
zipfi.internal_fa = 0;
|
zipfi.internal_fa = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
bool is_shbang(const String &p_path) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
|
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 String get_os_name() const override { return "macOS"; }
|
||||||
virtual Ref<Texture2D> get_logo() const override { return logo; }
|
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 {
|
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
|
||||||
List<String> list;
|
List<String> list;
|
||||||
if (use_dmg()) {
|
if (use_dmg()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user