fix: toolchain - update docs
This commit is contained in:
+78
-4
@@ -38,9 +38,80 @@ What the target does by default:
|
|||||||
wanted.
|
wanted.
|
||||||
- Defines `__montauk__` / `__MONTAUK__`.
|
- Defines `__montauk__` / `__MONTAUK__`.
|
||||||
|
|
||||||
C++ works with `-fno-exceptions -fno-rtti` (the project convention).
|
The in-tree programs are built `-fno-exceptions -fno-rtti` (the project
|
||||||
There is no libstdc++ yet — only libgcc is built. A hosted libstdc++
|
convention), but that is a project style choice, not a toolchain limit —
|
||||||
needs a more complete libc and is the next step toward self-hosting.
|
see the STL section below.
|
||||||
|
|
||||||
|
## C++ standard library (hosted libstdc++)
|
||||||
|
|
||||||
|
`build-montauk-toolchain.sh` builds and installs a **hosted** libstdc++
|
||||||
|
(`all-target-libstdc++-v3`), so the full STL is available to
|
||||||
|
`x86_64-montauk-g++` with no special flags:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolchain/local/bin/x86_64-montauk-g++ app.cpp -o app.elf
|
||||||
|
```
|
||||||
|
|
||||||
|
Headers live in `toolchain/local/x86_64-montauk/include/c++/14.2.0/`,
|
||||||
|
the library in `toolchain/local/x86_64-montauk/lib/libstdc++.a`.
|
||||||
|
`_GLIBCXX_HOSTED` follows `__STDC_HOSTED__`, i.e. 1 for ordinary
|
||||||
|
compiles.
|
||||||
|
|
||||||
|
Note that `toolchain/sysroot/usr/include/` *also* holds a freestanding
|
||||||
|
C++ subset (copied from `kernel/freestnd-cxx-hdrs`, which is what the
|
||||||
|
kernel and the in-tree programs build against). That directory is last
|
||||||
|
on the include search path, so for a plain `g++` invocation the hosted
|
||||||
|
headers win and the freestanding copies are shadowed. Check
|
||||||
|
`g++ -x c++ -E -v -` if you ever need to confirm the order.
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
Link-verified with the cross compiler, no flags beyond the source file:
|
||||||
|
|
||||||
|
| Feature | Status |
|
||||||
|
|---------|--------|
|
||||||
|
| `<string>`, `<vector>`, `<map>`, `<algorithm>` | works |
|
||||||
|
| `<memory>` (`unique_ptr`, `shared_ptr`, `make_*`) | works |
|
||||||
|
| Exceptions (`throw` / `catch`, `std::exception`) | works |
|
||||||
|
| RTTI (`typeid`, `dynamic_cast`) | works |
|
||||||
|
| `<iostream>`, `<sstream>` | works (links a large binary — see below) |
|
||||||
|
| Static constructors | works (`crt1.c` runs `.init_array`) |
|
||||||
|
|
||||||
|
`toolchain/files/cxx-test.cpp` is the on-OS regression check for this;
|
||||||
|
`make devkit` compiles it to `0:/sdk/bin/cxx-test.elf`. Run it on the
|
||||||
|
target to confirm the above at **runtime** rather than just at link
|
||||||
|
time — that is the authoritative check, since a clean link does not by
|
||||||
|
itself prove exception unwinding works on hardware.
|
||||||
|
|
||||||
|
### What does not work
|
||||||
|
|
||||||
|
- **Threads.** libstdc++ is built `gthr-single`
|
||||||
|
(`_GLIBCXX_HAS_GTHREADS` is undefined), because the libc has no
|
||||||
|
pthreads. `std::thread`, `std::mutex`, `std::condition_variable`,
|
||||||
|
`std::async` and `std::call_once` do not exist — code using them
|
||||||
|
fails to *compile*, not to link.
|
||||||
|
|
||||||
|
Consequence worth knowing: in single-threaded mode libstdc++ selects
|
||||||
|
the **non-atomic** `shared_ptr` refcount path. The kernel does have
|
||||||
|
real threads (`SYS_THREAD_SPAWN/EXIT/JOIN/SELF`,
|
||||||
|
`programs/include/montauk/thread.h`), so it is possible to spawn
|
||||||
|
threads and share a `shared_ptr` across them — that will corrupt the
|
||||||
|
refcount and is a silent use-after-free. Do not do it until a
|
||||||
|
pthreads/gthreads shim exists and libstdc++ is rebuilt against it.
|
||||||
|
|
||||||
|
- **`<iostream>` is expensive.** It drags in the static locale and
|
||||||
|
iostream init machinery; a hello-world using it links to roughly
|
||||||
|
5.7 MB versus ~1.8 MB for `<string>` + `<vector>`. Prefer `<cstdio>`
|
||||||
|
where binary size matters, which on a ramdisk image is most places.
|
||||||
|
|
||||||
|
- **`libm.a` is an empty stand-in.** The math functions live inside
|
||||||
|
`libc.a` (the g++ driver links `-lm` unconditionally, hence the empty
|
||||||
|
archive). Roughly 50 functions are present — `sqrt`, `sin`, `cos`,
|
||||||
|
`pow`, `log`, `exp`, `atan2`, `hypot`, `floor`, `ceil`, `fmod`,
|
||||||
|
`round` and some `float` variants. Absent: `fma`, `cbrt`, `expm1`,
|
||||||
|
`log1p`, `erf`, `tgamma`, `nearbyint`, `remquo`, most remaining
|
||||||
|
`float` variants, and all `long double` variants. Ports that need
|
||||||
|
these have to add them to `programs/lib/libc/libc.c`.
|
||||||
|
|
||||||
## Refreshing the sysroot
|
## Refreshing the sysroot
|
||||||
|
|
||||||
@@ -146,7 +217,10 @@ Notes:
|
|||||||
- The `devkit` target in programs/GNUmakefile ships the staged tools
|
- The `devkit` target in programs/GNUmakefile ships the staged tools
|
||||||
into the OS image at 0:/sdk/bin (as.elf, ld.elf, ar.elf, ...) with a
|
into the OS image at 0:/sdk/bin (as.elf, ld.elf, ar.elf, ...) with a
|
||||||
target-side sysroot at 0:/sdk/include + 0:/sdk/lib (libc.a, crt
|
target-side sysroot at 0:/sdk/include + 0:/sdk/lib (libc.a, crt
|
||||||
objects, empty libm/libstdc++) - the Montauk SDK. The kernel
|
objects, the real hosted libstdc++.a plus its c++/ headers, and an
|
||||||
|
empty libm stand-in) - the Montauk SDK. On-OS g++ therefore gets the
|
||||||
|
same STL as the cross compiler; see the C++ standard library section
|
||||||
|
above for what is and is not supported. The kernel
|
||||||
resolves driveless absolute paths ("/sdk/lib") against the cwd
|
resolves driveless absolute paths ("/sdk/lib") against the cwd
|
||||||
drive, so the --prefix=/sdk layout works natively. The shell
|
drive, so the --prefix=/sdk layout works natively. The shell
|
||||||
searches 0:/sdk/bin and tab-completes it. Future ports configure
|
searches 0:/sdk/bin and tab-completes it. Future ports configure
|
||||||
|
|||||||
@@ -121,8 +121,12 @@ cp -r "${REPO_DIR}/programs/include/libc/." "${SYSROOT}/usr/include/"
|
|||||||
cp -r "${REPO_DIR}/programs/include/montauk" "${SYSROOT}/usr/include/montauk"
|
cp -r "${REPO_DIR}/programs/include/montauk" "${SYSROOT}/usr/include/montauk"
|
||||||
cp -r "${REPO_DIR}/programs/include/Api" "${SYSROOT}/usr/include/Api"
|
cp -r "${REPO_DIR}/programs/include/Api" "${SYSROOT}/usr/include/Api"
|
||||||
# Freestanding C++ headers (<cstdint>, <type_traits>, <atomic>, ...) —
|
# Freestanding C++ headers (<cstdint>, <type_traits>, <atomic>, ...) —
|
||||||
# there is no hosted libstdc++ yet, so C++ programs get the same
|
# the subset the kernel and the in-tree programs build against. This is
|
||||||
# freestanding subset the rest of the tree builds against.
|
# NOT the whole C++ story: a hosted libstdc++ is built further down and
|
||||||
|
# installs its own headers under ${PREFIX}/x86_64-montauk/include/c++.
|
||||||
|
# That directory comes first on the include path and this one comes
|
||||||
|
# last, so a plain g++ invocation gets the hosted headers and these are
|
||||||
|
# shadowed. See "C++ standard library" in README.md.
|
||||||
cp -r "${REPO_DIR}/kernel/freestnd-cxx-hdrs/x86_64/include/." "${SYSROOT}/usr/include/"
|
cp -r "${REPO_DIR}/kernel/freestnd-cxx-hdrs/x86_64/include/." "${SYSROOT}/usr/include/"
|
||||||
cp "${REPO_DIR}/programs/lib/libc/crt1.o" \
|
cp "${REPO_DIR}/programs/lib/libc/crt1.o" \
|
||||||
"${REPO_DIR}/programs/lib/libc/crti.o" \
|
"${REPO_DIR}/programs/lib/libc/crti.o" \
|
||||||
@@ -161,9 +165,11 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Build GCC ─────────────────────────────────────────────────────────────────
|
# ── Build GCC ─────────────────────────────────────────────────────────────────
|
||||||
# Hosted against the Montauk libc headers in the sysroot. Only the
|
# Hosted against the Montauk libc headers in the sysroot. Builds the
|
||||||
# compiler and libgcc are built; libstdc++ needs a more complete libc
|
# compiler, libgcc, and a hosted libstdc++ (full STL: string/vector/map,
|
||||||
# (that is the self-hosting step, not the cross-toolchain step).
|
# exceptions, RTTI, iostream). libstdc++ is built gthr-single because
|
||||||
|
# the libc has no pthreads, so <thread>/<mutex> are absent and
|
||||||
|
# shared_ptr uses non-atomic refcounts. See README.md.
|
||||||
if [[ -x "${PREFIX}/bin/${TARGET}-gcc" ]]; then
|
if [[ -x "${PREFIX}/bin/${TARGET}-gcc" ]]; then
|
||||||
bold "GCC already installed — skipping."
|
bold "GCC already installed — skipping."
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user