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

[msbuild/generator] Compile api definitions in MSBuild logic instead of inside the generator. #18398

Merged
merged 1 commit into from Jun 26, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 14 additions & 14 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/BTouchTaskBase.cs
Expand Up @@ -23,8 +23,6 @@ public abstract class BTouchTaskBase : XamarinToolTask {
[Required]
public string BTouchToolExe { get; set; }

public string DotNetCscCompiler { get; set; }

public ITaskItem [] ObjectiveCLibraries { get; set; }

public ITaskItem [] AdditionalLibPaths { get; set; }
Expand All @@ -39,6 +37,8 @@ public abstract class BTouchTaskBase : XamarinToolTask {

public string AttributeAssembly { get; set; }

public ITaskItem CompiledApiDefinitionAssembly { get; set; }

public ITaskItem [] CoreSources { get; set; }

public string DefineConstants { get; set; }
Expand Down Expand Up @@ -79,9 +79,15 @@ public abstract class BTouchTaskBase : XamarinToolTask {
get {
// Return the dotnet executable we're executing with.
var dotnet_path = Environment.GetEnvironmentVariable ("DOTNET_HOST_PATH");
if (string.IsNullOrEmpty (dotnet_path))
throw new InvalidOperationException ($"DOTNET_HOST_PATH is not set");
return dotnet_path;
if (!string.IsNullOrEmpty (dotnet_path))
return dotnet_path;

if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
// This might happen when building from inside VS (design-time builds, etc.)
return "dotnet.exe";
}

throw new InvalidOperationException ($"DOTNET_HOST_PATH is not set");
}
}

Expand Down Expand Up @@ -123,6 +129,9 @@ protected override string GenerateCommandLineCommands ()
cmd.Add ("/v");
#endif

if (CompiledApiDefinitionAssembly is not null)
cmd.AddQuotedSwitchIfNotNull ("/compiled-api-definition-assembly:", CompiledApiDefinitionAssembly.ItemSpec);

cmd.Add ("/nostdlib");
cmd.AddQuotedSwitchIfNotNull ("/baselib:", BaseLibDll);
cmd.AddQuotedSwitchIfNotNull ("/out:", OutputAssembly);
Expand All @@ -144,14 +153,6 @@ protected override string GenerateCommandLineCommands ()
if (AllowUnsafeBlocks)
cmd.Add ("/unsafe");

if (!string.IsNullOrEmpty (DotNetCscCompiler)) {
var compileCommand = new string [] {
DotNetPath,
DotNetCscCompiler,
};
cmd.AddQuoted ("/compile-command:" + string.Join (" ", StringUtils.QuoteForProcess (compileCommand)));
}

cmd.AddQuotedSwitchIfNotNull ("/ns:", Namespace);

if (NoNFloatUsing)
Expand Down Expand Up @@ -266,7 +267,6 @@ public override bool Execute ()
BaseLibDll = PathUtils.ConvertToMacPath (BaseLibDll);
BTouchToolExe = PathUtils.ConvertToMacPath (BTouchToolExe);
BTouchToolPath = PathUtils.ConvertToMacPath (BTouchToolPath);
DotNetCscCompiler = PathUtils.ConvertToMacPath (DotNetCscCompiler);

if (IsDotNet) {
var customHome = Environment.GetEnvironmentVariable ("DOTNET_CUSTOM_HOME");
Expand Down
90 changes: 85 additions & 5 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Expand Up @@ -1602,6 +1602,11 @@ Copyright (C) 2018 Microsoft. All rights reserved.
$(_GenerateBindingsDependsOn);
</_GenerateBindingsDependsOn>

<_GenerateBindingsDependsOn Condition="'$(UsingAppleNETSdk)' == 'true'">
_CompileApiDefinitions;
$(_GenerateBindingsDependsOn);
</_GenerateBindingsDependsOn>

<_WriteGeneratorPropertiesDependsOn Condition="'$(UsingAppleNETSdk)' == 'true'">
$(_WriteGeneratorPropertiesDependsOn);
_ComputeBindingVariables;
Expand All @@ -1620,6 +1625,85 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<WriteLinesToFile File="$(OutputFilePath)" Lines="@(_ComputedRemoteGeneratorProperties)" />
</Target>

<PropertyGroup>
<_ComputeCompileApiDefinitionsInputsDependsOn Condition="'$(UsingAppleNETSdk)' == 'true'">
$(_ComputeCompileApiDefinitionsInputsDependsOn);
_ComputeBindingVariables;
</_ComputeCompileApiDefinitionsInputsDependsOn>
</PropertyGroup>

<Target Name="_ComputeCompileApiDefinitionsInputs" DependsOnTargets="$(_ComputeCompileApiDefinitionsInputsDependsOn)">
<ItemGroup>
<BTouchReferencePath Include="@(ReferenceCopyLocalPaths)" Condition="'%(Extension)' == '.dll'" />
</ItemGroup>

<PropertyGroup>
<_CompiledApiDefinitionAssembly>$(DeviceSpecificIntermediateOutputPath)compiled-api-definitions.dll</_CompiledApiDefinitionAssembly>
<_CompiledApiDefinitionDefines>$(DefineConstants)</_CompiledApiDefinitionDefines>
<_CompiledApiDefinitionDefines Condition="'$(UsingAppleNETSdk)' == 'true'">$(_CompiledApiDefinitionDefines);NET</_CompiledApiDefinitionDefines>

<_CompiledApiDefinitionLibPaths>$(AdditionalLibPaths);$([System.IO.Path]::GetDirectoryName('$(BaseLibDllPath)'))</_CompiledApiDefinitionLibPaths>

<_CompiledApiDefinitionGlobalUsingsFile Condition="'$(UsingAppleNETSdk)' == 'true' And '$(NoNFloatUsing)' != 'true'">$(DeviceSpecificIntermediateOutputPath)compiled-api-definitions-usings.cs</_CompiledApiDefinitionGlobalUsingsFile>
</PropertyGroup>


<ItemGroup>
<_CompiledApiDefinitionReferences Include="$(_GeneratorAttributeAssembly)" />
<_CompiledApiDefinitionReferences Include="@(ReferencePath)" />
<_CompiledApiDefinitionReferences Include="@(BTouchReferencePath)" />

<_CompiledApiDefinitionsCompile Include="@(ObjcBindingApiDefinition)" />
<_CompiledApiDefinitionsCompile Include="@(ObjcBindingCoreSource)" />
</ItemGroup>

<WriteLinesToFile
Condition="'$(_CompiledApiDefinitionGlobalUsingsFile)' != ''"
File="$(_CompiledApiDefinitionGlobalUsingsFile)"
Lines="global using nfloat = global::System.Runtime.InteropServices.NFloat%3B"
Overwrite="true"
WriteOnlyWhenDifferent="true" />

<ItemGroup Condition="'$(_CompiledApiDefinitionGlobalUsingsFile)' != ''">
<_CompiledApiDefinitionsCompile Include="$(_CompiledApiDefinitionGlobalUsingsFile)" />
</ItemGroup>

</Target>

<Target Name="_CompileApiDefinitions"
Inputs="$(MSBuildAllProjects);
$(_CompiledApiDefinitionLibPaths);
$(_CompiledApiDefinitionGlobalUsingsFile);
@(_CompiledApiDefinitionReferences);
@(_CompiledApiDefinitionsCompile);"
Outputs="$(_CompiledApiDefinitionAssembly)"
DependsOnTargets="_ComputeCompileApiDefinitionsInputs"
Condition="'$(IsBindingProject)' == 'true' And '$(DesignTimeBuild)' != 'true'"
>

<!-- This is a mirror of the method GetCompiledApiBindingsAssembly in BindingTouch.cs where the compilation is done inside bgen -->
<Csc
AdditionalLibPaths="$(_CompiledApiDefinitionLibPaths)"
AllowUnsafeBlocks="true"
DebugType="portable"
DefineConstants="$(_CompiledApiDefinitionDefines)"
DisabledWarnings="436"
NoConfig="true"
NoStandardLib="true"
Deterministic="true"
OutputAssembly="$(_CompiledApiDefinitionAssembly)"
References="@(_CompiledApiDefinitionReferences)"
Sources="@(_CompiledApiDefinitionsCompile)"
TargetType="library"
ToolExe="$(CscToolExe)"
ToolPath="$(CscToolPath)"
UseHostCompilerIfAvailable="$(UseHostCompilerIfAvailable)"
UseSharedCompilation="$(UseSharedCompilation)"
VsSessionGuid="$(VsSessionGuid)"
>
</Csc>
</Target>

<Target Name="_GenerateBindings"
Inputs="$(MSBuildAllProjects);@(ObjcBindingApiDefinition);@(ObjcBindingCoreSource);@(ReferencePath);@(ObjcBindingNativeLibrary)"
Outputs="$(_GeneratedSourcesFileList)"
Expand All @@ -1628,10 +1712,6 @@ Copyright (C) 2018 Microsoft. All rights reserved.

<Warning Condition="'$(IsMacEnabled)' != 'true'" Text="It's currently not supported to build a binding project from Windows unless a connection to a Mac is available." />

<ItemGroup>
<BTouchReferencePath Include="@(ReferenceCopyLocalPaths)" Condition="'%(Extension)' == '.dll'" />
</ItemGroup>

<PropertyGroup>
<BTouchEmitDebugInformation>false</BTouchEmitDebugInformation>
<BTouchEmitDebugInformation Condition="'$(Debug)' != ''">true</BTouchEmitDebugInformation>
Expand Down Expand Up @@ -1664,8 +1744,8 @@ Copyright (C) 2018 Microsoft. All rights reserved.
AttributeAssembly="$(_GeneratorAttributeAssembly)"
BaseLibDll="$(BaseLibDllPath)"
CoreSources="@(ObjcBindingCoreSource)"
CompiledApiDefinitionAssembly="$(_CompiledApiDefinitionAssembly)"
DefineConstants="$(DefineConstants)"
DotNetCscCompiler="$(_DotNetCscCompiler)"
EmitDebugInformation="$(BTouchEmitDebugInformation)"
ExtraArgs="$(BTouchExtraArgs)"
GeneratedSourcesDir="$(GeneratedSourcesDir)"
Expand Down
106 changes: 59 additions & 47 deletions src/bgen/BindingTouch.cs
Expand Up @@ -61,6 +61,8 @@ public class BindingTouch : IDisposable {
string []? compile_command = null;
string? baselibdll;
string? attributedll;
string compiled_api_definition_assembly = string.Empty;
bool noNFloatUsing;

List<string> libs = new List<string> ();
List<string> references = new List<string> ();
Expand Down Expand Up @@ -235,7 +237,6 @@ int Main3 (string [] args)
var defines = new List<string> ();
string? generate_file_list = null;
bool process_enums = false;
bool noNFloatUsing = false;

ErrorHelper.ClearWarningLevels ();

Expand Down Expand Up @@ -327,6 +328,7 @@ int Main3 (string [] args)
noNFloatUsing = string.Equals ("true", v, StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty (v);
}
},
{ "compiled-api-definition-assembly=", "An assembly with the compiled api definitions.", (v) => compiled_api_definition_assembly = v },
new Mono.Options.ResponseFileSource (),
};

Expand Down Expand Up @@ -446,47 +448,7 @@ int Main3 (string [] args)
var paths = libs.Select ((v) => "-lib:" + v);

try {
var tmpass = Path.Combine (tmpdir, "temp.dll");

// -nowarn:436 is to avoid conflicts in definitions between core.dll and the sources
// Keep source files at the end of the command line - csc will create TWO assemblies if any sources preceed the -out parameter
var cargs = new List<string> ();

cargs.Add ("-debug");
cargs.Add ("-unsafe");
cargs.Add ("-target:library");
cargs.Add ("-nowarn:436");
cargs.Add ("-out:" + tmpass);
cargs.Add ("-r:" + GetAttributeLibraryPath ());
cargs.AddRange (refs);
if (unsafef)
cargs.Add ("-unsafe");
cargs.Add ("-r:" + baselibdll);
foreach (var def in defines)
cargs.Add ("-define:" + def);
#if NET
cargs.Add ("-define:NET");
#endif
cargs.AddRange (paths);
if (nostdlib) {
cargs.Add ("-nostdlib");
cargs.Add ("-noconfig");
}
cargs.AddRange (api_sources);
cargs.AddRange (core_sources);
if (!string.IsNullOrEmpty (Path.GetDirectoryName (baselibdll)))
cargs.Add ("-lib:" + Path.GetDirectoryName (baselibdll));

#if NET
var tmpusing = Path.Combine (tmpdir, "GlobalUsings.g.cs");
if (!noNFloatUsing) {
File.WriteAllText (tmpusing, "global using nfloat = global::System.Runtime.InteropServices.NFloat;\n");
cargs.Add (tmpusing);
}
#endif

Compile (cargs, 2);

var tmpass = GetCompiledApiBindingsAssembly (tmpdir, refs, nostdlib, api_sources, core_sources, defines, paths);
universe = new MetadataLoadContext (
new SearchPathsAssemblyResolver (
GetLibraryDirectories ().ToArray (),
Expand Down Expand Up @@ -595,7 +557,7 @@ int Main3 (string [] args)
return 0;
}

cargs.Clear ();
var cargs = new List<string> ();
if (unsafef)
cargs.Add ("-unsafe");
cargs.Add ("-target:library");
Expand All @@ -618,10 +580,7 @@ int Main3 (string [] args)
if (!string.IsNullOrEmpty (Path.GetDirectoryName (baselibdll)))
cargs.Add ("-lib:" + Path.GetDirectoryName (baselibdll));

#if NET
if (!noNFloatUsing)
cargs.Add (tmpusing);
#endif
AddNFloatUsing (cargs, tmpdir);

Compile (cargs, 1000);
} finally {
Expand All @@ -631,6 +590,59 @@ int Main3 (string [] args)
return 0;
}

// If anything is modified in this function, check if the _CompileApiDefinitions MSBuild target needs to be updated as well.
string GetCompiledApiBindingsAssembly (string tmpdir, IEnumerable<string> refs, bool nostdlib, List<string> api_sources, List<string> core_sources, List<string> defines, IEnumerable<string> paths)
{
if (!string.IsNullOrEmpty (compiled_api_definition_assembly))
return compiled_api_definition_assembly;

var tmpass = Path.Combine (tmpdir, "temp.dll");

// -nowarn:436 is to avoid conflicts in definitions between core.dll and the sources
// Keep source files at the end of the command line - csc will create TWO assemblies if any sources preceed the -out parameter
var cargs = new List<string> ();

cargs.Add ("-debug");
cargs.Add ("-unsafe");
cargs.Add ("-target:library");
cargs.Add ("-nowarn:436");
cargs.Add ("-out:" + tmpass);
cargs.Add ("-r:" + GetAttributeLibraryPath ());
cargs.AddRange (refs);
cargs.Add ("-r:" + baselibdll);
foreach (var def in defines)
cargs.Add ("-define:" + def);
#if NET
cargs.Add ("-define:NET");
#endif
cargs.AddRange (paths);
if (nostdlib) {
cargs.Add ("-nostdlib");
cargs.Add ("-noconfig");
}
cargs.AddRange (api_sources);
cargs.AddRange (core_sources);
if (!string.IsNullOrEmpty (Path.GetDirectoryName (baselibdll)))
cargs.Add ("-lib:" + Path.GetDirectoryName (baselibdll));

AddNFloatUsing (cargs, tmpdir);

Compile (cargs, 2);

return tmpass;
}

void AddNFloatUsing (List<string> cargs, string tmpdir)
{
#if NET
if (noNFloatUsing)
return;
var tmpusing = Path.Combine (tmpdir, "GlobalUsings.g.cs");
File.WriteAllText (tmpusing, "global using nfloat = global::System.Runtime.InteropServices.NFloat;\n");
cargs.Add (tmpusing);
#endif
}

void Compile (List<string> arguments, int errorCode)
{
if (compile_command is null || compile_command.Length == 0) {
Expand Down