# Atmel Studio `master` carries `bootloader.atsln`, so this branch does too: `ide/bootloader.atsln` builds the loaders from the same sources Ninja does, to a **byte-identical `.text`** — 404 B for the 328P pureboot loader, 510 B for the `tsb_asm` tier in its 512-byte section. CMake remains the build system; the solution is here so the port opens in Studio as its predecessor did. ## The two projects, and why two pureboot is a chip × backend × clock × baud matrix — `pureboot_add_loader()` resolves a deployment into compile definitions — and a `.cppproj` is one binary at one set of flags, so a project can only ever be one point of it. `pureboot` is that point: the stock 328P deployment, USART0 at 115200 on a 16 MHz crystal, an 8-second activation window. `tsb_asm` is the TinySafeBoot tier that occupies the same 512-byte section `master`'s `tsb` project targeted. The other three tsb tiers (`tsb_pure`, `tsb_tricks`, `tsb_policy`) are not here. They differ from `tsb_asm` in their source file, their section size, and — for `tsb_policy` — two loop flags; nothing about that is a Studio concern, and what they exist to demonstrate is a size gradient only the CMake size tests measure. Adding one is a copy of `tsb_asm/tsb_asm.cppproj` in its own directory, with its name, its GUID, its source path and its `--section-start` changed (`0x7c00` for the 1 KiB tiers), plus four lines in the solution. `avrdevice` is a project property, so each project gets its own directory: Studio builds into `/` whatever `OutputDirectory` says, and two projects sharing a directory would share one object file. ## Debug keeps `-Os` Both configurations compile at `-Os`; Debug adds only `-gdwarf-4`. The `.text` is therefore identical in both, which is the point — a loader's section is a **correctness** bound and not a budget. `-Og` builds this same source to 590 B, and linking it at `--section-start=.text=0x7e00` on a 32 KiB part puts 78 bytes past flash end **without a diagnostic**: `rcall`/`rjmp` targets there wrap modulo flash size, so the image dies right after activation. A debug configuration that silently produces that is worse than none, and DWARF costs no flash, so the optimisation level stays where correctness needs it. ## What Studio needs from the machine libavr from the **submodule**, found at `$(MSBuildProjectDirectory)\..\..\libavr\include` — correct by construction, and anchored to the project because a plain relative path resolves against the generated makefile's directory (the configuration's output directory), not the project's. There is no `LIBAVR_ROOT` escape hatch: a variable exported in a shell is invisible to Studio launched from the Start menu, and the failure reads as a missing `libavr/libavr.hpp` — which is what the submodule answers. A GCC 16.1 toolchain registered as flavour `avr-g++-16.1.0`, nothing older reaching `-std=c++26`. ## Generating and gating One generated file is required before a project will load at all, and one command per project checks the flags have not drifted (both from libavr's `tools/atmelstudio/`): ```sh for name in pureboot tsb_asm; do python libavr/tools/atmelstudio/componentinfo.py \ "ide/$name/$name.componentinfo.xml" --device ATmega328P python libavr/tools/atmelstudio/check-flags.py \ --solution ide/bootloader.atsln --project "$name" --target "$name" \ --compile-commands build/atmega328p-generated/compile_commands.json \ --log "build/as-$name.log" done ``` `--project` because one reference describes one binary; `--target` because `pureboot.cpp` is compiled by every point of the size matrix and the flags differ per point, so the basename alone does not name a reference. Release is what the gate compares — the presets define no debug build, and Debug differs from Release only in `-gdwarf-4`. Legacy (the yazoalfa-era submodules) stays on `master`.