Third-party apps do not link against the firmware directly: the app SDK is
generated from the firmware sources at build time. When you expose a new
function to apps (i.e. anything declared in an applib/ header that user apps
can call), three things must change together — the firmware build alone will
not surface it to apps:
Implement the applib wrapper and syscall — add the function to the
appropriate fw/applib/.../<area>.c/.h, declare the sys_* syscall in
fw/syscall/syscall.h, and define it with DEFINE_SYSCALL (from
fw/syscall/syscall_internal.h), either in the matching
fw/syscall/<area>_syscalls.c or alongside the implementation it
wraps.
Register the symbol in
tools/generate_native_sdk/exported_symbols.json under the matching
group, with an addedRevision matching the new SDK revision.
Bump the SDK revision in
fw/process_management/pebble_process_info.h: increment
PROCESS_INFO_CURRENT_SDK_VERSION_MINOR and add a comment line above the
#define following the existing pattern, e.g. // sdk.major:0x5 .minor:0x66 -- <description> (rev 105). The rev number in the comment
must match addedRevision from step 2.
Forgetting steps 2 or 3 means the function compiles into the firmware but is invisible to the app SDK build, so third-party apps can’t link against it.
Warning
It is not possible to add publicly exposed functions to an already
released firmware/SDK combination. The generated pebble.auto.c
function-pointer table must be compiled into the firmware the SDK targets:
an app built against a newer SDK calls a trampoline that indexes past the
end of an older firmware’s table and crashes. New exports always ship as a
new firmware plus a new SDK build.
The generator (tools/generate_native_sdk/generate_pebble_native_sdk_files.py)
runs automatically as part of the firmware build (normal variant only — PRF
and test builds skip it). It exports the white-listed functions, typedefs
and #defines from the firmware tree and produces the files needed to build
native watchapps, all under build/:
build/sdk/<platform>/include/pebble.h — typedefs, defines and function
prototypes for apps (plus pebble_worker.h for background workers and a
few version/fonts headers). Exported declarations are copied verbatim, so
the SDK also ships pbl/kernel/compiler.h and its backends, included from
pebble.h, and exported headers use its PBL_* macros rather than raw
__attribute__.
build/sdk/<platform>/lib/libpebble.a — static library containing
trampolines that call the exported functions in flash
build/fw/pebble.auto.c — g_pbl_system_tbl, the table of function
pointers the trampolines use to find an exported function’s address;
compiled into the firmware image
The rest of the distribution is packaged by the firmware build’s sdk
target, which fills in the same build/sdk/ tree:
pbl configure --board $BOARD
pbl build sdk
tools/cmake/sdk.py copies the common files from sdk/ into
build/sdk/common/ — the app project templates under sdk/defaults/, and
the tools and resource pipeline the app build shares with the firmware —
and bundles sdk/waftools/ into the waf binary app developers use to
build their apps. That waf is the only one left in the tree: everything it
needs lives under sdk/, and it is built out of tree, so packaging leaves
the checkout untouched.
exported_symbols.json format{
"revision": "<exported symbols revision number>",
"version": "x.x",
"files": ["<files to parse>"],
"exports": ["<symbols to export>"]
}
Each exported symbol has a type of function, define, type,
forward_struct, or group:
{
"type": "function",
"name": "<symbol name>",
"sortName": "<sort order>",
"addedRevision": "<revision number>"
}
A group nests further exports under a name. Functions support
additional flags (internal, removed, deprecated, appOnly,
workerOnly, implName, skipDefinition) — see existing entries and
tools/generate_native_sdk/exports.py for their meaning.
Notes:
Functions are sorted by addedRevision, then alphabetically (by sortName
if present, else name) within a revision. This ordering is the ABI — it
is why new functions must use a new revision: it guarantees new firmware
stays backwards compatible with apps compiled against an older
libpebble.a.
types are emitted in the order listed; put typedefs after the typedefs
they depend on (includeAfter is the escape hatch for ordering
exceptions).
The generator errors out on exports it cannot find in the parsed headers
and on inconsistent revision numbers, but it does not verify that the
resulting pebble.h compiles — review its output.
The comment ledger above PROCESS_INFO_CURRENT_SDK_VERSION_MINOR is the
only mapping between SDK revisions and version minors: no formula relates
them (the minor once jumped 0x19 → 0x20 between revs 35 and 36, and a
few minors and revs are skipped or doubled up). Treat the ledger as
append-only history.
Generated from PebbleOS 91af4a22c. This page is maintained in the pebbleos repository: docs/development/sdk_export.md.