Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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.XUnitV3Extensions" Version="$(MicrosoftDotNetXUnitV3ExtensionsVersion)" />
<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-assets 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>
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Outdated
<MicrosoftCodeAnalysisPooledObjectsVersion>5.0.0-1.25277.114</MicrosoftCodeAnalysisPooledObjectsVersion>
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
Expand All @@ -13,6 +13,7 @@
<Reference Include="System.Net.Http" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />

<PackageReference Include="Shouldly" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Outdated

<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;
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
using Windows.Win32;
Expand Down Expand Up @@ -250,6 +250,39 @@ public void Dispose()
FileTrackerTestHelper.CleanTlogs();
}

[Fact]
public void CompileCSharpExecutable_CompilesSimpleProgram()
{
if (NativeMethodsShared.IsUnixLike)
{
return; // This test is Windows-only
}
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Outdated

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");
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Outdated
}
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 @@ -444,8 +477,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 @@ -454,7 +485,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 @@ -479,13 +509,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 @@ -563,7 +588,6 @@ static void Main(string[] args)
}
finally
{
File.Delete(codeFile);
File.Delete(outputFile);
}
}
Expand All @@ -576,21 +600,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 @@ -602,7 +620,6 @@ public void FileTrackerFindStrInIncludeDuplicates()
}
finally
{
File.Delete(codeFile);
File.Delete(outputFile);
}

Expand Down Expand Up @@ -632,7 +649,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 @@ -646,14 +662,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 @@ -674,7 +684,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 @@ -2390,7 +2399,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 @@ -2435,15 +2443,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 @@ -2476,7 +2476,6 @@ static void Main(string[] args)
}
}
}
#endif // ENABLE_TRACKER_TESTS

private static void InProcTrackingSpawnsToolWithTracker(bool useTrackerResponseFile)
{
Expand Down Expand Up @@ -2721,6 +2720,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));
}

Comment thread
huulinhnguyen-dev marked this conversation as resolved.
// Determine platform
Platform targetPlatform = Platform.AnyCpu;
if (!string.IsNullOrEmpty(platform))
{
switch (platform.ToLowerInvariant())
{
case "x86":
targetPlatform = Platform.X86;
break;
case "x64":
targetPlatform = Platform.X64;
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Outdated
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 },
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Outdated
references: references,
options: options);

EmitResult result = compilation.Emit(outputPath);
Comment thread
huulinhnguyen-dev marked this conversation as resolved.

if (!result.Success)
{
foreach (Diagnostic diagnostic in result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error))
{
Console.WriteLine($"Compilation error: {diagnostic.GetMessage()}");
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Outdated
}
}

return result.Success;
Comment thread
huulinhnguyen-dev marked this conversation as resolved.
Outdated
}
}
}
#endif
Loading