Consolidate build into one root Makefile; split run.sh into run-engine.sh/run-interpreter.sh

This commit is contained in:
ml
2026-07-05 16:35:18 +02:00
parent bd739ccfdf
commit 28558b4343
12 changed files with 300 additions and 199 deletions
+1 -2
View File
@@ -1,8 +1,7 @@
# Build output, including dist/user.properties which holds real birth
# data once filled in — never commit it.
/dist
/engine/build
/interpreter/build
/build
*.o
core
+35 -22
View File
@@ -16,15 +16,17 @@ built so it can be linked straight into it later without rework (see
## Build & run
```bash
cd engine
make # builds dist/deck-engine, dist/img/, dist/i18n/, dist/run.sh, dist/user.properties
make test # builds and runs engine/tests/smoke_test.c
make clean # removes build/ and the generated binary/img/i18n (never touches dist/user.properties)
make # builds dist/{deck-engine,interpreter-cli}, dist/img/, dist/i18n/,
# dist/run-engine.sh, dist/run-interpreter.sh, dist/user.properties
make test # builds and runs engine/tests/smoke_test.c and interpreter/tests/*_test.c
make clean # removes build/ and the generated binaries/img/i18n (never touches dist/user.properties)
```
Build output goes to `dist/`, a sibling of `engine/` and `res/` (not
inside `engine/`). There is no `make install`; `dist/` is meant to be run
in place.
A single `Makefile` at the repo root builds both `engine/` and
`interpreter/` — there is no per-module Makefile, and no `cd` needed
before running `make`. Build output goes to `dist/`, a sibling of
`engine/`, `interpreter/`, and `res/`. There is no `make install`;
`dist/` is meant to be run in place.
Two ways to run a reading:
@@ -35,17 +37,22 @@ dist/deck-engine --seed "2026-07-03" \
--birth-lat 52.5200 --birth-lon 13.4050 \
[--date YYYY-MM-DDTHH:MM] [--format text|html|json] [--lang en|de] [--i18n-dir <path>]
# 2. dist/run.sh [text|html] [lang] — wraps the binary for daily use: seed
# and --date come from the OS clock (today's date / current UTC time),
# birth data + default language are read from dist/user.properties
# next to the script; the optional [lang] arg overrides that language
# for a single run.
# 2. dist/run-engine.sh [text|html|json] [lang] — wraps the binary for
# daily use: seed and --date come from the OS clock (today's date /
# current UTC time), birth data + default language are read from
# dist/user.properties next to the script; the optional [lang] arg
# overrides that language for a single run.
```
`dist/user.properties` is seeded once from `engine/scripts/user.properties.template`
with placeholder values (`YOUR_BIRTH_DATE_HERE`, etc.) and is **never
overwritten by later builds** — `run.sh` refuses to run (with a clear
error) until the placeholders are replaced with real values.
overwritten by later builds** — `run-engine.sh`/`run-interpreter.sh`
refuse to run (with a clear error) until the placeholders are replaced
with real values. `dist/run-interpreter.sh` is the equivalent daily-use
wrapper for the interpreter: it runs `run-engine.sh`'s same OS-clock
seed/date and `user.properties` birth data through `deck-engine --format
json`, piped straight into `dist/interpreter-cli` — see "Interpretation"
below.
Run a single smoke test by editing `engine/tests/smoke_test.c`'s `main()`
temporarily, or just read its assertions — there's no test filter flag,
@@ -74,10 +81,10 @@ deck_in_a_dash/
main.c CLI entry point.
i18n/en.lang, i18n/de.lang Translation source files, one per language.
tests/smoke_test.c
scripts/run.sh, scripts/user.properties.template
Makefile
scripts/run-engine.sh, scripts/run-interpreter.sh, scripts/user.properties.template
interpreter/ Separate module + binary; see "Interpretation" below.
dist/ Build output (gitignored-style; see Build & run).
Makefile Single root Makefile, builds both engine/ and interpreter/.
```
### Data flow / the real API
@@ -193,14 +200,19 @@ deliberately unchanged by this beyond gaining `--format json`; the two
binaries compose over that JSON, never by linking together:
```bash
cd engine && make # -> dist/deck-engine (unchanged; --format json is new)
cd interpreter && make # -> dist/interpreter-cli
cd interpreter && make test # builds and runs both interpreter/tests/*_test.c
make # -> dist/deck-engine (unchanged; --format json is new) and dist/interpreter-cli
make test # builds and runs both engine/tests/*_test.c and interpreter/tests/*_test.c
dist/deck-engine ... --format json | dist/interpreter-cli
# or: dist/deck-engine ... --format json > reading.json && dist/interpreter-cli reading.json
# or, for daily use (OS clock + user.properties, same as run-engine.sh):
dist/run-interpreter.sh
```
The root `Makefile` builds both from one invocation, but keeps them as
separate compilation units throughout — no object file is ever shared
between the two binaries (see the next bullet).
- `interpret_daily_reading(reading, &out)` (`significance.h/.c`) scores
every aspect in `reading->transits.aspects[]`, keeps the **top 5** by
score in `DailyInterpretation.top_items[]` (descending, evicting the
@@ -237,8 +249,9 @@ dist/deck-engine ... --format json | dist/interpreter-cli
today"), makes the whole load fail rather than silently dropping data.
- **Deliberately header-only dependency on the engine, throughout**:
`significance.h`/`reading_io.h` `#include engine/src/reading.h` for the
struct/enum *definitions*, but `interpreter/Makefile` never compiles or
links any engine `.c` file (or the vendored Astronomy Engine) — every
struct/enum *definitions*, but the root `Makefile` never compiles or
links any engine `.c` file (or the vendored Astronomy Engine) into the
interpreter's binary or tests — every
test in `interpreter/tests/` runs against hand-built JSON text or
hand-built `DailyReading` values, with no real ephemeris/tarot-draw
call involved anywhere. Consequently `reading_io.c` (planet/aspect
@@ -251,7 +264,7 @@ dist/deck-engine ... --format json | dist/interpreter-cli
## Licensing
- Engine code (`engine/src/`, `engine/scripts/`, `engine/Makefile`):
- Engine code (`engine/src/`, `engine/scripts/`) and the root `Makefile`:
MIT, per the repo's top-level `LICENSE`.
- `engine/third_party/astronomy/`: vendored MIT code, unmodified — see
`VENDORED.md` for the pinned upstream commit.
+114
View File
@@ -0,0 +1,114 @@
CC ?= cc
CFLAGS ?= -std=c99 -Wall -Wextra -O2
LDLIBS := -lm
BUILD_DIR := build
OBJ_DIR := $(BUILD_DIR)/obj
DIST_DIR := dist
DIST_IMG_DIR := $(DIST_DIR)/img
DIST_I18N_DIR := $(DIST_DIR)/i18n
# ---- engine ----
ENGINE_SRC_DIR := engine/src
ENGINE_THIRD_PARTY := engine/third_party/astronomy/astronomy.c
ENGINE_TEST_DIR := engine/tests
ENGINE_I18N_DIR := engine/i18n
ENGINE_SCRIPTS_DIR := engine/scripts
RES_IMG_DIR := res/img
# Engine logic shared by the CLI and the test binary (no main()).
ENGINE_SRCS := $(ENGINE_SRC_DIR)/rng.c $(ENGINE_SRC_DIR)/tarot.c $(ENGINE_SRC_DIR)/tarot_data.c \
$(ENGINE_SRC_DIR)/astro.c $(ENGINE_SRC_DIR)/reading.c $(ENGINE_SRC_DIR)/i18n.c \
$(ENGINE_THIRD_PARTY)
ENGINE_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(ENGINE_SRCS))
ENGINE_MAIN_OBJ := $(OBJ_DIR)/$(ENGINE_SRC_DIR)/main.o
ENGINE_TEST_OBJ := $(OBJ_DIR)/$(ENGINE_TEST_DIR)/smoke_test.o
ENGINE_BINARY := $(DIST_DIR)/deck-engine
ENGINE_TEST_BINARY := $(BUILD_DIR)/smoke_test
# ---- interpreter ----
# Only ever compiles this module's own sources - significance.h/
# reading_io.h reach into engine/src/ for struct/enum *definitions*
# (plain #includes), but no engine/src/*.c (or the vendored Astronomy
# Engine) is compiled or linked here. That's what keeps this module (and
# its tests) independent of the engine's actual ephemeris/tarot-draw
# implementation - see significance.c's and reading_io.c's own comments
# for why each duplicates a small table instead of linking astro.c.
INTERP_SRC_DIR := interpreter/src
INTERP_TEST_DIR := interpreter/tests
INTERP_LIB_SRCS := $(INTERP_SRC_DIR)/significance.c $(INTERP_SRC_DIR)/json.c $(INTERP_SRC_DIR)/reading_io.c
INTERP_LIB_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(INTERP_LIB_SRCS))
INTERP_MAIN_OBJ := $(OBJ_DIR)/$(INTERP_SRC_DIR)/main.o
INTERP_BINARY := $(DIST_DIR)/interpreter-cli
SIGNIFICANCE_TEST_OBJ := $(OBJ_DIR)/$(INTERP_TEST_DIR)/significance_test.o
JSON_TEST_OBJ := $(OBJ_DIR)/$(INTERP_TEST_DIR)/json_test.o
SIGNIFICANCE_TEST_BIN := $(BUILD_DIR)/significance_test
JSON_TEST_BIN := $(BUILD_DIR)/json_test
.PHONY: all test clean images i18n scripts
all: $(ENGINE_BINARY) $(INTERP_BINARY) images i18n scripts
$(ENGINE_BINARY): $(ENGINE_OBJS) $(ENGINE_MAIN_OBJ)
@mkdir -p $(DIST_DIR)
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS)
$(INTERP_BINARY): $(INTERP_LIB_OBJS) $(INTERP_MAIN_OBJ)
@mkdir -p $(DIST_DIR)
$(CC) $(CFLAGS) -o $@ $^
# The HTML report expects card art at img/<file> next to deck-engine, so
# every build refreshes a copy alongside it (cheap: 22 small JPEGs).
images:
@mkdir -p $(DIST_IMG_DIR)
cp $(RES_IMG_DIR)/*.jpeg $(DIST_IMG_DIR)/
# deck-engine expects translation files at i18n/<lang>.lang next to it
# (default --i18n-dir), so every build refreshes a copy alongside it,
# same as images/. Add a new language by dropping another <code>.lang
# file into engine/i18n/ - no code or Makefile change needed.
i18n:
@mkdir -p $(DIST_I18N_DIR)
cp $(ENGINE_I18N_DIR)/*.lang $(DIST_I18N_DIR)/
# run-engine.sh/run-interpreter.sh are refreshed every build.
# user.properties is only seeded once (from the placeholder template) so
# a rebuild never clobbers the user's own filled-in birth data.
scripts:
@mkdir -p $(DIST_DIR)
cp $(ENGINE_SCRIPTS_DIR)/run-engine.sh $(DIST_DIR)/run-engine.sh
chmod +x $(DIST_DIR)/run-engine.sh
cp $(ENGINE_SCRIPTS_DIR)/run-interpreter.sh $(DIST_DIR)/run-interpreter.sh
chmod +x $(DIST_DIR)/run-interpreter.sh
test -f $(DIST_DIR)/user.properties || \
cp $(ENGINE_SCRIPTS_DIR)/user.properties.template $(DIST_DIR)/user.properties
test: $(ENGINE_TEST_BINARY) $(SIGNIFICANCE_TEST_BIN) $(JSON_TEST_BIN)
./$(ENGINE_TEST_BINARY)
./$(SIGNIFICANCE_TEST_BIN)
./$(JSON_TEST_BIN)
$(ENGINE_TEST_BINARY): $(ENGINE_OBJS) $(ENGINE_TEST_OBJ)
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS)
$(SIGNIFICANCE_TEST_BIN): $(OBJ_DIR)/$(INTERP_SRC_DIR)/significance.o $(SIGNIFICANCE_TEST_OBJ)
$(CC) $(CFLAGS) -o $@ $^
$(JSON_TEST_BIN): $(OBJ_DIR)/$(INTERP_SRC_DIR)/json.o $(OBJ_DIR)/$(INTERP_SRC_DIR)/reading_io.o $(JSON_TEST_OBJ)
$(CC) $(CFLAGS) -o $@ $^
$(OBJ_DIR)/%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -rf $(BUILD_DIR) $(ENGINE_BINARY) $(INTERP_BINARY) $(DIST_IMG_DIR) $(DIST_I18N_DIR) \
$(DIST_DIR)/run-engine.sh $(DIST_DIR)/run-interpreter.sh
# user.properties holds the user's own data - never removed by clean.
+22 -17
View File
@@ -41,14 +41,15 @@ engine/
src/ Engine source (rng, tarot, astro, i18n, reading, CLI).
i18n/ Translation files (en.lang, de.lang, ...).
tests/smoke_test.c Determinism, ephemeris, and i18n regression checks.
scripts/ run.sh and the user.properties template.
Makefile
scripts/ run-engine.sh, run-interpreter.sh, and
the user.properties template.
dist/ Build output (gitignored) — see below.
interpreter/ Separate module + binary (dist/interpreter-cli):
scores how significant a day's transits are,
reading deck-engine's --format json output
(see CLAUDE.md).
docs/ Architecture/dataflow diagrams, input/output format reference.
Makefile Single root Makefile, builds both engine/ and interpreter/.
```
See [`CLAUDE.md`](CLAUDE.md) for the detailed architecture and the sharp
@@ -61,25 +62,25 @@ struct format reference
## Building
```bash
cd engine
make # -> dist/deck-engine, dist/img/, dist/i18n/, dist/run.sh, dist/user.properties
make test # builds and runs engine/tests/smoke_test.c
make # -> dist/deck-engine, dist/interpreter-cli, dist/img/, dist/i18n/,
# dist/run-engine.sh, dist/run-interpreter.sh, dist/user.properties
make test # builds and runs engine/tests/smoke_test.c and interpreter/tests/*_test.c
```
Requires only a C99 compiler and `make` — no other dependencies.
## Running
**Daily use**, via `dist/run.sh`: pulls today's date and the current UTC
time from the OS clock (used as the tarot seed and the transit moment)
and reads your birth data from `dist/user.properties`. Edit that file
first — it's seeded once from a placeholder template and is never
overwritten by later builds:
**Daily use**, via `dist/run-engine.sh`: pulls today's date and the
current UTC time from the OS clock (used as the tarot seed and the
transit moment) and reads your birth data from `dist/user.properties`.
Edit that file first — it's seeded once from a placeholder template and
is never overwritten by later builds:
```bash
dist/run.sh # text output, language from user.properties (default en)
dist/run.sh html # HTML report with card art, open in a browser
dist/run.sh html de # override the language for this run
dist/run-engine.sh # text output, language from user.properties (default en)
dist/run-engine.sh html # HTML report with card art, open in a browser
dist/run-engine.sh html de # override the language for this run
```
**Direct CLI**, with every input explicit:
@@ -91,19 +92,23 @@ dist/deck-engine --seed "2026-07-03" \
[--date YYYY-MM-DDTHH:MM] [--format text|html|json] [--lang en|de]
```
**Interpreter** (`interpreter/`, built separately with `cd interpreter && make`):
**Interpreter** (`interpreter/`, built by the same root `make`):
scores how significant a day's transits are, reading `deck-engine`'s
`--format json` output — the two binaries compose over that JSON, they're
never linked together:
never linked together. `dist/run-interpreter.sh` is the daily-use
equivalent of `run-engine.sh` (same OS clock + `user.properties` inputs),
piping straight into `interpreter-cli`:
```bash
dist/deck-engine ... --format json | dist/interpreter-cli
# or, for daily use:
dist/run-interpreter.sh
```
## License
The engine source code in this repository (`engine/src/`, `engine/scripts/`,
`engine/Makefile`) is released under the **MIT License** — see
The engine source code in this repository (`engine/src/`, `engine/scripts/`)
and the root `Makefile` are released under the **MIT License** — see
[`LICENSE`](LICENSE).
`engine/third_party/astronomy/` is vendored from
+17 -12
View File
@@ -33,10 +33,11 @@ know before changing the engine. This document is the visual overview.
- **`engine/i18n/`** holds the translation source files (`en.lang`,
`de.lang`, ...), one `key=value` file per language — see
[`CLAUDE.md`](../CLAUDE.md) for the key-naming convention.
- **`dist/`** is generated by `make`: the `deck-engine` binary, a copy of
the card art under `img/`, a copy of the translation files under
`i18n/`, `run.sh`, and a `user.properties` template that's seeded once
and never overwritten by later builds.
- **`dist/`** is generated by the single root `Makefile`: the
`deck-engine` and `interpreter-cli` binaries, a copy of the card art
under `img/`, a copy of the translation files under `i18n/`,
`run-engine.sh`/`run-interpreter.sh`, and a `user.properties` template
that's seeded once and never overwritten by later builds.
- **The Pebble watchapp does not exist yet.** When it's built, it will
call `reading_generate()` directly and walk the returned struct to lay
out its own screens — it has no reason to touch `reading_print_*`.
@@ -70,15 +71,19 @@ Every display string produced along the way (`tarot_data.c`'s card and
position text, `astro.c`'s body/sign/moon-phase/aspect names, and
`reading.c`'s section headers) is looked up in `i18n.c`'s translation
catalog, with the built-in English text as the fallback. `main.c` loads
the catalog from `--lang`/`--i18n-dir` (or `run.sh`'s `lang=` property)
before calling `reading_generate`, so this is orthogonal to the three
computations above — it only affects how their results are rendered as
text, not the underlying `TarotCard`/`ZodiacSign`/etc. enum values.
the catalog from `--lang`/`--i18n-dir` (or `run-engine.sh`'s `lang=`
property) before calling `reading_generate`, so this is orthogonal to
the three computations above — it only affects how their results are
rendered as text, not the underlying `TarotCard`/`ZodiacSign`/etc. enum
values.
Both entry points (direct CLI flags, or `run.sh` pulling the seed/date
from the OS clock and birth data from `user.properties`) converge on the
same `main.c` argument parsing before calling `reading_generate` — there
is exactly one code path from parsed input to a reading.
Both entry points (direct CLI flags, or `run-engine.sh` pulling the
seed/date from the OS clock and birth data from `user.properties`)
converge on the same `main.c` argument parsing before calling
`reading_generate` — there is exactly one code path from parsed input to
a reading. `run-interpreter.sh` reuses those same OS-clock/`user.properties`
inputs, but calls `deck-engine --format json` and pipes the result into
`interpreter-cli` instead of printing a reading directly.
## Regenerating the diagrams
+16 -9
View File
@@ -1,8 +1,8 @@
# Input & output formats
See [`architecture.md`](architecture.md) for how these fit together.
There are two ways to provide input (direct CLI flags, or `run.sh` +
`user.properties`) and three output formats (`text`, `html`, `json`); the
There are two ways to provide input (direct CLI flags, or `run-engine.sh`
+ `user.properties`) and three output formats (`text`, `html`, `json`); the
`DailyReading` struct is the programmatic form all three are rendered
from, and the one the future watchapp will consume directly. `json` is
also `interpreter-cli`'s input format — see "The interpreter" at the
@@ -34,9 +34,10 @@ deck-engine --seed <string> --birth-date YYYY-MM-DD --birth-time HH:MM
Birth latitude/longitude only affect the Ascendant/houses — planet signs
are geocentric and location-independent.
### `run.sh` + `user.properties`
### `run-engine.sh` + `user.properties`
`dist/run.sh [text|html] [lang]` wraps the binary for daily use:
`dist/run-engine.sh [text|html|json] [lang]` wraps the binary for daily
use:
- **Seed and `--date`** come from the OS clock: `date +%Y-%m-%d` (stable
all day) and `date -u +%Y-%m-%dT%H:%M`.
@@ -55,12 +56,16 @@ are geocentric and location-independent.
The file is seeded once from `engine/scripts/user.properties.template`
with placeholder values (`YOUR_BIRTH_DATE_HERE`, etc.) and is **never
overwritten by later builds**. `run.sh` checks every birth field for an
empty value or a leftover `YOUR_` placeholder and refuses to run with a
clear error until the file is filled in; `lang` has no such check since
it always has a usable default (`en`).
overwritten by later builds**. `run-engine.sh` checks every birth field
for an empty value or a leftover `YOUR_` placeholder and refuses to run
with a clear error until the file is filled in; `lang` has no such
check since it always has a usable default (`en`).
- The optional second argument overrides `lang=` for a single run without
editing the file, e.g. `dist/run.sh html de`.
editing the file, e.g. `dist/run-engine.sh html de`.
- `dist/run-interpreter.sh` (no arguments) is the equivalent wrapper for
the interpreter: same OS clock + `user.properties` inputs, but calls
`deck-engine --format json` and pipes it straight into
`dist/interpreter-cli` — see "The interpreter" below.
### Translations (`--lang`, `dist/i18n/`)
@@ -226,6 +231,8 @@ dist/deck-engine ... --format json | dist/interpreter-cli
# or:
dist/deck-engine ... --format json > reading.json
dist/interpreter-cli reading.json
# or, for daily use (OS clock + user.properties, same inputs as run-engine.sh):
dist/run-interpreter.sh
```
- **Input**: a file path argument, or stdin if no argument (or `-`) is
-74
View File
@@ -1,74 +0,0 @@
CC ?= cc
CFLAGS ?= -std=c99 -Wall -Wextra -O2
LDLIBS := -lm
SRC_DIR := src
THIRD_PARTY := third_party/astronomy/astronomy.c
TEST_DIR := tests
BUILD_DIR := build
OBJ_DIR := $(BUILD_DIR)/obj
# Final build output lives in dist/, next to (not inside) engine/ and res/.
DIST_DIR := ../dist
DIST_IMG_DIR := $(DIST_DIR)/img
DIST_I18N_DIR := $(DIST_DIR)/i18n
RES_IMG_DIR := ../res/img
I18N_DIR := i18n
SCRIPTS_DIR := scripts
# Engine logic shared by the CLI and the test binary (no main()).
ENGINE_SRCS := $(SRC_DIR)/rng.c $(SRC_DIR)/tarot.c $(SRC_DIR)/tarot_data.c \
$(SRC_DIR)/astro.c $(SRC_DIR)/reading.c $(SRC_DIR)/i18n.c $(THIRD_PARTY)
ENGINE_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(ENGINE_SRCS))
MAIN_OBJ := $(OBJ_DIR)/$(SRC_DIR)/main.o
TEST_OBJ := $(OBJ_DIR)/$(TEST_DIR)/smoke_test.o
BINARY := $(DIST_DIR)/deck-engine
TEST_BINARY := $(BUILD_DIR)/smoke_test
.PHONY: all test clean images scripts i18n
all: $(BINARY) images scripts i18n
$(BINARY): $(ENGINE_OBJS) $(MAIN_OBJ)
@mkdir -p $(DIST_DIR)
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS)
# The HTML report expects card art at img/<file> next to the binary, so
# every build refreshes a copy alongside it (cheap: 22 small JPEGs).
images:
@mkdir -p $(DIST_IMG_DIR)
cp $(RES_IMG_DIR)/*.jpeg $(DIST_IMG_DIR)/
# The CLI expects translation files at i18n/<lang>.lang next to the
# binary (default --i18n-dir), so every build refreshes a copy alongside
# it, same as images/. Add a new language by dropping another <code>.lang
# file into engine/i18n/ - no code or Makefile change needed.
i18n:
@mkdir -p $(DIST_I18N_DIR)
cp $(I18N_DIR)/*.lang $(DIST_I18N_DIR)/
# run.sh is refreshed every build. user.properties is only seeded once
# (from the placeholder template) so a rebuild never clobbers the user's
# own filled-in birth data.
scripts:
@mkdir -p $(DIST_DIR)
cp $(SCRIPTS_DIR)/run.sh $(DIST_DIR)/run.sh
chmod +x $(DIST_DIR)/run.sh
test -f $(DIST_DIR)/user.properties || \
cp $(SCRIPTS_DIR)/user.properties.template $(DIST_DIR)/user.properties
test: $(TEST_BINARY)
./$(TEST_BINARY)
$(TEST_BINARY): $(ENGINE_OBJS) $(TEST_OBJ)
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS)
$(OBJ_DIR)/%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -rf $(BUILD_DIR) $(BINARY) $(DIST_IMG_DIR) $(DIST_I18N_DIR) $(DIST_DIR)/run.sh
# user.properties holds the user's own data - never removed by clean.
@@ -1,11 +1,12 @@
#!/bin/sh
# Runs deck-engine for "today": the tarot seed and the transit moment come
# from the OS clock, birth data comes from user.properties next to this
# script. Usage: ./run.sh [text|html] [lang]
# script. Usage: ./run-engine.sh [text|html|json] [lang]
#
# [lang] overrides user.properties' lang= for this run only (e.g.
# ./run.sh html de); omit it to use lang= from user.properties, which
# itself defaults to "en" if unset.
# ./run-engine.sh html de); omit it to use lang= from user.properties,
# which itself defaults to "en" if unset. See run-interpreter.sh for a
# significance report instead of the full reading.
set -eu
+84
View File
@@ -0,0 +1,84 @@
#!/bin/sh
# Runs deck-engine (--format json) piped straight into interpreter-cli for
# "today": same OS-clock seed/transit-moment and user.properties birth
# data as run-engine.sh, but reports how significant today's transits are
# instead of printing the full reading. Usage: ./run-interpreter.sh
#
# Requires both dist/deck-engine (built by engine/'s Makefile) and
# dist/interpreter-cli (built by interpreter/'s own Makefile) to already
# exist next to this script.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ENGINE_BINARY="$SCRIPT_DIR/deck-engine"
INTERPRETER_BINARY="$SCRIPT_DIR/interpreter-cli"
PROPERTIES_FILE="$SCRIPT_DIR/user.properties"
if [ ! -x "$ENGINE_BINARY" ]; then
echo "error: $ENGINE_BINARY not found or not executable (run 'make' in engine/ first)" >&2
exit 1
fi
if [ ! -x "$INTERPRETER_BINARY" ]; then
echo "error: $INTERPRETER_BINARY not found or not executable (run 'make' in interpreter/ first)" >&2
exit 1
fi
if [ ! -f "$PROPERTIES_FILE" ]; then
echo "error: $PROPERTIES_FILE not found" >&2
exit 1
fi
birth_date=""
birth_time=""
birth_utc_offset=""
birth_lat=""
birth_lon=""
while IFS='=' read -r key value || [ -n "$key" ]; do
key="$(printf '%s' "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
value="$(printf '%s' "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
case "$key" in
'' | '#'*) continue ;;
esac
case "$key" in
birth_date) birth_date="$value" ;;
birth_time) birth_time="$value" ;;
birth_utc_offset) birth_utc_offset="$value" ;;
birth_lat) birth_lat="$value" ;;
birth_lon) birth_lon="$value" ;;
esac
done <"$PROPERTIES_FILE"
check_set() {
case "$2" in
'' | *YOUR_*)
echo "error: $PROPERTIES_FILE: '$1' is not set - edit the file and fill in your details." >&2
exit 1
;;
esac
}
check_set birth_date "$birth_date"
check_set birth_time "$birth_time"
check_set birth_utc_offset "$birth_utc_offset"
check_set birth_lat "$birth_lat"
check_set birth_lon "$birth_lon"
# OS-provided inputs: today's date is the tarot seed (stable all day, a
# new spread each day), current UTC time drives today's transits. The
# tarot seed doesn't matter for --format json (only "transits" is read
# downstream) but it's kept identical to run-engine.sh's for consistency.
seed="$(date +%Y-%m-%d)"
transit_date="$(date -u +%Y-%m-%dT%H:%M)"
"$ENGINE_BINARY" \
--seed "$seed" \
--birth-date "$birth_date" \
--birth-time "$birth_time" \
--birth-utc-offset "$birth_utc_offset" \
--birth-lat "$birth_lat" \
--birth-lon "$birth_lon" \
--date "$transit_date" \
--format json \
| exec "$INTERPRETER_BINARY"
+2 -1
View File
@@ -1,6 +1,7 @@
# deck-in-a-dash user properties
#
# Fill in your birth details below, then run ./run.sh (or ./run.sh html).
# Fill in your birth details below, then run ./run-engine.sh (or
# ./run-engine.sh html).
# This file is only copied here once by the build - it will not be
# overwritten by later builds, so it's safe to edit in place.
#
+5 -5
View File
@@ -137,13 +137,13 @@ static void test_reading_print_json_shape(void) {
printf("PASS test_reading_print_json_shape\n");
}
/* Run with cwd == engine/ (as `make test` does), so the shipped
* engine/i18n/ .lang files are reachable as i18n/<code>.lang. */
/* Run with cwd == repo root (as `make test` does), so the shipped
* engine/i18n/ .lang files are reachable at that path. */
static void test_i18n_fallback_and_translation(void) {
/* No catalog loaded yet: every lookup returns the caller's fallback. */
assert(strcmp(i18n_get("does.not.exist", "fallback text"), "fallback text") == 0);
bool loaded = i18n_load("i18n/de.lang");
bool loaded = i18n_load("engine/i18n/de.lang");
assert(loaded && "expected engine/i18n/de.lang to exist and load");
assert(strcmp(i18n_get("body.sun", "Sun"), "Sonne") == 0);
assert(strcmp(i18n_get("does.not.exist", "fallback text"), "fallback text") == 0);
@@ -158,11 +158,11 @@ static void test_i18n_fallback_and_translation(void) {
/* Loading a file that doesn't exist fails and leaves the previously
* loaded catalog in place, rather than silently clearing it. */
assert(!i18n_load("i18n/does-not-exist.lang"));
assert(!i18n_load("engine/i18n/does-not-exist.lang"));
assert(strcmp(i18n_get("body.sun", "Sun"), "Sonne") == 0);
/* Loading a different language replaces the catalog wholesale. */
loaded = i18n_load("i18n/en.lang");
loaded = i18n_load("engine/i18n/en.lang");
assert(loaded);
assert(strcmp(astro_body_name(PLANET_MOON), "Moon") == 0);
-54
View File
@@ -1,54 +0,0 @@
CC ?= cc
CFLAGS ?= -std=c99 -Wall -Wextra -O2
SRC_DIR := src
TEST_DIR := tests
BUILD_DIR := build
OBJ_DIR := $(BUILD_DIR)/obj
# Shares deck-engine's build output directory (see ../engine/Makefile),
# so a daily run can find both binaries in one place:
# dist/deck-engine ... --format json | dist/interpreter-cli
DIST_DIR := ../dist
BINARY := $(DIST_DIR)/interpreter-cli
# Only ever compiles this module's own sources - significance.h/
# reading_io.h reach into engine/src/ for struct/enum *definitions*
# (plain #includes), but no engine/src/*.c (or the vendored Astronomy
# Engine) is compiled or linked here. That's what keeps this module (and
# its tests) independent of the engine's actual ephemeris/tarot-draw
# implementation - see significance.c's and reading_io.c's own comments
# for why each duplicates a small table instead of linking astro.c.
LIB_SRCS := $(SRC_DIR)/significance.c $(SRC_DIR)/json.c $(SRC_DIR)/reading_io.c
LIB_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(LIB_SRCS))
MAIN_OBJ := $(OBJ_DIR)/$(SRC_DIR)/main.o
SIGNIFICANCE_TEST_OBJ := $(OBJ_DIR)/$(TEST_DIR)/significance_test.o
JSON_TEST_OBJ := $(OBJ_DIR)/$(TEST_DIR)/json_test.o
SIGNIFICANCE_TEST_BIN := $(BUILD_DIR)/significance_test
JSON_TEST_BIN := $(BUILD_DIR)/json_test
.PHONY: all test clean
all: $(BINARY)
$(BINARY): $(LIB_OBJS) $(MAIN_OBJ)
@mkdir -p $(DIST_DIR)
$(CC) $(CFLAGS) -o $@ $^
test: $(SIGNIFICANCE_TEST_BIN) $(JSON_TEST_BIN)
./$(SIGNIFICANCE_TEST_BIN)
./$(JSON_TEST_BIN)
$(SIGNIFICANCE_TEST_BIN): $(OBJ_DIR)/$(SRC_DIR)/significance.o $(SIGNIFICANCE_TEST_OBJ)
$(CC) $(CFLAGS) -o $@ $^
$(JSON_TEST_BIN): $(OBJ_DIR)/$(SRC_DIR)/json.o $(OBJ_DIR)/$(SRC_DIR)/reading_io.o $(JSON_TEST_OBJ)
$(CC) $(CFLAGS) -o $@ $^
$(OBJ_DIR)/%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -rf $(BUILD_DIR) $(BINARY)