Skip to content

C#: Fix autobuild on macos without mono #19251

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

Merged
merged 4 commits into from
Apr 15, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ IEnumerable<string> IBuildActions.EnumerateDirectories(string dir)

bool IBuildActions.IsRunningOnAppleSilicon() => IsRunningOnAppleSilicon;

public bool IsMonoInstalled { get; set; }

bool IBuildActions.IsMonoInstalled() => IsMonoInstalled;

public string PathCombine(params string[] parts)
{
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
Expand Down Expand Up @@ -797,11 +801,32 @@ public void TestDirsProjWindows()
}

[Fact]
public void TestDirsProjLinux()
public void TestDirsProjLinux_WithMono()
{
actions.IsMonoInstalled = true;

actions.RunProcess[@"nuget restore C:\Project/dirs.proj -DisableParallelProcessing"] = 1;
actions.RunProcess[@"mono scratch/.nuget/nuget.exe restore C:\Project/dirs.proj -DisableParallelProcessing"] = 0;
actions.RunProcess[@"msbuild C:\Project/dirs.proj /t:rebuild"] = 0;

var autobuilder = TestDirsProjLinux();
TestAutobuilderScript(autobuilder, 0, 3);
}

[Fact]
public void TestDirsProjLinux_WithoutMono()
{
actions.IsMonoInstalled = false;

actions.RunProcess[@"dotnet msbuild /t:restore C:\Project/dirs.proj"] = 0;
actions.RunProcess[@"dotnet msbuild C:\Project/dirs.proj /t:rebuild"] = 0;

var autobuilder = TestDirsProjLinux();
TestAutobuilderScript(autobuilder, 0, 2);
}

private CSharpAutobuilder TestDirsProjLinux()
{
actions.FileExists["csharp.log"] = true;
actions.FileExists[@"C:\Project/a/test.csproj"] = true;
actions.FileExists[@"C:\Project/dirs.proj"] = true;
Expand Down Expand Up @@ -830,8 +855,7 @@ public void TestDirsProjLinux()
</Project>");
actions.LoadXml[@"C:\Project/dirs.proj"] = dirsproj;

var autobuilder = CreateAutoBuilder(false);
TestAutobuilderScript(autobuilder, 0, 3);
return CreateAutoBuilder(false);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ IEnumerable<string> IBuildActions.EnumerateDirectories(string dir)

bool IBuildActions.IsRunningOnAppleSilicon() => IsRunningOnAppleSilicon;

public bool IsMonoInstalled { get; set; }

bool IBuildActions.IsMonoInstalled() => IsMonoInstalled;

string IBuildActions.PathCombine(params string[] parts)
{
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
Expand Down
17 changes: 10 additions & 7 deletions csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ internal static class MsBuildCommandExtensions
/// <summary>
/// Appends a call to msbuild.
/// </summary>
/// <param name="cmdBuilder"></param>
/// <param name="builder"></param>
/// <returns></returns>
public static CommandBuilder MsBuildCommand(this CommandBuilder cmdBuilder, IAutobuilder<AutobuildOptionsShared> builder)
public static CommandBuilder MsBuildCommand(this CommandBuilder cmdBuilder, IAutobuilder<AutobuildOptionsShared> builder, bool preferDotnet)
{
// mono doesn't ship with `msbuild` on Arm-based Macs, but we can fall back to
// msbuild that ships with `dotnet` which can be invoked with `dotnet msbuild`
// perhaps we should do this on all platforms?
return builder.Actions.IsRunningOnAppleSilicon()
// Similarly, there's no point in trying to rely on mono if it's not installed.
// In which case we can still fall back to `dotnet msbuild`.
return preferDotnet
? cmdBuilder.RunCommand("dotnet").Argument("msbuild")
: cmdBuilder.RunCommand("msbuild");
}
Expand Down Expand Up @@ -75,13 +75,16 @@ BuildScript GetNugetRestoreScript() =>
QuoteArgument(projectOrSolution.FullPath).
Argument("-DisableParallelProcessing").
Script;

var preferDotnet = builder.Actions.IsRunningOnAppleSilicon() || !builder.Actions.IsWindows() && !builder.Actions.IsMonoInstalled();

var nugetRestore = GetNugetRestoreScript();
var msbuildRestoreCommand = new CommandBuilder(builder.Actions).
MsBuildCommand(builder).
MsBuildCommand(builder, preferDotnet).
Argument("/t:restore").
QuoteArgument(projectOrSolution.FullPath);

if (builder.Actions.IsRunningOnAppleSilicon())
if (preferDotnet)
{
// On Apple Silicon, only try package restore with `dotnet msbuild /t:restore`
ret &= BuildScript.Try(msbuildRestoreCommand.Script);
Expand Down Expand Up @@ -119,7 +122,7 @@ BuildScript GetNugetRestoreScript() =>
command.RunCommand("set Platform=&& type NUL", quoteExe: false);
}

command.MsBuildCommand(builder);
command.MsBuildCommand(builder, preferDotnet);
command.QuoteArgument(projectOrSolution.FullPath);

var target = "rebuild";
Expand Down
24 changes: 24 additions & 0 deletions csharp/extractor/Semmle.Util/BuildActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@
/// <returns>True if we are running on Apple Silicon.</returns>
bool IsRunningOnAppleSilicon();

/// <summary>
/// Checks if Mono is installed.
/// </summary>
bool IsMonoInstalled();

/// <summary>
/// Combine path segments, Path.Combine().
/// </summary>
Expand Down Expand Up @@ -250,10 +255,10 @@
return false;
}

try
{
thisBuildActions.RunProcess("sysctl", "machdep.cpu.brand_string", workingDirectory: null, env: null, out var stdOut);
return stdOut?.Any(s => s?.ToLowerInvariant().Contains("apple") == true) ?? false;

Check notice

Code scanning / CodeQL

Generic catch clause Note

Generic catch clause.
}
catch (Exception)
{
Expand All @@ -261,6 +266,25 @@
}
}

bool IBuildActions.IsMonoInstalled()
Copy link
Contributor

@michaelnebel michaelnebel Apr 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great!

{
var thisBuildActions = (IBuildActions)this;

if (thisBuildActions.IsWindows())
{
return false;
}

try
{
return 0 == thisBuildActions.RunProcess("mono", "--version", workingDirectory: null, env: null);
}
catch (Exception)
{
return false;
}
}

string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);

void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
import pytest
import runs_on


# Skipping the test on macos-15, as we're running into trouble.
@pytest.mark.only_if(not runs_on.macos_15)
def test(codeql, csharp):
codeql.database.create(_assert_failure=True)