integration-ebpf: artifact dependency bpf-linker

Replace the manual dependency machinery in integration-test/build.rs
with:

- integration-ebpf -[artifact-dependency]-> bpf-linker.
- integration-test -[build-dependency]-> integration-ebpf.
- integration-ebpf: build.rs that makes bpf-linker available to rustc.
- integration-ebpf: lib.rs (empty) creates a lib target, allows dep from
  integration-test.
- xtask: filter for test binaries now that the build also produces the
  bpf-linker binary.
- github: remove `cargo install bpf-linker` and commentary about cache
  invalidation.
- integration-test: remove bpf-linker installation instructions.
reviewable/pr676/r1
Tamir Duberstein 2 years ago
parent b28d4c34ee
commit 13d47b8aff
No known key found for this signature in database

@ -9,3 +9,9 @@ linker = "arm-linux-gnueabihf-gcc"
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
# See https://github.com/rust-lang/rust-analyzer/issues/14510.
#
# Turns out this affects all cargo invocations in the project, not just rust-analyzer.
[unstable]
bindeps = true

@ -38,9 +38,6 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: Prereqs
run: cargo install bpf-linker
- uses: taiki-e/install-action@cargo-hack
- name: Build
env:

@ -32,9 +32,6 @@ jobs:
.tmp/*.qcow2
.tmp/test_rsa
.tmp/test_rsa.pub
# FIXME: we should invalidate the cache on new bpf-linker releases.
# For now we must manually delete the cache when we release a new
# bpf-linker version.
key: tmp-files-${{ hashFiles('test/run.sh') }}
- name: Run integration tests

@ -6,7 +6,7 @@
# ignored if you run from the workspace root. See
# https://doc.rust-lang.org/cargo/reference/config.html#hierarchical-structure
[build]
target = "bpfel-unknown-none"
target = ["bpfeb-unknown-none", "bpfel-unknown-none"]
[unstable]
build-std = ["core"]

@ -10,14 +10,12 @@ common usage behaviours work on real Linux distros
To run locally all you need is:
1. Rust nightly
1. `cargo install bpf-linker`
1. `bpftool` [^1]
### Other OSs
1. A POSIX shell
1. `rustup target add x86_64-unknown-linux-musl`
1. `cargo install bpf-linker`
1. Install `qemu` and `cloud-init-utils` package - or any package that provides `cloud-localds`
## Usage

@ -0,0 +1,12 @@
# We have this so that one doesn't need to manually pass
# --target=bpfel-unknown-none -Z build-std=core when running cargo
# check/build/doc etc.
#
# NB: this file gets loaded only if you run cargo from this directory, it's
# ignored if you run from the workspace root. See
# https://doc.rust-lang.org/cargo/reference/config.html#hierarchical-structure
[build]
target = ["bpfeb-unknown-none", "bpfel-unknown-none"]
[unstable]
build-std = ["core"]

@ -8,6 +8,9 @@ publish = false
aya-bpf = { path = "../../bpf/aya-bpf" }
aya-log-ebpf = { path = "../../bpf/aya-log-ebpf" }
[build-dependencies]
bpf-linker = { git = "https://github.com/aya-rs/bpf-linker.git", artifact = "bin" }
[[bin]]
name = "log"
path = "src/log.rs"

@ -0,0 +1,28 @@
fn main() {
let out_dir = std::env::var_os("OUT_DIR").unwrap();
let out_dir = std::path::PathBuf::from(out_dir);
let bpf_linker = std::env::var("CARGO_BIN_FILE_BPF_LINKER").unwrap();
// There seems to be no way to pass `-Clinker={}` to rustc from here.
//
// We assume rustc is going to look for `bpf-linker` on the PATH, so we can create a symlink and
// put it on the PATH.
let bin_dir = out_dir.join("bin");
std::fs::create_dir_all(&bin_dir).unwrap();
let bpf_linker_symlink = bin_dir.join("bpf-linker");
match std::fs::remove_file(&bpf_linker_symlink) {
Ok(()) => {}
Err(err) => {
if err.kind() != std::io::ErrorKind::NotFound {
panic!("failed to remove symlink: {err}")
}
}
}
std::os::unix::fs::symlink(bpf_linker, bpf_linker_symlink).unwrap();
let path = std::env::var_os("PATH");
let path = path.as_ref();
let paths = std::iter::once(bin_dir).chain(path.into_iter().flat_map(std::env::split_paths));
let path = std::env::join_paths(paths).unwrap();
println!("cargo:rustc-env=PATH={}", path.to_str().unwrap());
}

@ -25,5 +25,13 @@ tokio = { version = "1.24", default-features = false, features = [
[build-dependencies]
cargo_metadata = { version = "0.15.4", default-features = false }
which = { version = "4.4.0", default-features = false }
# TODO(https://github.com/rust-lang/cargo/issues/12375): this should be an artifact dependency, but
# it's not possible to tell cargo to use `-Z build-std` to build it. We cargo-in-cargo in the build
# script to build this, but we want to teach cargo about the dependecy so that cache invalidation
# works properly.
#
# Note also that https://github.com/rust-lang/cargo/issues/10593 occurs when `target = ...` is added
# to an artifact dependency; it seems possible to work around that by setting `resolver = "1"` in
# Cargo.toml in the workspace root.
integration-ebpf = { path = "../integration-ebpf" }
xtask = { path = "../../xtask" }

@ -1,5 +1,4 @@
use std::{
collections::{HashMap, HashSet},
env,
ffi::OsString,
fmt::Write as _,
@ -10,9 +9,8 @@ use std::{
};
use cargo_metadata::{
Artifact, CompilerMessage, Dependency, Message, Metadata, MetadataCommand, Package, Target,
Artifact, CompilerMessage, Message, Metadata, MetadataCommand, Package, Target,
};
use which::which;
use xtask::{exec, LIBBPF_DIR};
fn main() {
@ -28,16 +26,11 @@ fn main() {
}
};
const INTEGRATION_EBPF_PACKAGE: &str = "integration-ebpf";
let Metadata { packages, .. } = MetadataCommand::new().no_deps().exec().unwrap();
let packages: HashMap<String, _> = packages
let integration_ebpf_package = packages
.into_iter()
.map(|package| {
let Package { name, .. } = &package;
(name.clone(), package)
})
.collect();
.find(|Package { name, .. }| name == "integration-ebpf")
.unwrap();
let manifest_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
let manifest_dir = PathBuf::from(manifest_dir);
@ -121,44 +114,8 @@ fn main() {
let target = format!("{target}-unknown-none");
// Teach cargo about our dependencies.
let mut visited = HashSet::new();
let mut frontier = vec![INTEGRATION_EBPF_PACKAGE];
while let Some(package) = frontier.pop() {
if !visited.insert(package) {
continue;
}
let Package { dependencies, .. } = packages.get(package).unwrap();
for Dependency { name, path, .. } in dependencies {
if let Some(path) = path {
println!("cargo:rerun-if-changed={}", path.as_str());
frontier.push(name);
}
}
}
// Create a symlink in the out directory to work around the fact that cargo ignores anything
// in `$CARGO_HOME`, which is also where `cargo install` likes to place binaries. Cargo will
// stat through the symlink and discover that bpf-linker has changed.
//
// This was introduced in https://github.com/rust-lang/cargo/commit/99f841c.
{
let bpf_linker = which("bpf-linker").unwrap();
let bpf_linker_symlink = out_dir.join("bpf-linker");
match fs::remove_file(&bpf_linker_symlink) {
Ok(()) => {}
Err(err) => {
if err.kind() != std::io::ErrorKind::NotFound {
panic!("failed to remove symlink: {err}")
}
}
}
std::os::unix::fs::symlink(&bpf_linker, &bpf_linker_symlink).unwrap();
println!(
"cargo:rerun-if-changed={}",
bpf_linker_symlink.to_str().unwrap()
);
}
let Package { manifest_path, .. } = integration_ebpf_package;
let integration_ebpf_dir = manifest_path.parent().unwrap();
let mut cmd = Command::new("cargo");
cmd.args([
@ -172,8 +129,6 @@ fn main() {
]);
// Workaround to make sure that the rust-toolchain.toml is respected.
let Package { manifest_path, .. } = packages.get(INTEGRATION_EBPF_PACKAGE).unwrap();
let integration_ebpf_dir = manifest_path.parent().unwrap();
cmd.env_remove("RUSTUP_TOOLCHAIN")
.current_dir(integration_ebpf_dir);
@ -231,7 +186,7 @@ fn main() {
fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}"));
}
let Package { targets, .. } = packages.get(INTEGRATION_EBPF_PACKAGE).unwrap();
let Package { targets, .. } = integration_ebpf_package;
for Target { name, kind, .. } in targets {
if *kind != ["bin"] {
continue;

@ -196,7 +196,6 @@ EOF
exec_vm 'curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \
-y --profile minimal --default-toolchain nightly --component rust-src --component clippy'
exec_vm 'echo source ~/.cargo/env >> ~/.bashrc'
exec_vm cargo install bpf-linker --no-default-features
}
scp_vm() {

@ -6,7 +6,7 @@ use std::{
};
use anyhow::{Context as _, Result};
use cargo_metadata::{Artifact, CompilerMessage, Message, Target};
use cargo_metadata::{Artifact, ArtifactProfile, CompilerMessage, Message, Target};
use clap::Parser;
#[derive(Debug, Parser)]
@ -61,10 +61,13 @@ pub fn build(opts: BuildOptions) -> Result<Vec<(String, PathBuf)>> {
Message::CompilerArtifact(Artifact {
executable,
target: Target { name, .. },
profile: ArtifactProfile { test, .. },
..
}) => {
if let Some(executable) = executable {
executables.push((name, executable.into()));
if test {
if let Some(executable) = executable {
executables.push((name, executable.into()));
}
}
}
Message::CompilerMessage(CompilerMessage { message, .. }) => {

Loading…
Cancel
Save