Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add C# iOS support #82729

Merged
merged 1 commit into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -317,6 +318,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();

shana marked this conversation as resolved.
Show resolved Hide resolved
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
Loading