From 39628d4eeb431468fd7e7d718cdd270ece98dbd8 Mon Sep 17 00:00:00 2001 From: Faolan <46481567+Faolan-Rad@users.noreply.github.com> Date: Wed, 23 Aug 2023 04:47:07 -0400 Subject: [PATCH] LibGodot --- SConstruct | 18 +++- core/SCsub | 1 + core/config/project_settings.cpp | 5 ++ core/extension/gdextension.cpp | 24 ++++-- core/extension/gdextension.h | 4 +- core/extension/gdextension_interface.cpp | 2 + core/extension/gdextension_manager.cpp | 6 ++ core/io/logger.cpp | 3 + core/libgodot/SCsub | 5 ++ core/libgodot/libgodot.cpp | 85 +++++++++++++++++++ core/libgodot/libgodot.h | 71 ++++++++++++++++ editor/editor_file_system.cpp | 4 +- main/main.cpp | 36 ++++++-- .../GodotPluginsInitializerGenerator.cs | 7 +- modules/mono/mono_gd/gd_mono.cpp | 25 ++++-- modules/mono/mono_gd/gd_mono.h | 2 +- platform/ios/godot_ios.mm | 7 ++ platform/linuxbsd/SCsub | 7 +- platform/linuxbsd/godot_linuxbsd.cpp | 7 ++ platform/macos/SCsub | 7 +- platform/macos/godot_main_macos.mm | 7 ++ platform/uwp/SCsub | 7 +- platform/windows/SCsub | 41 +++++---- platform/windows/detect.py | 2 +- platform/windows/godot_windows.cpp | 35 +++++--- 25 files changed, 358 insertions(+), 60 deletions(-) create mode 100644 core/libgodot/SCsub create mode 100644 core/libgodot/libgodot.cpp create mode 100644 core/libgodot/libgodot.h diff --git a/SConstruct b/SConstruct index 7d4c8975e765..c7ef9c14d668 100644 --- a/SConstruct +++ b/SConstruct @@ -140,7 +140,6 @@ env_base.__class__.use_windows_spawn_fix = methods.use_windows_spawn_fix env_base.__class__.add_shared_library = methods.add_shared_library env_base.__class__.add_library = methods.add_library -env_base.__class__.add_program = methods.add_program env_base.__class__.CommandNoCache = methods.CommandNoCache env_base.__class__.Run = methods.Run env_base.__class__.disable_warnings = methods.disable_warnings @@ -198,6 +197,14 @@ opts.Add("custom_modules", "A list of comma-separated directory paths containing opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True)) # Advanced options +opts.Add( + EnumVariable( + "library_type", + "Build library type", + "executable", + ("executable", "static_library", "shared_library"), + ) +) opts.Add(BoolVariable("dev_mode", "Alias for dev options: verbose=yes warnings=extra werror=yes tests=yes", False)) opts.Add(BoolVariable("tests", "Build the unit tests", False)) opts.Add(BoolVariable("fast_unsafe", "Enable unsafe options for faster rebuilds", False)) @@ -270,6 +277,15 @@ opts.Update(env_base) selected_platform = "" +if env_base["library_type"] == "static_library": + env_base.Append(CPPDEFINES=["LIBRARY_ENABLED"]) +elif env_base["library_type"] == "shared_library": + env_base.Append(CPPDEFINES=["LIBRARY_ENABLED"]) + env_base.Append(CCFLAGS=["-fPIC"]) + env_base.Append(STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME=True) +else: + env_base.__class__.add_program = methods.add_program + if env_base["platform"] != "": selected_platform = env_base["platform"] elif env_base["p"] != "": diff --git a/core/SCsub b/core/SCsub index ab78eeedc714..98d2101519b5 100644 --- a/core/SCsub +++ b/core/SCsub @@ -216,6 +216,7 @@ SConscript("debugger/SCsub") SConscript("input/SCsub") SConscript("variant/SCsub") SConscript("extension/SCsub") +SConscript("libgodot/SCsub") SConscript("object/SCsub") SConscript("templates/SCsub") SConscript("string/SCsub") diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 1bfb7456627b..2da53688c26a 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -86,6 +86,11 @@ const PackedStringArray ProjectSettings::get_required_features() { // Returns the features supported by this build of Godot. Includes all required features. const PackedStringArray ProjectSettings::_get_supported_features() { PackedStringArray features = get_required_features(); + +#ifdef LIBRARY_ENABLED + features.append("Embedded"); +#endif + #ifdef MODULE_MONO_ENABLED features.append("C#"); #endif diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index e39a531d0d71..c3b8289e94cd 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -470,9 +470,14 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb } GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr; - GDExtensionBool ret = initialization_function(&gdextension_get_proc_address, this, &initialization); + return initialize_extension_function(initialization_function, p_entry_symbol); +} - if (ret) { +Error GDExtension::initialize_extension_function(GDExtensionInitializationFunction initialization_function, const String &p_entry_symbol) { + if (library == nullptr) { + embedded = true; + } + if (initialization_function(&gdextension_get_proc_address, this, &initialization)) { level_initialized = -1; return OK; } else { @@ -482,6 +487,9 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb } void GDExtension::close_library() { + if (embedded) { + return; + } ERR_FAIL_COND(library == nullptr); OS::get_singleton()->close_dynamic_library(library); @@ -495,17 +503,21 @@ void GDExtension::close_library() { library = nullptr; } +bool GDExtension::is_embedded() const { + return embedded; +} + bool GDExtension::is_library_open() const { - return library != nullptr; + return (library != nullptr) || embedded; } GDExtension::InitializationLevel GDExtension::get_minimum_library_initialization_level() const { - ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE); + ERR_FAIL_COND_V(library == nullptr && !embedded, INITIALIZATION_LEVEL_CORE); return InitializationLevel(initialization.minimum_initialization_level); } void GDExtension::initialize_library(InitializationLevel p_level) { - ERR_FAIL_COND(library == nullptr); + ERR_FAIL_COND(library == nullptr && !embedded); ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized)); level_initialized = int32_t(p_level); @@ -515,7 +527,7 @@ void GDExtension::initialize_library(InitializationLevel p_level) { initialization.initialize(initialization.userdata, GDExtensionInitializationLevel(p_level)); } void GDExtension::deinitialize_library(InitializationLevel p_level) { - ERR_FAIL_COND(library == nullptr); + ERR_FAIL_COND(library == nullptr && !embedded); ERR_FAIL_COND(p_level > int32_t(level_initialized)); level_initialized = int32_t(p_level) - 1; diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 5a0e39302b5a..d35bc00779d4 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -41,6 +41,7 @@ class GDExtension : public Resource { GDCLASS(GDExtension, Resource) + bool embedded = false; void *library = nullptr; // pointer if valid, String library_path; #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) @@ -76,6 +77,7 @@ class GDExtension : public Resource { static String get_extension_list_config_file(); static String find_extension_library(const String &p_path, Ref p_config, std::function p_has_feature, PackedStringArray *r_tags = nullptr); + Error initialize_extension_function(GDExtensionInitializationFunction initialization_function, const String &p_entry_symbol); Error open_library(const String &p_path, const String &p_entry_symbol); void close_library(); @@ -90,7 +92,7 @@ class GDExtension : public Resource { INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE, INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR }; - + bool is_embedded() const; bool is_library_open() const; InitializationLevel get_minimum_library_initialization_level() const; diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index b4541de8fee8..4f81f6567909 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -1077,10 +1077,12 @@ static GDExtensionMethodBindPtr gdextension_classdb_get_method_bind(GDExtensionC return nullptr; } ERR_FAIL_COND_V(!mb, nullptr); +#ifndef LIBRARY_ENABLED if (mb->get_hash() != p_hash) { ERR_PRINT("Hash mismatch for method '" + classname + "." + methodname + "'."); return nullptr; } +#endif return (GDExtensionMethodBindPtr)mb; } diff --git a/core/extension/gdextension_manager.cpp b/core/extension/gdextension_manager.cpp index 63e809bc7c30..15b507db0c3e 100644 --- a/core/extension/gdextension_manager.cpp +++ b/core/extension/gdextension_manager.cpp @@ -30,6 +30,9 @@ #include "gdextension_manager.h" #include "core/io/file_access.h" +#ifdef LIBRARY_ENABLED +#include "core/libgodot/libgodot.h" +#endif GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) { if (gdextension_map.has(p_path)) { @@ -143,6 +146,9 @@ void GDExtensionManager::load_extensions() { ERR_CONTINUE_MSG(err == LOAD_STATUS_FAILED, "Error loading extension: " + s); } } +#ifdef LIBRARY_ENABLED + libgodot_init_resource(); +#endif } GDExtensionManager *GDExtensionManager::get_singleton() { diff --git a/core/io/logger.cpp b/core/io/logger.cpp index b262c1cf286a..0b5ce61b19a1 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -173,6 +173,9 @@ void RotatedFileLogger::rotate_file() { } file = FileAccess::open(base_path, FileAccess::WRITE); + if (file == nullptr) { + return; + } file->detach_from_objectdb(); // Note: This FileAccess instance will exist longer than ObjectDB, therefore can't be registered in ObjectDB. } diff --git a/core/libgodot/SCsub b/core/libgodot/SCsub new file mode 100644 index 000000000000..0a9bd476e430 --- /dev/null +++ b/core/libgodot/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") +env_libgodot = env.Clone() +env_libgodot.add_source_files(env.core_sources, "*.cpp") diff --git a/core/libgodot/libgodot.cpp b/core/libgodot/libgodot.cpp new file mode 100644 index 000000000000..71876458d75c --- /dev/null +++ b/core/libgodot/libgodot.cpp @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* libgodot.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifdef LIBRARY_ENABLED +#include "libgodot.h" +#include "core/extension/gdextension_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void *godotsharp_game_main_init; +GDExtensionInitializationFunction initialization_function; +void (*scene_load_function)(void *); + +void *libgodot_sharp_main_init() { + return godotsharp_game_main_init; +} + +LIBGODOT_API void libgodot_mono_bind(void *sharp_main_init, void (*scene_function_bind)(void *)) { + godotsharp_game_main_init = sharp_main_init; + scene_load_function = scene_function_bind; +} + +LIBGODOT_API void libgodot_gdextension_bind(GDExtensionInitializationFunction initialization_bind, void (*scene_function_bind)(void *)) { + initialization_function = initialization_bind; + scene_load_function = scene_function_bind; +} + +void libgodot_scene_load(void *scene) { + if (scene_load_function != nullptr) { + scene_load_function(scene); + } +} + +int libgodot_is_scene_loadable() { + return scene_load_function != nullptr; +} + +void libgodot_init_resource() { + if (initialization_function != nullptr) { + Ref libgodot; + libgodot.instantiate(); + Error err = libgodot->initialize_extension_function(initialization_function, "LibGodot"); + if (err != OK) { + ERR_PRINT("LibGodot Had an error initialize_extension_function'"); + } else { + print_verbose("LibGodot initialization"); + libgodot->set_path("res://LibGodotGDExtension"); + GDExtensionManager::get_singleton()->load_extension("res://LibGodotGDExtension"); + } + } +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/core/libgodot/libgodot.h b/core/libgodot/libgodot.h new file mode 100644 index 000000000000..9b3c1ce96065 --- /dev/null +++ b/core/libgodot/libgodot.h @@ -0,0 +1,71 @@ +/**************************************************************************/ +/* libgodot.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef LIBGODOT_H +#define LIBGODOT_H + +#if defined(LIBRARY_ENABLED) + +#if defined(WINDOWS_ENABLED) | defined(UWP_ENABLED) +#define LIBGODOT_API __declspec(dllexport) +#elif defined(ANDROID_ENABLED) +#include +#define LIBGODOT_API JNIEXPORT +#else +#define LIBGODOT_API +#endif + +#include "core/extension/gdextension_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void libgodot_init_resource(); + +void libgodot_scene_load(void *scene); + +int libgodot_is_scene_loadable(); + +void *libgodot_sharp_main_init(); + +LIBGODOT_API void libgodot_mono_bind(void *sharp_main_init, void (*scene_function_bind)(void *)); + +LIBGODOT_API void libgodot_gdextension_bind(GDExtensionInitializationFunction initialization_bind, void (*scene_function_bind)(void *)); + +LIBGODOT_API int godot_main(int argc, char *argv[]); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif // LIBGODOT_H diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 6f3b6ecdb0e2..cda49fa797eb 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -2488,7 +2488,9 @@ bool EditorFileSystem::_scan_extensions() { Vector loaded_extensions = GDExtensionManager::get_singleton()->get_loaded_extensions(); for (int i = 0; i < loaded_extensions.size(); i++) { if (!extensions.has(loaded_extensions[i])) { - extensions_removed.push_back(loaded_extensions[i]); + if (!GDExtensionManager::get_singleton()->get_extension(loaded_extensions[i])->is_embedded()) { + extensions_removed.push_back(loaded_extensions[i]); + } } } diff --git a/main/main.cpp b/main/main.cpp index 0a9ebd4c6103..445fa7439ef2 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -106,6 +106,10 @@ #endif // DISABLE_DEPRECATED #endif // TOOLS_ENABLED +#ifdef LIBRARY_ENABLED +#include "core/libgodot/libgodot.h" +#endif + #include "modules/modules_enabled.gen.h" // For mono. #if defined(MODULE_MONO_ENABLED) && defined(TOOLS_ENABLED) @@ -1545,11 +1549,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph #ifdef TOOLS_ENABLED editor = false; #else - const String error_msg = "Error: Couldn't load project data at path \"" + project_path + "\". Is the .pck file missing?\nIf you've renamed the executable, the associated .pck file should also be renamed to match the executable's name (without the extension).\n"; - OS::get_singleton()->print("%s", error_msg.utf8().get_data()); - OS::get_singleton()->alert(error_msg); +#ifdef LIBRARY_ENABLED + if (!libgodot_is_scene_loadable()) { +#endif + const String error_msg = "Error: Couldn't load project data at path \"" + project_path + "\". Is the .pck file missing?\nIf you've renamed the executable, the associated .pck file should also be renamed to match the executable's name (without the extension).\n"; + OS::get_singleton()->print("%s", error_msg.utf8().get_data()); + OS::get_singleton()->alert(error_msg); - goto error; + goto error; +#ifdef LIBRARY_ENABLED + } +#endif #endif } @@ -1638,10 +1648,16 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph #ifdef TOOLS_ENABLED if (!editor && !project_manager) { #endif - const String error_msg = "Error: Can't run project: no main scene defined in the project.\n"; - OS::get_singleton()->print("%s", error_msg.utf8().get_data()); - OS::get_singleton()->alert(error_msg); - goto error; +#ifdef LIBRARY_ENABLED + if (!libgodot_is_scene_loadable()) { +#endif + const String error_msg = "Error: Can't run project: no main scene defined in the project.\n"; + OS::get_singleton()->print("%s", error_msg.utf8().get_data()); + OS::get_singleton()->alert(error_msg); + goto error; +#ifdef LIBRARY_ENABLED + } +#endif #ifdef TOOLS_ENABLED } #endif @@ -3138,6 +3154,10 @@ bool Main::start() { } } +#ifdef LIBRARY_ENABLED + libgodot_scene_load((void *)sml); +#endif + #ifdef TOOLS_ENABLED EditorNode *editor_node = nullptr; if (editor) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs index 467313dc28d7..abe349ec3a21 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs @@ -24,10 +24,13 @@ public void Execute(GeneratorExecutionContext context) namespace GodotPlugins.Game { - internal static partial class Main + public static partial class Main { + /// + /// Should not be touched endless you know what your doing this is a UnmanagedCallersOnly function + /// [UnmanagedCallersOnly(EntryPoint = ""godotsharp_game_main_init"")] - private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks, + public static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks, IntPtr unmanagedCallbacks, int unmanagedCallbacksSize) { try diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 247968e25194..f0ea4e353abe 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -53,6 +53,10 @@ #include #endif +#ifdef LIBRARY_ENABLED +#include "core/libgodot/libgodot.h" +#endif + // TODO mobile #if 0 #ifdef IOS_ENABLED @@ -383,13 +387,22 @@ void GDMono::initialize() { } if (!load_hostfxr(hostfxr_dll_handle)) { +#ifdef LIBRARY_ENABLED + if (libgodot_sharp_main_init() != nullptr) { + godot_plugins_initialize = (godot_plugins_initialize_fn)libgodot_sharp_main_init(); + } +#endif #if !defined(TOOLS_ENABLED) - godot_plugins_initialize = try_load_native_aot_library(hostfxr_dll_handle); - - if (godot_plugins_initialize != nullptr) { - is_native_aot = true; + if (godot_plugins_initialize == nullptr) { + godot_plugins_initialize = try_load_native_aot_library(hostfxr_dll_handle); + + if (godot_plugins_initialize != nullptr) { + is_external_function = true; + } else { + ERR_FAIL_MSG(".NET: Failed to load hostfxr"); + } } else { - ERR_FAIL_MSG(".NET: Failed to load hostfxr"); + is_external_function = true; } #else @@ -399,7 +412,7 @@ void GDMono::initialize() { #endif } - if (!is_native_aot) { + if (!is_external_function) { godot_plugins_initialize = initialize_hostfxr_and_godot_plugins(runtime_initialized); ERR_FAIL_NULL(godot_plugins_initialize); } diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index c629ab2eff68..5020a1773dd3 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -64,7 +64,7 @@ class GDMono { bool finalizing_scripts_domain = false; void *hostfxr_dll_handle = nullptr; - bool is_native_aot = false; + bool is_external_function = false; String project_assembly_path; uint64_t project_assembly_modified_time = 0; diff --git a/platform/ios/godot_ios.mm b/platform/ios/godot_ios.mm index 5e66c8b47bbb..15dd63090196 100644 --- a/platform/ios/godot_ios.mm +++ b/platform/ios/godot_ios.mm @@ -117,3 +117,10 @@ void ios_finish() { Main::cleanup(); delete os; } + +#if defined(LIBRARY_ENABLED) +#include "core/libgodot/libgodot.h" +extern "C" LIBGODOT_API int godot_main(int argc, char *argv[]) { + return ios_main(argc, argv); +} +#endif diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index 4dd74ff9d09f..dfb7801f6da1 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -36,7 +36,12 @@ if env["dbus"]: if env["use_sowrap"]: common_linuxbsd.append("dbus-so_wrap.c") -prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) +if env["library_type"] == "static_library": + prog = env.add_library("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) +elif env["library_type"] == "shared_library": + prog = env.add_shared_library("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) +else: + prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) if env["debug_symbols"] and env["separate_debug_symbols"]: env.AddPostAction(prog, run_in_subprocess(platform_linuxbsd_builders.make_debug_linuxbsd)) diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp index d059d60b725c..6e9e0564c6b9 100644 --- a/platform/linuxbsd/godot_linuxbsd.cpp +++ b/platform/linuxbsd/godot_linuxbsd.cpp @@ -84,3 +84,10 @@ int main(int argc, char *argv[]) { return os.get_exit_code(); } + +#if defined(LIBRARY_ENABLED) +#include "core/libgodot/libgodot.h" +extern "C" LIBGODOT_API int godot_main(int argc, char *argv[]) { + return main(argc, argv); +} +#endif diff --git a/platform/macos/SCsub b/platform/macos/SCsub index 7ffb80f70b59..b4359ee853c1 100644 --- a/platform/macos/SCsub +++ b/platform/macos/SCsub @@ -27,7 +27,12 @@ files = [ "gl_manager_macos_legacy.mm", ] -prog = env.add_program("#bin/godot", files) +if env["library_type"] == "static_library": + prog = env.add_library("#bin/godot", files) +elif env["library_type"] == "shared_library": + prog = env.add_shared_library("#bin/godot", files) +else: + prog = env.add_program("#bin/godot", files) if env["debug_symbols"] and env["separate_debug_symbols"]: env.AddPostAction(prog, run_in_subprocess(platform_macos_builders.make_debug_macos)) diff --git a/platform/macos/godot_main_macos.mm b/platform/macos/godot_main_macos.mm index 58263471b098..100700159138 100644 --- a/platform/macos/godot_main_macos.mm +++ b/platform/macos/godot_main_macos.mm @@ -81,3 +81,10 @@ int main(int argc, char **argv) { return os.get_exit_code(); } + +#if defined(LIBRARY_ENABLED) +#include "core/libgodot/libgodot.h" +extern "C" LIBGODOT_API int godot_main(int argc, char *argv[]) { + return main(argc, argv); +} +#endif diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub index 8726d32d617f..3d06aca6d42e 100644 --- a/platform/uwp/SCsub +++ b/platform/uwp/SCsub @@ -14,7 +14,12 @@ files = [ if "build_angle" in env and env["build_angle"]: cmd = env.AlwaysBuild(env.ANGLE("libANGLE.lib", None)) -prog = env.add_program("#bin/godot", files) +if env["library_type"] == "static_library": + prog = env.add_library("#bin/godot", files) +elif env["library_type"] == "shared_library": + prog = env.add_shared_library("#bin/godot", files) +else: + prog = env.add_program("#bin/godot", files) if "build_angle" in env and env["build_angle"]: env.Depends(prog, [cmd]) diff --git a/platform/windows/SCsub b/platform/windows/SCsub index efbb47d965b9..29668c26eae4 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -27,23 +27,30 @@ res_file = "godot_res.rc" res_target = "godot_res" + env["OBJSUFFIX"] res_obj = env.RES(res_target, res_file) -prog = env.add_program("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGSUFFIX"]) - -# Build console wrapper app. -if env["windows_subsystem"] == "gui": - env_wrap = env.Clone() - res_wrap_file = "godot_res_wrap.rc" - res_wrap_target = "godot_res_wrap" + env["OBJSUFFIX"] - res_wrap_obj = env_wrap.RES(res_wrap_target, res_wrap_file) - - if env.msvc: - env_wrap.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) - env_wrap.Append(LINKFLAGS=["version.lib"]) - else: - env_wrap.Append(LINKFLAGS=["-Wl,--subsystem,console"]) - env_wrap.Append(LIBS=["version"]) - - prog_wrap = env_wrap.add_program("#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"]) +if env["library_type"] == "static_library": + prog = env.add_library("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGSUFFIX"]) +elif env["library_type"] == "shared_library": + prog = env.add_shared_library("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGSUFFIX"]) +else: + prog = env.add_program("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGSUFFIX"]) + + # Build console wrapper app. + if env["windows_subsystem"] == "gui": + env_wrap = env.Clone() + res_wrap_file = "godot_res_wrap.rc" + res_wrap_target = "godot_res_wrap" + env["OBJSUFFIX"] + res_wrap_obj = env_wrap.RES(res_wrap_target, res_wrap_file) + + if env.msvc: + env_wrap.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) + env_wrap.Append(LINKFLAGS=["version.lib"]) + else: + env_wrap.Append(LINKFLAGS=["-Wl,--subsystem,console"]) + env_wrap.Append(LIBS=["version"]) + + prog_wrap = env_wrap.add_program( + "#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"] + ) # Microsoft Visual Studio Project Generation if env["vsproj"]: diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 9548939695a4..53a91616f9b3 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -335,7 +335,7 @@ def configure_msvc(env, vcvars_msvc_config): ## Build type # TODO: Re-evaluate the need for this / streamline with common config. - if env["target"] == "template_release": + if env["target"] == "template_release" and env["library_type"] == "executable": env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"]) if env["windows_subsystem"] == "gui": diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp index 8d63b1747ed4..6b7f4ac5e4d9 100644 --- a/platform/windows/godot_windows.cpp +++ b/platform/windows/godot_windows.cpp @@ -149,27 +149,16 @@ char *wc_to_utf8(const wchar_t *wc) { return ubuf; } -int widechar_main(int argc, wchar_t **argv) { +int utf8_char_main(int argc, char **argv_utf8) { OS_Windows os(nullptr); setlocale(LC_CTYPE, ""); - char **argv_utf8 = new char *[argc]; - - for (int i = 0; i < argc; ++i) { - argv_utf8[i] = wc_to_utf8(argv[i]); - } - TEST_MAIN_PARAM_OVERRIDE(argc, argv_utf8) Error err = Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]); if (err != OK) { - for (int i = 0; i < argc; ++i) { - delete[] argv_utf8[i]; - } - delete[] argv_utf8; - if (err == ERR_HELP) { // Returned by --help and --version, so success. return 0; } @@ -181,12 +170,23 @@ int widechar_main(int argc, wchar_t **argv) { } Main::cleanup(); + return os.get_exit_code(); +} + +int widechar_main(int argc, wchar_t **argv) { + char **argv_utf8 = new char *[argc]; + + for (int i = 0; i < argc; ++i) { + argv_utf8[i] = wc_to_utf8(argv[i]); + } + int returnCode = utf8_char_main(argc, argv_utf8); + for (int i = 0; i < argc; ++i) { delete[] argv_utf8[i]; } delete[] argv_utf8; - return os.get_exit_code(); + return returnCode; } int _main() { @@ -207,6 +207,14 @@ int _main() { return result; } +#if defined(LIBRARY_ENABLED) +#include "core/libgodot/libgodot.h" +extern "C" LIBGODOT_API int godot_main(int argc, char *argv[]) { + return utf8_char_main(argc, argv); +} + +#else + int main(int argc, char **argv) { // override the arguments for the test handler / if symbol is provided // TEST_MAIN_OVERRIDE @@ -230,3 +238,4 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine godot_hinstance = hInstance; return main(0, nullptr); } +#endif