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
6 changes: 5 additions & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v6
with:
dotnet-version: 6.0.x
dotnet-version: |
6.0.x
10.0.x
- name: Run CI
run: dotnet fsi src/build.fsx
- name: Test NativeAOT package consumer
run: dotnet fsi src/build.fsx -- -p NativeAOT
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ nupkg
_UpgradeReport_Files/
[Pp]ackages/

.vscode/

Thumbs.db
Desktop.ini
.DS_Store
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<linker>
<!-- SafeInputLists looks up ListModule.OfArray by name during initialization. -->
<assembly fullname="FSharp.Core">
<type fullname="Microsoft.FSharp.Collections.ListModule">
<method name="OfArray" />
</type>
</assembly>
</linker>
5 changes: 5 additions & 0 deletions src/FSharp.SystemCommandLine/FSharp.SystemCommandLine.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
<Compile Include="CommandBuilders.fs" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="FSharp.SystemCommandLine.TrimmerRoots.xml"
LogicalName="ILLink.Descriptors.xml" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/TestConsole/TestConsole.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFrameworks>net6.0;net10.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
18 changes: 18 additions & 0 deletions src/TestNativeAot/Program.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
open System
open System.Runtime.CompilerServices
open FSharp.SystemCommandLine
open Input

[<EntryPoint>]
let main argv =
if RuntimeFeature.IsDynamicCodeSupported then
failwith "This smoke test must run as a NativeAOT executable."

rootCommand argv {
description "NativeAOT startup and scalar/array parsing regression test"
inputs (argument<string array> "words" |> arity ZeroOrMore, option<int> "--count")
setAction (fun (words, count) ->
// Avoid printf's own reflection requirements so this tests the library's input path.
Console.WriteLine("words=" + String.Join(",", words) + ";count=" + count.ToString())
)
}
15 changes: 15 additions & 0 deletions src/TestNativeAot/TestNativeAot.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<PublishAot>true</PublishAot>
<IsPackable>false</IsPackable>
<RestoreAdditionalProjectSources>$(MSBuildThisFileDirectory)obj/packages</RestoreAdditionalProjectSources>
</PropertyGroup>

<ItemGroup>
<Compile Include="Program.fs" />
<!-- Consume the package, including its embedded descriptor, without application roots. -->
<PackageReference Include="FSharp.SystemCommandLine" Version="$(SmokePackageVersion)" />
</ItemGroup>
</Project>
7 changes: 7 additions & 0 deletions src/TestNativeAot/global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"sdk": {
"version": "10.0.100",
"rollForward": "latestFeature",
"allowPrerelease": false
}
}
57 changes: 56 additions & 1 deletion src/build.fsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#r "nuget: Fun.Build, 1.1.17"

open Fun.Build
open System
open System.Diagnostics
open System.IO
open System.Runtime.InteropServices

let src = __SOURCE_DIRECTORY__
let fsproj = $"{src}/FSharp.SystemCommandLine/FSharp.SystemCommandLine.fsproj"
Expand All @@ -19,6 +23,57 @@ pipeline "Build" {
runIfOnlySpecified false
}

// Use a unique package version so repeated local runs cannot reuse a cached build.
let smokeDir = Path.Combine(src, "TestNativeAot")
let smokePackages = Path.Combine(smokeDir, "obj", "packages")
let smokeOutput = Path.Combine(smokeDir, "bin", "native-aot")
let smokeVersion = "0.0.0-aot-" + Guid.NewGuid().ToString("N")
let smokeExecutable =
Path.Combine(smokeOutput, if OperatingSystem.IsWindows() then "TestNativeAot.exe" else "TestNativeAot")

let checkNativeAot args expectedExitCode expectedOutput =
let startInfo = ProcessStartInfo(smokeExecutable)
startInfo.UseShellExecute <- false
startInfo.RedirectStandardOutput <- true
startInfo.RedirectStandardError <- true
for arg in args do startInfo.ArgumentList.Add(arg)
use child = Process.Start(startInfo)
let stdout = child.StandardOutput.ReadToEndAsync()
let stderr = child.StandardError.ReadToEndAsync()
if not (child.WaitForExit(30_000)) then
child.Kill(true)
failwithf "NativeAOT smoke test timed out: %A" args
let output = stdout.GetAwaiter().GetResult()
let errors = stderr.GetAwaiter().GetResult()
if child.ExitCode <> expectedExitCode || not (output.Contains(expectedOutput: string)) then
failwithf "NativeAOT smoke test %A: expected exit %d and output containing %A; got exit %d.\n%s\n%s"
args expectedExitCode expectedOutput child.ExitCode output errors
printfn "NativeAOT smoke test passed: %A" args

pipeline "NativeAOT" {
// The consumer's global.json selects .NET 10 for both pack and publish.
workingDir smokeDir

stage "Pack library for NativeAOT" {
run $"dotnet pack \"{fsproj}\" --configuration Release --output \"{smokePackages}\" -p:PackageVersion={smokeVersion}"
}

stage "Publish NativeAOT package consumer" {
run $"dotnet publish TestNativeAot.fsproj --configuration Release --runtime {RuntimeInformation.RuntimeIdentifier} --output \"{smokeOutput}\" -p:SmokePackageVersion={smokeVersion}"
}

stage "Run NativeAOT smoke tests" {
run (fun _ ->
checkNativeAot [ "--help" ] 0 "--count"
checkNativeAot [ "hello"; "world"; "--count"; "2" ] 0 "words=hello,world;count=2"
checkNativeAot [] 0 "words=;count=0"
checkNativeAot [ "--count"; "invalid" ] 1 ""
)
}

runIfOnlySpecified true
}

open System.Xml.Linq

pipeline "Publish" {
Expand All @@ -39,4 +94,4 @@ pipeline "Publish" {
runIfOnlySpecified true
}

tryPrintPipelineCommandHelp ()
tryPrintPipelineCommandHelp ()