Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions cuda-oxide/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cuda-oxide/crates/oxide-artifacts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "oxide-artifacts"
version = "0.2.1"
version = "0.2.2"
edition.workspace = true
description = "Architecture-neutral embedded device artifact metadata for cuda-oxide"
readme = "README.md"
Expand Down
116 changes: 115 additions & 1 deletion cuda-oxide/crates/oxide-artifacts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,58 @@ pub fn build_host_object_for_target_with_legacy_anchor(
pub fn build_host_anchor_object_for_target(
target: &str,
anchor_symbol: &str,
) -> Result<Vec<u8>, ArtifactError> {
build_host_anchor_object_for_target_with_strength(target, anchor_symbol, true)
}

/// Build a host object that only defines a strong artifact link-anchor symbol.
///
/// Unlike [`build_host_anchor_object_for_target`], the anchor is a strong
/// global definition, the same binding a full `.oxart` embed gives it. The
/// CUDA backend uses this for a selected crate whose `#[cuda_module]` only has
/// generic kernels that this crate does not monomorphize: the macro still
/// references the anchor to keep the rlib member linked (#72, #1365), but
/// there is no device bundle to embed. Artifact discovery sees no `.oxart`
/// section in the result.
#[cfg(feature = "object-write")]
pub fn build_host_strong_anchor_object_for_target(
target: &str,
anchor_symbol: &str,
) -> Result<Vec<u8>, ArtifactError> {
build_host_anchor_object_for_target_with_strength(target, anchor_symbol, false)
}

/// Like [`build_host_strong_anchor_object_for_target`], plus a weak legacy
/// alias.
///
/// The target-specific anchor is strong and the legacy package anchor is weak,
/// matching [`build_host_object_for_target_with_legacy_anchor`] for full
/// embeds, so older macro expansions that still reference the legacy name
/// link against the same placeholder.
#[cfg(feature = "object-write")]
pub fn build_host_strong_anchor_object_for_target_with_legacy_anchor(
target: &str,
anchor_symbol: &str,
legacy_anchor_symbol: &str,
) -> Result<Vec<u8>, ArtifactError> {
if anchor_symbol.is_empty() || legacy_anchor_symbol.is_empty() {
return Err(ArtifactError::Malformed(
"embedded artifact anchor symbol is empty".to_string(),
));
}
build_host_object_with_section(
ARTIFACT_ANCHOR_SECTION_NAME,
&[0],
target,
&[(anchor_symbol, false), (legacy_anchor_symbol, true)],
)
}

#[cfg(feature = "object-write")]
fn build_host_anchor_object_for_target_with_strength(
target: &str,
anchor_symbol: &str,
weak: bool,
) -> Result<Vec<u8>, ArtifactError> {
if anchor_symbol.is_empty() {
return Err(ArtifactError::Malformed(
Expand All @@ -766,7 +818,7 @@ pub fn build_host_anchor_object_for_target(
ARTIFACT_ANCHOR_SECTION_NAME,
&[0],
target,
&[(anchor_symbol, true)],
&[(anchor_symbol, weak)],
)
}

Expand Down Expand Up @@ -1306,6 +1358,68 @@ mod tests {
);
}

/// A strong anchor-only object binds the anchor like a full embed does
/// (#72, #1365) and still carries no artifact bundle.
#[cfg(all(feature = "object-read", feature = "object-write"))]
#[test]
fn strong_anchor_only_object_is_global_and_not_weak() {
use object::{Object, ObjectSymbol};

let bytes = build_host_strong_anchor_object_for_target(
"x86_64-unknown-linux-gnu",
"selected_empty_merge_anchor",
)
.unwrap();
let file = object::File::parse(bytes.as_slice()).unwrap();
let anchor = file
.symbols()
.find(|symbol| symbol.name() == Ok("selected_empty_merge_anchor"))
.expect("strong anchor symbol missing");

assert!(anchor.is_definition());
assert!(anchor.is_global());
assert!(!anchor.is_weak());
assert!(
read_artifact_bundles_from_object_bytes(&bytes)
.unwrap()
.is_empty()
);
}

#[cfg(all(feature = "object-read", feature = "object-write"))]
#[test]
fn strong_target_anchor_also_defines_weak_legacy_alias() {
use object::{Object, ObjectSymbol};

let bytes = build_host_strong_anchor_object_for_target_with_legacy_anchor(
"x86_64-unknown-linux-gnu",
"target_stub_anchor",
"legacy_stub_anchor",
)
.unwrap();
let file = object::File::parse(bytes.as_slice()).unwrap();
let target = file
.symbols()
.find(|symbol| symbol.name() == Ok("target_stub_anchor"))
.expect("strong target anchor missing");
let legacy = file
.symbols()
.find(|symbol| symbol.name() == Ok("legacy_stub_anchor"))
.expect("weak legacy alias missing");

assert!(target.is_definition());
assert!(target.is_global());
assert!(!target.is_weak());
assert!(legacy.is_definition());
assert!(legacy.is_global());
assert!(legacy.is_weak());
assert!(
read_artifact_bundles_from_object_bytes(&bytes)
.unwrap()
.is_empty()
);
}

#[cfg(feature = "object-write")]
#[test]
fn anchor_only_object_rejects_empty_symbol() {
Expand Down