Skip to content

Commit

Permalink
[iOS] Remove cmake build dependency for library mode (#89869)
Browse files Browse the repository at this point in the history
This change removes cmake as a build dependency and instead uses clang directly when building for iOS/tvOS/Macatalyst library mode.
  • Loading branch information
steveisok authored Aug 8, 2023
1 parent 3e293bc commit 39f4921
Show file tree
Hide file tree
Showing 14 changed files with 775 additions and 275 deletions.
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
- src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets
- src/installer/pkg/sfx/bundle/shared-framework-distribution-template-x64.xml
- src/installer/pkg/sfx/bundle/shared-framework-distribution-template-arm64.xml
- src/tasks/MobileBuildTasks/Apple/AppleProject.cs
-->
<AndroidApiLevelMin>21</AndroidApiLevelMin>
<iOSVersionMin>11.0</iOSVersionMin>
Expand Down
33 changes: 25 additions & 8 deletions src/mono/msbuild/apple/build/AppleBuild.targets
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
<PropertyGroup>
<AppleGenerateAppBundle Condition="'$(AppleGenerateAppBundle)' == '' and '$(GenerateAppBundle)' != ''">$(GenerateAppBundle)</AppleGenerateAppBundle>
<AppleGenerateAppBundle Condition="'$(AppleGenerateAppBundle)' == ''">true</AppleGenerateAppBundle>
<!-- Unable to properly integrate nativelib into app build, so not supported for now. -->
<AppleGenerateAppBundle Condition="'$(_IsLibraryMode)' == 'true'">false</AppleGenerateAppBundle>
<AppleGenerateAppBundle Condition="'$(_IsLibraryMode)' == 'true' and '$(ForceLibraryModeGenerateAppBundle)' != 'true'">false</AppleGenerateAppBundle>
<_ProcessRuntimeComponentsForLibraryMode Condition="'$(_IsLibraryMode)' == 'true'">_ProcessRuntimeComponentsForLibraryMode</_ProcessRuntimeComponentsForLibraryMode>
<EnableDefaultAssembliesToBundle Condition="'$(EnableDefaultAssembliesToBundle)' == ''">false</EnableDefaultAssembliesToBundle>
</PropertyGroup>
Expand Down Expand Up @@ -53,10 +52,23 @@
<AppName Condition="'$(AppName)' == ''">$(AssemblyName)</AppName>
</PropertyGroup>

<PropertyGroup>
<RuntimeComponents Condition="'$(RuntimeComponents)' == ''">marshal-ilgen</RuntimeComponents>
</PropertyGroup>

<!-- common linker arguments for app and library builds -->
<ItemGroup>
<_CommonLinkerArgs Condition="'$(_IsLibraryMode)' == 'true' and '$(TargetOS)' != 'tvos' and '$(TargetOS)' != 'tvossimulator'" Include="-framework GSS" />
</ItemGroup>

<ItemGroup Condition="'$(_IsLibraryMode)' == 'true'">
<_CommonLinkerArgs Include="-lz" />
<_CommonLinkerArgs Include="-lc++" />
<_CommonLinkerArgs Include="-liconv" />
<_CommonLinkerArgs Include="-framework Foundation" />
<_CommonLinkerArgs Include="-framework Security" />
<_CommonLinkerArgs Include="-framework UIKit" />
</ItemGroup>
</Target>

<Target Name="_BeforeAppleBuild">
Expand Down Expand Up @@ -262,36 +274,41 @@
<ExtraAppLinkerArgs Include="@(_CommonLinkerArgs)" />
</ItemGroup>

<ItemGroup Condition="'$(_IsLibraryMode)' == 'true'">
<NativeDependencies Include="$(LibraryOutputPath)" />
</ItemGroup>

<Error Condition="'$(NativeMainSource)' != '' and !Exists('$(NativeMainSource)')" Text="Project property NativeMainSource is defined, but the specified file: '$(NativeMainSource)' does not exist." />

<AppleAppBuilderTask
UseNativeAOTRuntime="$(UseNativeAOTRuntime)"
NativeDependencies="$(NativeDependencies)"
AppDir="$(AppleBuildDir)"
Arch="$(TargetArchitecture)"
Assemblies="@(_AssembliesToBundleInternal)"
BuildAppBundle="$(GenerateXcodeProject)"
DevTeamProvisioning="$(DevTeamProvisioning)"
DiagnosticPorts="$(DiagnosticPorts)"
EnableAppSandbox="$(EnableAppSandbox)"
ExcludeFromAppDir="@(_ExcludeFromAppDir)"
ExtraLinkerArguments="@(ExtraAppLinkerArgs)"
ForceAOT="$(RunAOTCompilation)"
ForceInterpreter="$(MonoForceInterpreter)"
GenerateCMakeProject="$(GenerateCMakeProject)"
GenerateXcodeProject="$(GenerateXcodeProject)"
InvariantGlobalization="$(InvariantGlobalization)"
HybridGlobalization="$(HybridGlobalization)"
InvariantGlobalization="$(InvariantGlobalization)"
IsLibraryMode="$(_IsLibraryMode)"
MainLibraryFileName="$(MainLibraryFileName)"
MonoRuntimeHeaders="$(_MonoHeaderPath)"
NativeMainSource="$(NativeMainSource)"
NativeDependencies="@(NativeDependencies)"
Optimized="$(Optimized)"
OutputDirectory="$(AppleBundleDir)"
ProjectName="$(AppName)"
RuntimeComponents="$(RuntimeComponents)"
TargetOS="$(TargetOS)"
StripSymbolTable="$(StripDebugSymbols)"
ExcludeFromAppDir="@(_ExcludeFromAppDir)"
UseConsoleUITemplate="$(UseConsoleUITemplate)">
TargetOS="$(TargetOS)"
UseConsoleUITemplate="$(UseConsoleUITemplate)"
UseNativeAOTRuntime="$(UseNativeAOTRuntime)">
<Output TaskParameter="AppBundlePath" PropertyName="AppBundlePath" />
<Output TaskParameter="XcodeProjectPath" PropertyName="XcodeProjectPath" />
</AppleAppBuilderTask>
Expand Down
61 changes: 35 additions & 26 deletions src/tasks/AppleAppBuilder/AppleAppBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ public string TargetOS
/// </summary>
public string[] NativeDependencies { get; set; } = Array.Empty<string>();

/// <summary>
/// Mode to control whether runtime is a self-contained library or not
/// </summary>
public bool IsLibraryMode { get; set; }

public void ValidateRuntimeSelection()
{
if (UseNativeAOTRuntime)
Expand Down Expand Up @@ -260,39 +265,38 @@ public override bool Execute()
List<string> assemblerFiles = new List<string>();
List<string> assemblerDataFiles = new List<string>();
List<string> assemblerFilesToLink = new List<string>();
foreach (ITaskItem file in Assemblies)
{
// use AOT files if available
string obj = file.GetMetadata("AssemblerFile");
string llvmObj = file.GetMetadata("LlvmObjectFile");
string dataFile = file.GetMetadata("AotDataFile");

if (!string.IsNullOrEmpty(obj))
if (!IsLibraryMode)
{
foreach (ITaskItem file in Assemblies)
{
assemblerFiles.Add(obj);
}
// use AOT files if available
string obj = file.GetMetadata("AssemblerFile");
string llvmObj = file.GetMetadata("LlvmObjectFile");
string dataFile = file.GetMetadata("AotDataFile");

if (!string.IsNullOrEmpty(dataFile))
{
assemblerDataFiles.Add(dataFile);
if (!string.IsNullOrEmpty(obj))
{
assemblerFiles.Add(obj);
}

if (!string.IsNullOrEmpty(dataFile))
{
assemblerDataFiles.Add(dataFile);
}

if (!string.IsNullOrEmpty(llvmObj))
{
assemblerFilesToLink.Add(llvmObj);
}
}

if (!string.IsNullOrEmpty(llvmObj))
if (!ForceInterpreter && (shouldStaticLink || ForceAOT) && (assemblerFiles.Count == 0 && !UseNativeAOTRuntime))
{
assemblerFilesToLink.Add(llvmObj);
throw new InvalidOperationException("Need list of AOT files for static linked builds.");
}
}

foreach (var nativeDependency in NativeDependencies)
{
assemblerFilesToLink.Add(nativeDependency);
}

if (!ForceInterpreter && (shouldStaticLink || ForceAOT) && (assemblerFiles.Count == 0 && !UseNativeAOTRuntime))
{
throw new InvalidOperationException("Need list of AOT files for static linked builds.");
}

if (!string.IsNullOrEmpty(DiagnosticPorts))
{
bool validDiagnosticsConfig = false;
Expand All @@ -313,6 +317,11 @@ public override bool Execute()
throw new ArgumentException("DevTeamProvisioning must be set to a valid value when App Sandbox is enabled, using '-' is not supported.");
}

foreach (var nativeDependency in NativeDependencies)
{
assemblerFilesToLink.Add(nativeDependency);
}

List<string> extraLinkerArgs = new List<string>();
foreach(ITaskItem item in ExtraLinkerArguments)
{
Expand All @@ -324,7 +333,7 @@ public override bool Execute()
if (GenerateXcodeProject)
{
XcodeProjectPath = generator.GenerateXCode(ProjectName, MainLibraryFileName, assemblerFiles, assemblerDataFiles, assemblerFilesToLink, extraLinkerArgs, excludes,
AppDir, binDir, MonoRuntimeHeaders, !shouldStaticLink, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, HybridGlobalization, Optimized, EnableRuntimeLogging, EnableAppSandbox, DiagnosticPorts, RuntimeComponents, NativeMainSource, UseNativeAOTRuntime);
AppDir, binDir, MonoRuntimeHeaders, !shouldStaticLink, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, HybridGlobalization, Optimized, EnableRuntimeLogging, EnableAppSandbox, DiagnosticPorts, RuntimeComponents, NativeMainSource, UseNativeAOTRuntime, IsLibraryMode);

if (BuildAppBundle)
{
Expand All @@ -350,7 +359,7 @@ public override bool Execute()
else if (GenerateCMakeProject)
{
generator.GenerateCMake(ProjectName, MainLibraryFileName, assemblerFiles, assemblerDataFiles, assemblerFilesToLink, extraLinkerArgs, excludes,
AppDir, binDir, MonoRuntimeHeaders, !shouldStaticLink, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, HybridGlobalization, Optimized, EnableRuntimeLogging, EnableAppSandbox, DiagnosticPorts, RuntimeComponents, NativeMainSource, UseNativeAOTRuntime);
AppDir, binDir, MonoRuntimeHeaders, !shouldStaticLink, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, HybridGlobalization, Optimized, EnableRuntimeLogging, EnableAppSandbox, DiagnosticPorts, RuntimeComponents, NativeMainSource, UseNativeAOTRuntime, IsLibraryMode);
}

return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
cmake_minimum_required(VERSION 3.16)

project(%ProjectName%)
enable_language(OBJC ASM)

set(APP_RESOURCES
%AppResources%
lib%ProjectName%.dylib
)

add_executable(
%ProjectName%
%MainSource%
${APP_RESOURCES}
)

if(NOT %UseNativeAOTRuntime%)
target_sources(
%ProjectName%
PRIVATE
runtime.m)
endif()

%Defines%

if(NOT %UseNativeAOTRuntime%)
include_directories("%MonoInclude%")
endif()

#set_target_properties(%ProjectName% %AotTargetsList% PROPERTIES
# XCODE_ATTRIBUTE_SUPPORTS_MACCATALYST "YES"
#)

set_target_properties(%ProjectName% PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
XCODE_ATTRIBUTE_ENABLE_BITCODE "NO"
XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING "NO"
XCODE_EMIT_EFFECTIVE_PLATFORM_NAME "YES"
XCODE_EMBED_FRAMEWORKS "%DYLIB_PATH%"
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks"
RESOURCE "${APP_RESOURCES}"
)

set(HARDENED_RUNTIME
%HardenedRuntime%
)

set(HARDENED_RUNTIME_USE_ENTITLEMENTS_FILE
%HardenedRuntimeUseEntitlementsFile%
)

if("${HARDENED_RUNTIME}")
set_target_properties(%ProjectName% PROPERTIES XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES")
if("${HARDENED_RUNTIME_USE_ENTITLEMENTS_FILE}")
set_target_properties(%ProjectName% PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "app.entitlements")
add_custom_command(
TARGET %ProjectName% POST_BUILD
COMMAND if test \"$CODE_SIGN_IDENTITY\"\; then codesign -fs \"$CODE_SIGN_IDENTITY\" $CODESIGNING_FOLDER_PATH/Contents/Resources/*.dylib\; fi
)
endif()
endif()

# FIXME: `XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING` should not be NO

target_link_libraries(
%ProjectName%
PRIVATE
"-framework Foundation"
"-framework Security"
"-framework UIKit"
"-lz"
"-lc++"
"-liconv"
%NativeLibrariesToLink%
%APP_LINK_LIBRARIES%
)

set_target_properties(
%ProjectName%
PROPERTIES LINK_FLAGS
%EXTRA_LINKER_ARGS%
)
81 changes: 81 additions & 0 deletions src/tasks/AppleAppBuilder/Templates/runtime-librarymode.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#import <Foundation/Foundation.h>
#include <mono/utils/mono-publib.h>
#include <mono/utils/mono-logger.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/class.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/object.h>
#include <mono/jit/jit.h>
#include <mono/jit/mono-private-unstable.h>
#include <TargetConditionals.h>
#import <os/log.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>

#import "util.h"

static char *bundle_path;

int SayHello (void);

int invoke_netlibrary_entrypoints (void)
{
return SayHello ();
}

const char *
get_bundle_path (void)
{
if (bundle_path)
return bundle_path;
NSBundle* main_bundle = [NSBundle mainBundle];
NSString* path = [main_bundle bundlePath];

#if TARGET_OS_MACCATALYST
path = [path stringByAppendingString:@"/Contents/Resources"];
#endif

bundle_path = strdup ([path UTF8String]);

return bundle_path;
}

void
mono_ios_runtime_init (void)
{
#if INVARIANT_GLOBALIZATION
setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE);
#endif

#if HYBRID_GLOBALIZATION
setenv ("DOTNET_SYSTEM_GLOBALIZATION_HYBRID", "1", TRUE);
#endif

#if ENABLE_RUNTIME_LOGGING
setenv ("MONO_LOG_LEVEL", "debug", TRUE);
setenv ("MONO_LOG_MASK", "all", TRUE);
#endif

// build using DiagnosticPorts property in AppleAppBuilder
// or set DOTNET_DiagnosticPorts env via mlaunch, xharness when undefined.
// NOTE, using DOTNET_DiagnosticPorts requires app build using AppleAppBuilder and RuntimeComponents=diagnostics_tracing
#ifdef DIAGNOSTIC_PORTS
setenv ("DOTNET_DiagnosticPorts", DIAGNOSTIC_PORTS, true);
#endif

// When not bundling, this will make sure the runtime can access all the assemblies
const char* bundle = get_bundle_path ();
chdir (bundle);

int res = invoke_netlibrary_entrypoints ();

exit (res);
}
Loading

0 comments on commit 39f4921

Please sign in to comment.