Reference › Public surface census — what each SDK actually exports
kind: reference#surface#api#exported#internal#distribution#census

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 SDKICoreBlocks SDK
Treesrc/ICoreEssentials/src/ICoreSDK/ + include/icore/
Headers in tree216682 + 2
Named export setnone — no install() rules exist2 headers, listed by hand as ICORE_SDK_PUBLIC_HEADERS
De-facto surfacethe 40 wrapper headers named by ICoreEssentials.h, reached as ICoreEssentials/<Family>/<Header>.hinclude/icore/Application.h, include/icore/EditorWindow.h
CMake targetICoreEssentials (STATIC)icore_sdk / icore::sdk (INTERFACE)
Install rulesnoneheaders + export set (no package config)
Links for a consumeryes — provenno — header-only, definitions in the app
Third-party in the surfaceQt 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.sh scans include/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_selftest target 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.