Quick Start
From one machine, you build a program for every target, then a CMake project with import std, for the host and for another target.
Prerequisites
- pixi and git.
- bash. On Windows, that is Git Bash.
- On macOS, Xcode or the Command Line Tools. The macOS targets build against their SDK.
- For step 4, CMake 3.28 or later and Ninja 1.11 or later.
pip install cmake ninjagives both.
1. Install
The files are in the examples/ directory of the repository:
git clone --depth 1 https://github.com/clice-io/xclang
cd xclang/examples/quickstartpixi.toml is a pixi workspace with xclang from the clice conda channel:
[workspace]
name = "hello"
channels = ["conda-forge", "https://conda.clice.io"]
platforms = ["linux-64", "linux-aarch64", "osx-64", "osx-arm64", "win-64", "win-arm64"]
[dependencies]
xclang = "*"pixi installpixi run and pixi shell put xclang's bin/ first in PATH. Other ways to get xclang are in installation.
2. Build a Program for Every Target
hello.cpp throws and catches an exception, which needs the C++ runtime:
#include <iostream>
#include <stdexcept>
#include <string>
int main() {
try {
throw std::runtime_error("hello from xclang");
} catch (const std::exception& e) {
std::cout << e.what() << '\n';
}
}Build it for this machine, and for each Linux and Windows target:
pixi run clang++ -O2 hello.cpp -o hello
./hello
pixi run clang++ -O2 --target=x86_64-unknown-linux-gnu hello.cpp -o hello-linux-x64
pixi run clang++ -O2 --target=aarch64-unknown-linux-gnu hello.cpp -o hello-linux-arm64
pixi run clang++ -O2 --target=x86_64-w64-mingw32 hello.cpp -o hello-windows-x64.exe
pixi run clang++ -O2 --target=aarch64-w64-mingw32 hello.cpp -o hello-windows-arm64.exe./hello prints hello from xclang. On a macOS host, build the macOS targets too:
pixi run clang++ -O2 --target=aarch64-apple-darwin hello.cpp -o hello-macos-arm64
pixi run clang++ -O2 --target=x86_64-apple-darwin hello.cpp -o hello-macos-x64No sysroot to install, no --sysroot, no -L. For each --target, clang reads the config file of that target in xclang's bin/, which names its sysroot and runtimes (cross-compiling). On a Windows host, the first command writes hello.exe, because a MinGW link adds .exe to a name without one.
3. Check What the Programs Need
pixi run llvm-readobj --needed-libs hello-linux-x64 hello-windows-x64.exeOn every host, this prints the libraries each program loads. The output is trimmed here:
File: hello-linux-x64
NeededLibraries [
ld-linux-x86-64.so.2
libc.so.6
libdl.so.2
libm.so.6
libpthread.so.0
]
File: hello-windows-x64.exe
NeededLibraries [
KERNEL32.dll
api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-environment-l1-1-0.dll
...
api-ms-win-crt-time-l1-1-0.dll
]A macOS program needs /usr/lib/libSystem.B.dylib alone. That is the whole list: glibc 2.17 or later on Linux, Windows 10 or later with its UCRT, macOS 13 or later. There is no libstdc++.so.6, libc++.dll, libgcc_s_seh-1.dll or libwinpthread-1.dll. Each program runs on any machine of its target as a single file (hermeticity).
4. Build a CMake Project with import std
The project is in examples/cmake:
cmake_minimum_required(VERSION 3.28)
project(hello LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(xclang REQUIRED CONFIG)
add_executable(hello main.cpp)
target_link_libraries(hello PRIVATE xclang::std)import std;
int main() {
std::vector<std::string> targets{"windows", "linux", "macos"};
std::ranges::sort(targets);
try {
throw std::runtime_error(std::format("{} targets, the first {}", targets.size(), targets[0]));
} catch (const std::exception& e) {
std::println("hello from xclang: {}", e.what());
}
}pixi run cmake -G Ninja -S ../cmake -B build -DCMAKE_CXX_COMPILER=clang++
pixi run cmake --build build
./build/helloIt prints hello from xclang: 3 targets, the first linux. xclang::std is the std and std.compat modules of libc++, built for this build with its options, without an experimental CMake switch (C++20 modules).
Build the same project for Windows on Arm. XCLANG is the toolchain directory that pixi installed:
XCLANG=$PWD/.pixi/envs/default/opt/xclang
pixi run cmake -G Ninja -S ../cmake -B build-aarch64-w64-mingw32 \
--toolchain "$XCLANG/lib/cmake/xclang/toolchain.cmake" -DXCLANG_TARGET=aarch64-w64-mingw32
pixi run cmake --build build-aarch64-w64-mingw32XCLANG_TARGET takes any of the six targets and the MSVC targets. The MSVC targets, and the macOS ones on Linux and Windows hosts, need the SDK that the xclang command fetches (CMake). Copy build-aarch64-w64-mingw32/hello.exe to a Windows on Arm machine, and it runs there with nothing installed.
Next
- Cross-Compiling: the targets, and running what you built.
- CMake, Bazel, Make and Meson, Cargo.
- Why xclang?: what the toolchain does for a build.
