Skip to content
Open
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
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<PackageVersion Include="Microsoft.Build.NuGetSdkResolver" Version="$(NuGetBuildTasksVersion)" />
<PackageVersion Include="Microsoft.CodeAnalysis.Collections" Version="$(MicrosoftCodeAnalysisCollectionsVersion)" />
<PackageVersion Include="Microsoft.CodeAnalysis.Contracts" Version="$(MicrosoftCodeAnalysisContractsVersion)" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisCSharpVersion)" />
<PackageVersion Include="Microsoft.CodeAnalysis.PooledObjects" Version="$(MicrosoftCodeAnalysisPooledObjectsVersion)" />
<PackageVersion Include="Microsoft.DotNet.XUnitExtensions" Version="$(MicrosoftDotNetXUnitExtensionsVersion)" />
<PackageVersion Include="Microsoft.IO.Redist" Version="$(MicrosoftIORedistVersion)" />
Expand Down
1 change: 1 addition & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
When updating the version make sure to add the new version to source-build-reference-packages first. -->
<MicrosoftCodeAnalysisCollectionsVersion>5.0.0-1.25277.114</MicrosoftCodeAnalysisCollectionsVersion>
<MicrosoftCodeAnalysisContractsVersion>5.0.0-1.25277.114</MicrosoftCodeAnalysisContractsVersion>
<MicrosoftCodeAnalysisCSharpVersion>5.0.0-1.25277.114</MicrosoftCodeAnalysisCSharpVersion>
<MicrosoftCodeAnalysisPooledObjectsVersion>5.0.0-1.25277.114</MicrosoftCodeAnalysisPooledObjectsVersion>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<Reference Include="System.Net.Http" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />

<PackageReference Include="Shouldly" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />

<ProjectReference Include="..\Utilities\Microsoft.Build.Utilities.csproj" />
<ProjectReference Include="..\Build\Microsoft.Build.csproj" />
Expand Down
161 changes: 117 additions & 44 deletions src/Utilities.UnitTests/TrackedDependencies/FileTrackerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
using Microsoft.Build.Shared;
using Microsoft.Build.Utilities;

#if ENABLE_TRACKER_TESTS // https://github.com/dotnet/msbuild/issues/12063
using Microsoft.CodeAnalysis.BuildTasks;
#endif
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;

using Xunit;
using BackEndNativeMethods = Microsoft.Build.BackEnd.NativeMethods;
Expand Down Expand Up @@ -92,6 +92,39 @@ public void Dispose()
FileTrackerTestHelper.CleanTlogs();
}

[Fact]
public void CompileCSharpExecutable_CompilesSimpleProgram()
{
if (NativeMethodsShared.IsUnixLike)
{
return; // This test is Windows-only
}

string outputFile = Path.Combine(Path.GetTempPath(), $"TestCompile_{Guid.NewGuid()}.exe");
try
{
string codeContent = @"
using System;
class Program
{
static void Main()
{
Console.WriteLine(""Hello from compiled code!"");
}
}";
bool compileSucceeded = FileTrackerTestHelper.CompileCSharpExecutable(codeContent, outputFile);
Assert.True(compileSucceeded, "Compilation should succeed");
Assert.True(File.Exists(outputFile), "Output executable should exist");
}
finally
{
if (File.Exists(outputFile))
{
File.Delete(outputFile);
}
}
}

[Fact(Skip = "FileTracker tests require VS2015 Update 3 or a packaged version of Tracker.exe https://github.com/dotnet/msbuild/issues/649")]
public void FileTrackerHelp()
{
Expand Down Expand Up @@ -286,8 +319,6 @@ public void FileTrackerFindStrInOperationsExtended_AttributesOnly()
Assert.True(foundCreateFileW || foundCreateFileA);
}


#if ENABLE_TRACKER_TESTS // https://github.com/dotnet/msbuild/issues/12063
[Fact(Skip = "FileTracker tests require VS2015 Update 3 or a packaged version of Tracker.exe https://github.com/dotnet/msbuild/issues/649")]
public void FileTrackerExtendedDirectoryTracking()
{
Expand All @@ -296,7 +327,6 @@ public void FileTrackerExtendedDirectoryTracking()
File.Delete("directoryattributes.read.1.tlog");
File.Delete("directoryattributes.write.1.tlog");

string codeFile = null;
string outputFile = Path.Combine(Path.GetTempPath(), "directoryattributes.exe");
string codeContent = @"
using System.IO;
Expand All @@ -321,13 +351,8 @@ static void Main(string[] args)

try
{
codeFile = FileUtilities.GetTemporaryFileName();
File.WriteAllText(codeFile, codeContent);
Csc csc = new Csc();
csc.BuildEngine = new MockEngine3();
csc.Sources = new ITaskItem[] { new TaskItem(codeFile) };
csc.OutputAssembly = new TaskItem(outputFile);
csc.Execute();
bool compileSucceeded = FileTrackerTestHelper.CompileCSharpExecutable(codeContent, outputFile);
Assert.True(compileSucceeded);

string trackerPath = FileTracker.GetTrackerPath(ExecutableType.ManagedIL);
string fileTrackerPath = FileTracker.GetFileTrackerPath(ExecutableType.ManagedIL);
Expand Down Expand Up @@ -405,7 +430,6 @@ static void Main(string[] args)
}
finally
{
File.Delete(codeFile);
File.Delete(outputFile);
}
}
Expand All @@ -418,21 +442,15 @@ public void FileTrackerFindStrInIncludeDuplicates()
File.Delete("findstr.read.1.tlog");
FileTrackerTestHelper.WriteAll("test.in", "foo");

string codeFile = null;
string outputFile = Path.Combine(Path.GetTempPath(), "readtwice.exe");
File.Delete(outputFile);

try
{
string inputPath = Path.GetFullPath("test.in");
codeFile = FileUtilities.GetTemporaryFileName();
string codeContent = @"using System.IO; class X { static void Main() { File.ReadAllText(@""" + inputPath + @"""); File.ReadAllText(@""" + inputPath + @"""); }}";
File.WriteAllText(codeFile, codeContent);
Csc csc = new Csc();
csc.BuildEngine = new MockEngine3();
csc.Sources = new[] { new TaskItem(codeFile) };
csc.OutputAssembly = new TaskItem(outputFile);
csc.Execute();
bool compileSucceeded = FileTrackerTestHelper.CompileCSharpExecutable(codeContent, outputFile);
Assert.True(compileSucceeded);

string trackerPath = FileTracker.GetTrackerPath(ExecutableType.ManagedIL);
string fileTrackerPath = FileTracker.GetFileTrackerPath(ExecutableType.ManagedIL);
Expand All @@ -444,7 +462,6 @@ public void FileTrackerFindStrInIncludeDuplicates()
}
finally
{
File.Delete(codeFile);
File.Delete(outputFile);
}

Expand Down Expand Up @@ -474,7 +491,6 @@ public void FileTrackerDoNotRecordWriteAsRead()
try
{
writeFile = Path.Combine(testDirectory, "test.out");
string codeFile = Path.Combine(testDirectory, "code.cs");
string codeContent = @"
using System.IO;
using System.Runtime.InteropServices;
Expand All @@ -488,14 +504,8 @@ static void Main()
}
}";

File.WriteAllText(codeFile, codeContent);
Csc csc = new Csc();
csc.BuildEngine = new MockEngine3();
csc.Sources = new[] { new TaskItem(codeFile) };
csc.OutputAssembly = new TaskItem(outputFile);
bool success = csc.Execute();

Assert.True(success);
bool compileSucceeded = FileTrackerTestHelper.CompileCSharpExecutable(codeContent, outputFile);
Assert.True(compileSucceeded);

string trackerPath = FileTracker.GetTrackerPath(ExecutableType.ManagedIL);
string fileTrackerPath = FileTracker.GetFileTrackerPath(ExecutableType.ManagedIL);
Expand All @@ -516,7 +526,6 @@ static void Main()
FileTrackerTestHelper.AssertDidntFindStringInTLog("CreateFileW, Desired Access=0xc0000000, Creation Disposition=0x1:" + writeFile.ToUpperInvariant(), "writenoread.read.1.tlog");
FileTrackerTestHelper.AssertFoundStringInTLog("CreateFileW, Desired Access=0xc0000000, Creation Disposition=0x1:" + writeFile.ToUpperInvariant(), "writenoread.write.1.tlog");
}
#endif // ENABLE_TRACKER_TESTS

[Fact(Skip = "FileTracker tests require VS2015 Update 3 or a packaged version of Tracker.exe https://github.com/dotnet/msbuild/issues/649")]
public void FileTrackerFindStrInCommandLine()
Expand Down Expand Up @@ -2232,7 +2241,6 @@ public void LaunchMultipleOfSameTool_DifferentContexts()
}
}

#if ENABLE_TRACKER_TESTS // https://github.com/dotnet/msbuild/issues/12063
[Fact(Skip = "Needs investigation")]
public void LaunchMultipleOfSameTool_ToolLaunchesOthers()
{
Expand Down Expand Up @@ -2277,15 +2285,7 @@ static void Main(string[] args)

File.Delete(outputFile);

string codeFile = Path.Combine(testDir, "Program.cs");
File.WriteAllText(codeFile, codeContent);
Csc csc = new Csc();
csc.BuildEngine = new MockEngine3();
csc.Sources = new ITaskItem[] { new TaskItem(codeFile) };
csc.OutputAssembly = new TaskItem(outputFile);
csc.Platform = "x86";
bool compileSucceeded = csc.Execute();

bool compileSucceeded = FileTrackerTestHelper.CompileCSharpExecutable(codeContent, outputFile, "x86");
Assert.True(compileSucceeded);

// Item1: appname
Expand Down Expand Up @@ -2318,7 +2318,6 @@ static void Main(string[] args)
}
}
}
#endif // ENABLE_TRACKER_TESTS

private static void InProcTrackingSpawnsToolWithTracker(bool useTrackerResponseFile)
{
Expand Down Expand Up @@ -2563,6 +2562,80 @@ public static void AssertFoundStringInTLog(string file, string tlog, int timesFo
}

public static void AssertFoundStringInTLog(string file, string tlog) => AssertFoundStringInTLog(file, tlog, 1);

/// <summary>
/// Compiles C# source code into an executable using Roslyn.
/// </summary>
/// <param name="sourceCode">The C# source code to compile.</param>
/// <param name="outputPath">The path where the executable will be written.</param>
/// <param name="platform">Optional platform target (e.g., "x86", "x64", "AnyCpu"). Defaults to AnyCpu.</param>
/// <returns>True if compilation succeeded, false otherwise.</returns>
public static bool CompileCSharpExecutable(string sourceCode, string outputPath, string platform = null)
{
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);

string assemblyName = Path.GetFileNameWithoutExtension(outputPath);

// Add references to required assemblies
var references = new List<MetadataReference>
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Console).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.IO.File).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.Diagnostics.Process).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.Runtime.InteropServices.DllImportAttribute).Assembly.Location),
};

// Add reference to System.Runtime for core types
string runtimePath = Path.GetDirectoryName(typeof(object).Assembly.Location);
string systemRuntimePath = Path.Combine(runtimePath, "System.Runtime.dll");
if (File.Exists(systemRuntimePath))
{
references.Add(MetadataReference.CreateFromFile(systemRuntimePath));
}

// Determine platform
Platform targetPlatform = Platform.AnyCpu;
if (!string.IsNullOrEmpty(platform))
{
switch (platform.ToLowerInvariant())
{
case "x86":
targetPlatform = Platform.X86;
break;
case "x64":
targetPlatform = Platform.X64;
break;
case "anycpu":
default:
targetPlatform = Platform.AnyCpu;
break;
}
}

CSharpCompilationOptions options = new CSharpCompilationOptions(
OutputKind.ConsoleApplication,
optimizationLevel: OptimizationLevel.Release,
platform: targetPlatform);

CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: options);

EmitResult result = compilation.Emit(outputPath);

if (!result.Success)
{
foreach (Diagnostic diagnostic in result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error))
{
Console.WriteLine($"Compilation error: {diagnostic.GetMessage()}");
}
}

return result.Success;
}
}
}
#endif
Loading