Skip to content

Commit 3d8d133

Browse files
committed
Move build tasks into SDK and add cross-platform resource parser
- Copy 6 build-task sources from `Tools.BuildTasks-2019` into `src\nanoFramework.Tools.BuildTasks\`. - Remove cross-repo `<Compile>` links and comment block from `nanoFramework.Tools.BuildTasks.csproj`. - Delete `GenerateNanoResourceTask.Stub.cs`. - Add `ProcessResourceFiles.CrossPlatform.cs`: replacing `System.Drawing`, `AppDomain`, `BinaryFormatter`, and WinForms `ResXResourceReader` with `SixLabors.ImageSharp`, `System.Resources.Extensions`, `System.Text.Json`, and direct XML parsing. - Add `PackageReference`s for `SixLabors.ImageSharp`, `System.Resources.Extensions`, `System.CodeDom` . - Pack new runtime deps under `tasks\net8.0\` in `nanoFramework.NET.Sdk.csproj`. - Update `nanoFramework.Resources.targets` wiring. - Add `BuildTasks.Tests` with unit tests for `NanoResxResourceReader`, `ProcessResourceFiles`, and RGB565 conversion. - Add `SmokeTest` resources (`.resx`, bitmap, binary blob) for end-to-end validation. Assisted by Claude Opus 4.8
1 parent 955d30c commit 3d8d133

22 files changed

Lines changed: 5094 additions & 78 deletions

azure-pipelines.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,29 @@ stages:
119119
# displayName: 'Publish Quality Gate Result'
120120
# continueOnError: true
121121

122+
- task: VisualStudioTestPlatformInstaller@1
123+
condition: succeeded()
124+
displayName: 'Install VS Test Platform'
125+
inputs:
126+
versionSelector: latestStable
127+
128+
- task: VSTest@2
129+
condition: succeeded()
130+
displayName: 'Running Unit Tests'
131+
continueOnError: false
132+
inputs:
133+
testSelector: 'testAssemblies'
134+
testAssemblyVer2: |
135+
**\*Tests*.dll
136+
!**\obj\**
137+
!**\TestAdapter\**
138+
searchFolder: '$(System.DefaultWorkingDirectory)'
139+
platform: '$(BuildPlatform)'
140+
configuration: '$(BuildConfiguration)'
141+
diagnosticsEnabled: true
142+
vsTestVersion: toolsInstaller
143+
codeCoverageEnabled: true
144+
122145
- task: DotNetCoreCLI@2
123146
displayName: Install Sign Client CLI
124147
condition: >-
@@ -220,6 +243,22 @@ stages:
220243
command: 'build'
221244
projects: 'test/SmokeTest/SmokeTest.csproj'
222245
arguments: '--configuration $(buildConfiguration) --no-restore'
246+
247+
- task: PowerShell@2
248+
displayName: Validate SmokeTest native checksum
249+
inputs:
250+
targetType: inline
251+
script: |
252+
$expectedChecksum = '0x1DA81E42'
253+
$actualChecksum = $env:NF_NATIVE_ASSEMBLY_CHECKSUM
254+
255+
if ($actualChecksum -ine $expectedChecksum)
256+
{
257+
Write-Host "##vso[task.logissue type=error]Smoke test assembly checksum mismatch: expected $expectedChecksum but got '$actualChecksum'."
258+
exit 1
259+
}
260+
261+
Write-Host "Smoke test assembly checksum matches expected value: $expectedChecksum."
223262
224263
- task: NuGetCommand@2
225264
condition: >-

nanoFramework.NET.Sdk.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "nanoFramework.Tools.BuildTa
77
EndProject
88
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "nanoFramework.NET.Sdk", "nanoFramework.NET.Sdk\nanoFramework.NET.Sdk.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
99
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildTasks.Tests", "test\BuildTasks.Tests\BuildTasks.Tests.csproj", "{C3D4E5F6-A7B8-9012-CDEF-123456789012}"
11+
EndProject
1012
Global
1113
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1214
Debug|Any CPU = Debug|Any CPU
@@ -21,5 +23,9 @@ Global
2123
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Build.0 = Debug|Any CPU
2224
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.ActiveCfg = Release|Any CPU
2325
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.Build.0 = Release|Any CPU
26+
{C3D4E5F6-A7B8-9012-CDEF-123456789012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{C3D4E5F6-A7B8-9012-CDEF-123456789012}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{C3D4E5F6-A7B8-9012-CDEF-123456789012}.Release|Any CPU.ActiveCfg = Release|Any CPU
29+
{C3D4E5F6-A7B8-9012-CDEF-123456789012}.Release|Any CPU.Build.0 = Release|Any CPU
2430
EndGlobalSection
2531
EndGlobal

nanoFramework.NET.Sdk/Sdk/nanoFramework.Resources.targets

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,61 @@
2828
Condition="'$(NF_MSBUILDTASK_PATH)' != ''"
2929
AssemblyFile="$(NF_MSBUILDTASK_PATH)\nanoFramework.Tools.BuildTasks.dll" />
3030

31+
<!--
32+
Suppress the standard resource pipeline for nanoFramework .resx items.
33+
34+
The standard CoreResGen target (Microsoft.Common.CurrentVersion.targets) runs the
35+
GenerateResource task, which rejects non-string resources (bitmaps, binary blobs)
36+
unless the project references System.Resources.Extensions — an assembly that does
37+
not exist in the nanoFramework BCL, and whose .resources output nanoFramework never
38+
consumes anyway (the MetadataProcessor imports our .nanoresources directly, see
39+
nanoFramework.Mdp.targets ImportResources).
40+
41+
We move the .resx items out of @(EmbeddedResource) into the private @(_NanoResxItems)
42+
before CoreResGen runs, so the standard task never sees them
43+
(no MSB3822/MSB3823, no dead .resources in the IL).
44+
NanoGenerateResources then converts @(_NanoResxItems) into .nanoresources.
45+
46+
Runs before CoreResGen (so the items are gone by the time it executes) but after
47+
PrepareResourceNames (so %(ManifestResourceName) is already assigned for the
48+
output path below).
49+
-->
50+
<Target Name="_NanoInterceptResxItems" BeforeTargets="CoreResGen">
51+
<ItemGroup>
52+
<_NanoResxItems Include="@(EmbeddedResource)"
53+
Condition="'%(EmbeddedResource.Type)' == 'Resx'" />
54+
<EmbeddedResource Remove="@(_NanoResxItems)" />
55+
</ItemGroup>
56+
</Target>
57+
58+
<!--
59+
Emit a build error when .resx resources are present but the project does not
60+
reference nanoFramework.ResourceManager.
61+
62+
Set $(NanoSkipResourceManagerCheck) = true to suppress this error (e.g., in the
63+
nanoFramework.ResourceManager package itself or any framework-level project that
64+
provides resources without taking a self-reference).
65+
-->
66+
<Target Name="_NanoCheckResourceManagerRef"
67+
Condition="'@(_NanoResxItems)' != '' AND '$(NanoSkipResourceManagerCheck)' != 'true'">
68+
<ItemGroup>
69+
<_NanoResManagerRef Include="@(PackageReference)"
70+
Condition="'%(Identity)' == 'nanoFramework.ResourceManager'" />
71+
</ItemGroup>
72+
<Error Condition="'@(_NanoResManagerRef)' == ''"
73+
Code="NFSDK0002"
74+
Text="Projects that include .resx resources require a reference to the 'nanoFramework.ResourceManager' NuGet package. Add &lt;PackageReference Include=&quot;nanoFramework.ResourceManager&quot; /&gt; to your project file, or set &lt;NanoSkipResourceManagerCheck&gt;true&lt;/NanoSkipResourceManagerCheck&gt; to suppress this check." />
75+
</Target>
76+
3177
<Target Name="NanoGenerateResources"
32-
Condition="'@(EmbeddedResource)' != ''">
78+
Condition="'@(_NanoResxItems)' != ''"
79+
DependsOnTargets="_NanoInterceptResxItems;_NanoCheckResourceManagerRef">
3380
<GenerateNanoResourceTask
34-
Sources="@(EmbeddedResource)"
35-
Condition="'%(EmbeddedResource.Type)' == 'Resx' and '%(EmbeddedResource.GenerateResource)' != 'false'"
81+
Sources="@(_NanoResxItems)"
3682
References="@(ReferencePath)"
3783
UseSourcePath="$(UseSourcePath)"
3884
StateFile="$(IntermediateOutputPath)$(MSBuildProjectFile).NanoGenerateResources.Cache"
39-
OutputResources="@(EmbeddedResource->'$(IntermediateOutputPath)%(ManifestResourceName).nanoresources')">
85+
OutputResources="@(_NanoResxItems->'$(IntermediateOutputPath)%(ManifestResourceName).nanoresources')">
4086
<Output TaskParameter="OutputResources" ItemName="_NanoResources" />
4187
<Output TaskParameter="FilesWritten" ItemName="FileWrites" />
4288
</GenerateNanoResourceTask>

nanoFramework.NET.Sdk/nanoFramework.NET.Sdk.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@
102102
<None Include="..\nanoFramework.Tools.BuildTasks\bin\$(Configuration)\net8.0\nanoFramework.Tools.BuildTasks.dll" Pack="true" PackagePath="tasks\net8.0" />
103103
<None Include="..\nanoFramework.Tools.BuildTasks\bin\$(Configuration)\net8.0\nanoFramework.Tools.BuildTasks.pdb" Pack="true" PackagePath="tasks\net8.0" Condition="Exists('..\nanoFramework.Tools.BuildTasks\bin\$(Configuration)\net8.0\nanoFramework.Tools.BuildTasks.pdb')" />
104104

105+
<!-- Cross-platform resource-processing dependencies, loaded alongside the net8.0 task DLL -->
106+
<None Include="..\nanoFramework.Tools.BuildTasks\bin\$(Configuration)\net8.0\SixLabors.ImageSharp.dll" Pack="true" PackagePath="tasks\net8.0" />
107+
<None Include="..\nanoFramework.Tools.BuildTasks\bin\$(Configuration)\net8.0\System.CodeDom.dll" Pack="true" PackagePath="tasks\net8.0" />
108+
105109
<!-- Package README -->
106110
<None Include="..\README.md" Pack="true" PackagePath="" />
107111
</ItemGroup>
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
4+
// See LICENSE file in the project root for full license information.
5+
//
6+
7+
using Microsoft.Build.Framework;
8+
using Microsoft.Build.Utilities;
9+
using nanoFramework.Tools.Utilities;
10+
using System.Collections.Generic;
11+
using System.ComponentModel;
12+
using System.IO;
13+
using System.Linq;
14+
15+
namespace nanoFramework.Tools
16+
{
17+
[Description("GenerateBinaryOutputTaskEntry")]
18+
19+
public class GenerateBinaryOutputTask : Task
20+
{
21+
#region public properties for the task
22+
23+
public string Assembly { get; set; }
24+
25+
public string AssemblyPE { get; set; }
26+
27+
public ITaskItem[] AssemblyReferences { get; set; }
28+
29+
30+
/// <summary>
31+
/// The name(s) of binary file created.
32+
/// </summary>
33+
[Output]
34+
public ITaskItem FileWritten { get; private set; }
35+
36+
#endregion
37+
38+
public override bool Execute()
39+
{
40+
// report to VS output window what step the build is
41+
Log.LogMessage(MessageImportance.Normal, "Generating binary output file...");
42+
43+
// wait for debugger on var
44+
DebuggerHelper.WaitForDebuggerIfEnabled(TasksConstants.BuildTaskDebugVar);
45+
46+
// default with null, indicating that we've generated nothing
47+
FileWritten = null;
48+
49+
// get paths for PE files
50+
// rename extension .dll with .pe
51+
List<string> peCollection = new List<string>();
52+
peCollection = AssemblyReferences?.Select(a => { return a.GetMetadata("FullPath").Replace(".dll", ".pe").Replace(".exe", ".pe"); }).ToList();
53+
54+
// add executable PE
55+
peCollection.Add(AssemblyPE);
56+
57+
// get executable path and file name
58+
// rename executable extension .exe with .bin
59+
var binOutputFile = Assembly.Replace(".exe", ".bin");
60+
61+
using (FileStream binFile = new FileStream(binOutputFile, FileMode.Create))
62+
{
63+
// now we will re-deploy all system assemblies
64+
foreach (string peItem in peCollection)
65+
{
66+
// append to the deploy blob the assembly
67+
using (FileStream fs = File.Open(peItem, FileMode.Open, FileAccess.Read, FileShare.Read))
68+
{
69+
long length = (fs.Length + 3) / 4 * 4;
70+
byte[] buffer = new byte[length];
71+
72+
fs.Read(buffer, 0, (int)fs.Length);
73+
74+
// copy this assembly to the bin file too
75+
binFile.Write(buffer, 0, (int)length);
76+
}
77+
}
78+
}
79+
80+
// bin file written
81+
FileWritten = new TaskItem(binOutputFile);
82+
83+
return true;
84+
}
85+
}
86+
}

nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.Stub.cs

Lines changed: 0 additions & 53 deletions
This file was deleted.

0 commit comments

Comments
 (0)