C3 is a programming language that builds on the syntax and semantics of the C language, with the goal of evolving it while still retaining familiarity for C programmers.
It's an evolution, not a revolution: the C-like for programmers who like C.
Precompiled binaries for the following operating systems are available:
The manual for C3 can be found at www.c3-lang.org.
Thanks to full ABI compatibility with C, it's possible to mix C and C3 in the same project with no effort. As a demonstration, vkQuake was compiled with a small portion of the code converted to C3 and compiled with the c3c compiler. (The fork can be found at https://github.com/c3lang/vkQuake)
C3 owes its inspiration to the C2 language: to iterate on top of C without trying to be a whole new language.
The following code shows generic modules (more examples can be found at https://c3-lang.org/references/docs/examples/).
module stack (<Type>);
// Above: the parameterized type is applied to the entire module.
struct Stack
{
usz capacity;
usz size;
Type* elems;
}
// The type methods offers dot syntax calls,
// so this function can either be called
// Stack.push(&my_stack, ...) or
// my_stack.push(...)
fn void Stack.push(Stack* this, Type element)
{
if (this.capacity == this.size)
{
this.capacity *= 2;
if (this.capacity < 16) this.capacity = 16;
this.elems = realloc(this.elems, Type.sizeof * this.capacity);
}
this.elems[this.size++] = element;
}
fn Type Stack.pop(Stack* this)
{
assert(this.size > 0);
return this.elems[--this.size];
}
fn bool Stack.empty(Stack* this)
{
return !this.size;
}
Testing it out:
import stack;
// Define our new types, the first will implicitly create
// a complete copy of the entire Stack module with "Type" set to "int"
def IntStack = Stack(<int>);
// The second creates another copy with "Type" set to "double"
def DoubleStack = Stack(<double>);
// If we had added "define IntStack2 = Stack(<int>)"
// no additional copy would have been made (since we already
// have an parameterization of Stack(<int>)) so it would
// be same as declaring IntStack2 an alias of IntStack
// Importing an external C function is straightforward
// here is an example of importing libc's printf:
extern fn int printf(char* format, ...);
fn void main()
{
IntStack stack;
// Note that C3 uses zero initialization by default
// so the above is equivalent to IntStack stack = {};
stack.push(1);
// The above can also be written IntStack.push(&stack, 1);
stack.push(2);
// Prints pop: 2
printf("pop: %d\n", stack.pop());
// Prints pop: 1
printf("pop: %d\n", stack.pop());
DoubleStack dstack;
dstack.push(2.3);
dstack.push(3.141);
dstack.push(1.1235);
// Prints pop: 1.123500
printf("pop: %f\n", dstack.pop());
}
The current stable version of the compiler is version 0.6.4.
The upcoming 0.6.x releases will focus on expanding the standard library. Follow the issues here.
If you have suggestions on how to improve the language, either file an issue or discuss C3 on its dedicated Discord: https://discord.gg/qN76R87.
The compiler is currently verified to compile on Linux, Windows and MacOS.
Support matrix
Platform | Native C3 compiler available? | Target supported | Stack trace | Threads | Sockets | Inline asm |
---|---|---|---|---|---|---|
Win32 x64 | Yes | Yes + cross compilation | Yes | Yes | Yes | Yes* |
Win32 Aarch64 | Untested | Untested | Untested | Untested | Untested | Yes* |
MacOS x64 | Yes | Yes + cross compilation | Yes | Yes | Yes | Yes* |
MacOS Aarch64 | Yes | Yes + cross compilation | Yes | Yes | Yes | Yes* |
iOS Aarch64 | No | Untested | Untested | Yes | Yes | Yes* |
Linux x86 | Yes | Yes | Yes | Yes | Yes | Yes* |
Linux x64 | Yes | Yes | Yes | Yes | Yes | Yes* |
Linux Aarch64 | Yes | Yes | Yes | Yes | Yes | Yes* |
Linux Riscv32 | Yes | Yes | Yes | Yes | Yes | Untested |
Linux Riscv64 | Yes | Yes | Yes | Yes | Yes | Untested |
ELF freestanding x86 | No | Untested | No | No | No | Yes* |
ELF freestanding x64 | No | Untested | No | No | No | Yes* |
ELF freestanding Aarch64 | No | Untested | No | No | No | Yes* |
ELF freestanding Riscv64 | No | Untested | No | No | No | Untested |
ELF freestanding Riscv32 | No | Untested | No | No | No | Untested |
FreeBSD x86 | Untested | Untested | No | Yes | Untested | Yes* |
FreeBSD x64 | Untested | Untested | No | Yes | Untested | Yes* |
NetBSD x86 | Untested | Untested | No | Yes | Untested | Yes* |
NetBSD x64 | Untested | Untested | No | Yes | Untested | Yes* |
OpenBSD x86 | Untested | Untested | No | Yes | Untested | Yes* |
OpenBSD x64 | Untested | Untested | No | Yes | Untested | Yes* |
MCU x86 | No | Untested | No | No | No | Yes* |
Wasm32 | No | Yes | No | No | No | No |
Wasm64 | No | Untested | No | No | No | No |
* Inline asm is still a work in progress
More platforms will be supported in the future.
msvc_build_libraries.py
Python script which will download the necessary files to compile on Windows. c3c.exe
../c3c
../c3c
../c3c
.(*Note that there is a known issue with debug symbol generation on MacOS 13, see issue #1086)
Arch includes c3c in the official 'extra' repo. It can be easily installed the usual way:
sudo pacman -S c3c
# or paru -S c3c
# or yay -S c3c
# or aura -A c3c
There is also an AUR package for the c3c compiler : c3c-git.
You can use your AUR package manager:
paru -S c3c-git
# or yay -S c3c-git
# or aura -A c3c-git
Or clone it manually:
git clone https://aur.archlinux.org/c3c-git.git
cd c3c-git
makepkg -si
You can build c3c
using either an Ubuntu 18.04 or 20.04 container:
./build-with-docker.sh 18
Replace 18
with 20
to build through Ubuntu 20.04.
For a release build specify:
./build-with-docker.sh 20 Release
A c3c
executable will be found under bin/
.
brew install cmake
brew install llvm
git clone https://github.com/c3lang/c3c.git
cd c3c
.mkdir build
cd build
cmake ..
cmake --build .
Create a main.c3
file with:
module hello_world;
import std::io;
fn void main()
{
io::printn("Hello, world!");
}
Make sure you have the standard libraries at either ../lib/std/
or /lib/std/
.
Then run
c3c compile main.c3
The generated binary will by default be named after the module that contains the main
function. In our case that is hello_world
, so the resulting binary will be
called hello_world
or hello_world.exe
depending on platform.
c3c/resources/install_win_reqs.bat
to automate this)git clone https://github.com/c3lang/c3c.git
cd c3c
.cmake -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
You should now have a c3c
executable.
You can try it out by running some sample code: c3c.exe compile ../resources/examples/hash.c3
Note that if you run into linking issues when building, make sure that you are using the latest version of VS17.
sudo apt-get install cmake git clang zlib1g zlib1g-dev libllvm18 llvm llvm-dev llvm-runtime liblld-dev liblld-18 libpolly-18-dev
git clone https://github.com/c3lang/c3c.git
cd c3c
.mkdir build
cd build
cmake ..
cmake --build .
You should now have a c3c
executable.
You can try it out by running some sample code: ./c3c compile ../resources/examples/hash.c3
xbps-install git cmake llvm17 llvm17-devel lld17-devel libcurl-devel ncurses-devel zlib-devel libzstd-devel libxml2-devel
git clone https://github.com/c3lang/c3c.git
git clone https://github.com/c3lang/c3c.git --depth=1
cd c3c
mkdir build
cd build
cmake ..
cmake --build .
Your c3c executable should have compiled properly. You may want to test it: ./c3c compile ../resources/examples/hash.c3
For a sytem-wide installation, run the following as root: cmake --install .
git clone https://github.com/c3lang/c3c.git
cd c3c
.mkdir build
cd build
cmake ..
. At this point you may need to manually
provide the link path to the LLVM CMake directories, e.g. cmake -DLLVM_DIR=/usr/local/opt/llvm/lib/cmake/llvm/ ..
cmake --build .
A note on compiling for Linux/Unix/MacOS: to be able to fetch vendor libraries libcurl is needed. The CMake script should detect it if it is available. Note that this functionality is non-essential and it is perfectly fine to user the compiler without it.
The C3 compiler is licensed under LGPL 3.0, the standard library itself is MIT licensed.
Editor plugins can be found at https://github.com/c3lang/editor-plugins.
/test/unit/
or add
a new file. (If testing the standard library, put it in the /test/unit/stdlib/
subdirectory).@test
attribute. c3c compile-test -O0 test/unit
.
test/unit/
is the relative path to the test directory, so adjust as required)A huge THANK YOU goes out to all contributors and sponsors.
A special thank you to sponsors Caleb-o and devdad for going the extra mile.