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.
Measured 2026-08-16 at commit ccf005c8.
The census#
| ICore Platform SDK | ICoreBlocks SDK | |
|---|---|---|
| Tree | src/ICoreEssentials/ | src/ICoreSDK/ + include/icore/ |
| Headers in tree | 216 | 682 + 2 |
| Named export set | none — no install() rules exist | 2 headers, listed by hand as ICORE_SDK_PUBLIC_HEADERS |
| De-facto surface | the 40 wrapper headers named by ICoreEssentials.h, reached as ICoreEssentials/<Family>/<Header>.h | include/icore/Application.h, include/icore/EditorWindow.h |
| CMake target | ICoreEssentials (STATIC) | icore_sdk / icore::sdk (INTERFACE) |
| Install rules | none | headers + export set (no package config) |
| Links for a consumer | yes — proven | no — header-only, definitions in the app |
| Third-party in the surface | Qt required transitively (the umbrella) | none: compiles with no Qt on the path |
The platform SDK's surface is the umbrella, and it is not curated#
There is no export set, so "public" means "what a consumer can reach", and what
a consumer can reach is everything under ICoreEssentials/. In practice the
usable surface is the 40 wrapper headers named by ICoreEssentials.h,
because that file is the single written-down answer to "which wrappers exist"
and because the individual headers are not self-contained — a TU that includes
one directly fails on a type the umbrella would have delivered
(Consuming the ICore Platform SDK — CMake, include roots, hello-world has the measured error).
Consequences worth stating plainly:
- Every header under
ICoreEssentials/is reachable and therefore, today, effectively public. 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. - 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 in the surface transitively, even though no wrapper header names a Qt type. A consumer needs Qt's headers on the path to compile against the umbrella. That is a distribution fact, not a boundary violation.
The blocks SDK's surface is 2 headers of 684, and it is curated#
ICORE_SDK_PUBLIC_HEADERS names Application.h and EditorWindow.h
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.
Everything else under src/ICoreSDK/ — all 682 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 2 public headers. 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 who includes an internal header gets it. The items that would make internal mean something — visibility, export set, shared-vs-static — 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; when the export set lands (D8), the API pages gain the
internal/exported mark and this table becomes generated rather than counted by
hand.