Guides › Consuming the ICore Platform SDK — CMake, include roots, hello-world
kind: guide#platform#sdk#cmake#consumer#hello-world#umbrella

Consuming the ICore Platform SDK#

How to build code against src/ICoreEssentials/ — the include root you need, the umbrella you must include, the toolchain minimum, and a hello-world that was compiled, linked and run to produce the output shown below.

Read Packaging — what is decided, and the decisions that are open first if you were about to write find_package. The platform SDK has no install() rules at all today. It is consumed by building it as part of your project, not by installing it. Everything below describes that, honestly, and nothing below invents a package that does not exist.

What you get#

One static library target, ICoreEssentials, and 216 headers under ICoreEssentials/. The public vocabulary is ICore* types that expose no third-party type in a header; Qt is an implementation detail behind Impl.

Invariants a consumer must respect#

  • Include the umbrella, not an individual wrapper header. The wrapper headers are not self-contained — see the trap below. #include "ICoreEssentials/ICoreEssentials.h", or precompile it as this tree does.
  • The include root is the directory that CONTAINS ICoreEssentials/, so that ICoreEssentials/... resolves. In this tree that is src/; the library target itself is given a staged root holding only a link to the module, which is what makes its independence a compile error rather than a review comment.
  • C++17 minimum. The tree compiles with -std=gnu++17; the public SDK target declares cxx_std_17.
  • Qt 6 is required to build it (Qt 6.10.2 here), and its headers must be on the path because the umbrella pulls them in transitively. Your own code never names a Qt type.

The CMake you write#

There is no installed package, so you add the module to your build. Inside a checkout of this tree, the target already exists and you link it:

cmake_minimum_required(VERSION 3.21)
project(hello_platform CXX)

find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Svg Charts Network PrintSupport)

add_executable(hello_platform main.cpp)
target_compile_features(hello_platform PRIVATE cxx_std_17)

# The include root is the directory that CONTAINS ICoreEssentials/.
target_include_directories(hello_platform PRIVATE "${ICOREBLOCKS_ROOT}/src")

# The umbrella is delivered by the PCH here, exactly as it is for the library.
target_precompile_headers(hello_platform PRIVATE
        "${ICOREBLOCKS_ROOT}/src/ICoreEssentials/pch.h")

target_link_libraries(hello_platform PRIVATE ICoreEssentials)

ICoreEssentials propagates no include directories of its own (its own root is PRIVATE and deliberately firewalled), which is why the consumer names src/ itself. Qt arrives through the Qt6::* targets the library links.

Hello-world#

main.cpp — this is the file that was built, not a sketch of one:

// hello-world for the ICore Platform SDK -- no ICoreBlocks, no block library,
// no Studio: src/ICoreEssentials/ and Qt, nothing else.
//
// The umbrella is what makes the wrappers usable: the individual wrapper
// headers are NOT self-contained (ICorePath.h names ICoreDateTime without
// including it), so a consumer includes ICoreEssentials/ICoreEssentials.h.
#include "ICoreEssentials/ICoreEssentials.h"
#include <cstdio>

int main() {
    const ICoreString greeting = ICoreString("hello, ") + ICoreString("platform SDK");
    const ICorePath  path(ICoreString("/tmp/icore/notes.txt"));
    std::printf("%s\n%s | %s\n",
                greeting.toUpper().toStdString().c_str(),
                path.fileName().toStdString().c_str(),
                path.suffix().toStdString().c_str());
    return 0;
}

Built and run without CMake, to show every flag that actually matters (2026-08-16, commit ccf005c8, macOS arm64, Qt 6.10.2, Apple clang):

QT=$HOME/Qt/6.10.2/macos
c++ -std=gnu++17 -O2 -arch arm64 -I"$REPO/src" \
    -isystem $QT/lib/QtCore.framework/Headers -iframework $QT/lib \
    -isystem $QT/mkspecs/macx-clang -isystem $QT/include \
    -isystem $QT/lib/QtGui.framework/Headers \
    -isystem $QT/lib/QtWidgets.framework/Headers \
    -isystem $QT/lib/QtSvg.framework/Headers \
    -isystem $QT/lib/QtCharts.framework/Headers \
    -isystem $QT/lib/QtNetwork.framework/Headers \
    -isystem $QT/lib/QtPrintSupport.framework/Headers \
    -c main.cpp -o main.o

c++ -arch arm64 main.o "$REPO/build-mac/libICoreEssentials.a" \
    -F$QT/lib -Wl,-rpath,$QT/lib \
    -framework QtCore -framework QtGui -framework QtWidgets -framework QtSvg \
    -framework QtCharts -framework QtNetwork -framework QtPrintSupport \
    -framework AppKit -framework CoreFoundation -framework Security -framework IOKit \
    -o hello

Its output:

HELLO, PLATFORM SDK
notes.txt | txt

That is the whole claim this guide makes: the platform SDK compiles, links and runs outside the application that ships it.

Traps#

  • #include "ICoreEssentials/Filesystem/ICorePath.h" alone does not compile. It fails with unknown type name 'ICoreDateTime' at line 126, because every TU in this tree gets the umbrella from the PCH and no wrapper header ever needed to include its siblings. Include the umbrella instead. The symptom is an error naming a type you never used.
  • ICorePath path("/tmp/x.txt") is ambiguous. A const char* converts equally to ICoreString and std::string and both constructors exist; the error says "ambiguous" and names neither of the types you were thinking about. Wrap the literal: ICorePath(ICoreString("/tmp/x.txt")).
  • The rpath is not optional. Linking succeeds without -Wl,-rpath,$QT/lib and then the binary dies at startup with Library not loaded: @rpath/QtCore.framework/... Reason: no LC_RPATH's found — which reads like a broken build rather than a missing flag.
  • ":/" paths are invisible. ICoreDir/ICoreFile are std::filesystem underneath and return EMPTY for a toolkit resource path, with no error. Mirror to disk and read the copy.
  • Do not add anything above the platform to a PCH. pch.h is the std set plus the umbrella. That is what keeps a TU compiling with only the includes it really has.

What is not settled#

No export set, no install(), no version stamp, no shared-vs-static decision, no symbol-visibility policy, no namespace. Those are the open D8 effort and they are listed by name on Packaging — what is decided, and the decisions that are open. Until they land, "consuming" means what this page describes: build the module as part of your project.