Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions en/xclang/design/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,10 @@ its C compiler and linker. Every toolchain archive carries it, as

| item | status |
|---|---|
| <a id="libc-on-demand"></a>libc++, libc++abi and libunwind built from source on demand | Planned |
| <a id="msan"></a>MemorySanitizer, through libc++ built on demand | Planned |
| <a id="libc-on-demand"></a>libc++, libc++abi and libunwind built from source on demand | Unreleased |
| <a id="msan"></a>MemorySanitizer, through libc++ built on demand | Unreleased |
| <a id="runtimes-msvc"></a>Runtimes from source for the MSVC targets | Planned |
| <a id="runtimes-bazel-lto"></a>LTO of the runtimes from source with the program, in Bazel | Considered |
| <a id="mingw-sanitizers"></a>Sanitizers for MinGW targets | Considered |
| <a id="musl-sanitizers"></a>ASan, TSan, LSan and libFuzzer for musl targets, with a dynamically linked musl (Alpine's way) | Considered |
| <a id="bazel-gsymutil"></a>`@xclang//bazel:llvm-gsymutil`, the toolchain's llvm-gsymutil for `bazel run` | Supported |
Expand All @@ -187,16 +189,29 @@ its C compiler and linker. Every toolchain archive carries it, as

**libc++ built on demand** means libc++, libc++abi and libunwind built from
source inside a CMake or Bazel build, from LLVM's runtime sources of the
release, with its [patches](../reference/patches.md). It covers what the
prebuilt runtimes cannot be:

- **MemorySanitizer**, which needs every library instrumented, libc++ too.
ThreadSanitizer also reports better through an instrumented libc++.
release, with its [patches](../reference/patches.md), which every toolchain
carries in `libc++/src`
([runtimes from source](../features/runtimes-from-source.md)). On `main`,
the CMake package's toolchain file (`XCLANG_RUNTIMES=source`) and the Bazel
module (`--@xclang//runtimes:source`) build them for every target but the
MSVC ones. They cover what the prebuilt runtimes cannot be:

- **MemorySanitizer**, which needs every library instrumented, libc++ too,
and compiler-rt's runtime of it, built with them. ThreadSanitizer and
AddressSanitizer also report through an instrumented libc++.
- **Hardening and ABI options**: a hardening mode checked inside the
library, libc++'s ABI version 2, bounded iterators, an ABI namespace of
one's own, and builds without exceptions or RTTI.
- **LTO and PGO** of libc++ together with the program.
- **Targets without prebuilt runtimes**: tier 3 ones and Apple's devices.
- **LTO** of libc++ together with the program, in CMake builds. Bazel runs
ThinLTO's backends only for the objects of the libraries it knows, which
the runtimes, linked by the toolchain, are not: making them such
libraries is considered.
- **Targets without prebuilt runtimes**: tier 3 ones and Apple's devices,
once they are targets.

The MSVC targets' libc++ builds on Microsoft's C++ ABI library with
clang-cl, against the fetched SDK; building it from source there is
planned.

The prebuilt runtimes stay the default.

Expand Down
28 changes: 26 additions & 2 deletions en/xclang/dev/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ rest are called by them, by release.yml, or started by hand.
|---|---|---|---|---|---|
| docs.yml | every push and pull request, by itself | | | | `tests/docs/docs.ts` and the types (`npm run check`); on `main`, then publishing to docs.clice.io |
| test-archives.yml | `tests/toolchain`, `tests/libclang`, `toolchain/config` | stage `test` | | | `tests/toolchain/smoke.ts` and `tests/libclang/libclang.ts` on a machine of each host; the programs the smoke test builds for other targets run on those (on-target.yml); with `repack-of`, `tests/release/repack.ts`: each host's archives against those of the release repacked (or of an earlier run of the same revision, which a full rebuild must give again), file by file, only the packaging's files differ |
| test-cmake.yml | `packages/cmake`, `tests/cmake`, `tests/libclang` | stage `cmake` | the tag fetched from GitHub | | `tests/cmake/cmake.ts`: the package by `PATH`, through the toolchain file, and from FetchContent |
| test-bazel.yml | `packages/bazel`, `tests/bazel` | stage `bazel`: `tests/bazel` only | ✓ | ✓ | `tests/bazel` with the module, `tests/bazel/bazel.ts`, and cross builds run on the target (`tests/bazel/cross.ts`) |
| test-cmake.yml | `packages/cmake`, `tests/cmake`, `tests/libclang`, `toolchain/runtimes-src.ts`, `toolchain/cmake/caches` | stage `cmake` | the tag fetched from GitHub | | `tests/cmake/cmake.ts`: the package by `PATH`, through the toolchain file, from FetchContent, and with the runtimes from source; their programs for other targets run there (on-target.yml) |
| test-bazel.yml | `packages/bazel`, `tests/bazel`, `toolchain/runtimes-src.ts` | stage `bazel`: `tests/bazel` and the runtimes from source | ✓ | ✓ | `tests/bazel` with the module, `tests/bazel/bazel.ts`, the runtimes from source (`tests/bazel/runtimes.ts`), and cross builds run on the target (`tests/bazel/cross.ts`) |
| test-sdk.yml | `tests/sdk`, `toolchain/config`, `packages/cmake` | stage `sdk`; needs `cli`, as the archives' `xclang` fetches the SDKs | | | the MSVC targets (`tests/sdk/msvc.ts`) and the macOS targets from Linux and Windows hosts (`tests/sdk/macos.ts`); their programs on Windows and Macs |
| cli.yml | `xclang`, `tests/cli`, `tests/sdk` | the build, for stage `package`; stage `cli` | | ✓ | the `xclang` command: rustfmt, clippy, unit tests, `tests/cli/cli.ts`, `tests/cli/cargo.ts` |
| examples.yml | `examples` | | once conda.clice.io has the release and `latest` names it | ✓ | the commands and `examples/` of the docs, as written; the programs for other targets on their runners |
Expand Down Expand Up @@ -164,6 +164,19 @@ Ninja 1.11, and with the newest of both:
downloads `SHA256SUMS` and the host toolchain.
4. `tests/libclang` with the ThinLTO cache. A second link takes every
module's code from the cache, and the program is the same.
5. **The runtimes from source**, with a toolchain that has their sources
(the archives action adds this checkout's to a release before them):
`tests/cmake/runtimes` once per variant, through the toolchain file.
With no options they are the prebuilt runtimes again: the same
`__config_site` and module sources, and for Linux and MinGW the same
code. A hardening mode traps on a read past a vector's end; an ABI
namespace and ABI macros of its own, without exceptions and RTTI, name
the code of `import std` in the program; on Linux x64, MemorySanitizer
reports a use of uninitialized memory inside libc++ and nothing of what
libc++ itself writes, and libc++ of ThinLTO is bitcode. From Linux x64
(to Linux arm64 and both MinGW targets) and arm64 macOS (to x86_64
macOS), with the newest CMake, the hardening variant's programs run on a
machine of the target (on-target.yml).

`tests/cmake` covers a C++ module of partitions, `xclang::std` with
`std.compat`, `xclang_add_std` with `-fno-exceptions`, and
Expand Down Expand Up @@ -216,6 +229,17 @@ and libclang; a Linux host runs the musl tests of its architecture
`modules_embed_all_files`, an importer cannot open the source of the
module it imports.

`tests/bazel/runtimes.ts`, after them, builds `tests/bazel/runtimes` with the
runtimes from source (`--@xclang//runtimes:source`), with a toolchain that
has their sources, once per variant: with no options, the prebuilt
`__config_site` again; a hardening mode that traps; an ABI namespace and
ABI macros without exceptions and RTTI, which the code of `import std` is
named with; on Linux x64, `--features=msan` reporting inside libc++ and not
on what it writes, and `--features=thin_lto`. From Linux x64 and arm64
macOS, the hardening variant for other targets runs on their machines.
`packages/bazel/runtimes.ts check` (by hand) says whether
`runtimes_sources.bzl` is still what LLVM's CMake build compiles.

test-bazel.yml's cross jobs build `tests/bazel` on every host for every
other target, and run its tests on a runner of that target. Its sdk jobs do
the same for the targets of the vendor SDKs, the module accepting their
Expand Down
152 changes: 152 additions & 0 deletions en/xclang/features/runtimes-from-source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# C++ Runtimes from Source

xclang's prebuilt C++ runtimes are one build of libc++, libc++abi and
libunwind per target: no hardening mode, ABI version 1, exceptions and
RTTI, no instrumentation but the ASan libc++
([sanitizers](sanitizers.md)). A CMake or Bazel build can instead compile
them from the sources every toolchain carries, with options of its own, and
link its programs against those. This is for what the prebuilt runtimes
cannot be:

- **MemorySanitizer**, which needs every library instrumented, libc++ too,
and compiler-rt's runtime of it, which the toolchain does not carry.
ThreadSanitizer and AddressSanitizer report through an instrumented
libc++ too.
- **libc++'s hardening modes**, checked inside the library as well as in
its headers.
- **ABI options**: libc++'s ABI version 2, bounded iterators, an inline
namespace of one's own.
- **No exceptions, no RTTI** in libc++ and libc++abi.
- **LTO of libc++ with the program** (CMake).

The prebuilt runtimes stay the default. Runtimes from source are in no
release yet ([Unreleased](../design/roadmap.md#libc-on-demand)); the
toolchains of the release after 23.1.2.10 carry the sources.

## Usage

### CMake

The option is the toolchain file's, `XCLANG_RUNTIMES=source`, with
libc++'s options next to it:

<!-- not run: in no release yet; tests/cmake/cmake.ts builds the same variants (test-cmake.yml) -->
```sh
cmake -G Ninja -B build --toolchain "$XCLANG/lib/cmake/xclang/toolchain.cmake" \
-DXCLANG_RUNTIMES=source -DXCLANG_LIBCXX_HARDENING=fast
cmake --build build
```

The first configure builds the variant, about half a minute on four cores,
into `build/xclang-runtimes/<target>-<digest>`; later configures use it, and
other options make another variant beside it. Every compile and link of the
build is against it, CMake's own checks too, and `xclang::std` is built
from its modules. A MemorySanitizer build, which builds compiler-rt's
runtime of it first:

<!-- not run: in no release yet; tests/cmake/cmake.ts builds the same on Linux x64 (test-cmake.yml) -->
```sh
cmake -G Ninja -B build-msan --toolchain "$XCLANG/lib/cmake/xclang/toolchain.cmake" \
-DXCLANG_RUNTIMES=source -DXCLANG_SANITIZER=memory -DCMAKE_BUILD_TYPE=RelWithDebInfo
```

`XCLANG_SANITIZER` gives the whole build its `-fsanitize=` and runtimes
that suit it, so the project's flags need no `-fsanitize=` of their own.
With the prebuilt runtimes it works too, for the sanitizers they have:
`address` then links the prebuilt ASan libc++.

For another target, add `-DXCLANG_TARGET=<target>`: the variant is built for
it, by the same toolchain file.

### Bazel

The flags of the whole build are in `@xclang//runtimes`, and the
sanitizers are the features they always were:

<!-- not run: in no release yet; tests/bazel/runtimes.ts builds the same variants (test-bazel.yml) -->
```sh
bazel build --@xclang//runtimes:source --@xclang//runtimes:hardening=fast //...
bazel test --@xclang//runtimes:source --features=msan //...
```

The runtimes are libraries of the toolchain's repository, compiled for the
target platform with the build's features (a sanitizer's instrumentation)
and `--copt`, and cached as any other action. A `.bazelrc` names the
variants a project uses:

```text
build:msan --@xclang//runtimes:source --features=msan
build:hardened --@xclang//runtimes:source --@xclang//runtimes:hardening=extensive
```

## Options

| | CMake (toolchain file) | Bazel |
|---|---|---|
| runtimes from source | `XCLANG_RUNTIMES=source` | `--@xclang//runtimes:source` |
| libc++'s hardening mode: `none`, `fast`, `extensive`, `debug` | `XCLANG_LIBCXX_HARDENING` | `--@xclang//runtimes:hardening` |
| libc++'s ABI version, `1` or `2` | `XCLANG_LIBCXX_ABI_VERSION` | `--@xclang//runtimes:abi_version` |
| libc++'s inline namespace, `__<name>` | `XCLANG_LIBCXX_ABI_NAMESPACE` | `--@xclang//runtimes:abi_namespace` |
| libc++'s ABI macros, `_LIBCPP_ABI_*` | `XCLANG_LIBCXX_ABI_DEFINES` (a list) | `--@xclang//runtimes:abi_defines` (comma-separated) |
| libc++ and libc++abi without exceptions | `XCLANG_RUNTIMES_EXCEPTIONS=OFF` | `--@xclang//runtimes:exceptions=false` |
| libc++ without RTTI (and without exceptions) | `XCLANG_RUNTIMES_RTTI=OFF` | `--@xclang//runtimes:rtti=false` |
| sanitizers: `address`, `memory`, `thread`, `undefined`, `leak` | `XCLANG_SANITIZER` | `--features=asan`, `msan`, `tsan`, `ubsan`, `lsan` |
| more compile options of libc++ and libc++abi | `XCLANG_RUNTIMES_FLAGS` | the build's `--copt` |
| LTO of libc++ with the program | `XCLANG_RUNTIMES_FLAGS=-flto=thin` | not available |
| more options of LLVM's CMake build | `XCLANG_RUNTIMES_CMAKE_ARGS` | |
| where the variants are built | `XCLANG_RUNTIMES_DIR` | Bazel's output base and caches |

The program's own options are its own: a build without exceptions passes
`-fno-exceptions` (`CMAKE_CXX_FLAGS`, `--copt`) as well. The
[CMake API](../reference/cmake-api.md#runtimes-from-source) and the
[Bazel API](../reference/bazel-api.md#runtimes-from-source) list them again.

## Behavior

- **The same build as the prebuilt runtimes.** CMake builds LLVM's
`runtimes/` with the CMake cache and options of xclang's own build of
the runtimes, by the toolchain file and the config file of the target.
With no options, the result is the prebuilt runtimes: the same
`__config_site`, and the same code. Bazel compiles the same translation
units with the same flags, which `packages/bazel/runtimes.ts` takes from
LLVM's CMake build of every target.
- **What is built**: libc++ with libc++abi in it, libc++experimental, and
libunwind (none for macOS, which unwinds with the system's). With
MemorySanitizer, compiler-rt's runtime of it.
- **In place of the prebuilt ones.** The variant's `__config_site` comes
before libc++'s other headers, and its libraries are linked instead of
the prebuilt ones (`-nostdlib++`). `import std` follows the variant:
`xclang::std` and `@xclang//bazel:std` are built from it.
- **libunwind stays uninstrumented** with sanitizers, as in the prebuilt
ASan libc++: the sanitizers' runtimes unwind with it, and MemorySanitizer
would report the registers it reads.
- **MemorySanitizer is for the Linux targets** (glibc), x64 and arm64. Its
runtime is linked into executables as clang links the others, whole, with
its interface exported.
- **Every library of a program must use the same variant.** A library
built against the prebuilt runtimes, with another ABI namespace, ABI
version or set of ABI macros, does not link, or breaks at run time; under
MemorySanitizer, its code reports what it was not instrumented to see.
- **Bazel does not run ThinLTO on the runtimes**: `--features=thin_lto`
links programs of ThinLTO against runtimes of native code. Bazel's ThinLTO
backends compile the objects of the libraries it knows, and the toolchain
links the runtimes' by their paths.
- **CMake needs Python 3**, as LLVM's build of the runtimes does. Bazel
needs nothing more.

## The Sources

Every toolchain directory has the sources once, for every target, in
`libc++/src`, next to libc++'s headers: llvm-project's own layout
(`runtimes/`, `cmake/`, `llvm/cmake/`, `libcxx/`, `libcxxabi/`,
`libunwind/`, `compiler-rt/`, and the headers of LLVM's libc that libc++
includes), without tests and documentation, with xclang's
[patches](../reference/patches.md) of libc++ applied. They are 35 MB
unpacked, 2.3 MB of each archive.

## Not Yet Supported

| | status |
|---|---|
| [Runtimes from source for the MSVC targets](../design/roadmap.md#runtimes-msvc) | Planned |
| [LTO of the runtimes with the program in Bazel](../design/roadmap.md#runtimes-bazel-lto) | Considered |
11 changes: 7 additions & 4 deletions en/xclang/features/sanitizers.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,12 @@ clang++ --target=x86_64-unknown-linux-musl -fsanitize=undefined -O1 ubsan.cpp -o
|---|---|
| [Sanitizers for MinGW targets](../design/roadmap.md#mingw-sanitizers) | Considered |
| [ASan, TSan, LSan and libFuzzer for musl targets](../design/roadmap.md#musl-sanitizers) | Considered |
| [MemorySanitizer](../design/roadmap.md#msan) | Planned |
| [MemorySanitizer](../design/roadmap.md#msan) | Unreleased |

MemorySanitizer needs every library instrumented, libc++ too, and
ThreadSanitizer reports better through an instrumented libc++. Both need
libc++ built from source with the options of the program, which is
[planned](../design/roadmap.md#libc-on-demand).
compiler-rt's runtime of it, which the toolchain does not carry. On `main`,
the runtimes built from source give it both, for the Linux targets
([runtimes from source](runtimes-from-source.md)): `XCLANG_RUNTIMES=source`
with `XCLANG_SANITIZER=memory` in CMake, `--@xclang//runtimes:source` with
`--features=msan` in Bazel. ThreadSanitizer and AddressSanitizer report
through runtimes from source as well, instrumented like the program.
2 changes: 1 addition & 1 deletion en/xclang/guide/comparisons.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ libclang.
| [Android](../design/roadmap.md#android), [WebAssembly](../design/roadmap.md#wasm), [the BSDs](../design/roadmap.md#freebsd), [bare metal](../design/roadmap.md#bare-metal) | Considered | the NDK, wasi-sdk, zig cc |
| [iOS and Apple's other devices](../design/roadmap.md#ios) | In research | Xcode |
| [Windows 7 and XP](../design/roadmap.md#windows-7) | In research | llvm-mingw's msvcrt variant |
| [Runtimes built from source with other options: MemorySanitizer, libc++ hardening, an ABI of one's own](../design/roadmap.md#libc-on-demand) | Planned | zig cc builds its runtimes on first use |
| [Runtimes built from source with other options: MemorySanitizer, libc++ hardening, an ABI of one's own](../design/roadmap.md#libc-on-demand) | Unreleased | zig cc builds its runtimes on first use |

## Known Limitations

Expand Down
2 changes: 1 addition & 1 deletion en/xclang/guide/why-xclang.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ FetchContent or the Bazel registry.
| | status |
|---|---|
| [More Linux architectures, WebAssembly, Android, BSDs, bare metal](../design/roadmap.md#targets) | Considered |
| [MemorySanitizer, through libc++ built on demand](../design/roadmap.md#msan) | Planned |
| [MemorySanitizer, through libc++ built on demand](../design/roadmap.md#msan) | Unreleased |
| [Sanitizers for MinGW targets](../design/roadmap.md#mingw-sanitizers) | Considered |
| [Relative debug paths in CMake builds](../design/roadmap.md#cmake-relative-paths) | Planned |
| [Immutable releases](../design/roadmap.md#immutable-releases) | Planned |
Expand Down
7 changes: 7 additions & 0 deletions en/xclang/integrations/bazel.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ sanitizers. The MSVC targets have `ubsan`, and x64 also has `asan`. ASan's
runtime there is a DLL, which a program finds beside itself or on `PATH`
([MSVC targets](../features/sanitizers.md#msvc-targets)).

With `--@xclang//runtimes:source`, libc++, libc++abi and libunwind are
built from the toolchain's sources, instrumented by the build's sanitizer
features, and `msan` works too, for the Linux targets
([runtimes from source](../features/runtimes-from-source.md#bazel)); the
same flag takes libc++'s hardening and ABI options. It is in no release
yet.

## Debug in gdb, lldb and VS Code

Every path in the debug information is relative to the execution root
Expand Down
10 changes: 10 additions & 0 deletions en/xclang/integrations/cmake.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ importer's ([matching options](../features/modules.md#behavior)). So:
Before putting ccache in front of the compiler, read
[build caches and modules](../features/modules.md#build-caches-and-modules).

## Build the C++ Runtimes from Source

With the toolchain file, `-DXCLANG_RUNTIMES=source` builds libc++,
libc++abi and libunwind from the toolchain's sources at the first
configure, with options the prebuilt ones lack: MemorySanitizer
(`-DXCLANG_SANITIZER=memory`), libc++'s hardening modes, ABI options, no
exceptions. The whole build, `xclang::std` included, is then against
them. It is in no release yet
([runtimes from source](../features/runtimes-from-source.md#cmake)).

## Ship Debug Symbols

`xclang_debug_symbols(<program>)` makes the debug symbols of a program
Expand Down
Loading
Loading