Install & first run: build, boot log, first request
From zero to your first request takes exactly two things: a GCC and a Python. Every log line and response in this chapter is real output from demo-single — you can reproduce it verbatim.
Overview
2.1 Intro
Deploying a new server stack, the painful part is rarely writing code — it is environment prep: Node wants nvm and node_modules, Go wants a toolchain and GOPATH, a traditional C service wants its own build pipeline. XServer's answer is to fold all of it into build time and the binary itself: at build time your GCC produces xs.exe while the TCC compiler, the full SDK headers and system library definitions are LZMA-compressed into the binary; at runtime the target machine needs nothing installed.
So "installing XServer" is really two actions: build the host once, then run a ready-made app directory (demo-single). We start with those two.
2.2 Building the host
Two prerequisites only: GCC (select with --cc) and Python 3. In the xserver repository root:
$ build.bat # minimal variant: default $ build.bat sqlite xtp # compile in the SQLite and XTP2 extensions $ build.bat --list-extensions available extensions: sqlite, xtp
The Linux equivalent is bash build.sh sqlite xtp. The build pipeline does five things:
The last step deserves emphasis: the artifact is replaced only after a successful link. On a failed build the xs.exe in the release directory stays untouched — this "failure protection" is guarded by a dedicated test case; interrupting a build at any moment never yields a broken binary.
2.3 Running the demo, reading the log
demo-single is the complete sample app shipped in the repository (routing, templates, SQLite, controlled pages). Enter the directory and run:
$ cd release/demo-single $ ./xs.exe [xs] config loaded: D:\GIT\xserver\release\demo-single/xs.json (1 servers) [xs] server 'demo' class=http 127.0.0.1:9080 tls=off enabled [xs] default-host 'app' path=...\wwwroot devfile=...\main.c [xs] engine started, workers=12 [xs] script loaded: ...\main.c (2.6 KB gen 1) [demo] database opened: ...\db\main.db [xs] server 'demo' http bound on 127.0.0.1:9080 [xs] running, press Ctrl+C to stop
What just happened — line by line:
| Log line | Meaning | What to note |
|---|---|---|
config loaded (1 servers) | xs.json parsed | fail-fast: an invalid field exits right here with the field name |
server 'demo' class=http ... | service config echo | your last chance to check listen address / port / TLS |
engine started, workers=12 | concurrency engine ready | worker count from engine.workers, 0 = xrt default (12 on this machine) |
script loaded (2.6 KB gen 1) | TCC compile finished | note gen 1 — the "generation", protagonist of chapter 3 |
[demo] database opened | your ServiceInit is running | lines prefixed [demo] come from the app script itself |
http bound on 127.0.0.1:9080 | listening is live | a failed bind rolls back every already-bound listener |
running, press Ctrl+C to stop | serving state | Ctrl+C / SIGTERM triggers the five-phase graceful shutdown |
2.4 Making requests
Open another terminal and send the demo a few requests (all real output):
$ curl -s http://127.0.0.1:9080/json {"server":"xs3 demo","ok":true,"host":"app"} $ curl -s http://127.0.0.1:9080/text demo-single ok (from includes/demo_extra.h) $ curl -s http://127.0.0.1:9080/api/v1/items/42 {"id":42,"name":"bench-write","created":1788494894} $ curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:9080/nope 404 $ curl -sI http://127.0.0.1:9080/json HTTP/1.1 405 Method Not Allowed Allow: GET
What just happened:
/jsonwent through the app script'sHandle_JSON— building an object with xvalue and serializing it (chapter 18's topic);/api/v1/items/42hit the dynamic route/api/v1/items/{id}; the captured segment 42 was looked up in SQLite (chapter 17);/nopematched no route and no app handler → 404;HEAD /jsongot 405 + Allow: GET — the route's method mask registered only GET, and HEAD was rejected at the method slot before reaching the handler. A real routing detail; chapter 17 covers how to handle HEAD.
2.5 Contract
- Threading:
workersis fixed at startup and immutable across hot reload (changes are rejected). - Variants: the build variant decides which symbols scripts may use — the default variant has no sqlite3_* / xtp2_*; using them fails the compile.
- Data: the demo's db/main.db is a real data file; experiment freely and rebuild the repository to restore it.
Common mistakes
- Symptom
bind failed, process exits; with multiple listeners configured, previously bound ports are not left half-serving either.- Cause
- The target port is occupied. XServer's assembly is transactional: when any listener fails, the already-bound ones are fully rolled back before exit — no "half a service running" intermediate state.
./xs
bind failed
./xs /* retry over and over, no idea who holds the port */netstat -ano | findstr 9080
/* change xs.json's port, or kill the holder */- Symptom
config load failed— even though you are sure xs.json sits in some directory.- Cause
- When run without arguments, XServer looks for xs.json in the directory of the executable, not the current working directory. Copy xs.exe somewhere alone and double-click, and of course it cannot find the app.
copy xs.exe C:\tools\
C:\tools\xs.exe /* config load failed *//* keep xs.json and the source directory next to the exe;
* or pass the config path explicitly */
./xs D:\apps\myapp\xs.jsonExercises
Change the demo's xs.json port from 9080 to 19080, restart and verify with curl.
http bound on 127.0.0.1:19080 and curl /json returns the same JSON as this chapter.Rebuild with build.bat sqlite, run the demo and confirm /api/list works; then switch back to the default variant and observe what the script compile reports.
Register /hello (GET) in the demo's route.h with a handler returning your name. Restart to verify — hot reload is volume 4's business; for now use the "restart to apply" mental model.
curl /hello returns what you wrote; the log shows script loaded ... gen 2 (does a restart bump the generation counter? Try it and find the answer at the start of chapter 3).Summary
| Point | Conclusion |
|---|---|
| Requirements | GCC + Python 3, nothing else |
| Build variants | build.bat [sqlite] [xtp]; atomic replace only on a successful link |
| Boot order | config → engine → script compile → ServiceInit → bind → running |
| Key log lines | gen N (generation), workers=N, bound; lines with an app prefix come from your script |
| Config lookup | xs.json is sought next to the exe by default; pass a path to override |
- xrt book · dev environment — details of the GCC toolchain the host build uses
- xrt book · memory debugging — the low-level weapon for troubleshooting (chapter 6 returns to it)