From 239acac2c527828b312304810a9216bfba794496 Mon Sep 17 00:00:00 2001
From: Thomas Eizinger <thomas@eizinger.io>
Date: Thu, 27 Mar 2025 11:03:17 +1100
Subject: [PATCH] workspace: include eBPF crates in default-members

Being able to compile the eBPF crates for the host architecture is
useful because it allows `cargo build` and `cargo test` to "just work".

To achieve that, we feature-gate `no_std` and `no_main` on the bpf
target architecture.
---
 Cargo.toml                                  |  7 ++++---
 ebpf/aya-ebpf/src/lib.rs                    | 10 ++++++++++
 test/integration-ebpf/src/bpf_probe_read.rs |  5 +++--
 test/integration-ebpf/src/log.rs            |  5 +++--
 test/integration-ebpf/src/map_test.rs       |  5 +++--
 test/integration-ebpf/src/memmove_test.rs   |  5 +++--
 test/integration-ebpf/src/name_test.rs      |  5 +++--
 test/integration-ebpf/src/pass.rs           |  5 +++--
 test/integration-ebpf/src/raw_tracepoint.rs |  5 +++--
 test/integration-ebpf/src/redirect.rs       |  5 +++--
 test/integration-ebpf/src/relocations.rs    |  5 +++--
 test/integration-ebpf/src/ring_buf.rs       |  5 +++--
 test/integration-ebpf/src/simple_prog.rs    |  5 +++--
 test/integration-ebpf/src/strncmp.rs        |  5 +++--
 test/integration-ebpf/src/tcx.rs            |  5 +++--
 test/integration-ebpf/src/test.rs           |  5 +++--
 test/integration-ebpf/src/two_progs.rs      |  5 +++--
 test/integration-ebpf/src/uprobe_cookie.rs  |  5 +++--
 test/integration-ebpf/src/xdp_sec.rs        |  5 +++--
 xtask/public-api/aya-ebpf.txt               |  1 +
 20 files changed, 66 insertions(+), 37 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index b21d6f34..c7748639 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -42,9 +42,10 @@ default-members = [
     "aya-ebpf-macros",
     "aya-log-ebpf-macros",
 
-    # ebpf crates are omitted; they must be built with:
-    # --target bpfe{b,l}-unknown-none
-    # CARGO_CFG_BPF_TARGET_ARCH={x86_64,aarch64,arm,riscv64,powerpc64,s390x,mips}
+    "ebpf/aya-ebpf",
+    "ebpf/aya-ebpf-bindings",
+    "ebpf/aya-log-ebpf",
+    "test/integration-ebpf",
 ]
 
 [workspace.package]
diff --git a/ebpf/aya-ebpf/src/lib.rs b/ebpf/aya-ebpf/src/lib.rs
index ae1f6132..d97dff56 100644
--- a/ebpf/aya-ebpf/src/lib.rs
+++ b/ebpf/aya-ebpf/src/lib.rs
@@ -133,6 +133,16 @@ pub fn check_bounds_signed(value: i64, lower: i64, upper: i64) -> bool {
     }
 }
 
+#[macro_export]
+macro_rules! main_stub {
+    () => {
+        #[cfg(not(target_arch = "bpf"))]
+        fn main() {
+            panic!(r#"eBPF kernels are not designed to be executed in user-space. This main function is only a placeholder to allow the code to compile on the host system (i.e. on any system that is not `target_arch = "bpf"`). This works in tandem with the `no_main` attribute which is only applied when compiling for `target_arch = "bpf"`."#)
+        }
+    };
+}
+
 #[macro_export]
 macro_rules! panic_handler {
     () => {
diff --git a/test/integration-ebpf/src/bpf_probe_read.rs b/test/integration-ebpf/src/bpf_probe_read.rs
index 53908d00..d98e53c9 100644
--- a/test/integration-ebpf/src/bpf_probe_read.rs
+++ b/test/integration-ebpf/src/bpf_probe_read.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{
     helpers::{bpf_probe_read_kernel_str_bytes, bpf_probe_read_user_str_bytes},
diff --git a/test/integration-ebpf/src/log.rs b/test/integration-ebpf/src/log.rs
index 55d51677..d732ab9a 100644
--- a/test/integration-ebpf/src/log.rs
+++ b/test/integration-ebpf/src/log.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 
diff --git a/test/integration-ebpf/src/map_test.rs b/test/integration-ebpf/src/map_test.rs
index 0d10b5ae..04ea6f0b 100644
--- a/test/integration-ebpf/src/map_test.rs
+++ b/test/integration-ebpf/src/map_test.rs
@@ -1,8 +1,9 @@
 // Socket Filter program for testing with an arbitrary program with maps.
 // This is mainly used in tests with consideration for old kernels.
 
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{
     macros::{map, socket_filter},
diff --git a/test/integration-ebpf/src/memmove_test.rs b/test/integration-ebpf/src/memmove_test.rs
index 0a2748bb..90204797 100644
--- a/test/integration-ebpf/src/memmove_test.rs
+++ b/test/integration-ebpf/src/memmove_test.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use core::mem;
 
diff --git a/test/integration-ebpf/src/name_test.rs b/test/integration-ebpf/src/name_test.rs
index 0e5a8d90..67255f00 100644
--- a/test/integration-ebpf/src/name_test.rs
+++ b/test/integration-ebpf/src/name_test.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext};
 
diff --git a/test/integration-ebpf/src/pass.rs b/test/integration-ebpf/src/pass.rs
index 0b0371b4..25ed3744 100644
--- a/test/integration-ebpf/src/pass.rs
+++ b/test/integration-ebpf/src/pass.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext};
 
diff --git a/test/integration-ebpf/src/raw_tracepoint.rs b/test/integration-ebpf/src/raw_tracepoint.rs
index 4c1917f0..b2393381 100644
--- a/test/integration-ebpf/src/raw_tracepoint.rs
+++ b/test/integration-ebpf/src/raw_tracepoint.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{
     macros::{map, raw_tracepoint},
diff --git a/test/integration-ebpf/src/redirect.rs b/test/integration-ebpf/src/redirect.rs
index 88e67f76..597a17c3 100644
--- a/test/integration-ebpf/src/redirect.rs
+++ b/test/integration-ebpf/src/redirect.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{
     bindings::xdp_action,
diff --git a/test/integration-ebpf/src/relocations.rs b/test/integration-ebpf/src/relocations.rs
index d2f4fcdf..73600b48 100644
--- a/test/integration-ebpf/src/relocations.rs
+++ b/test/integration-ebpf/src/relocations.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use core::hint;
 
diff --git a/test/integration-ebpf/src/ring_buf.rs b/test/integration-ebpf/src/ring_buf.rs
index 5a508046..2e57c072 100644
--- a/test/integration-ebpf/src/ring_buf.rs
+++ b/test/integration-ebpf/src/ring_buf.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{
     macros::{map, uprobe},
diff --git a/test/integration-ebpf/src/simple_prog.rs b/test/integration-ebpf/src/simple_prog.rs
index df21a7ff..a26f7b6d 100644
--- a/test/integration-ebpf/src/simple_prog.rs
+++ b/test/integration-ebpf/src/simple_prog.rs
@@ -1,8 +1,9 @@
 // Socket Filter program for testing with an arbitrary program.
 // This is mainly used in tests with consideration for old kernels.
 
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{macros::socket_filter, programs::SkBuffContext};
 
diff --git a/test/integration-ebpf/src/strncmp.rs b/test/integration-ebpf/src/strncmp.rs
index 39157d46..e92ee225 100644
--- a/test/integration-ebpf/src/strncmp.rs
+++ b/test/integration-ebpf/src/strncmp.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{
     cty::c_long,
diff --git a/test/integration-ebpf/src/tcx.rs b/test/integration-ebpf/src/tcx.rs
index 3b9953ad..f6d8aecb 100644
--- a/test/integration-ebpf/src/tcx.rs
+++ b/test/integration-ebpf/src/tcx.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{bindings::tcx_action_base::TCX_NEXT, macros::classifier, programs::TcContext};
 
diff --git a/test/integration-ebpf/src/test.rs b/test/integration-ebpf/src/test.rs
index 8a944309..c87dd3b6 100644
--- a/test/integration-ebpf/src/test.rs
+++ b/test/integration-ebpf/src/test.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{
     bindings::{bpf_ret_code, xdp_action},
diff --git a/test/integration-ebpf/src/two_progs.rs b/test/integration-ebpf/src/two_progs.rs
index d727c809..23fd23b5 100644
--- a/test/integration-ebpf/src/two_progs.rs
+++ b/test/integration-ebpf/src/two_progs.rs
@@ -1,7 +1,8 @@
 // Two programs in the same ELF section
 
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{macros::tracepoint, programs::TracePointContext};
 
diff --git a/test/integration-ebpf/src/uprobe_cookie.rs b/test/integration-ebpf/src/uprobe_cookie.rs
index 39f47b5d..3848009c 100644
--- a/test/integration-ebpf/src/uprobe_cookie.rs
+++ b/test/integration-ebpf/src/uprobe_cookie.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{
     EbpfContext as _, helpers,
diff --git a/test/integration-ebpf/src/xdp_sec.rs b/test/integration-ebpf/src/xdp_sec.rs
index 9d442342..39b3cf49 100644
--- a/test/integration-ebpf/src/xdp_sec.rs
+++ b/test/integration-ebpf/src/xdp_sec.rs
@@ -1,5 +1,6 @@
-#![no_std]
-#![no_main]
+#![cfg_attr(target_arch = "bpf", no_std)]
+#![cfg_attr(target_arch = "bpf", no_main)]
+aya_ebpf::main_stub!();
 
 use aya_ebpf::{bindings::xdp_action::XDP_PASS, macros::xdp, programs::XdpContext};
 
diff --git a/xtask/public-api/aya-ebpf.txt b/xtask/public-api/aya-ebpf.txt
index 90255811..70b7bba8 100644
--- a/xtask/public-api/aya-ebpf.txt
+++ b/xtask/public-api/aya-ebpf.txt
@@ -2728,6 +2728,7 @@ pub fn aya_ebpf::programs::xdp::XdpContext::borrow_mut(&mut self) -> &mut T
 impl<T> core::convert::From<T> for aya_ebpf::programs::xdp::XdpContext
 pub fn aya_ebpf::programs::xdp::XdpContext::from(t: T) -> T
 pub macro aya_ebpf::bpf_printk!
+pub macro aya_ebpf::main_stub!
 pub macro aya_ebpf::panic_handler!
 pub struct aya_ebpf::PtRegs
 impl aya_ebpf::PtRegs