exports.txt lists the functions a LibLoad library makes available. It looks like a
convenience file. It is not: it is the library's binary interface.
How resolution actually works#
LibLoad does not resolve imports by name at runtime. It resolves them by ordinal, meaning by position in the export table.
When a program is compiled against your library, the linker records "call entry 2 of DEMO". When it runs, LibLoad loads the appvar and jumps to whatever entry 2 is now.
demo_init # ordinal 0
demo_draw # ordinal 1
demo_shutdown # ordinal 2The rule#
Appending a new name to the end. Existing ordinals do not move.
Reordering, removing, or inserting anywhere but the end.
File format#
One name per line. Blank lines and lines starting with # are ignored, so comments are free.
# DEMO library exports.
#
# APPEND ONLY. Never reorder, never remove a line.
# Retired entries stay in place as stubs.
demo_init
demo_draw
demo_shutdown
# --- added in library version 2 ---
demo_draw_scaled
demo_set_paletteRetiring a function#
You cannot remove the line. Keep it, and make the implementation harmless:
// Retired in library version 3. The ordinal has to stay so that programs
// compiled against versions 1 and 2 keep resolving correctly.
void demo_old_draw(void) {
}Callers that were compiled against it keep working, badly but predictably. New callers do not see it because you removed the declaration from the header.
Checking the file against your header#
ce-libify will compare the two for you:
ce-libify exports --exports exports.txt --header demo.hThat catches the two ordinary mistakes: a function declared in the header but never exported, which fails to link for callers, and a name in the export table that no longer exists, which fails to build for you.
Filter by naming convention when the header also declares internal helpers:
ce-libify exports --exports exports.txt --header demo.h --prefix demo_The library version number#
[library] version in the manifest is passed to ce-libify as the library version. It is metadata
that travels with the appvar, not something LibLoad enforces, and it is independent of the
[program] version that names the release.
A reasonable convention:
Bump the program version on every release
1.0.0,1.0.1,1.1.0. This is what people see on Roost.Bump the library version when you append exports
So that a caller can tell at a glance whether the appvar on the calculator is new enough to have the function it wants.
Never bump the library version to signal a break
There is no mechanism that would act on it. If you truly must break the ABI, publish a new library at a new address.
Breaking it anyway#
If the ABI has to change incompatibly, the honest move is a new project with a new address and a new
LibLoad name. Both are permanent for exactly this reason: demo-library keeps meaning what it meant,
and demo-library-2 is a thing people opt into.
Why nothing in CEagle is ever released and reissued.