jetc: rename --shared build output convention from .so to .jtc

Purely a naming-convention change per user request, not a format
change - the output is still a real ELF shared object (-shared -fPIC),
still dlopen()-able exactly as before. .jtc ("jet compiled") marks it as
an APIServer-loadable content module rather than a generic library.

build-shared.sh: usage text and STEM derivation
(basename "$OUTPUT" .so -> .jtc) both updated - the STEM change is the
one functional piece here, everything else in this commit is comments/
usage strings. Doc comments in jetc.cpp/JetCodegen.h/host_test.cpp/
api_test.cpp updated to match.

Verified live: rebuilt jetc and all five demo*.jtc modules, reran
api_test/host_test against demo3.jtc (still resolves jetc_api_demo3/
jetc_render_demo3 and renders correctly) - the extension is purely
cosmetic to dlopen(), as expected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Brad ArantandClaude Sonnet 5 committed 2026-08-25 11:41:44 -07:00
1 parent 3f273b0a95
commit 9bbb95cc57
6 files changed
+28 -22

No files matched your search

+6 -2
View File
@@ -6,7 +6,7 @@ docs/JetCore.dvi
docs/JetCore.log docs/JetCore.log
docs/JetCore.toc docs/JetCore.toc
# jetc build byproducts (compiled JET-to-C++ output, binaries, .so/.a artifacts). # jetc build byproducts (compiled JET-to-C++ output, binaries, .jtc/.a artifacts).
# Generated .cpp files are always named "*.compiled.cpp" (see build-compiled.sh/ # Generated .cpp files are always named "*.compiled.cpp" (see build-compiled.sh/
# build-shared.sh) - deliberately not a blanket "*.cpp", which would also # build-shared.sh) - deliberately not a blanket "*.cpp", which would also
# swallow real source files added to jetc/ later (bit us once already: an # swallow real source files added to jetc/ later (bit us once already: an
@@ -19,7 +19,11 @@ jetc/host_test
jetc/api_test jetc/api_test
jetc/demo.cpp jetc/demo.cpp
jetc/demo2.cpp jetc/demo2.cpp
jetc/demo4
jetc/demo5
jetc/demo6
jetc/demo7
jetc/*.compiled.cpp jetc/*.compiled.cpp
jetc/*.pic.o jetc/*.pic.o
jetc/*.so jetc/*.jtc
jetc/libCoreUtils_pic.a jetc/libCoreUtils_pic.a
+3 -3
View File
@@ -10,7 +10,7 @@ namespace jetc {
// One `#api METHOD /path` directive from the top of the source template // One `#api METHOD /path` directive from the top of the source template
// (see jetc.cpp) - a compile-time-known route this template wants to // (see jetc.cpp) - a compile-time-known route this template wants to
// serve once loaded as a .so. Purely descriptive data handed to Codegen; // serve once loaded as a .jtc. Purely descriptive data handed to Codegen;
// jetc itself never interprets the method/path beyond storing them. // jetc itself never interprets the method/path beyond storing them.
struct ApiRoute { struct ApiRoute {
std::string method; std::string method;
@@ -34,7 +34,7 @@ namespace jetc {
// //
// sharedMode == true: emits no main() at all. Instead the render // sharedMode == true: emits no main() at all. Instead the render
// logic is exported as `extern "C" void <entrySymbol>(jet::Global // logic is exported as `extern "C" void <entrySymbol>(jet::Global
// &global, coreutils::MString &out)`, meant to be built into a .so // &global, coreutils::MString &out)`, meant to be built into a .jtc
// (see build-shared.sh) and dlsym()'d by a long-running host server - // (see build-shared.sh) and dlsym()'d by a long-running host server -
// one call renders one request into the caller-owned `out`, using // one call renders one request into the caller-owned `out`, using
// whatever Global the host passes in (its lifecycle, cgi/session // whatever Global the host passes in (its lifecycle, cgi/session
@@ -45,7 +45,7 @@ namespace jetc {
// letting coreutils::Exception propagate to the caller) across the // letting coreutils::Exception propagate to the caller) across the
// dlopen() boundary is safe; this is a same-ABI plugin boundary, not // dlopen() boundary is safe; this is a same-ABI plugin boundary, not
// a foreign C ABI one. entrySymbol should be unique per compiled // a foreign C ABI one. entrySymbol should be unique per compiled
// template (see jetc.cpp) so multiple .so's can coexist even if a // template (see jetc.cpp) so multiple .jtc's can coexist even if a
// host ever dlopen()s them RTLD_GLOBAL instead of keeping separate // host ever dlopen()s them RTLD_GLOBAL instead of keeping separate
// handles. // handles.
// //
+2 -2
View File
@@ -1,7 +1,7 @@
// Minimal dlsym() check for the jetc_api_<name> route-metadata export added // Minimal dlsym() check for the jetc_api_<name> route-metadata export added
// alongside jetc_render_<name> in --shared mode (see JetCodegen.cpp). Proves // alongside jetc_render_<name> in --shared mode (see JetCodegen.cpp). Proves
// a host can discover a compiled module's declared routes purely from the // a host can discover a compiled module's declared routes purely from the
// .so itself, with no separate manifest file - the actual point of putting // .jtc itself, with no separate manifest file - the actual point of putting
// routing metadata in an exported symbol instead of a sidecar file. // routing metadata in an exported symbol instead of a sidecar file.
#include <dlfcn.h> #include <dlfcn.h>
#include <iostream> #include <iostream>
@@ -12,7 +12,7 @@ typedef const JetApiRoute *(*ApiFn)(int *count);
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc < 3) { if (argc < 3) {
std::cerr << "usage: api_test <module.so> <api-symbol>" << std::endl; std::cerr << "usage: api_test <module.jtc> <api-symbol>" << std::endl;
return 1; return 1;
} }
void *handle = dlopen(argv[1], RTLD_NOW); void *handle = dlopen(argv[1], RTLD_NOW);
+10 -8
View File
@@ -1,12 +1,14 @@
#!/bin/bash #!/bin/bash
# Compiles a .jet file into a shared object exporting a stable, dlsym()-able # Compiles a .jet file into a shared object (conventionally named .jtc -
# render entry point - `jetc_render_<basename>(jet::Global &global, # "jet compiled" - to mark it as an APIServer-loadable content module, not
# coreutils::MString &out)` - for a long-running server to load and call # a generic .so) exporting a stable, dlsym()-able render entry point -
# directly instead of spawning a jet-2.0 process per request. # `jetc_render_<basename>(jet::Global &global, coreutils::MString &out)`
# - for a long-running server to load and call directly instead of
# spawning a jet-2.0 process per request.
# #
# Usage: ./build-shared.sh <input.jet> <output.so> # Usage: ./build-shared.sh <input.jet> <output.jtc>
# #
# The host server links/dlopen()s the .so and calls the exported symbol # The host server links/dlopen()s the .jtc and calls the exported symbol
# (see the "entry symbol:" line jetc prints) with its own jet::Global - # (see the "entry symbol:" line jetc prints) with its own jet::Global -
# this script does not decide that lifecycle, only builds the module. # this script does not decide that lifecycle, only builds the module.
# coreutils::Exception propagates out of the call uncaught; the host # coreutils::Exception propagates out of the call uncaught; the host
@@ -18,13 +20,13 @@ CU="$JC/../CoreUtils"
HERE="$JC/jetc" HERE="$JC/jetc"
if [ $# -ne 2 ]; then if [ $# -ne 2 ]; then
echo "usage: $0 <input.jet> <output.so>" echo "usage: $0 <input.jet> <output.jtc>"
exit 1 exit 1
fi fi
INPUT="$1" INPUT="$1"
OUTPUT="$2" OUTPUT="$2"
STEM="$(basename "$OUTPUT" .so)" STEM="$(basename "$OUTPUT" .jtc)"
if [ ! -x "$HERE/jetc" ]; then if [ ! -x "$HERE/jetc" ]; then
echo "Building jetc..." echo "Building jetc..."
Executable → Regular
+4 -4
View File
@@ -1,5 +1,5 @@
// Minimal stand-in for the not-yet-built server: dlopen()s a compiled // Minimal stand-in for a server: dlopen()s a compiled
// template .so and calls its exported render entry point directly, the // template .jtc and calls its exported render entry point directly, the
// way a persistent content-provider process would (no process spawn per // way a persistent content-provider process would (no process spawn per
// request, no re-parsing the .jet source - both the compile step AND // request, no re-parsing the .jet source - both the compile step AND
// the shared-object load happen once, ahead of time). // the shared-object load happen once, ahead of time).
@@ -14,7 +14,7 @@ typedef void (*RenderFn)(jet::Global &, coreutils::MString &);
int main(int argc, char **argv, char **envp) { int main(int argc, char **argv, char **envp) {
if (argc < 3) { if (argc < 3) {
std::cerr << "usage: host_test <module.so> <symbol>" << std::endl; std::cerr << "usage: host_test <module.jtc> <symbol>" << std::endl;
return 1; return 1;
} }
void *handle = dlopen(argv[1], RTLD_NOW); void *handle = dlopen(argv[1], RTLD_NOW);
@@ -31,7 +31,7 @@ int main(int argc, char **argv, char **envp) {
} }
// Simulate the host calling the SAME module twice, for two different // Simulate the host calling the SAME module twice, for two different
// "requests", to prove the .so is reusable across calls without being // "requests", to prove the .jtc is reusable across calls without being
// reloaded - the actual point of a persistent content provider. // reloaded - the actual point of a persistent content provider.
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
jet::Global global(envp); jet::Global global(envp);
+3 -3
View File
@@ -63,7 +63,7 @@ int main(int argc, char **argv) {
// is stripped - a plain directive line, not a new tag/attribute concept, // is stripped - a plain directive line, not a new tag/attribute concept,
// since jetc's parser has no existing notion of the enclosing <jet> tag's // since jetc's parser has no existing notion of the enclosing <jet> tag's
// attributes to hang this off of. Each becomes one route this template // attributes to hang this off of. Each becomes one route this template
// wants to serve once loaded as a .so (see JetCodegen's apiRoutes). // wants to serve once loaded as a .jtc (see JetCodegen's apiRoutes).
std::vector<jetc::ApiRoute> apiRoutes; std::vector<jetc::ApiRoute> apiRoutes;
while (src.rfind("#api ", 0) == 0) { while (src.rfind("#api ", 0) == 0) {
size_t nl = src.find('\n'); size_t nl = src.find('\n');
@@ -88,8 +88,8 @@ int main(int argc, char **argv) {
jetc::Codegen codegen; jetc::Codegen codegen;
// Both symbols are derived from the input filename (not the output // Both symbols are derived from the input filename (not the output
// path) so they stay stable and predictable for whatever builds and // path) so they stay stable and predictable for whatever builds and
// dlsym()'s the resulting .so - unique per template, so multiple // dlsym()'s the resulting .jtc - unique per template, so multiple
// compiled templates' .so's can coexist in one process even under // compiled templates' .jtc's can coexist in one process even under
// dlopen(..., RTLD_GLOBAL) instead of requiring isolated handles. // dlopen(..., RTLD_GLOBAL) instead of requiring isolated handles.
std::string baseIdent = sanitizeIdent(baseNameNoExt(inputPath)); std::string baseIdent = sanitizeIdent(baseNameNoExt(inputPath));
std::string symbol = "jetc_render_" + baseIdent; std::string symbol = "jetc_render_" + baseIdent;