Skip to content

Commit

Permalink
Merge pull request #82729 from shana/shana/ios-csharp
Browse files Browse the repository at this point in the history
Add C# iOS support
  • Loading branch information
akien-mga committed Oct 9, 2023
2 parents 98287fe + ee9a735 commit 4a5801b
Show file tree
Hide file tree
Showing 16 changed files with 463 additions and 290 deletions.
2 changes: 1 addition & 1 deletion modules/mono/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Prior to .NET Core, we supported these: ["windows", "macos", "linuxbsd", "android", "web", "ios"]
# Eventually support for each them should be added back.
supported_platforms = ["windows", "macos", "linuxbsd", "android"]
supported_platforms = ["windows", "macos", "linuxbsd", "android", "ios"]


def can_build(env, platform):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@
<None Include="$(GodotSdkPackageVersionsFilePath)" Pack="true" PackagePath="Sdk">
<Link>Sdk\SdkPackageVersions.props</Link>
</None>
<None Include="Sdk\iOSNativeAOT.props" Pack="true" PackagePath="Sdk" />
<None Include="Sdk\iOSNativeAOT.targets" Pack="true" PackagePath="Sdk" />
</ItemGroup>
</Project>
14 changes: 14 additions & 0 deletions modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@
</PropertyGroup>

<!-- Auto-detect the target Godot platform if it was not specified. -->
<PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' ">
<GodotTargetPlatform Condition=" $(RuntimeIdentifier.StartsWith('ios')) ">ios</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('android')) ">android</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('browser')) ">web</GodotTargetPlatform>

<GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('linux')) ">linuxbsd</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('freebsd')) ">linuxbsd</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('osx')) ">macos</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('win')) ">windows</GodotTargetPlatform>
</PropertyGroup>

<!-- Auto-detect the target Godot platform if it was not specified and there's no runtime identifier information. -->
<PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' ">
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Linux))' ">linuxbsd</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(FreeBSD))' ">linuxbsd</GodotTargetPlatform>
Expand Down Expand Up @@ -97,4 +109,6 @@

<DefineConstants>$(GodotDefineConstants);$(DefineConstants)</DefineConstants>
</PropertyGroup>

<Import Project="$(MSBuildThisFileDirectory)\iOSNativeAOT.props" Condition=" '$(GodotTargetPlatform)' == 'ios' " />
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@
<PackageReference Include="GodotSharp" Version="$(PackageVersion_GodotSharp)" />
<PackageReference Include="GodotSharpEditor" Version="$(PackageVersion_GodotSharp)" Condition=" '$(Configuration)' == 'Debug' " />
</ItemGroup>

<!-- iOS-specific build targets -->
<Import Project="$(MSBuildThisFileDirectory)\iOSNativeAOT.targets" Condition=" '$(GodotTargetPlatform)' == 'ios' " />

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project>
<PropertyGroup>
<PublishAot>true</PublishAot>
<PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
<UseNativeAOTRuntime>true</UseNativeAOTRuntime>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<Project>
<ItemGroup>
<TrimmerRootAssembly Include="GodotSharp" />
<TrimmerRootAssembly Include="$(TargetName)" />
<LinkerArg Include="-install_name '@rpath/$(TargetName)$(NativeBinaryExt)'" />
</ItemGroup>

<PropertyGroup>
<LinkStandardCPlusPlusLibrary>true</LinkStandardCPlusPlusLibrary>
<FindXCode Condition=" '$(XCodePath)' == '' and '$([MSBuild]::IsOsPlatform(OSX))' ">true</FindXCode>
<XCodePath Condition=" '$(XCodePath)' == '' ">/Applications/Xcode.app/Contents/Developer</XCodePath>
<XCodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XCodePath>
</PropertyGroup>

<Target Name="PrepareBeforeIlcCompile"
BeforeTargets="IlcCompile">

<Copy SourceFiles="%(ResolvedRuntimePack.PackageDirectory)/runtimes/$(RuntimeIdentifier)/native/icudt.dat" DestinationFolder="$(PublishDir)"/>

<!-- We need to find the path to Xcode so we can set manual linker args to the correct SDKs
Once https://github.com/dotnet/runtime/issues/88737 is released, we can take this out
-->

<Exec Command="xcrun xcode-select -p" ConsoleToMSBuild="true" Condition=" '$(FindXCode)' == 'true' ">
<Output TaskParameter="ConsoleOutput" PropertyName="XcodeSelect" />
</Exec>

<PropertyGroup Condition=" '$(FindXCode)' == 'true' ">
<XCodePath>$(XcodeSelect)</XCodePath>
<XCodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XCodePath>
</PropertyGroup>

<Message Importance="normal" Text="Found XCode at $(XcodeSelect)" Condition=" '$(FindXCode)' == 'true' "/>

<ItemGroup>
<LinkerArg Include="-isysroot %22$(XCodePath)Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk%22"
Condition=" $(RuntimeIdentifier.Contains('simulator')) "/>
<LinkerArg Include="-isysroot %22$(XCodePath)Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk%22"
Condition=" !$(RuntimeIdentifier.Contains('simulator')) "/>
</ItemGroup>

</Target>

<Target Name="FixSymbols"
AfterTargets="Publish">

<RemoveDir Directories="$(PublishDir)$(TargetName).framework.dSYM"/>

<!-- create-xcframework (called from the export plugin wants the symbol files in a directory
with a slightly different name from the one created by dotnet publish, so we copy them over
to the correctly-named directory -->
<ItemGroup>
<SymbolFiles Include="$(NativeBinary).dsym\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="@(SymbolFiles)" DestinationFolder="$(PublishDir)$(TargetName).framework.dSYM"/>
</Target>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public static ProjectRootElement GenGameProject(string name)
mainGroup.AddProperty("TargetFramework", "net6.0");
mainGroup.AddProperty("EnableDynamicLoading", "true");

var net8 = mainGroup.AddProperty("TargetFramework", "net8.0");
net8.Condition = " '$(GodotTargetPlatform)' == 'ios' ";

string sanitizedName = IdentifierUtils.SanitizeQualifiedIdentifier(name, allowEmptyIdentifiers: true);

// If the name is not a valid namespace, manually set RootNamespace to a sanitized one.
Expand Down
44 changes: 42 additions & 2 deletions modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
Expand Down Expand Up @@ -67,7 +68,7 @@ private static bool Build(BuildInfo buildInfo)
{
BuildStarted?.Invoke(buildInfo);

// Required in order to update the build tasks list
// Required in order to update the build tasks list.
Internal.GodotMainIteration();

try
Expand Down Expand Up @@ -162,7 +163,7 @@ private static bool Publish(BuildInfo buildInfo)
{
BuildStarted?.Invoke(buildInfo);

// Required in order to update the build tasks list
// Required in order to update the build tasks list.
Internal.GodotMainIteration();

try
Expand Down Expand Up @@ -323,6 +324,45 @@ public static bool PublishProjectBlocking(
) => PublishProjectBlocking(CreatePublishBuildInfo(configuration,
platform, runtimeIdentifier, publishOutputDir, includeDebugSymbols));

public static bool GenerateXCFrameworkBlocking(
List<string> outputPaths,
string xcFrameworkPath)
{
using var pr = new EditorProgress("generate_xcframework", "Generating XCFramework...", 1);

pr.Step("Running xcodebuild -create-xcframework", 0);

if (!GenerateXCFramework(outputPaths, xcFrameworkPath))
{
ShowBuildErrorDialog("Failed to generate XCFramework");
return false;
}

return true;
}

private static bool GenerateXCFramework(List<string> outputPaths, string xcFrameworkPath)
{
// Required in order to update the build tasks list.
Internal.GodotMainIteration();

try
{
int exitCode = BuildSystem.GenerateXCFramework(outputPaths, xcFrameworkPath, StdOutputReceived, StdErrorReceived);

if (exitCode != 0)
PrintVerbose(
$"xcodebuild create-xcframework exited with code: {exitCode}.");

return exitCode == 0;
}
catch (Exception e)
{
Console.Error.WriteLine(e);
return false;
}
}

public static bool EditorBuildCallback()
{
if (!File.Exists(GodotSharpDirs.ProjectCsProjPath))
Expand Down
78 changes: 78 additions & 0 deletions modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
using System.Threading.Tasks;
using Godot;
using GodotTools.BuildLogger;
using GodotTools.Internals;
using GodotTools.Utils;
using Directory = GodotTools.Utils.Directory;

namespace GodotTools.Build
{
Expand Down Expand Up @@ -293,5 +295,81 @@ private static void RemovePlatformVariable(StringDictionary environmentVariables
foreach (string env in platformEnvironmentVariables)
environmentVariables.Remove(env);
}

private static Process DoGenerateXCFramework(List<string> outputPaths, string xcFrameworkPath,
Action<string> stdOutHandler, Action<string> stdErrHandler)
{
if (Directory.Exists(xcFrameworkPath))
{
Directory.Delete(xcFrameworkPath, true);
}

var startInfo = new ProcessStartInfo("xcrun");

BuildXCFrameworkArguments(outputPaths, xcFrameworkPath, startInfo.ArgumentList);

string launchMessage = startInfo.GetCommandLineDisplay(new StringBuilder("Packaging: ")).ToString();
stdOutHandler?.Invoke(launchMessage);
if (Godot.OS.IsStdOutVerbose())
Console.WriteLine(launchMessage);

startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;

if (OperatingSystem.IsWindows())
{
startInfo.StandardOutputEncoding = Encoding.UTF8;
startInfo.StandardErrorEncoding = Encoding.UTF8;
}

// Needed when running from Developer Command Prompt for VS.
RemovePlatformVariable(startInfo.EnvironmentVariables);

var process = new Process { StartInfo = startInfo };

if (stdOutHandler != null)
process.OutputDataReceived += (_, e) => stdOutHandler.Invoke(e.Data);
if (stdErrHandler != null)
process.ErrorDataReceived += (_, e) => stdErrHandler.Invoke(e.Data);

process.Start();

process.BeginOutputReadLine();
process.BeginErrorReadLine();

return process;
}

public static int GenerateXCFramework(List<string> outputPaths, string xcFrameworkPath, Action<string> stdOutHandler, Action<string> stdErrHandler)
{
using (var process = DoGenerateXCFramework(outputPaths, xcFrameworkPath, stdOutHandler, stdErrHandler))
{
process.WaitForExit();

return process.ExitCode;
}
}

private static void BuildXCFrameworkArguments(List<string> outputPaths,
string xcFrameworkPath, Collection<string> arguments)
{
var baseDylib = $"{GodotSharpDirs.ProjectAssemblyName}.dylib";
var baseSym = $"{GodotSharpDirs.ProjectAssemblyName}.framework.dSYM";

arguments.Add("xcodebuild");
arguments.Add("-create-xcframework");

foreach (var outputPath in outputPaths)
{
arguments.Add("-library");
arguments.Add(Path.Combine(outputPath, baseDylib));
arguments.Add("-debug-symbols");
arguments.Add(Path.Combine(outputPath, baseSym));
}

arguments.Add("-output");
arguments.Add(xcFrameworkPath);
}
}
}
Loading

0 comments on commit 4a5801b

Please sign in to comment.