Skip to content

Commit

Permalink
Merge pull request #362 from ZigEmbeddedGroup/foundation-libc
Browse files Browse the repository at this point in the history
Foundation libc
  • Loading branch information
mattnite authored Jan 24, 2025
2 parents 6c91a35 + 9eef75c commit 8ae6b47
Show file tree
Hide file tree
Showing 35 changed files with 1,563 additions and 0 deletions.
26 changes: 26 additions & 0 deletions modules/foundation-libc/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
Language: Cpp
BasedOnStyle: LLVM

# basic indentation is 4 spaces, indented by spaces:
IndentWidth: 4
TabWidth: 4
UseTab: Never

# use east const for better readability:
QualifierAlignment: Right

# do not tack pointer to type nor value:
PointerAlignment: Middle

# align function names and keep them apart at least one line
AlignConsecutiveDeclarations: AcrossEmptyLines

# we sort includes to prevent merge conflicts:
SortIncludes: CaseSensitive

# disable column limit:
ColumnLimit: 0

---

1 change: 1 addition & 0 deletions modules/foundation-libc/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.zig text=auto eol=lf
28 changes: 28 additions & 0 deletions modules/foundation-libc/.github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Continuous Integration

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]

runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Zig
uses: mlugg/setup-zig@v1
with:
version: 0.13.0

- name: Generate and validate packages
working-directory: test
run: |
zig build validate
2 changes: 2 additions & 0 deletions modules/foundation-libc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.zig-cache/
zig-out/
19 changes: 19 additions & 0 deletions modules/foundation-libc/LICENCE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2024 Felix "xq" Queißner

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
125 changes: 125 additions & 0 deletions modules/foundation-libc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Foundation libc

[![Continuous Integration](https://github.com/ZigEmbeddedGroup/foundation-libc/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/ZigEmbeddedGroup/foundation-libc/actions/workflows/build.yml)

A C standard library that only implements a subset of functions that can be safely used without an operating system.
This is called a [freestanding environment](https://en.cppreference.com/w/cpp/freestanding).

This libc is primarily meant to be used with microcontrollers, hobbyist operating systems and so on.

## Support

The first goal is to reach full C11 *freestanding* support.

- No support for locales
- No allocator (ship your own!)
- No support for functions that require an operating system of sorts in the background.
- No support for `wchar_t` and `wchar.h` as it isn't portable between compilers.
- Multi-byte character strings are implemented as UTF-8.

## Customization

Foundation libc doesn't really support much customization/configuration except for the hard required options.

There is [`foundation/libc.h`](include/foundation/libc.h) which documents the behaviour of all required configurations.

Right now, the following configurations exist:

- `foundation_libc_panic_handler`, which allows users to catch detectable undefined behaviour.

You can also configure the libc by chosing the build mode:

- `Debug`: Implements additional safety checks and adds breakpoints in panics.
- `ReleaseSafe`: Keeps the safety checks, but removes breakpoints.
- `ReleaseSmall`: Still keeps a certain amount of safety, but drops long internal strings to reduce code and ram size.
- `ReleaseFast`: Gotta go fast. Drops all safety and assumes all code behaves well.

There are also certain "usage" configurations that can be chosen to affect behaviour when *using* the headers. Those are implemented as C macros/defines:

- `FOUNDATION_LIBC_ASSERT` is a global macro that defines how `assert()` should behave:
- `FOUNDATION_LIBC_ASSERT_DEFAULT=0`: Behaves like a regular assert that can print file name, assertion message and line.
- `FOUNDATION_LIBC_ASSERT_NOFILE=1`: Drops the filename from the assertion to reduce code size.
- `FOUNDATION_LIBC_ASSERT_NOMSG=2`: Additionally drops the assertion message from the assertion to reduce code size.
- `FOUNDATION_LIBC_ASSERT_EXPECTED=3`: Replaces `assert(…)` with a construct that tells the compiler the assertion is always met. Makes code very fast. Assertions aren't checked.

## Development

Zig Version: 0.11

Run
```sh-session
user@microzig ~/foundation-libc $ zig build
user@microzig ~/foundation-libc $
```

to compile the libc and generate a lib file in `zig-out/lib` as well as the headers in `zig-out/include`.

## Contribution

Start by grabbing a header marked with ⏳ or 🛠 and implement the functions from that header. See if others already have a PR open for those functions so you don't do work twice!

Leverage functions from Zig `std` if possible as they are already well tested and should work.

Which functions belong into which header can be figured out by taking a look at the *C11 Standard Draft* document or the *IBM libc functions* list. [cppreference.com](https://en.cppreference.com/w/c) usually has the better docs though, so best check out both.

### Style Guides

- The header files are ment to be as minimal as possible
- Do not use comments documenting the functions, they are well documented everywhere else.
- Only insert empty lines between functions if necessarity for clarity
- Keep function names sorted alphabetically
- Try not to use macros at all
- Use `clang-format` with the provided style file.


## Links

- [C11 Standard](https://www.iso.org/standard/57853.html)
- [C11 Standard Draft](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf)
- [ziglibc](https://github.com/marler8997/ziglibc)
- [libc-test](https://wiki.musl-libc.org/libc-test.html) by musl
- [cppreference on freestanding](https://en.cppreference.com/w/cpp/freestanding)
- [GCC on freestanding](https://gcc.gnu.org/onlinedocs/gcc/Standards.html#C-Language)
- [IBM libc functions](https://www.ibm.com/docs/en/i/7.5?topic=extensions-standard-c-library-functions-table-by-name) (function to header map)
- [cppreference](https://en.cppreference.com/w/c)
- [clang-format style options](https://releases.llvm.org/16.0.0/tools/clang/docs/ClangFormatStyleOptions.html)

## Status

⏳ (not started), 🛠 (work in progress), ⚠️ (partial support), ✅ (full support), ❌ (no support), 🔮 (potential future support), 🔀 (implemented by compiler)

| Header File | Header Status | Implementation Status | Description |
| --------------- | ------------- | --------------------- | ------------------------------------------------------------------------------------------------------- |
| `assert.h` ||| Conditionally compiled macro that compares its argument to zero |
| `complex.h` || | (since C99) Complex number arithmetic |
| `ctype.h` ||| Functions to determine the type contained in character data |
| `errno.h` ||| Macros reporting error conditions |
| `fenv.h` | 🔮 | | (since C99) Floating-point environment |
| `float.h` | 🔀 | | Limits of floating-point types |
| `inttypes.h` ||| (since C99) Format conversion of integer types |
| `iso646.h` | 🔀 | | (since C95) Alternative operator spellings |
| `limits.h` | 🔀 | | Ranges of integer types |
| `locale.h` || | Localization utilities |
| `math.h` | 🛠 || Common mathematics functions |
| `setjmp.h` | 🛠 || Nonlocal jumps |
| `signal.h` || | Signal handling |
| `stdalign.h` | 🔀 | | (since C11) alignas and alignof convenience macros |
| `stdarg.h` | 🔀 | | Variable arguments |
| `stdatomic.h` | 🔮 | | (since C11) Atomic operations |
| `stdbit.h` | 🔮 | | (since C23) Macros to work with the byte and bit representations of types |
| `stdbool.h` | 🔀 | | (since C99) Macros for boolean type |
| `stdckdint.h` | 🔮 | | (since C23) macros for performing checked integer arithmetic |
| `stddef.h` | 🔀 | | Common macro definitions |
| `stdint.h` | 🔀 | | (since C99) Fixed-width integer types |
| `stdio.h` || | Input/output |
| `stdlib.h` | 🛠 | 🛠 | General utilities: memory management, program utilities, string conversions, random numbers, algorithms |
| `stdnoreturn.h` | 🔀 | | (since C11) noreturn convenience macro |
| `string.h` || 🛠 | String handling |
| `tgmath.h` ||| (since C99) Type-generic math (macros wrapping math.h and complex.h) |
| `threads.h` || | (since C11) Thread library |
| `time.h` || | Time/date utilities |
| `uchar.h` | 🛠 || (since C11) UTF-16 and UTF-32 character utilities |
| `wchar.h` || | (since C95) Extended multibyte and wide character utilities |
| `wctype.h` || | (since C95) Functions to determine the type contained in wide character data |


48 changes: 48 additions & 0 deletions modules/foundation-libc/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const std = @import("std");

pub fn build(b: *std.Build) void {
const validation_step = b.step("validate", "Runs the test suite and validates everything. Automatically triggered in Debug builds.");

const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const single_threaded = b.option(bool, "single_threaded", "Create a single-threaded libc implementation (default: false)") orelse false;

// Run validation in debug builds for convenience:
if (optimize == .Debug) {
b.getInstallStep().dependOn(validation_step);
}

const libc = b.addStaticLibrary(.{
.name = "foundation",
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/libc.zig"),
.single_threaded = single_threaded,
});

libc.addIncludePath(b.path("include"));
for (header_files) |header_name|
libc.installHeader(
b.path(b.fmt("include/{s}", .{header_name})),
header_name,
);

libc.installHeadersDirectory(b.path("include/foundation"), "foundation", .{});

b.installArtifact(libc);
}

const header_files = [_][]const u8{
"assert.h",
"ctype.h",
"errno.h",
"inttypes.h",
"math.h",
"setjmp.h",
"stdlib.h",
"string.h",
"tgmath.h",
"uchar.h",
"foundation/libc.h",
};
12 changes: 12 additions & 0 deletions modules/foundation-libc/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.{
.name = "foundation-libc",
.version = "0.0.0",
.paths = .{
"LICENSE",
"README.md",
"build.zig",
"build.zig.zon",
"include",
"src",
},
}
Loading

0 comments on commit 8ae6b47

Please sign in to comment.