Public surface census — what each SDK actually exports#
What is the exported surface of each SDK, and what is internal. This page
exists because the two answers differ sharply, and because the nominal answer
("include/icore/ is the public API") describes only one of the two products
while real consumers of the other include ICoreEssentials/… paths directly.
First measured 2026-08-16; the counts and the install story re-taken 2026-09-26, and the ICoreBlocks SDK's header count again on 2026-09-29.
The census#
| ICore Platform SDK | ICoreBlocks SDK | |
|---|---|---|
| Tree | ICoreEssentials/ | src/ICoreBlocks/ + include/icore/ |
| Headers in tree | 856 | 1447 + 3 (+ the generated Version.h) |
| Named export set | the headers sdk_surface.txt marks public or detail, installed with the icore::platform target | 4 headers, listed by hand as ICORE_SDK_PUBLIC_HEADERS |
| De-facto surface | the 75 wrapper headers named by ICoreEssentials.h, reached as ICoreEssentials/<Family>/<Header>.h | include/icore/Application.h, include/icore/EditorWindow.h, include/icore/License.h, include/icore/Version.h (generated) |
| CMake target | ICoreEssentials (STATIC) | icore_sdk / icore::sdk (INTERFACE) |
| Install rules | archives, headers, export set and package config — find_package(ICorePlatform) (since 2026-09-23) | headers, export set and package config — find_package(ICoreBlocks) (since 2026-08-18) |
| Links for a consumer | yes — proven | no — header-only, definitions in the app |
| Third-party in the surface | none — no configuration builds Qt, and the toolkit backends are internal | none: compiles with no Qt on the path |
The platform SDK's surface is the umbrella, and it is not curated#
This paragraph opened "There is no export set, so 'public' means 'what a
consumer can reach'" until 2026-09-23; the platform package now installs only
the public and detail headers (below). In practice the usable surface is the
75 wrapper headers named by ICoreEssentials.h,
because that file is the single written-down answer to "which wrappers exist"
and because, until 2026-09-23, the individual headers were not self-contained:
a TU that included one directly failed on a type the umbrella would have
delivered (Consuming the ICore Platform SDK — find_package, icore::platform, hello-world has the measured error). Since then every
public header compiles on its own.
Consequences worth stating plainly:
- Every header under
ICoreEssentials/is reachable from inside the source tree, and was effectively public until the package existed. ⚠ This bullet went on "Marking a subset 'internal' is part of the undecided export-set work on Packaging — what is decided, and the decisions that are open, not something this page can assert". Since 2026-09-23 the subset is marked:ICoreEssentials/sdk_surface.txtputs each header in public, detail or internal (ICore Platform SDK — what it is and what it gives you, "The header surface"). Until the package had install rules, that was a statement about what would ship; since 2026-09-23 the installed package carries only the public and detail headers, so an internal header is absent from a consumer's include path rather than merely discouraged. It is still not a link-time property. - The umbrella is the surface's index, and it shrinks as well as grows — a wrapper that loses its backing store takes its prerequisite include with it, and a wrapper with no call sites is deleted rather than kept for symmetry.
- Qt is not in the surface, on any configuration. This bullet read "Qt is
in the surface transitively on a Qt build, and only there", and warned that
Qt would leave; it has. The two CMake switches that choose the toolkit have
lost their
qtvalue —ICORE_UI_BACKENDisappkit,gtk4,winui,web,uikitorandroid, andICORE_CORE_BACKENDisnative— and namingqton either stops the configure with an error that says so. The Qt sources have left the source tree and CMake no longer looks for Qt. Behind the wrappers sits each platform's own toolkit, and those backends are internal.
The blocks SDK's surface is 4 headers of 1451, and it is curated#
ICORE_SDK_PUBLIC_HEADERS names Application.h, EditorWindow.h,
License.h and Version.h (the last one generated at build time, so the
version it carries is always the version being built)
explicitly rather than globbing them, so adding a public header is a deliberate
act that appears in review. The glob that exists feeds sdk_header_selftest,
where catching every file is the point.
License.h (2026-08-19) is the newest, and it is read-only by construction: it answers what this copy is allowed to do and offers no way to change the answer. What installs a licence — the gate, the store, the client, the verifier — is ICoreAccount, internal, and reached through an internal binding header deliberately kept out of include/icore/, because a consumer able to install a gate is a consumer able to install one that says yes to everything. It also follows EditorWindow's notification convention rather than the design sketch's: onStateChanged(std::function<…>), not a signal type, so the header names nothing from inside the tree.
Everything else under src/ICoreBlocks/ — all 1447 headers, including every
ICoreStudio and ICoreBlockLibrary header — is internal. It is on the
app target's include path because the app is built from it, not because it is
offered to anyone.
Two properties of this surface are guarded rather than asserted:
- No Qt in it.
tools/check_sdk_boundary.shscansinclude/icore/, and census row R2.3 reports 0 Qt references in the 3 public headers (4 with the generatedVersion.h). Verified independently here by compiling a consumer TU with no Qt include path. - It compiles standalone. The
sdk_header_selftesttarget compiles every public header, once, with Qt off the include path — the same mechanism that proves the Theme module Qt-free.
What "internal" cannot mean yet#
Neither SDK has symbol visibility, a namespace policy or an export macro, so "internal" today is a documentation statement and a header-path convention, not a link-time property. A consumer building inside this source tree who includes an internal header gets it; an installed package simply does not carry one. The items that would make internal mean something — visibility and shared-vs-static; both SDKs have an export set now — are named on Packaging — what is decided, and the decisions that are open.
How the generated API pages relate to this#
The generated API reference under docs/generated/api/ documents every module's
headers, internal ones included, because an agent working inside the tree needs
them. That is not a claim that they are exported. This page is the one that says
what is exported. Both export sets now exist, but the API pages do not yet
carry the internal/exported mark (D8), and this table is still counted by hand
rather than generated.