Mono/C#: Allow debugging exported games
- Include PDB files in exported games. - Release export templates also allow debugging now. Right now the only way to enable debugging in exported games is with the environment variables, which may be cumbersome or not even possible on some platforms.
This commit is contained in:
parent
bb9d89d78c
commit
71fc87e101
|
@ -168,13 +168,13 @@ namespace GodotTools.Export
|
|||
|
||||
// Add dependency assemblies
|
||||
|
||||
var dependencies = new Godot.Collections.Dictionary<string, string>();
|
||||
var assemblies = new Godot.Collections.Dictionary<string, string>();
|
||||
|
||||
string projectDllName = GodotSharpEditor.ProjectAssemblyName;
|
||||
string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig);
|
||||
string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll");
|
||||
|
||||
dependencies[projectDllName] = projectDllSrcPath;
|
||||
assemblies[projectDllName] = projectDllSrcPath;
|
||||
|
||||
if (platform == OS.Platforms.Android)
|
||||
{
|
||||
|
@ -184,15 +184,15 @@ namespace GodotTools.Export
|
|||
if (!File.Exists(monoAndroidAssemblyPath))
|
||||
throw new FileNotFoundException("Assembly not found: 'Mono.Android'", monoAndroidAssemblyPath);
|
||||
|
||||
dependencies["Mono.Android"] = monoAndroidAssemblyPath;
|
||||
assemblies["Mono.Android"] = monoAndroidAssemblyPath;
|
||||
}
|
||||
|
||||
string bclDir = DeterminePlatformBclDir(platform);
|
||||
|
||||
var initialDependencies = dependencies.Duplicate();
|
||||
internal_GetExportedAssemblyDependencies(initialDependencies, buildConfig, bclDir, dependencies);
|
||||
var initialAssemblies = assemblies.Duplicate();
|
||||
internal_GetExportedAssemblyDependencies(initialAssemblies, buildConfig, bclDir, assemblies);
|
||||
|
||||
AddI18NAssemblies(dependencies, bclDir);
|
||||
AddI18NAssemblies(assemblies, bclDir);
|
||||
|
||||
string outputDataDir = null;
|
||||
|
||||
|
@ -211,22 +211,34 @@ namespace GodotTools.Export
|
|||
Directory.CreateDirectory(outputDataGameAssembliesDir);
|
||||
}
|
||||
|
||||
foreach (var dependency in dependencies)
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
void AddToAssembliesDir(string fileSrcPath)
|
||||
{
|
||||
string dependSrcPath = dependency.Value;
|
||||
|
||||
if (assembliesInsidePck)
|
||||
{
|
||||
string dependDstPath = Path.Combine(resAssembliesDir, dependSrcPath.GetFile());
|
||||
AddFile(dependSrcPath, dependDstPath);
|
||||
string fileDstPath = Path.Combine(resAssembliesDir, fileSrcPath.GetFile());
|
||||
AddFile(fileSrcPath, fileDstPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
string dependDstPath = Path.Combine(outputDataDir, "Assemblies", dependSrcPath.GetFile());
|
||||
File.Copy(dependSrcPath, dependDstPath);
|
||||
Debug.Assert(outputDataDir != null);
|
||||
string fileDstPath = Path.Combine(outputDataDir, "Assemblies", fileSrcPath.GetFile());
|
||||
File.Copy(fileSrcPath, fileDstPath);
|
||||
}
|
||||
}
|
||||
|
||||
string assemblySrcPath = assembly.Value;
|
||||
|
||||
string assemblyPathWithoutExtension = Path.ChangeExtension(assemblySrcPath, null);
|
||||
string pdbSrcPath = assemblyPathWithoutExtension + ".pdb";
|
||||
|
||||
AddToAssembliesDir(assemblySrcPath);
|
||||
|
||||
if (File.Exists(pdbSrcPath))
|
||||
AddToAssembliesDir(pdbSrcPath);
|
||||
}
|
||||
|
||||
// AOT compilation
|
||||
bool aotEnabled = platform == OS.Platforms.iOS || (bool)ProjectSettings.GetSetting("mono/export/aot/enabled");
|
||||
|
||||
|
@ -254,7 +266,7 @@ namespace GodotTools.Export
|
|||
ToolchainPath = aotToolchainPath
|
||||
};
|
||||
|
||||
AotBuilder.CompileAssemblies(this, aotOpts, features, platform, isDebug, bclDir, outputDir, outputDataDir, dependencies);
|
||||
AotBuilder.CompileAssemblies(this, aotOpts, features, platform, isDebug, bclDir, outputDir, outputDataDir, assemblies);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,7 +378,7 @@ namespace GodotTools.Export
|
|||
if (PlatformRequiresCustomBcl(platform))
|
||||
throw new FileNotFoundException($"Missing BCL (Base Class Library) for platform: {platform}");
|
||||
|
||||
platformBclDir = typeof(object).Assembly.Location; // Use the one we're running on
|
||||
platformBclDir = typeof(object).Assembly.Location.GetBaseDir(); // Use the one we're running on
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,7 +437,7 @@ namespace GodotTools.Export
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern void internal_GetExportedAssemblyDependencies(Godot.Collections.Dictionary<string, string> initialDependencies,
|
||||
string buildConfig, string customBclDir, Godot.Collections.Dictionary<string, string> dependencies);
|
||||
private static extern void internal_GetExportedAssemblyDependencies(Godot.Collections.Dictionary<string, string> initialAssemblies,
|
||||
string buildConfig, string customBclDir, Godot.Collections.Dictionary<string, string> dependencyAssemblies);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,14 +231,14 @@ int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObje
|
|||
return err;
|
||||
}
|
||||
|
||||
uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoObject *p_initial_dependencies,
|
||||
MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_dependencies) {
|
||||
Dictionary initial_dependencies = GDMonoMarshal::mono_object_to_variant(p_initial_dependencies);
|
||||
uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoObject *p_initial_assemblies,
|
||||
MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_assembly_dependencies) {
|
||||
Dictionary initial_dependencies = GDMonoMarshal::mono_object_to_variant(p_initial_assemblies);
|
||||
String build_config = GDMonoMarshal::mono_string_to_godot(p_build_config);
|
||||
String custom_bcl_dir = GDMonoMarshal::mono_string_to_godot(p_custom_bcl_dir);
|
||||
Dictionary dependencies = GDMonoMarshal::mono_object_to_variant(r_dependencies);
|
||||
Dictionary assembly_dependencies = GDMonoMarshal::mono_object_to_variant(r_assembly_dependencies);
|
||||
|
||||
return GodotSharpExport::get_exported_assembly_dependencies(initial_dependencies, build_config, custom_bcl_dir, dependencies);
|
||||
return GodotSharpExport::get_exported_assembly_dependencies(initial_dependencies, build_config, custom_bcl_dir, assembly_dependencies);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) {
|
||||
|
|
|
@ -50,13 +50,13 @@ String get_assemblyref_name(MonoImage *p_image, int index) {
|
|||
return String::utf8(mono_metadata_string_heap(p_image, cols[MONO_ASSEMBLYREF_NAME]));
|
||||
}
|
||||
|
||||
Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies) {
|
||||
Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_assembly_dependencies) {
|
||||
MonoImage *image = p_assembly->get_image();
|
||||
|
||||
for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) {
|
||||
String ref_name = get_assemblyref_name(image, i);
|
||||
|
||||
if (r_dependencies.has(ref_name))
|
||||
if (r_assembly_dependencies.has(ref_name))
|
||||
continue;
|
||||
|
||||
GDMonoAssembly *ref_assembly = nullptr;
|
||||
|
@ -93,17 +93,17 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String>
|
|||
ERR_FAIL_COND_V_MSG(!ref_assembly, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
|
||||
|
||||
// Use the path we got from the search. Don't try to get the path from the loaded assembly as we can't trust it will be from the selected BCL dir.
|
||||
r_dependencies[ref_name] = path;
|
||||
r_assembly_dependencies[ref_name] = path;
|
||||
|
||||
Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies);
|
||||
Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_assembly_dependencies);
|
||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load one of the dependencies for the assembly: '" + ref_name + "'.");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error get_exported_assembly_dependencies(const Dictionary &p_initial_dependencies,
|
||||
const String &p_build_config, const String &p_custom_bcl_dir, Dictionary &r_dependencies) {
|
||||
Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
|
||||
const String &p_build_config, const String &p_custom_bcl_dir, Dictionary &r_assembly_dependencies) {
|
||||
MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.Domain.ProjectExport");
|
||||
ERR_FAIL_NULL_V(export_domain, FAILED);
|
||||
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
|
||||
|
@ -113,16 +113,16 @@ Error get_exported_assembly_dependencies(const Dictionary &p_initial_dependencie
|
|||
Vector<String> search_dirs;
|
||||
GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_bcl_dir);
|
||||
|
||||
for (const Variant *key = p_initial_dependencies.next(); key; key = p_initial_dependencies.next(key)) {
|
||||
for (const Variant *key = p_initial_assemblies.next(); key; key = p_initial_assemblies.next(key)) {
|
||||
String assembly_name = *key;
|
||||
String assembly_path = p_initial_dependencies[*key];
|
||||
String assembly_path = p_initial_assemblies[*key];
|
||||
|
||||
GDMonoAssembly *assembly = nullptr;
|
||||
bool load_success = GDMono::get_singleton()->load_assembly_from(assembly_name, assembly_path, &assembly, /* refonly: */ true);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + assembly_name + "'.");
|
||||
|
||||
Error err = get_assembly_dependencies(assembly, search_dirs, r_dependencies);
|
||||
Error err = get_assembly_dependencies(assembly, search_dirs, r_assembly_dependencies);
|
||||
if (err != OK)
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ namespace GodotSharpExport {
|
|||
|
||||
Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies);
|
||||
|
||||
Error get_exported_assembly_dependencies(const Dictionary &p_initial_dependencies,
|
||||
const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_dependencies);
|
||||
Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
|
||||
const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_assembly_dependencies);
|
||||
|
||||
} // namespace GodotSharpExport
|
||||
|
||||
|
|
|
@ -129,12 +129,8 @@ void gd_mono_profiler_init() {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_ENABLED)
|
||||
|
||||
void gd_mono_debug_init() {
|
||||
|
||||
mono_debug_init(MONO_DEBUG_FORMAT_MONO);
|
||||
|
||||
CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
@ -159,6 +155,10 @@ void gd_mono_debug_init() {
|
|||
return; // Exported games don't use the project settings to setup the debugger agent
|
||||
#endif
|
||||
|
||||
// Debugging enabled
|
||||
|
||||
mono_debug_init(MONO_DEBUG_FORMAT_MONO);
|
||||
|
||||
// --debugger-agent=help
|
||||
const char *options[] = {
|
||||
"--soft-breakpoints",
|
||||
|
@ -167,7 +167,6 @@ void gd_mono_debug_init() {
|
|||
mono_jit_parse_options(2, (char **)options);
|
||||
}
|
||||
|
||||
#endif // defined(DEBUG_ENABLED)
|
||||
#endif // !defined(JAVASCRIPT_ENABLED)
|
||||
|
||||
#if defined(JAVASCRIPT_ENABLED)
|
||||
|
@ -175,6 +174,7 @@ MonoDomain *gd_initialize_mono_runtime() {
|
|||
const char *vfs_prefix = "managed";
|
||||
int enable_debugging = 0;
|
||||
|
||||
// TODO: Provide a way to enable debugging on WASM release builds.
|
||||
#ifdef DEBUG_ENABLED
|
||||
enable_debugging = 1;
|
||||
#endif
|
||||
|
@ -185,9 +185,7 @@ MonoDomain *gd_initialize_mono_runtime() {
|
|||
}
|
||||
#else
|
||||
MonoDomain *gd_initialize_mono_runtime() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
gd_mono_debug_init();
|
||||
#endif
|
||||
|
||||
#if defined(IPHONE_ENABLED) || defined(ANDROID_ENABLED)
|
||||
// I don't know whether this actually matters or not
|
||||
|
|
Loading…
Reference in New Issue