Skip to content

Move build tasks into SDK and add cross-platform resource parser#5

Merged
josesimoes merged 2 commits into
mainfrom
move-buildtasks-resources-to-sdk
Jun 24, 2026
Merged

Move build tasks into SDK and add cross-platform resource parser#5
josesimoes merged 2 commits into
mainfrom
move-buildtasks-resources-to-sdk

Conversation

@josesimoes

@josesimoes josesimoes commented Jun 24, 2026

Copy link
Copy Markdown
Member

Description

  • Copy build-task sources from Visual Studio repo 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 PackageReferences 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.

Motivation and Context

How Has This Been Tested?

  • Local build and new tests added.

Screenshots

Types of changes

  • Improvement (non-breaking change that improves a feature, code or algorithm)
  • Bug fix (non-breaking change which fixes an issue with code or algorithm)
  • New feature (non-breaking change which adds functionality to code)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Config and build (change in the configuration and build system, has no impact on code or features)
  • Dependencies (update dependencies and changes associated, has no impact on code or features)
  • Unit Tests (add new Unit Test(s) or improved existing one(s), has no impact on code or features)
  • Documentation (changes or updates in the documentation, has no impact on code or features)

Checklist:

  • My code follows the code style of this project (only if there are changes in source code).
  • My changes require an update to the documentation (there are changes that require the docs website to be updated).
  • I have updated the documentation accordingly (the changes require an update on the docs in this repo).
  • I have read the CONTRIBUTING document.
  • I have tested everything locally and all new and existing tests passed (only if there are changes in source code).
  • I have added new tests to cover my changes.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@josesimoes, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 21 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: nanoframework/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b3aa35b3-4720-4373-8ebe-a198c018177f

📥 Commits

Reviewing files that changed from the base of the PR and between 422b1ea and 9502fd6.

⛔ Files ignored due to path filters (2)
  • test/SmokeTest/data.bin is excluded by !**/*.bin
  • test/SmokeTest/logo.bmp is excluded by !**/*.bmp
📒 Files selected for processing (20)
  • azure-pipelines.yml
  • nanoFramework.NET.Sdk.sln
  • nanoFramework.NET.Sdk/Sdk/nanoFramework.Resources.targets
  • nanoFramework.NET.Sdk/nanoFramework.NET.Sdk.csproj
  • nanoFramework.Tools.BuildTasks/GenerateBinaryOutputTask.cs
  • nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.Stub.cs
  • nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.cs
  • nanoFramework.Tools.BuildTasks/ProcessResourceFiles.CrossPlatform.cs
  • nanoFramework.Tools.BuildTasks/ProcessResourceFiles.cs
  • nanoFramework.Tools.BuildTasks/ResolveRuntimeDependenciesTask.cs
  • nanoFramework.Tools.BuildTasks/TasksConstants.cs
  • nanoFramework.Tools.BuildTasks/Utilities/DebuggerHelper.cs
  • nanoFramework.Tools.BuildTasks/nanoFramework.Tools.BuildTasks.csproj
  • test/BuildTasks.Tests/BuildTasks.Tests.csproj
  • test/BuildTasks.Tests/Infrastructure/TestBuildEngine.cs
  • test/BuildTasks.Tests/NanoResxResourceReaderTests.cs
  • test/BuildTasks.Tests/ProcessResourceFilesTests.cs
  • test/BuildTasks.Tests/Rgb565ConversionTests.cs
  • test/SmokeTest/Resources.resx
  • test/SmokeTest/SmokeTest.csproj
📝 Walkthrough

Walkthrough

This PR replaces the cross-platform GenerateNanoResourceTask stub with a full incremental implementation backed by a binary dependency cache. It adds ProcessResourceFiles (the resource compilation engine), a cross-platform NanoResxResourceReader and CrossPlatformBitmap for net8.0, rewires the MSBuild targets pipeline to intercept .resx items, adds GenerateBinaryOutputTask and ResolveRuntimeDependenciesTask, and introduces a multi-TFM test project with CI VSTest execution.

Changes

nanoFramework Resource Pipeline and Build Tasks Overhaul

Layer / File(s) Summary
MSBuild targets pipeline: intercept, validate, and drive resource generation
nanoFramework.NET.Sdk/Sdk/nanoFramework.Resources.targets
_NanoInterceptResxItems moves .resx EmbeddedResource items into @(_NanoResxItems) before CoreResGen; _NanoCheckResourceManagerRef emits error NFSDK0002 when nanoFramework.ResourceManager is not referenced; NanoGenerateResources is updated to depend on both and to invoke GenerateNanoResourceTask with the intercepted list.
NanoResourceFile binary format, Entry model, and NanoResourceWriter
nanoFramework.Tools.BuildTasks/ProcessResourceFiles.cs (lines 968–2168)
Defines the NanoResourceFile binary format (header, resource structures, Serialize/Deserialize), CLR_GFX_BitmapDescription, and the full Entry hierarchy (StringEntry, BitmapEntry, BinaryEntry, NanoResourcesEntry). NanoResourceWriter accumulates entries and writes deterministic output. NanoResourceReader is stubbed.
ProcessResourceFiles: .resx reading, writing, and strongly-typed class generation
nanoFramework.Tools.BuildTasks/ProcessResourceFiles.cs (lines 1–963)
ProcessResourceFiles.Run detects format by extension, reads resources via ResXResourceReader (NETFRAMEWORK) or NanoResxResourceReader (non-NETFRAMEWORK), writes to text/binary/nanoresources, and optionally emits strongly-typed CodeDOM classes. BitmapEntry handles JPEG/GIF/BMP conversion paths with 1bpp orientation and compression on NETFRAMEWORK.
Cross-platform NanoResxResourceReader and CrossPlatformBitmap
nanoFramework.Tools.BuildTasks/ProcessResourceFiles.CrossPlatform.cs
NanoResxResourceReader parses .resx XML for inline strings, base64 arrays, and ResXFileRef entries, rejecting unsupported types via NotSupportedException. CrossPlatformBitmap detects BMP/GIF/JPEG, converts BMPs to RGB565 using ImageSharp, and serializes the device-ready bitmap payload. Both are #if !NETFRAMEWORK only.
GenerateNanoResourceTask: incremental execution with dependency cache
nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.cs, nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.Stub.cs
Full GenerateNanoResourceTask with ExceptionHandling helper, Dependencies/DependencyFile/StateFileBase/ResGenDependencies binary-serialized cache, ResXFile linked-file enumeration (both NETFRAMEWORK and cross-platform), and Execute() orchestration for per-source rebuild decisions, ProcessResourceFiles.Run dispatch, AppDomain management on NETFRAMEWORK, and state file persistence. Prior stub removed.
GenerateBinaryOutputTask, ResolveRuntimeDependenciesTask, TasksConstants, DebuggerHelper
nanoFramework.Tools.BuildTasks/GenerateBinaryOutputTask.cs, nanoFramework.Tools.BuildTasks/ResolveRuntimeDependenciesTask.cs, nanoFramework.Tools.BuildTasks/TasksConstants.cs, nanoFramework.Tools.BuildTasks/Utilities/DebuggerHelper.cs
GenerateBinaryOutputTask concatenates PE files with 4-byte padding into a .bin. ResolveRuntimeDependenciesTask populates a HostObject via reflection. TasksConstants defines the debug environment variable name. DebuggerHelper provides a debug-only wait-for-debugger loop.
Project and package wiring
nanoFramework.Tools.BuildTasks/nanoFramework.Tools.BuildTasks.csproj, nanoFramework.NET.Sdk/nanoFramework.NET.Sdk.csproj, nanoFramework.NET.Sdk.sln, test/SmokeTest/...
BuildTasks.csproj adds InternalsVisibleTo for the test assembly and switches cross-platform deps to SixLabors.ImageSharp/System.CodeDom with CopyLocalLockFileAssemblies. SDK.csproj packs both DLLs under tasks\net8.0. Solution registers the new test project. SmokeTest adds UseSourcePath, nanoFramework.ResourceManager reference, and a Resources.resx with string and file-ref entries.
Test project: infrastructure, unit tests, and CI
test/BuildTasks.Tests/*, azure-pipelines.yml
Multi-TFM test project (net8.0;net472) with TestBuildEngine/TestTask doubles. NanoResxResourceReaderTests covers cross-platform parsing. ProcessResourceFilesTests (net472) validates end-to-end .resx-to-.nanoresources round-trips including determinism. Rgb565ConversionTests validates RGB565 quantization and bitmap layout. CI gains a VSTest step with code coverage.

Sequence Diagram(s)

sequenceDiagram
  participant MSBuild
  participant _NanoInterceptResxItems
  participant _NanoCheckResourceManagerRef
  participant GenerateNanoResourceTask
  participant ProcessResourceFiles
  participant NanoResxResourceReader
  participant NanoResourceWriter

  MSBuild->>_NanoInterceptResxItems: move .resx from EmbeddedResource to _NanoResxItems
  _NanoInterceptResxItems->>_NanoCheckResourceManagerRef: verify nanoFramework.ResourceManager ref
  _NanoCheckResourceManagerRef->>GenerateNanoResourceTask: invoke with Sources=@(_NanoResxItems)
  GenerateNanoResourceTask->>GenerateNanoResourceTask: DeserializeCache / ShouldRebuildResgenOutputFile
  GenerateNanoResourceTask->>ProcessResourceFiles: Run(log, assemblies, inputs, outputs)
  ProcessResourceFiles->>NanoResxResourceReader: ReadResources(.resx)
  NanoResxResourceReader-->>ProcessResourceFiles: resource entries
  ProcessResourceFiles->>NanoResourceWriter: AddResource / Close → .nanoresources
  NanoResourceWriter-->>ProcessResourceFiles: file written
  ProcessResourceFiles-->>GenerateNanoResourceTask: UnsuccessfullyCreatedOutFiles
  GenerateNanoResourceTask->>GenerateNanoResourceTask: WriteStateFile / RecordFilesWritten
  GenerateNanoResourceTask-->>MSBuild: FilesWritten, OutputResources
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • nanoframework/nanoFramework.NET.Sdk#3: Directly modifies the same nanoFramework.Resources.targets pipeline (UsingTask registration and NanoResourceGenerator wiring) that this PR rewrites with the intercept/check/generate target chain.
  • nanoframework/nanoFramework.NET.Sdk#4: Introduces the NanoGenerateBinaryOutput target that invokes GenerateBinaryOutputTask, which is the same task added in this PR.

Suggested reviewers

  • danielmeza
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change by describing the SDK move and cross-platform resource parsing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description matches the changeset, covering source migration, cross-platform resource parsing, packaging, tests, and smoke-test assets.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

- 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
@josesimoes josesimoes force-pushed the move-buildtasks-resources-to-sdk branch from 422b1ea to 3d8d133 Compare June 24, 2026 17:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@nanoFramework.NET.Sdk/Sdk/nanoFramework.Resources.targets`:
- Around line 77-85: The emptiness check is currently on the
NanoGenerateResources target, which can prevent the dependent setup targets from
running. Remove the target-level Condition from NanoGenerateResources and move
the non-empty guard onto the GenerateNanoResourceTask invocation so
_NanoInterceptResxItems and _NanoCheckResourceManagerRef still execute. Keep the
task call in NanoGenerateResources the same otherwise, and ensure the task only
runs when @(_NanoResxItems) has items.

In `@nanoFramework.Tools.BuildTasks/GenerateBinaryOutputTask.cs`:
- Line 52: The PE path derivation in GenerateBinaryOutputTask should not use
substring replacement on the full path because it can alter directory names and
misses uppercase extensions. Update the AssemblyReferences selection that builds
peCollection to derive each path from GetMetadata("FullPath") using
Path.ChangeExtension with a .pe extension, keeping the logic localized to
GenerateBinaryOutputTask.
- Around line 67-75: The PE-file copy logic in GenerateBinaryOutputTask
currently relies on a single FileStream.Read call, which may not fill the entire
buffer before binFile.Write is called. Update the read path in the PE copy block
to ensure the buffer is fully populated before writing, either by looping until
all bytes are read or by using a read-to-completion helper if available, so the
assembly image written by GenerateBinaryOutputTask is complete and not partially
zero-filled.

In `@nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.cs`:
- Around line 843-848: Gate the LoadReferences() call in
GenerateNanoResourceTask so it only runs under NETFRAMEWORK, since the
cross-platform path does not use assemblyList but still hits
AssemblyName.GetAssemblyName() on unresolved @(ReferencePath) entries. Update
the assemblyList initialization in the resource generation flow to use
LoadReferences() on NETFRAMEWORK and an empty array otherwise, keeping the rest
of the logic in GenerateNanoResourceTask unchanged.

In `@nanoFramework.Tools.BuildTasks/ProcessResourceFiles.cs`:
- Around line 2112-2117: Update the .nanoresources write path in
ProcessResourceFiles so rewriting an existing file does not preserve stale
trailing bytes; the current File.Open(..., FileMode.OpenOrCreate) in the
serialization block can leave old data behind when the new output is smaller.
Change the file creation mode to overwrite/truncate the target when writing the
serialized resource data, and keep the change localized to the file write logic
around fileStream/BinaryWriter in this method.
- Around line 137-142: The failure tracking in ProcessResourceFiles.ProcessFiles
is adding the output task item itself instead of the output path string, which
breaks later enumeration in GenerateNanoResourceTask. Update the ProcessFile
failure branch to store outFiles[i].ItemSpec (or the equivalent string path) in
UnsuccessfullyCreatedOutFiles so it remains a string list and preserves the
original resource error.
- Around line 1839-1845: The resource file layout in the
serialization/deserialization path is still interleaving each Resource header
with its payload instead of matching the declared table-then-data format. Update
ProcessResourceFiles so the logic around Resource.header.Serialize,
writer.Write(resource.data), and the matching Deserialize path writes all
headers first, then all resource data blocks; keep Header.OffsetOfResourceData
consistent with the new order so multi-resource .nanoresources files are encoded
correctly.

In `@nanoFramework.Tools.BuildTasks/Utilities/DebuggerHelper.cs`:
- Around line 23-42: The debugger helper currently reads the flag with a
user-scoped environment variable and then calls Debugger.Break unconditionally,
which breaks on Unix-like systems and after timeout even when no debugger is
attached. Update DebuggerHelper to use the process-scoped
Environment.GetEnvironmentVariable overload for the debug flag, and in the wait
loop path only call Debugger.Break when Debugger.IsAttached is true so the
timeout can exit cleanly without interrupting execution.

In `@test/BuildTasks.Tests/Infrastructure/TestBuildEngine.cs`:
- Around line 42-46: Initialize the TestTask.BuildEngine property in
TestBuildEngine so it is usable by default, since TaskLoggingHelper construction
can fail when BuildEngine is left null. Update the TestTask helper to provide a
non-null default implementation or stub for IBuildEngine, keeping TestTask and
its Execute method unchanged so tests can instantiate it without extra setup.

In `@test/BuildTasks.Tests/NanoResxResourceReaderTests.cs`:
- Around line 35-40: Avoid disposing the backing StringReader before
NanoResxResourceReader is consumed; ParseResx currently creates the reader with
a using scope, so the source is closed too early and the tests depend on eager
parsing. Update ParseResx and any related test helpers in
NanoResxResourceReaderTests to keep the StringReader alive for the full lifetime
of the returned NanoResxResourceReader, so enumeration can happen after
construction without relying on implementation details.

In `@test/BuildTasks.Tests/ProcessResourceFilesTests.cs`:
- Around line 27-31: Update the test class comment in ProcessResourceFilesTests
so it matches the actual compile-time guard and runtime coverage. The note above
ReadResources/WriteResources currently says both net8.0 and net472 are
exercised, but this file is wrapped in NETFRAMEWORK only, so revise the wording
to describe framework-only compilation/coverage accurately. Use the
ProcessResourceFilesTests and ReadResources/WriteResources symbols to locate the
comment and keep the explanation consistent with the conditional compilation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: nanoframework/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e83d5fc5-26d7-49b8-8f32-5590349aef8c

📥 Commits

Reviewing files that changed from the base of the PR and between 955d30c and 422b1ea.

⛔ Files ignored due to path filters (2)
  • test/SmokeTest/data.bin is excluded by !**/*.bin
  • test/SmokeTest/logo.bmp is excluded by !**/*.bmp
📒 Files selected for processing (20)
  • azure-pipelines.yml
  • nanoFramework.NET.Sdk.sln
  • nanoFramework.NET.Sdk/Sdk/nanoFramework.Resources.targets
  • nanoFramework.NET.Sdk/nanoFramework.NET.Sdk.csproj
  • nanoFramework.Tools.BuildTasks/GenerateBinaryOutputTask.cs
  • nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.Stub.cs
  • nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.cs
  • nanoFramework.Tools.BuildTasks/ProcessResourceFiles.CrossPlatform.cs
  • nanoFramework.Tools.BuildTasks/ProcessResourceFiles.cs
  • nanoFramework.Tools.BuildTasks/ResolveRuntimeDependenciesTask.cs
  • nanoFramework.Tools.BuildTasks/TasksConstants.cs
  • nanoFramework.Tools.BuildTasks/Utilities/DebuggerHelper.cs
  • nanoFramework.Tools.BuildTasks/nanoFramework.Tools.BuildTasks.csproj
  • test/BuildTasks.Tests/BuildTasks.Tests.csproj
  • test/BuildTasks.Tests/Infrastructure/TestBuildEngine.cs
  • test/BuildTasks.Tests/NanoResxResourceReaderTests.cs
  • test/BuildTasks.Tests/ProcessResourceFilesTests.cs
  • test/BuildTasks.Tests/Rgb565ConversionTests.cs
  • test/SmokeTest/Resources.resx
  • test/SmokeTest/SmokeTest.csproj
💤 Files with no reviewable changes (1)
  • nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.Stub.cs

Comment thread nanoFramework.NET.Sdk/Sdk/nanoFramework.Resources.targets
Comment thread nanoFramework.Tools.BuildTasks/GenerateBinaryOutputTask.cs Outdated
Comment thread nanoFramework.Tools.BuildTasks/GenerateBinaryOutputTask.cs
Comment thread nanoFramework.Tools.BuildTasks/GenerateNanoResourceTask.cs
Comment thread nanoFramework.Tools.BuildTasks/ProcessResourceFiles.cs
Comment thread nanoFramework.Tools.BuildTasks/ProcessResourceFiles.cs Outdated
Comment thread nanoFramework.Tools.BuildTasks/Utilities/DebuggerHelper.cs
Comment thread test/BuildTasks.Tests/Infrastructure/TestBuildEngine.cs
Comment thread test/BuildTasks.Tests/NanoResxResourceReaderTests.cs Outdated
Comment thread test/BuildTasks.Tests/ProcessResourceFilesTests.cs Outdated
@josesimoes josesimoes merged commit eabe3e0 into main Jun 24, 2026
4 checks passed
@josesimoes josesimoes deleted the move-buildtasks-resources-to-sdk branch June 24, 2026 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants