Skip to content
Draft
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
186 changes: 186 additions & 0 deletions libc/docs/abi_policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
(abi_policy)=

# ABI and Public Header Policy

LLVM-libc defines its own ABI. This page explains how the layout of public
types is chosen, which symbols the library exports, and how public headers are
written. It applies to full builds, where LLVM-libc provides the headers. In
{ref}`overlay mode <overlay_mode>` the headers and the ABI belong to the system
libc.

See {ref}`design_philosophy` for why the project works this way.

## Nothing is frozen

LLVM-libc currently makes no ABI stability promise. The layouts of public
types, the names of internal symbols, and the values of implementation-defined
macros may change between two commits. Because the library is
{ref}`linked statically into the program it was built for <design_philosophy>`,
such a change does not break existing binaries.

This lack of stability gives the project the freedom to change the ABI without
fear of breaking users. If there's a mistake in the ABI, it can be fixed quickly
and uncontroversially.

The project intends to keep this freedom for as long as possible. A change that
would make part of the ABI hard to change later needs discussion with the
maintainers before it is written.

(choosing_type_layout)=

## Choosing the layout of a public type

When a public type is added or changed, its layout is decided by the first of
these that applies:

1. **The kernel.** If the type is passed to or received from a system call
without conversion, it must have the layout the kernel expects. `struct
timespec` and `stack_t` are examples.
2. **LLVM-libc.** Otherwise, design the type for LLVM-libc's implementation,
and convert at the system call boundary where necessary. `struct stat` is
LLVM-libc's own layout and is filled in from `statx`
(`src/__support/OSUtil/linux/stat/`). `struct sigaction` is converted to and
from the kernel's layout (`KernelSigaction` in
`src/signal/linux/signal_utils.h`).
3. **An existing implementation**, only when there is no other source of
truth. This happens when the kernel's UAPI headers are wrong or unusable
for user space, or when an interface has no real standard and one
implementation has become the de facto definition, as glibc has for
`termios`.

"A program built against another libc's headers expects this layout" is not a
reason to choose that layout. Programs that rely on details a standard does not
promise should be fixed, unless no standard exists at all.

### Opaque types

Where a standard allows a type to be opaque, keep it opaque. As an example,
LLVM-libc's `pthread_t` is a struct, which POSIX explicitly permits. Keeping it
a struct means its contents can change later without breaking correct programs.
Correct code that needs to compare thread IDs uses `pthread_equal`.

`FILE` and `DIR` are forward declarations in the public headers. Nothing
outside the library can depend on their contents.

### Widths of common types

In general it's best to have a single definition of a given type. A type that
differs between platforms requires extra care wherever it is handled. The `long`
type is an example: it is 32 or 64 bits wide depending on the target. `long` is
defined by the platform and the compiler, so LLVM-libc has to handle both
widths and cannot standardize it.

For types that are provided by LLVM-libc, it's generally preferred to use the
larger type. Smaller values will fit in larger types without issue, but the
reverse is not true.

`time_t` is 64 bits on every target, because 32-bit time ends in 2038. The
types that travel with it, such as `off_t`, `dev_t`, and `rlim_t`, are also 64
bits everywhere. This simplifies the build, and it means the `*64` variants of
file functions are not needed.

A few related types (`ino_t`, `nlink_t`, `blkcnt_t`) are still pointer width.
That is unfinished work and not a design decision.

## Feature-test macros

Public headers do not use feature-test macros such as `_GNU_SOURCE` or
`_POSIX_C_SOURCE` to hide declarations. Do not add `#ifdef` guards of that kind
to a header. The exception is a macro that a standard itself defines for this
purpose, such as `__STDC_WANT_LIB_EXT1__` for Annex K.

Headers are generated from the YAML files in `libc/include/` (see
{ref}`header_generation`), and a generated header declares only the functions
that are enabled for the target. A user who wants a different API surface
generates headers to match it, by pointing the `LIBC_CONFIG_PATH` CMake option
at their own `entrypoints.txt`, `headers.txt`, and configuration (see
{ref}`custom_config_directory`), instead of every user receiving one set of
headers full of conditionals.

Each function in the YAML files lists the `standards` it comes from (`stdc`,
`posix`, `gnu`, `bsd`, `linux`, `llvm_libc_ext`, and so on). Keep that field
accurate. It records where each declaration comes from.

## Exported symbols

Every public function is defined in the internal `LIBC_NAMESPACE` namespace and
exported under its standard C name by the `LLVM_LIBC_FUNCTION` macro (see
{ref}`implementation_standard`). The default namespace name includes the LLVM
version, and {ref}`Hand-in-Hand <hand_in_hand>` consumers compile the shared
code under a different namespace, so several copies of LLVM-libc code can be
linked into one program. Nothing may depend on the mangled names of internal
symbols.

### Aliases for another libc's symbols

LLVM-libc does not export another libc's private symbols in general.

The exception is the `LIBC_COPT_PROVIDE_GNU_ALIASES` option, which is enabled
for Linux. It provides a short list of glibc symbol names, such as
`__errno_location`, because some users must link precompiled libraries that
were built against glibc. The list is kept short deliberately. It is a
compromise for those users and not a step toward binary compatibility with
glibc. Additions need agreement from the maintainers.

Symbols that a compiler or a C++ standard library requires of any libc, such
as `__stack_chk_fail` or `__cxa_thread_atexit_impl`, are ordinary entrypoints
and are not covered by this restriction.

### Customization points

Some macros exist so that downstream users can control how LLVM-libc code is
compiled into their own library. Downstream users depend on `LIBC_INLINE` and
`LIBC_INLINE_VAR` being used on every inline function and variable, and
`LLVM_LIBC_FUNCTION_ATTR` lets a packager attach attributes to every public
function. Use these macros as documented in {ref}`code_style`, and do not
remove or bypass them.

## Kernel headers

A full build for Linux requires the kernel's UAPI headers.

A public header may include a UAPI header when that header is self-contained
and does not collide with LLVM-libc's own definitions. When a UAPI header
redefines a type LLVM-libc provides, or defines macros with different
spellings, define the needed constants and types in `llvm-libc-macros/` or
`llvm-libc-types/` instead. For example, UAPI headers that include
`<linux/fcntl.h>` redefine `struct flock` and so cannot be included.

## Dynamic loading

LLVM-libc is linked statically today. Dynamic loading is under development,
mainly so that `dlopen` can work. It is not intended to become the primary way
to use the library, and new code should be designed for the static case first.

## Other operating systems

The points above describe Linux and baremetal targets, where LLVM-libc is the
whole C library. A full build for macOS or Windows has not been designed yet.
The likely direction is for LLVM-libc to define its own API there too, shaped
appropriately for the platform, and not to reproduce POSIX on every system.

## Writing public headers

Public headers are read by every program and by compilers in every language
mode, so they are held to stricter rules than implementation code:

- A header must be valid in every C and C++ standard mode. Do not use language
features that some of those modes lack, such as attribute syntax (`[[...]]`),
which C gained only in C23.
- Names that the standard does not define must be reserved identifiers. This
includes structure members, macro parameters, and helper macros. A member
named `mutex` or a macro named `NUM_LOCALE_CATEGORIES` collides with user
code.
- Type headers in `llvm-libc-types/` define one type each and include only the
other type headers they need. Use the compiler's built-in type macros (for
example `__INT64_TYPE__`) instead of including `<stdint.h>`.

## Proposing an ABI change

To propose a non-trivial change to the layout of an existing public type or
the value of an existing public macro, or to export a symbol under a name
other than its standard one, contributors should start by reading
{ref}`choosing_type_layout`, then reach out to the maintainers with the
justification and/or write an RFC with the new design. A demo PR may be
helpful for explaining the design, but should not be expected to land without
significant changes.
30 changes: 21 additions & 9 deletions libc/docs/arch_support.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
# Architecture Support

The currently continuously tested architectures are:
The table below lists what is built and tested on every pull request.

- aarch64
- amdgpu
- arm
- nvptx
- riscv32
- riscv64
- x86_64
| Architecture | Tests run | Built only |
| --- | --- | --- |
| x86-64 | Linux (overlay and full build), Windows (overlay), FreeBSD (overlay) | UEFI |
| AArch64 | Linux (overlay and full build), macOS (overlay) | |
| 32-bit Arm | Linux (overlay, under QEMU) | Baremetal |
| 64-bit RISC-V | Linux (overlay, under QEMU) | |
| 32-bit RISC-V | | Baremetal |
| Hexagon | Baremetal | |
| AMDGPU | | GPU |

i386 support is [in the works](https://github.com/llvm/llvm-project/issues/93709).
NVPTX is also a supported GPU target. See {doc}`the GPU docs <gpu/index>` for
both GPU targets.

After a change lands, the
[postcommit buildbots](https://lab.llvm.org/buildbot/#/builders?tags=libc)
currently cover Linux on x86-64: Clang and GCC, overlay and full build, and
AddressSanitizer.

i386 support is [in the works](https://github.com/llvm/llvm-project/issues/93709),
though it may be sunset. See {ref}`platform_support` for the status of each
target.

See {doc}`Bringup on a New OS or Architecture <porting>` for more
information. Please do first file a bug in
Expand Down
25 changes: 15 additions & 10 deletions libc/docs/build_and_test.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,44 @@ The libc can be built and tested in two different modes:

1. **The overlay mode** - In this mode, one uses the static archive from LLVM's
libc along with the system libc. See {ref}`overlay_mode` for more details
on building and using the libc in this mode. You can only run the libc
unittests in this mode. To run them, one simply does:
on building and using the libc in this mode. To run the tests, one simply
does:

```sh
$> ninja check-libc
```

Note that, unittests for only those functions which are part of the overlay
Note that, tests for only those functions which are part of the overlay
static archive will be run with the above command.

2. **The full build mode** - In this mode, the libc is used as the only libc
for the user's application. See {ref}`full_host_build` for more details on
building and using the libc in this mode. Once configured for a full libc
build, you can run three kinds of tests:
build, the same command builds the tests against LLVM-libc's own headers
and startup code and runs them:

1. Unit tests - You can run unittests by the command:
```sh
$> ninja check-libc
```

```sh
$> ninja check-libc
```
Subsets of the tests have their own targets:

2. Integration tests - You can run integration tests by the command:
1. Integration tests - You can run integration tests by the command:

```sh
$> ninja libc-integration-tests
```

3. Shared tests - You can run tests for shared, standalone components (like math primitives) without needing the full libc runtime by the command:
2. Shared tests - You can run tests for shared, standalone components (like math primitives) without needing the full libc runtime by the command:

```sh
$> ninja libc-shared-tests
```

A change should be tested in both modes. See {ref}`testing_guide` for the
kinds of tests, how to run a single test, and how to confirm that a test was
not silently skipped.

## Building with VSCode

As a quickstart to using VSCode for development, install the cmake extension
Expand Down
6 changes: 6 additions & 0 deletions libc/docs/compiler_support.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ is required it is possible to bootstrap `Clang` with `GCC` and then use

- `Clang 11`
- `GCC 12.2`

Code that is shared with other LLVM projects through
{ref}`Hand-in-Hand <hand_in_hand>` is compiled as part of those projects, so
it must also build with the
[host compilers LLVM supports](https://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library),
which are older.
73 changes: 72 additions & 1 deletion libc/docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ a list of open projects that one can start with:
issue" by the team as potentially easier places to get started. Please do
first check if the bug has an assignee; if so please find another unless
there's been no movement on the issue from the assignee, in which place do
ask if you can help take over.
ask if you can help take over. Remember to follow the LLVM
[AI Tool Use Policy](https://llvm.org/docs/AIToolPolicy.html) which forbids
using LLMs for good first issues.
2. **Cleanup code-style** - The libc project follows the general
[LLVM style](https://llvm.org/docs/CodingStandards.html) with specific
conventions for naming (`snake_case` for functions, `CamelCase` for
Expand All @@ -39,3 +41,72 @@ a list of open projects that one can start with:
6. **Contribute a new OS/Architecture port** - You can contribute a new
operating system or target architecture port. See {ref}`porting` for more
information.

## Before you start

Read {ref}`design_philosophy` and {ref}`abi_policy` to understand what the
project is and is not trying to do. Read {ref}`patterns_to_avoid` before
modelling new code on something that is already in the tree, because older
code does not always follow the current conventions.

Some changes are worth discussing with the maintainers before investing in an
implementation:

- a non-trivial change to the layout of an existing public type or the value
of an existing public macro, or exporting a symbol under a name other than
its standard one (see {ref}`abi_policy`),
- a function that is not in the C or POSIX standards,
- a new configuration option,
- new code under `libc/shared/`, or a new user of it,
- any code written in assembly,
- any intentional deviation from a standard.

The easiest way to reach out is to ask in the `#libc` channel on the
[LLVM Discord](https://discord.gg/xS7Z362).

## Pull requests

- **Keep pull requests small and focused.** Add one function, or one closely
related family of functions, per pull request. Land refactoring separately
from the change that needs it. A bug found along the way gets its own pull
request.
- **Title.** Start the title with `[libc]`, and add a second tag where one
applies: `[libc][math]`, `[libc][docs]`, or `[libc][NFC]` for changes with
no functional effect.
- **Format the change.** Run `clang-format` on C++ sources and
`libc/utils/cmake_format.py -i` on the CMake files you edited.
- **Test in both build modes** where the code supports both. See
{ref}`testing_guide`.
- **Do not mention people with `@` in commit messages**, or in a pull request
description that will become one. GitHub notifies them again each time the
commit is pushed to another fork. Request reviews through the reviewers
field instead.
- **Bazel.** Updating the Bazel build files is not required, but it is
appreciated.

LLVM-libc follows LLVM's
[patch reversion policy](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy).
A change that breaks a buildbot is reverted or, if the fix is trivial, fixed
forward. When relanding, describe what went wrong and how it was fixed.

## AI-assisted contributions

LLVM's [AI Tool Use Policy](https://llvm.org/docs/AIToolPolicy.html) applies
to LLVM-libc. In short: a person must read, understand, and be able to answer
questions about everything they submit; contributions with substantial
tool-generated content are labelled, for example with an `Assisted-by:`
trailer; the policy strongly recommends writing the pull request description
yourself; and AI tools must not be used on issues labelled "good first issue".

Tools make some mistakes in this project more often than people do:

- They imitate the code around them, including code that follows outdated
conventions. See {ref}`patterns_to_avoid`.
- Asked to make a program work, they change LLVM-libc's types, symbols, or
behavior to match another libc, because that is the shortest path to a
passing build. See {ref}`making_existing_software_work`.
- They reproduce code from other C libraries. That is not allowed, regardless
of how the code was produced.
- They call one public function from another. See {ref}`code_organization`.

Check for these before asking for review.
Loading
Loading