Skip to content
Snippets Groups Projects
Commit 6d0d0ff0 authored by Martin Kröning's avatar Martin Kröning :crab:
Browse files

Add xtask crate for kernel building

parent 21a7ae68
No related branches found
No related tags found
No related merge requests found
[unstable] [alias]
# Keep in sync with CI! xtask = "run --package xtask --"
build-std = ["core", "alloc"]
build-std-features = ["compiler-builtins-mem"]
[build]
target = "targets/x86_64-unknown-none-hermitkernel.json"
rustflags = [
"-Zmutable-noalias=no"
]
[target.x86_64-unknown-none-hermitkernel] [target.x86_64-unknown-none-hermitkernel]
runner = "tests/hermit_test_runner.py" runner = "tests/hermit_test_runner.py"
...@@ -23,8 +23,6 @@ jobs: ...@@ -23,8 +23,6 @@ jobs:
matrix: matrix:
os: [ubuntu-latest] os: [ubuntu-latest]
steps: steps:
- name: Install cargo-binutils
run: cargo install cargo-binutils
- name: Checkout rusty-hermit - name: Checkout rusty-hermit
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
...@@ -41,9 +39,9 @@ jobs: ...@@ -41,9 +39,9 @@ jobs:
run: rustup show run: rustup show
- name: Build minimal kernel - name: Build minimal kernel
working-directory: libhermit-rs working-directory: libhermit-rs
run: cargo build --no-default-features --target targets/aarch64-unknown-none-hermitkernel.json -Z build-std=core,alloc run: cargo xtask build --arch aarch64 --no-default-features
- name: Build dev profile - name: Build dev profile
run: cargo build --target aarch64-unknown-hermit -p hello_world run: cargo build -Zbuild-std=core,alloc,std,panic_abort -Zbuild-std-features=compiler-builtins-mem --target aarch64-unknown-hermit --package hello_world
- name: Build loader - name: Build loader
run: make arch=aarch64 run: make arch=aarch64
working-directory: loader working-directory: loader
......
...@@ -10,6 +10,7 @@ on: ...@@ -10,6 +10,7 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUSTFLAGS: -Dwarnings
jobs: jobs:
clippy: clippy:
...@@ -24,4 +25,4 @@ jobs: ...@@ -24,4 +25,4 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install nasm sudo apt-get install nasm
- name: Clippy - name: Clippy
run: cargo clippy -- -D warnings run: cargo xtask clippy
...@@ -27,5 +27,5 @@ jobs: ...@@ -27,5 +27,5 @@ jobs:
env: env:
RUSTDOCFLAGS: -D warnings RUSTDOCFLAGS: -D warnings
run: | run: |
cargo doc --no-deps --document-private-items --target targets/x86_64-unknown-none-hermitkernel.json cargo doc -Z build-std=core,alloc --package rusty-hermit --no-deps --document-private-items --target targets/x86_64-unknown-none-hermitkernel.json
cargo doc --no-deps --document-private-items --target targets/aarch64-unknown-none-hermitkernel.json cargo doc -Z build-std=core,alloc --package rusty-hermit --no-deps --document-private-items --target targets/aarch64-unknown-none-hermitkernel.json
...@@ -21,7 +21,7 @@ jobs: ...@@ -21,7 +21,7 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install nasm sudo apt-get install nasm
- name: Generate documentation - name: Generate documentation
run: cargo doc run: cargo doc -Z build-std=core,alloc --package rusty-hermit
- name: Generate index.html - name: Generate index.html
run: | run: |
cat > target/x86_64-unknown-none-hermitkernel/doc/index.html <<EOL cat > target/x86_64-unknown-none-hermitkernel/doc/index.html <<EOL
......
...@@ -39,8 +39,6 @@ jobs: ...@@ -39,8 +39,6 @@ jobs:
choco install qemu nasm make choco install qemu nasm make
echo "C:\Program Files\qemu" >> $GITHUB_PATH echo "C:\Program Files\qemu" >> $GITHUB_PATH
echo "C:\Program Files\NASM" >> $GITHUB_PATH echo "C:\Program Files\NASM" >> $GITHUB_PATH
- name: Install cargo-binutils
run: cargo install cargo-binutils
- name: Checkout rusty-hermit - name: Checkout rusty-hermit
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
...@@ -57,9 +55,9 @@ jobs: ...@@ -57,9 +55,9 @@ jobs:
run: rustup show run: rustup show
- name: Build minimal kernel - name: Build minimal kernel
working-directory: libhermit-rs working-directory: libhermit-rs
run: cargo build --no-default-features -Z build-std=core,alloc run: cargo xtask build --arch x86_64 --no-default-features
- name: Build dev profile - name: Build dev profile
run: cargo build run: cargo build -Zbuild-std=core,alloc,std,panic_abort -Zbuild-std-features=compiler-builtins-mem --target x86_64-unknown-hermit
- name: Unittests on host (ubuntu) - name: Unittests on host (ubuntu)
if: ${{ matrix.os == 'ubuntu-latest' }} if: ${{ matrix.os == 'ubuntu-latest' }}
working-directory: libhermit-rs working-directory: libhermit-rs
...@@ -81,7 +79,7 @@ jobs: ...@@ -81,7 +79,7 @@ jobs:
run: cargo test --tests --no-fail-fast -- --bootloader_path=../loader/target/x86_64-unknown-hermit-loader/release/rusty-loader run: cargo test --tests --no-fail-fast -- --bootloader_path=../loader/target/x86_64-unknown-hermit-loader/release/rusty-loader
continue-on-error: true continue-on-error: true
- name: Build release profile - name: Build release profile
run: cargo build --release run: cargo build -Zbuild-std=core,alloc,std,panic_abort -Zbuild-std-features=compiler-builtins-mem --target x86_64-unknown-hermit --release
- name: Test release profile - name: Test release profile
run: | run: |
qemu-system-x86_64 -display none -smp 1 -m 128M -serial stdio \ qemu-system-x86_64 -display none -smp 1 -m 128M -serial stdio \
...@@ -91,7 +89,7 @@ jobs: ...@@ -91,7 +89,7 @@ jobs:
-initrd target/x86_64-unknown-hermit/release/rusty_demo -initrd target/x86_64-unknown-hermit/release/rusty_demo
- name: Build minimal profile - name: Build minimal profile
if: ${{ matrix.os == 'ubuntu-latest' }} if: ${{ matrix.os == 'ubuntu-latest' }}
run: cargo build --no-default-features --release -p hello_world run: cargo build -Zbuild-std=core,alloc,std,panic_abort -Zbuild-std-features=compiler-builtins-mem --target x86_64-unknown-hermit --no-default-features --release --package hello_world
- name: Test minimal profile - name: Test minimal profile
id: minimal id: minimal
if: ${{ matrix.os == 'ubuntu-latest' }} if: ${{ matrix.os == 'ubuntu-latest' }}
......
...@@ -43,8 +43,8 @@ build:demo: ...@@ -43,8 +43,8 @@ build:demo:
- if [ -d "libhermit-rs" ]; then rm -rf libhermit-rs; fi - if [ -d "libhermit-rs" ]; then rm -rf libhermit-rs; fi
- mkdir libhermit-rs - mkdir libhermit-rs
- shopt -s dotglob nullglob && mv $HOME/tmp_libhermit-rs/* libhermit-rs/. - shopt -s dotglob nullglob && mv $HOME/tmp_libhermit-rs/* libhermit-rs/.
- cargo build -p rusty_demo - cargo build -Zbuild-std=core,alloc,std,panic_abort -Zbuild-std-features=compiler-builtins-mem --target x86_64-unknown-hermit --package rusty_demo
- cargo build -p rusty_demo --release - cargo build -Zbuild-std=core,alloc,std,panic_abort -Zbuild-std-features=compiler-builtins-mem --target x86_64-unknown-hermit --package rusty_demo --release
artifacts: artifacts:
paths: paths:
- rusty-hermit/target/x86_64-unknown-hermit/debug/rusty_demo - rusty-hermit/target/x86_64-unknown-hermit/debug/rusty_demo
......
...@@ -84,3 +84,8 @@ x86 = { version = "0.47", default-features = false } ...@@ -84,3 +84,8 @@ x86 = { version = "0.47", default-features = false }
[target.'cfg(target_arch = "aarch64")'.dependencies.aarch64] [target.'cfg(target_arch = "aarch64")'.dependencies.aarch64]
version = "0.0.7" version = "0.0.7"
default-features = false default-features = false
[workspace]
members = [
"xtask",
]
...@@ -36,7 +36,6 @@ RUN set -eux; \ ...@@ -36,7 +36,6 @@ RUN set -eux; \
# Build dependencies with stable toolchain channel # Build dependencies with stable toolchain channel
FROM rust:bullseye as stable-deps FROM rust:bullseye as stable-deps
RUN set -eux; \ RUN set -eux; \
cargo install cargo-binutils; \
cargo install cargo-download; \ cargo install cargo-download; \
cargo install --git https://github.com/hermitcore/uhyve.git --locked uhyve; cargo install --git https://github.com/hermitcore/uhyve.git --locked uhyve;
...@@ -62,7 +61,6 @@ RUN set -eux; \ ...@@ -62,7 +61,6 @@ RUN set -eux; \
qemu-system-x86 \ qemu-system-x86 \
; \ ; \
rm -rf /var/lib/apt/lists/*; rm -rf /var/lib/apt/lists/*;
COPY --from=stable-deps $CARGO_HOME/bin/rust-objcopy $CARGO_HOME/bin/rust-objcopy
COPY --from=stable-deps $CARGO_HOME/bin/cargo-download $CARGO_HOME/bin/cargo-download COPY --from=stable-deps $CARGO_HOME/bin/cargo-download $CARGO_HOME/bin/cargo-download
COPY --from=stable-deps $CARGO_HOME/bin/uhyve $CARGO_HOME/bin/uhyve COPY --from=stable-deps $CARGO_HOME/bin/uhyve $CARGO_HOME/bin/uhyve
COPY --from=hermit-deps rusty-loader/target/x86_64-unknown-hermit-loader/release/rusty-loader /usr/local/bin/rusty-loader COPY --from=hermit-deps rusty-loader/target/x86_64-unknown-hermit-loader/release/rusty-loader /usr/local/bin/rusty-loader
/target
[package]
name = "xtask"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0"
goblin = { version = "0.5", default-features = false, features = ["archive", "std"] }
rustc_version = "0.4"
xflags = "0.2"
xshell = "0.2"
use std::path::PathBuf;
xflags::xflags! {
src "./src/flags.rs"
/// Run custom build command.
cmd xtask {
default cmd help {
/// Print help information.
optional -h, --help
}
/// Build the kernel.
cmd build
{
/// Build for the architecture.
required --arch arch: String
/// Directory for all generated artifacts.
optional --target-dir target_dir: PathBuf
/// Do not activate the `default` feature.
optional --no-default-features
/// Space or comma separated list of features to activate.
repeated --features features: String
/// Build artifacts in release mode, with optimizations.
optional -r, --release
/// Build artifacts with the specified profile.
optional --profile profile: String
/// Enable the `-Z instrument-mcount` flag.
optional --instrument-mcount
}
/// Run clippy for all targets.
cmd clippy {}
}
}
// generated start
// The following code is generated by `xflags` macro.
// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate.
#[derive(Debug)]
pub struct Xtask {
pub subcommand: XtaskCmd,
}
#[derive(Debug)]
pub enum XtaskCmd {
Help(Help),
Build(Build),
Clippy(Clippy),
}
#[derive(Debug)]
pub struct Help {
pub help: bool,
}
#[derive(Debug)]
pub struct Build {
pub arch: String,
pub target_dir: Option<PathBuf>,
pub no_default_features: bool,
pub features: Vec<String>,
pub release: bool,
pub profile: Option<String>,
pub instrument_mcount: bool,
}
#[derive(Debug)]
pub struct Clippy;
impl Xtask {
pub const HELP: &'static str = Self::HELP_;
#[allow(dead_code)]
pub fn from_env() -> xflags::Result<Self> {
Self::from_env_()
}
#[allow(dead_code)]
pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> {
Self::from_vec_(args)
}
}
// generated end
//! See <https://github.com/matklad/cargo-xtask/>.
mod flags;
mod rustc;
use std::{
env::{self, VarError},
ffi::OsString,
path::{Path, PathBuf},
};
use anyhow::{anyhow, Result};
use goblin::archive::Archive;
use xshell::{cmd, Shell};
const RUSTFLAGS: &[&str] = &[
// TODO: Re-enable mutable-noalias
// https://github.com/hermitcore/libhermit-rs/issues/200
"-Zmutable-noalias=no",
];
const KERNEL_CARGO_ARGS: &[&str] = &[
"-Zbuild-std=core,alloc",
"-Zbuild-std-features=compiler-builtins-mem",
];
fn main() -> Result<()> {
flags::Xtask::from_env()?.run()
}
impl flags::Xtask {
fn run(self) -> Result<()> {
match self.subcommand {
flags::XtaskCmd::Help(_) => {
println!("{}", flags::Xtask::HELP);
Ok(())
}
flags::XtaskCmd::Build(build) => build.run(),
flags::XtaskCmd::Clippy(clippy) => clippy.run(),
}
}
}
impl flags::Build {
fn run(self) -> Result<()> {
let sh = sh()?;
eprintln!("Building kernel");
cmd!(sh, "cargo build")
.env("CARGO_ENCODED_RUSTFLAGS", self.cargo_encoded_rustflags()?)
.args(KERNEL_CARGO_ARGS)
.arg(target_arg(&self.arch)?)
.args(self.target_dir_args())
.args(self.no_default_features_args())
.args(self.features_args())
.args(self.release_args())
.args(self.profile_args())
.run()?;
eprintln!("Exporting symbols");
self.export_syms()?;
eprintln!("Kernel available at {}", self.dist_archive().display());
Ok(())
}
fn cargo_encoded_rustflags(&self) -> Result<String> {
let outer_rustflags = match env::var("CARGO_ENCODED_RUSTFLAGS") {
Ok(s) => Some(s),
Err(VarError::NotPresent) => None,
Err(err) => return Err(err.into()),
};
let mut rustflags = outer_rustflags
.as_deref()
.map(|s| vec![s])
.unwrap_or_default();
rustflags.extend(RUSTFLAGS);
if self.instrument_mcount {
rustflags.push("-Zinstrument-mcount");
}
Ok(rustflags.join("\x1f"))
}
fn target_dir_args(&self) -> Vec<OsString> {
vec!["--target-dir".into(), self.target_dir().into()]
}
fn no_default_features_args(&self) -> &[&str] {
if self.no_default_features {
&["--no-default-features"]
} else {
&[]
}
}
fn features_args(&self) -> Vec<&str> {
if self.features.is_empty() {
vec![]
} else {
let mut features = vec!["--features"];
features.extend(self.features.iter().map(String::as_str));
features
}
}
fn release_args(&self) -> &[&str] {
if self.release {
&["--release"]
} else {
&[]
}
}
fn profile_args(&self) -> Vec<&str> {
match self.profile.as_deref() {
Some(profile) => vec!["--profile", profile],
None => vec![],
}
}
fn export_syms(&self) -> Result<()> {
let sh = sh()?;
let input = self.build_archive();
let output = self.dist_archive();
sh.create_dir(output.parent().unwrap())?;
sh.copy_file(&input, &output)?;
let objcopy = binutil("objcopy")?;
cmd!(sh, "{objcopy} --prefix-symbols=hermit_ {output}").run()?;
let archive_bytes = sh.read_binary_file(&input)?;
let archive = Archive::parse(&archive_bytes)?;
let sys_fns = archive
.summarize()
.into_iter()
.filter(|(member_name, _, _)| member_name.starts_with("hermit"))
.flat_map(|(_, _, symbols)| symbols)
.filter(|symbol| symbol.starts_with("sys_"));
let explicit_exports = [
"_start",
"__bss_start",
"__rg_oom",
"memcmp",
"memcpy",
"memmove",
"memset",
"runtime_entry",
]
.into_iter();
let symbol_redefinitions = explicit_exports
.chain(sys_fns)
.map(|symbol| format!("hermit_{symbol} {symbol}\n"))
.collect::<String>();
let exported_syms = self.exported_syms();
sh.write_file(&exported_syms, &symbol_redefinitions)?;
cmd!(sh, "{objcopy} --redefine-syms={exported_syms} {output}").run()?;
Ok(())
}
fn profile(&self) -> &str {
self.profile
.as_deref()
.unwrap_or(if self.release { "release" } else { "dev" })
}
fn target_dir(&self) -> &Path {
self.target_dir
.as_deref()
.unwrap_or_else(|| Path::new("target"))
}
fn out_dir(&self) -> PathBuf {
let mut out_dir = self.target_dir().to_path_buf();
out_dir.push(target(&self.arch).unwrap());
out_dir.push(match self.profile() {
"dev" => "debug",
profile => profile,
});
out_dir
}
fn dist_dir(&self) -> PathBuf {
let mut out_dir = self.target_dir().to_path_buf();
out_dir.push(&self.arch);
out_dir.push(match self.profile() {
"dev" => "debug",
profile => profile,
});
out_dir
}
fn build_archive(&self) -> PathBuf {
let mut built_archive = self.out_dir();
built_archive.push("libhermit.a");
built_archive
}
fn dist_archive(&self) -> PathBuf {
let mut dist_archive = self.dist_dir();
dist_archive.push("libhermit.a");
dist_archive
}
fn exported_syms(&self) -> PathBuf {
let mut redefine_syms_path = self.dist_dir();
redefine_syms_path.push("exported-syms");
redefine_syms_path
}
}
impl flags::Clippy {
fn run(self) -> Result<()> {
let sh = sh()?;
// TODO: Enable clippy for aarch64
// https://github.com/hermitcore/libhermit-rs/issues/381
for target in ["x86_64"] {
cmd!(sh, "cargo clippy")
.args(KERNEL_CARGO_ARGS)
.arg(target_arg(target)?)
.run()?;
}
cmd!(sh, "cargo clippy --package xtask").run()?;
Ok(())
}
}
fn target(arch: &str) -> Result<&'static str> {
match arch {
"x86_64" => Ok("x86_64-unknown-none-hermitkernel"),
"aarch64" => Ok("aarch64-unknown-none-hermitkernel"),
arch => Err(anyhow!("Unsupported arch: {arch}")),
}
}
fn target_arg(arch: &str) -> Result<String> {
let target = target(arch)?;
Ok(format!("--target=targets/{target}.json"))
}
fn binutil(name: &str) -> Result<PathBuf> {
let exe_suffix = env::consts::EXE_SUFFIX;
let exe = format!("llvm-{name}{exe_suffix}");
let mut path = rustc::rustlib()?;
path.push(exe);
Ok(path)
}
fn sh() -> Result<Shell> {
let sh = Shell::new()?;
sh.change_dir(project_root());
Ok(sh)
}
fn project_root() -> &'static Path {
Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap()
}
//! Taken from <https://github.com/rust-embedded/cargo-binutils/blob/980607cf8e4bb1b7db5cc7a35aafa38463818f7e/src/rustc.rs>.
use std::env;
use std::path::PathBuf;
use std::process::Command;
use anyhow::Result;
pub fn sysroot() -> Result<String> {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let output = Command::new(rustc).arg("--print").arg("sysroot").output()?;
// Note: We must trim() to remove the `\n` from the end of stdout
Ok(String::from_utf8(output.stdout)?.trim().to_owned())
}
// See: https://github.com/rust-lang/rust/blob/564758c4c329e89722454dd2fbb35f1ac0b8b47c/src/bootstrap/dist.rs#L2334-L2341
pub fn rustlib() -> Result<PathBuf> {
let sysroot = sysroot()?;
let mut pathbuf = PathBuf::from(sysroot);
pathbuf.push("lib");
pathbuf.push("rustlib");
pathbuf.push(rustc_version::version_meta()?.host); // TODO: Prevent calling rustc_version::version_meta() multiple times
pathbuf.push("bin");
Ok(pathbuf)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment