Add cargo bpf tools that invoke newer sbf tools and issue deprecation notice

This commit is contained in:
Dmitri Makarov 2022-05-24 17:36:12 -07:00 committed by Dmitri Makarov
parent 9425478f86
commit 4dfaf15a46
23 changed files with 417 additions and 197 deletions

18
Cargo.lock generated
View File

@ -4495,10 +4495,20 @@ dependencies = [
[[package]] [[package]]
name = "solana-cargo-build-bpf" name = "solana-cargo-build-bpf"
version = "1.11.0" version = "1.11.0"
dependencies = [
"cargo_metadata",
"clap 3.1.8",
"solana-sdk 1.11.0",
]
[[package]]
name = "solana-cargo-build-sbf"
version = "1.11.0"
dependencies = [ dependencies = [
"bzip2", "bzip2",
"cargo_metadata", "cargo_metadata",
"clap 3.1.8", "clap 3.1.8",
"log",
"regex", "regex",
"serial_test", "serial_test",
"solana-download-utils", "solana-download-utils",
@ -4514,6 +4524,14 @@ dependencies = [
"clap 3.1.8", "clap 3.1.8",
] ]
[[package]]
name = "solana-cargo-test-sbf"
version = "1.11.0"
dependencies = [
"cargo_metadata",
"clap 3.1.8",
]
[[package]] [[package]]
name = "solana-clap-utils" name = "solana-clap-utils"
version = "1.11.0" version = "1.11.0"

View File

@ -66,7 +66,9 @@ members = [
"runtime/store-tool", "runtime/store-tool",
"sdk", "sdk",
"sdk/cargo-build-bpf", "sdk/cargo-build-bpf",
"sdk/cargo-build-sbf",
"sdk/cargo-test-bpf", "sdk/cargo-test-bpf",
"sdk/cargo-test-sbf",
"sdk/gen-headers", "sdk/gen-headers",
"send-transaction-service", "send-transaction-service",
"stake-accounts", "stake-accounts",

19
cargo-build-bpf Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
here=$(dirname "$0")
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf"
for a in "$@"; do
if [[ $a = --bpf-sdk ]]; then
maybe_bpf_sdk=
fi
done
set -ex
if [[ ! -f "$here"/sdk/bpf/syscalls.txt ]]; then
"$here"/cargo build --manifest-path "$here"/programs/bpf_loader/gen-syscall-list/Cargo.toml
fi
if [[ ! -f "$here"/target/debug/cargo-build-sbf ]]; then
"$here"/cargo build --manifest-path "$here"/sdk/cargo-build-sbf/Cargo.toml
fi
exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-build-bpf/Cargo.toml -- $maybe_bpf_sdk "$@"

View File

@ -2,15 +2,15 @@
here=$(dirname "$0") here=$(dirname "$0")
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf" maybe_sbf_sdk="--sbf-sdk $here/sdk/bpf"
for a in "$@"; do for a in "$@"; do
if [[ $a = --bpf-sdk ]]; then if [[ $a = --sbf-sdk ]]; then
maybe_bpf_sdk= maybe_sbf_sdk=
fi fi
done done
set -ex set -ex
if [[ ! -f sdk/bpf/syscalls.txt ]]; then if [[ ! -f "$here"/sdk/bpf/syscalls.txt ]]; then
"$here"/cargo build --manifest-path "$here"/programs/bpf_loader/gen-syscall-list/Cargo.toml "$here"/cargo build --manifest-path "$here"/programs/bpf_loader/gen-syscall-list/Cargo.toml
fi fi
exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-build-bpf/Cargo.toml -- $maybe_bpf_sdk "$@" exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-build-sbf/Cargo.toml -- $maybe_sbf_sdk "$@"

20
cargo-test-bpf Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
here=$(dirname "$0")
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf"
for a in "$@"; do
if [[ $a = --bpf-sdk ]]; then
maybe_bpf_sdk=
fi
done
export CARGO_BUILD_BPF="$here"/cargo-build-bpf
set -x
if [[ ! -f "$here"/target/debug/cargo-build-sbf ]]; then
"$here"/cargo build --manifest-path "$here"/sdk/cargo-build-sbf/Cargo.toml
fi
if [[ ! -f "$here"/target/debug/cargo-test-sbf ]]; then
"$here"/cargo build --manifest-path "$here"/sdk/cargo-test-sbf/Cargo.toml
fi
exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-test-bpf/Cargo.toml -- $maybe_bpf_sdk "$@"

View File

@ -2,13 +2,13 @@
here=$(dirname "$0") here=$(dirname "$0")
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf" maybe_sbf_sdk="--sbf-sdk $here/sdk/bpf"
for a in "$@"; do for a in "$@"; do
if [[ $a = --bpf-sdk ]]; then if [[ $a = --sbf-sdk ]]; then
maybe_bpf_sdk= maybe_sbf_sdk=
fi fi
done done
export CARGO_BUILD_BPF="$here"/cargo-build-bpf export CARGO_BUILD_SBF="$here"/cargo-build-sbf
set -x set -x
exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-test-bpf/Cargo.toml -- $maybe_bpf_sdk "$@" exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-test-sbf/Cargo.toml -- $maybe_sbf_sdk "$@"

View File

@ -9,16 +9,16 @@ here="$(dirname "$0")"
SBF_TOOLS_VERSION=unknown SBF_TOOLS_VERSION=unknown
cargo_build_bpf_main="${here}/../sdk/cargo-build-bpf/src/main.rs" cargo_build_sbf_main="${here}/../sdk/cargo-build-sbf/src/main.rs"
if [[ -f "${cargo_build_bpf_main}" ]]; then if [[ -f "${cargo_build_sbf_main}" ]]; then
version=$(sed -e 's/^.*bpf_tools_version\s*=\s*"\(v[0-9.]\+\)".*/\1/;t;d' "${cargo_build_bpf_main}") version=$(sed -e 's/^.*sbf_tools_version\s*=\s*"\(v[0-9.]\+\)".*/\1/;t;d' "${cargo_build_sbf_main}")
if [[ ${version} != '' ]]; then if [[ ${version} != '' ]]; then
SBF_TOOLS_VERSION="${version}" SBF_TOOLS_VERSION="${version}"
else else
echo '--- unable to parse SBF_TOOLS_VERSION' echo '--- unable to parse SBF_TOOLS_VERSION'
fi fi
else else
echo "--- '${cargo_build_bpf_main}' not present" echo "--- '${cargo_build_sbf_main}' not present"
fi fi
echo SBF_TOOLS_VERSION="${SBF_TOOLS_VERSION}" echo SBF_TOOLS_VERSION="${SBF_TOOLS_VERSION}"

View File

@ -78,7 +78,7 @@ test-stable-bpf)
bpf_dump_archive="bpf-dumps.tar.bz2" bpf_dump_archive="bpf-dumps.tar.bz2"
rm -f "$bpf_dump_archive" rm -f "$bpf_dump_archive"
tar cjvf "$bpf_dump_archive" "${bpf_target_path}"/{deploy/*.txt,bpfel-unknown-unknown/release/*.so} tar cjvf "$bpf_dump_archive" "${bpf_target_path}"/{deploy/*.txt,sbf-solana-solana/release/*.so}
exit 0 exit 0
;; ;;
test-stable-perf) test-stable-perf)

View File

@ -401,6 +401,8 @@ fn default_shared_object_dirs() -> Vec<PathBuf> {
let mut search_path = vec![]; let mut search_path = vec![];
if let Ok(bpf_out_dir) = std::env::var("BPF_OUT_DIR") { if let Ok(bpf_out_dir) = std::env::var("BPF_OUT_DIR") {
search_path.push(PathBuf::from(bpf_out_dir)); search_path.push(PathBuf::from(bpf_out_dir));
} else if let Ok(bpf_out_dir) = std::env::var("SBF_OUT_DIR") {
search_path.push(PathBuf::from(bpf_out_dir));
} }
search_path.push(PathBuf::from("tests/fixtures")); search_path.push(PathBuf::from("tests/fixtures"));
if let Ok(dir) = std::env::current_dir() { if let Ok(dir) = std::env::current_dir() {
@ -450,7 +452,8 @@ impl Default for ProgramTest {
solana_runtime::system_instruction_processor=trace,\ solana_runtime::system_instruction_processor=trace,\
solana_program_test=info", solana_program_test=info",
); );
let prefer_bpf = std::env::var("BPF_OUT_DIR").is_ok(); let prefer_bpf =
std::env::var("BPF_OUT_DIR").is_ok() || std::env::var("SBF_OUT_DIR").is_ok();
Self { Self {
accounts: vec![], accounts: vec![],

1
sdk/cargo-build-bpf/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
Cargo.lock

View File

@ -0,0 +1,22 @@
[package]
name = "solana-cargo-build-bpf"
version = "1.11.0"
description = "Compile a local package and all of its dependencies using the Solana SBF SDK"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/"
license = "Apache-2.0"
edition = "2021"
publish = false
[dependencies]
cargo_metadata = "0.14.2"
clap = { version = "3.1.5", features = ["cargo", "env"] }
solana-sdk = { path = "..", version = "=1.11.0" }
[features]
program = []
[[bin]]
name = "cargo-build-bpf"
path = "src/main.rs"

View File

@ -0,0 +1,55 @@
use std::{
env,
path::PathBuf,
process::{exit, Command, Stdio},
};
fn main() {
println!("Warning: cargo-build-bpf is deprecated. Please, use cargo-build-sbf");
let mut args = env::args()
.map(|x| {
let s = x;
s.replace("--bpf", "--sbf")
})
.collect::<Vec<_>>();
let program = if let Some(arg0) = args.get(0) {
let arg0 = arg0.replace("build-bpf", "build-sbf");
args.remove(0);
PathBuf::from(arg0)
} else {
PathBuf::from("cargo-build-sbf")
};
// When run as a cargo subcommand, the first program argument is the subcommand name.
// Remove it
if let Some(arg1) = args.get(1) {
if arg1 == "build-bpf" {
args.remove(1);
}
}
print!("cargo-build-bpf child: {}", program.display());
for a in &args {
print!(" {}", a);
}
println!();
let child = Command::new(&program)
.args(&args)
.stdout(Stdio::piped())
.spawn()
.unwrap_or_else(|err| {
eprintln!("Failed to execute {}: {}", program.display(), err);
exit(1);
});
let output = child.wait_with_output().expect("failed to wait on child");
println!(
"{}",
output
.stdout
.as_slice()
.iter()
.map(|&c| c as char)
.collect::<String>()
);
let code = output.status.code().unwrap_or(1);
exit(code);
}

View File

@ -1,7 +1,7 @@
[package] [package]
name = "solana-cargo-build-bpf" name = "solana-cargo-build-sbf"
version = "1.11.0" version = "1.11.0"
description = "Compile a local package and all of its dependencies using the Solana BPF SDK" description = "Compile a local package and all of its dependencies using the Solana SBF SDK"
authors = ["Solana Maintainers <maintainers@solana.foundation>"] authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@ -13,6 +13,7 @@ publish = false
bzip2 = "0.4.3" bzip2 = "0.4.3"
cargo_metadata = "0.14.2" cargo_metadata = "0.14.2"
clap = { version = "3.1.5", features = ["cargo", "env"] } clap = { version = "3.1.5", features = ["cargo", "env"] }
log = { version = "0.4.14", features = ["std"] }
regex = "1.5.6" regex = "1.5.6"
solana-download-utils = { path = "../../download-utils", version = "=1.11.0" } solana-download-utils = { path = "../../download-utils", version = "=1.11.0" }
solana-sdk = { path = "..", version = "=1.11.0" } solana-sdk = { path = "..", version = "=1.11.0" }
@ -25,5 +26,5 @@ serial_test = "*"
program = [] program = []
[[bin]] [[bin]]
name = "cargo-build-bpf" name = "cargo-build-sbf"
path = "src/main.rs" path = "src/main.rs"

View File

@ -1,6 +1,7 @@
use { use {
bzip2::bufread::BzDecoder, bzip2::bufread::BzDecoder,
clap::{crate_description, crate_name, crate_version, Arg}, clap::{crate_description, crate_name, crate_version, Arg},
log::*,
regex::Regex, regex::Regex,
solana_download_utils::download_file, solana_download_utils::download_file,
solana_sdk::signature::{write_keypair_file, Keypair}, solana_sdk::signature::{write_keypair_file, Keypair},
@ -19,9 +20,9 @@ use {
struct Config<'a> { struct Config<'a> {
cargo_args: Option<Vec<&'a str>>, cargo_args: Option<Vec<&'a str>>,
bpf_out_dir: Option<PathBuf>, sbf_out_dir: Option<PathBuf>,
bpf_sdk: PathBuf, sbf_sdk: PathBuf,
bpf_tools_version: &'a str, sbf_tools_version: &'a str,
dump: bool, dump: bool,
features: Vec<String>, features: Vec<String>,
generate_child_script_on_failure: bool, generate_child_script_on_failure: bool,
@ -36,15 +37,15 @@ impl Default for Config<'_> {
fn default() -> Self { fn default() -> Self {
Self { Self {
cargo_args: None, cargo_args: None,
bpf_sdk: env::current_exe() sbf_sdk: env::current_exe()
.expect("Unable to get current executable") .expect("Unable to get current executable")
.parent() .parent()
.expect("Unable to get parent directory") .expect("Unable to get parent directory")
.to_path_buf() .to_path_buf()
.join("sdk") .join("sdk")
.join("bpf"), .join("bpf"),
bpf_out_dir: None, sbf_out_dir: None,
bpf_tools_version: "(unknown)", sbf_tools_version: "(unknown)",
dump: false, dump: false,
features: vec![], features: vec![],
generate_child_script_on_failure: false, generate_child_script_on_failure: false,
@ -63,18 +64,18 @@ where
S: AsRef<OsStr>, S: AsRef<OsStr>,
{ {
let args = args.into_iter().collect::<Vec<_>>(); let args = args.into_iter().collect::<Vec<_>>();
print!("cargo-build-bpf child: {}", program.display()); let mut msg = format!("cargo-build-sbf child: {}", program.display());
for arg in args.iter() { for arg in args.iter() {
print!(" {}", arg.as_ref().to_str().unwrap_or("?")); msg = msg + &format!(" {}", arg.as_ref().to_str().unwrap_or("?")).to_string();
} }
println!(); info!("{}", msg);
let child = Command::new(program) let child = Command::new(program)
.args(&args) .args(&args)
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn() .spawn()
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
eprintln!("Failed to execute {}: {}", program.display(), err); error!("Failed to execute {}: {}", program.display(), err);
exit(1); exit(1);
}); });
@ -83,9 +84,9 @@ where
if !generate_child_script_on_failure { if !generate_child_script_on_failure {
exit(1); exit(1);
} }
eprintln!("cargo-build-bpf exited on command execution failure"); error!("cargo-build-sbf exited on command execution failure");
let script_name = format!( let script_name = format!(
"cargo-build-bpf-child-script-{}.sh", "cargo-build-sbf-child-script-{}.sh",
program.file_name().unwrap().to_str().unwrap(), program.file_name().unwrap().to_str().unwrap(),
); );
let file = File::create(&script_name).unwrap(); let file = File::create(&script_name).unwrap();
@ -99,7 +100,7 @@ where
} }
writeln!(out).unwrap(); writeln!(out).unwrap();
out.flush().unwrap(); out.flush().unwrap();
eprintln!( error!(
"To rerun the failed command for debugging use {}", "To rerun the failed command for debugging use {}",
script_name, script_name,
); );
@ -123,7 +124,7 @@ fn install_if_missing(
) -> Result<(), String> { ) -> Result<(), String> {
// Check whether the target path is an empty directory. This can // Check whether the target path is an empty directory. This can
// happen if package download failed on previous run of // happen if package download failed on previous run of
// cargo-build-bpf. Remove the target_path directory in this // cargo-build-sbf. Remove the target_path directory in this
// case. // case.
if target_path.is_dir() if target_path.is_dir()
&& target_path && target_path
@ -149,7 +150,7 @@ fn install_if_missing(
fs::create_dir_all(&target_path).map_err(|err| err.to_string())?; fs::create_dir_all(&target_path).map_err(|err| err.to_string())?;
let mut url = String::from(url); let mut url = String::from(url);
url.push('/'); url.push('/');
url.push_str(config.bpf_tools_version); url.push_str(config.sbf_tools_version);
url.push('/'); url.push('/');
url.push_str(download_file_name); url.push_str(download_file_name);
let download_file_path = target_path.join(download_file_name); let download_file_path = target_path.join(download_file_name);
@ -166,8 +167,8 @@ fn install_if_missing(
fs::remove_file(download_file_path).map_err(|err| err.to_string())?; fs::remove_file(download_file_path).map_err(|err| err.to_string())?;
} }
// Make a symbolic link source_path -> target_path in the // Make a symbolic link source_path -> target_path in the
// sdk/bpf/dependencies directory if no valid link found. // sdk/sbf/dependencies directory if no valid link found.
let source_base = config.bpf_sdk.join("dependencies"); let source_base = config.sbf_sdk.join("dependencies");
if !source_base.exists() { if !source_base.exists() {
fs::create_dir_all(&source_base).map_err(|err| err.to_string())?; fs::create_dir_all(&source_base).map_err(|err| err.to_string())?;
} }
@ -293,7 +294,7 @@ fn postprocess_dump(program_dump: &Path) {
// Check whether the built .so file contains undefined symbols that are // Check whether the built .so file contains undefined symbols that are
// not known to the runtime and warn about them if any. // not known to the runtime and warn about them if any.
fn check_undefined_symbols(config: &Config, program: &Path) { fn check_undefined_symbols(config: &Config, program: &Path) {
let syscalls_txt = config.bpf_sdk.join("syscalls.txt"); let syscalls_txt = config.sbf_sdk.join("syscalls.txt");
let file = match File::open(syscalls_txt) { let file = match File::open(syscalls_txt) {
Ok(x) => x, Ok(x) => x,
_ => return, _ => return,
@ -308,9 +309,9 @@ fn check_undefined_symbols(config: &Config, program: &Path) {
Regex::new(r"^ *[0-9]+: [0-9a-f]{16} +[0-9a-f]+ +NOTYPE +GLOBAL +DEFAULT +UND +(.+)") Regex::new(r"^ *[0-9]+: [0-9a-f]{16} +[0-9a-f]+ +NOTYPE +GLOBAL +DEFAULT +UND +(.+)")
.unwrap(); .unwrap();
let readelf = config let readelf = config
.bpf_sdk .sbf_sdk
.join("dependencies") .join("dependencies")
.join("bpf-tools") .join("sbf-tools")
.join("llvm") .join("llvm")
.join("bin") .join("bin")
.join("llvm-readelf"); .join("llvm-readelf");
@ -322,7 +323,7 @@ fn check_undefined_symbols(config: &Config, program: &Path) {
config.generate_child_script_on_failure, config.generate_child_script_on_failure,
); );
if config.verbose { if config.verbose {
println!("{}", output); debug!("{}", output);
} }
let mut unresolved_symbols: Vec<String> = Vec::new(); let mut unresolved_symbols: Vec<String> = Vec::new();
for line in output.lines() { for line in output.lines() {
@ -336,20 +337,20 @@ fn check_undefined_symbols(config: &Config, program: &Path) {
} }
} }
if !unresolved_symbols.is_empty() { if !unresolved_symbols.is_empty() {
println!( warn!(
"Warning: the following functions are undefined and not known syscalls {:?}.", "The following functions are undefined and not known syscalls {:?}.",
unresolved_symbols unresolved_symbols
); );
println!(" Calling them will trigger a run-time error."); warn!(" Calling them will trigger a run-time error.");
} }
} }
// check whether custom BPF toolchain is linked, and link it if it is not. // check whether custom SBF toolchain is linked, and link it if it is not.
fn link_bpf_toolchain(config: &Config) { fn link_sbf_toolchain(config: &Config) {
let toolchain_path = config let toolchain_path = config
.bpf_sdk .sbf_sdk
.join("dependencies") .join("dependencies")
.join("bpf-tools") .join("sbf-tools")
.join("rust"); .join("rust");
let rustup = PathBuf::from("rustup"); let rustup = PathBuf::from("rustup");
let rustup_args = vec!["toolchain", "list", "-v"]; let rustup_args = vec!["toolchain", "list", "-v"];
@ -359,23 +360,23 @@ fn link_bpf_toolchain(config: &Config) {
config.generate_child_script_on_failure, config.generate_child_script_on_failure,
); );
if config.verbose { if config.verbose {
println!("{}", rustup_output); debug!("{}", rustup_output);
} }
let mut do_link = true; let mut do_link = true;
for line in rustup_output.lines() { for line in rustup_output.lines() {
if line.starts_with("bpf") { if line.starts_with("sbf") {
let mut it = line.split_whitespace(); let mut it = line.split_whitespace();
let _ = it.next(); let _ = it.next();
let path = it.next(); let path = it.next();
if path.unwrap() != toolchain_path.to_str().unwrap() { if path.unwrap() != toolchain_path.to_str().unwrap() {
let rustup_args = vec!["toolchain", "uninstall", "bpf"]; let rustup_args = vec!["toolchain", "uninstall", "sbf"];
let output = spawn( let output = spawn(
&rustup, &rustup,
&rustup_args, &rustup_args,
config.generate_child_script_on_failure, config.generate_child_script_on_failure,
); );
if config.verbose { if config.verbose {
println!("{}", output); debug!("{}", output);
} }
} else { } else {
do_link = false; do_link = false;
@ -384,19 +385,19 @@ fn link_bpf_toolchain(config: &Config) {
} }
} }
if do_link { if do_link {
let rustup_args = vec!["toolchain", "link", "bpf", toolchain_path.to_str().unwrap()]; let rustup_args = vec!["toolchain", "link", "sbf", toolchain_path.to_str().unwrap()];
let output = spawn( let output = spawn(
&rustup, &rustup,
&rustup_args, &rustup_args,
config.generate_child_script_on_failure, config.generate_child_script_on_failure,
); );
if config.verbose { if config.verbose {
println!("{}", output); debug!("{}", output);
} }
} }
} }
fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_metadata::Package) { fn build_sbf_package(config: &Config, target_directory: &Path, package: &cargo_metadata::Package) {
let program_name = { let program_name = {
let cdylib_targets = package let cdylib_targets = package
.targets .targets
@ -412,7 +413,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
match cdylib_targets.len() { match cdylib_targets.len() {
0 => { 0 => {
println!( warn!(
"Note: {} crate does not contain a cdylib target", "Note: {} crate does not contain a cdylib target",
package.name package.name
); );
@ -420,7 +421,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
} }
1 => Some(cdylib_targets[0].replace('-', "_")), 1 => Some(cdylib_targets[0].replace('-', "_")),
_ => { _ => {
eprintln!( error!(
"{} crate contains multiple cdylib targets: {:?}", "{} crate contains multiple cdylib targets: {:?}",
package.name, cdylib_targets package.name, cdylib_targets
); );
@ -431,61 +432,59 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
let legacy_program_feature_present = package.name == "solana-sdk"; let legacy_program_feature_present = package.name == "solana-sdk";
let root_package_dir = &package.manifest_path.parent().unwrap_or_else(|| { let root_package_dir = &package.manifest_path.parent().unwrap_or_else(|| {
eprintln!("Unable to get directory of {}", package.manifest_path); error!("Unable to get directory of {}", package.manifest_path);
exit(1); exit(1);
}); });
let bpf_out_dir = config let sbf_out_dir = config
.bpf_out_dir .sbf_out_dir
.as_ref() .as_ref()
.cloned() .cloned()
.unwrap_or_else(|| target_directory.join("deploy")); .unwrap_or_else(|| target_directory.join("deploy"));
let target_build_directory = target_directory let target_build_directory = target_directory.join("sbf-solana-solana").join("release");
.join("bpfel-unknown-unknown")
.join("release");
env::set_current_dir(&root_package_dir).unwrap_or_else(|err| { env::set_current_dir(&root_package_dir).unwrap_or_else(|err| {
eprintln!( error!(
"Unable to set current directory to {}: {}", "Unable to set current directory to {}: {}",
root_package_dir, err root_package_dir, err
); );
exit(1); exit(1);
}); });
println!("BPF SDK: {}", config.bpf_sdk.display()); info!("SBF SDK: {}", config.sbf_sdk.display());
if config.no_default_features { if config.no_default_features {
println!("No default features"); info!("No default features");
} }
if !config.features.is_empty() { if !config.features.is_empty() {
println!("Features: {}", config.features.join(" ")); info!("Features: {}", config.features.join(" "));
} }
if legacy_program_feature_present { if legacy_program_feature_present {
println!("Legacy program feature detected"); info!("Legacy program feature detected");
} }
let bpf_tools_download_file_name = if cfg!(target_os = "windows") { let sbf_tools_download_file_name = if cfg!(target_os = "windows") {
"solana-bpf-tools-windows.tar.bz2" "solana-sbf-tools-windows.tar.bz2"
} else if cfg!(target_os = "macos") { } else if cfg!(target_os = "macos") {
"solana-bpf-tools-osx.tar.bz2" "solana-sbf-tools-osx.tar.bz2"
} else { } else {
"solana-bpf-tools-linux.tar.bz2" "solana-sbf-tools-linux.tar.bz2"
}; };
let home_dir = PathBuf::from(env::var("HOME").unwrap_or_else(|err| { let home_dir = PathBuf::from(env::var("HOME").unwrap_or_else(|err| {
eprintln!("Can't get home directory path: {}", err); error!("Can't get home directory path: {}", err);
exit(1); exit(1);
})); }));
let package = "bpf-tools"; let package = "sbf-tools";
let target_path = home_dir let target_path = home_dir
.join(".cache") .join(".cache")
.join("solana") .join("solana")
.join(config.bpf_tools_version) .join(config.sbf_tools_version)
.join(package); .join(package);
install_if_missing( install_if_missing(
config, config,
package, package,
"https://github.com/solana-labs/bpf-tools/releases/download", "https://github.com/solana-labs/bpf-tools/releases/download",
bpf_tools_download_file_name, sbf_tools_download_file_name,
&target_path, &target_path,
) )
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
@ -493,22 +492,22 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
// installation, and it should be removed. // installation, and it should be removed.
let target_path_parent = target_path.parent().expect("Invalid package path"); let target_path_parent = target_path.parent().expect("Invalid package path");
fs::remove_dir_all(&target_path_parent).unwrap_or_else(|err| { fs::remove_dir_all(&target_path_parent).unwrap_or_else(|err| {
eprintln!( error!(
"Failed to remove {} while recovering from installation failure: {}", "Failed to remove {} while recovering from installation failure: {}",
target_path_parent.to_string_lossy(), target_path_parent.to_string_lossy(),
err, err,
); );
exit(1); exit(1);
}); });
eprintln!("Failed to install bpf-tools: {}", err); error!("Failed to install sbf-tools: {}", err);
exit(1); exit(1);
}); });
link_bpf_toolchain(config); link_sbf_toolchain(config);
let llvm_bin = config let llvm_bin = config
.bpf_sdk .sbf_sdk
.join("dependencies") .join("dependencies")
.join("bpf-tools") .join("sbf-tools")
.join("llvm") .join("llvm")
.join("bin"); .join("bin");
env::set_var("CC", llvm_bin.join("clang")); env::set_var("CC", llvm_bin.join("clang"));
@ -517,7 +516,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
env::set_var("OBJCOPY", llvm_bin.join("llvm-objcopy")); env::set_var("OBJCOPY", llvm_bin.join("llvm-objcopy"));
if config.verbose { if config.verbose {
println!( debug!(
"RUSTFLAGS={}", "RUSTFLAGS={}",
env::var("RUSTFLAGS").ok().as_deref().unwrap_or("") env::var("RUSTFLAGS").ok().as_deref().unwrap_or("")
); );
@ -525,10 +524,10 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
let cargo_build = PathBuf::from("cargo"); let cargo_build = PathBuf::from("cargo");
let mut cargo_build_args = vec![ let mut cargo_build_args = vec![
"+bpf", "+sbf",
"build", "build",
"--target", "--target",
"bpfel-unknown-unknown", "sbf-solana-solana",
"--release", "--release",
]; ];
if config.no_default_features { if config.no_default_features {
@ -562,18 +561,18 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
config.generate_child_script_on_failure, config.generate_child_script_on_failure,
); );
if config.verbose { if config.verbose {
println!("{}", output); debug!("{}", output);
} }
if let Some(program_name) = program_name { if let Some(program_name) = program_name {
let program_unstripped_so = target_build_directory.join(&format!("{}.so", program_name)); let program_unstripped_so = target_build_directory.join(&format!("{}.so", program_name));
let program_dump = bpf_out_dir.join(&format!("{}-dump.txt", program_name)); let program_dump = sbf_out_dir.join(&format!("{}-dump.txt", program_name));
let program_so = bpf_out_dir.join(&format!("{}.so", program_name)); let program_so = sbf_out_dir.join(&format!("{}.so", program_name));
let program_keypair = bpf_out_dir.join(&format!("{}-keypair.json", program_name)); let program_keypair = sbf_out_dir.join(&format!("{}-keypair.json", program_name));
fn file_older_or_missing(prerequisite_file: &Path, target_file: &Path) -> bool { fn file_older_or_missing(prerequisite_file: &Path, target_file: &Path) -> bool {
let prerequisite_metadata = fs::metadata(prerequisite_file).unwrap_or_else(|err| { let prerequisite_metadata = fs::metadata(prerequisite_file).unwrap_or_else(|err| {
eprintln!( error!(
"Unable to get file metadata for {}: {}", "Unable to get file metadata for {}: {}",
prerequisite_file.display(), prerequisite_file.display(),
err err
@ -592,7 +591,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
if !program_keypair.exists() { if !program_keypair.exists() {
write_keypair_file(&Keypair::new(), &program_keypair).unwrap_or_else(|err| { write_keypair_file(&Keypair::new(), &program_keypair).unwrap_or_else(|err| {
eprintln!( error!(
"Unable to get create {}: {}", "Unable to get create {}: {}",
program_keypair.display(), program_keypair.display(),
err err
@ -614,21 +613,21 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
); );
#[cfg(not(windows))] #[cfg(not(windows))]
let output = spawn( let output = spawn(
&config.bpf_sdk.join("scripts").join("strip.sh"), &config.sbf_sdk.join("scripts").join("strip.sh"),
&[&program_unstripped_so, &program_so], &[&program_unstripped_so, &program_so],
config.generate_child_script_on_failure, config.generate_child_script_on_failure,
); );
if config.verbose { if config.verbose {
println!("{}", output); debug!("{}", output);
} }
} }
if config.dump && file_older_or_missing(&program_unstripped_so, &program_dump) { if config.dump && file_older_or_missing(&program_unstripped_so, &program_dump) {
let dump_script = config.bpf_sdk.join("scripts").join("dump.sh"); let dump_script = config.sbf_sdk.join("scripts").join("dump.sh");
#[cfg(windows)] #[cfg(windows)]
{ {
eprintln!("Using Bash scripts from within a program is not supported on Windows, skipping `--dump`."); error!("Using Bash scripts from within a program is not supported on Windows, skipping `--dump`.");
eprintln!( error!(
"Please run \"{} {} {}\" from a Bash-supporting shell, then re-run this command to see the processed program dump.", "Please run \"{} {} {}\" from a Bash-supporting shell, then re-run this command to see the processed program dump.",
&dump_script.display(), &dump_script.display(),
&program_unstripped_so.display(), &program_unstripped_so.display(),
@ -642,7 +641,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
config.generate_child_script_on_failure, config.generate_child_script_on_failure,
); );
if config.verbose { if config.verbose {
println!("{}", output); debug!("{}", output);
} }
} }
postprocess_dump(&program_dump); postprocess_dump(&program_dump);
@ -650,17 +649,16 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
check_undefined_symbols(config, &program_so); check_undefined_symbols(config, &program_so);
println!(); info!("To deploy this program:");
println!("To deploy this program:"); info!(" $ solana program deploy {}", program_so.display());
println!(" $ solana program deploy {}", program_so.display()); info!("The program address will default to this keypair (override with --program-id):");
println!("The program address will default to this keypair (override with --program-id):"); info!(" {}", program_keypair.display());
println!(" {}", program_keypair.display());
} else if config.dump { } else if config.dump {
println!("Note: --dump is only available for crates with a cdylib target"); warn!("Note: --dump is only available for crates with a cdylib target");
} }
} }
fn build_bpf(config: Config, manifest_path: Option<PathBuf>) { fn build_sbf(config: Config, manifest_path: Option<PathBuf>) {
let mut metadata_command = cargo_metadata::MetadataCommand::new(); let mut metadata_command = cargo_metadata::MetadataCommand::new();
if let Some(manifest_path) = manifest_path { if let Some(manifest_path) = manifest_path {
metadata_command.manifest_path(manifest_path); metadata_command.manifest_path(manifest_path);
@ -670,18 +668,18 @@ fn build_bpf(config: Config, manifest_path: Option<PathBuf>) {
} }
let metadata = metadata_command.exec().unwrap_or_else(|err| { let metadata = metadata_command.exec().unwrap_or_else(|err| {
eprintln!("Failed to obtain package metadata: {}", err); error!("Failed to obtain package metadata: {}", err);
exit(1); exit(1);
}); });
if let Some(root_package) = metadata.root_package() { if let Some(root_package) = metadata.root_package() {
if !config.workspace { if !config.workspace {
build_bpf_package(&config, metadata.target_directory.as_ref(), root_package); build_sbf_package(&config, metadata.target_directory.as_ref(), root_package);
return; return;
} }
} }
let all_bpf_packages = metadata let all_sbf_packages = metadata
.packages .packages
.iter() .iter()
.filter(|package| { .filter(|package| {
@ -696,47 +694,47 @@ fn build_bpf(config: Config, manifest_path: Option<PathBuf>) {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for package in all_bpf_packages { for package in all_sbf_packages {
build_bpf_package(&config, metadata.target_directory.as_ref(), package); build_sbf_package(&config, metadata.target_directory.as_ref(), package);
} }
} }
fn main() { fn main() {
let default_config = Config::default(); let default_config = Config::default();
let default_bpf_sdk = format!("{}", default_config.bpf_sdk.display()); let default_sbf_sdk = format!("{}", default_config.sbf_sdk.display());
let mut args = env::args().collect::<Vec<_>>(); let mut args = env::args().collect::<Vec<_>>();
// When run as a cargo subcommand, the first program argument is the subcommand name. // When run as a cargo subcommand, the first program argument is the subcommand name.
// Remove it // Remove it
if let Some(arg1) = args.get(1) { if let Some(arg1) = args.get(1) {
if arg1 == "build-bpf" { if arg1 == "build-sbf" {
args.remove(1); args.remove(1);
} }
} }
// The following line is scanned by CI configuration script to // The following line is scanned by CI configuration script to
// separate cargo caches according to the version of sbf-tools. // separate cargo caches according to the version of sbf-tools.
let bpf_tools_version = "v1.27"; let sbf_tools_version = "v1.27";
let version = format!("{}\nbpf-tools {}", crate_version!(), bpf_tools_version); let version = format!("{}\nsbf-tools {}", crate_version!(), sbf_tools_version);
let matches = clap::Command::new(crate_name!()) let matches = clap::Command::new(crate_name!())
.about(crate_description!()) .about(crate_description!())
.version(version.as_str()) .version(version.as_str())
.arg( .arg(
Arg::new("bpf_out_dir") Arg::new("sbf_out_dir")
.env("BPF_OUT_PATH") .env("SBF_OUT_PATH")
.long("bpf-out-dir") .long("sbf-out-dir")
.value_name("DIRECTORY") .value_name("DIRECTORY")
.takes_value(true) .takes_value(true)
.help("Place final BPF build artifacts in this directory"), .help("Place final SBF build artifacts in this directory"),
) )
.arg( .arg(
Arg::new("bpf_sdk") Arg::new("sbf_sdk")
.env("BPF_SDK_PATH") .env("SBF_SDK_PATH")
.long("bpf-sdk") .long("sbf-sdk")
.value_name("PATH") .value_name("PATH")
.takes_value(true) .takes_value(true)
.default_value(&default_bpf_sdk) .default_value(&default_sbf_sdk)
.help("Path to the Solana BPF SDK"), .help("Path to the Solana SBF SDK"),
) )
.arg( .arg(
Arg::new("cargo_args") Arg::new("cargo_args")
@ -797,7 +795,7 @@ fn main() {
.long("workspace") .long("workspace")
.takes_value(false) .takes_value(false)
.alias("all") .alias("all")
.help("Build all BPF packages in the workspace"), .help("Build all SBF packages in the workspace"),
) )
.arg( .arg(
Arg::new("jobs") Arg::new("jobs")
@ -810,31 +808,31 @@ fn main() {
) )
.get_matches_from(args); .get_matches_from(args);
let bpf_sdk: PathBuf = matches.value_of_t_or_exit("bpf_sdk"); let sbf_sdk: PathBuf = matches.value_of_t_or_exit("sbf_sdk");
let bpf_out_dir: Option<PathBuf> = matches.value_of_t("bpf_out_dir").ok(); let sbf_out_dir: Option<PathBuf> = matches.value_of_t("sbf_out_dir").ok();
let config = Config { let config = Config {
cargo_args: matches cargo_args: matches
.values_of("cargo_args") .values_of("cargo_args")
.map(|vals| vals.collect::<Vec<_>>()), .map(|vals| vals.collect::<Vec<_>>()),
bpf_sdk: fs::canonicalize(&bpf_sdk).unwrap_or_else(|err| { sbf_sdk: fs::canonicalize(&sbf_sdk).unwrap_or_else(|err| {
eprintln!( error!(
"BPF SDK path does not exist: {}: {}", "SBF SDK path does not exist: {}: {}",
bpf_sdk.display(), sbf_sdk.display(),
err err
); );
exit(1); exit(1);
}), }),
bpf_out_dir: bpf_out_dir.map(|bpf_out_dir| { sbf_out_dir: sbf_out_dir.map(|sbf_out_dir| {
if bpf_out_dir.is_absolute() { if sbf_out_dir.is_absolute() {
bpf_out_dir sbf_out_dir
} else { } else {
env::current_dir() env::current_dir()
.expect("Unable to get current working directory") .expect("Unable to get current working directory")
.join(bpf_out_dir) .join(sbf_out_dir)
} }
}), }),
bpf_tools_version, sbf_tools_version,
dump: matches.is_present("dump"), dump: matches.is_present("dump"),
features: matches.values_of_t("features").ok().unwrap_or_default(), features: matches.values_of_t("features").ok().unwrap_or_default(),
generate_child_script_on_failure: matches.is_present("generate_child_script_on_failure"), generate_child_script_on_failure: matches.is_present("generate_child_script_on_failure"),
@ -845,5 +843,5 @@ fn main() {
jobs: matches.value_of_t("jobs").ok(), jobs: matches.value_of_t("jobs").ok(),
}; };
let manifest_path: Option<PathBuf> = matches.value_of_t("manifest_path").ok(); let manifest_path: Option<PathBuf> = matches.value_of_t("manifest_path").ok();
build_bpf(config, manifest_path); build_sbf(config, manifest_path);
} }

View File

@ -20,15 +20,15 @@ fn run_cargo_build(crate_name: &str, extra_args: &[&str]) -> Output {
.join(crate_name) .join(crate_name)
.join("Cargo.toml"); .join("Cargo.toml");
let toml = format!("{}", toml.display()); let toml = format!("{}", toml.display());
let mut args = vec!["--bpf-sdk", "../bpf", "--manifest-path", &toml]; let mut args = vec!["--sbf-sdk", "../bpf", "--manifest-path", &toml];
for arg in extra_args { for arg in extra_args {
args.push(arg); args.push(arg);
} }
let cargo_build_bpf = root.join("target").join("debug").join("cargo-build-bpf"); let cargo_build_sbf = root.join("target").join("debug").join("cargo-build-sbf");
let output = Command::new(cargo_build_bpf) let output = Command::new(cargo_build_sbf)
.args(&args) .args(&args)
.output() .output()
.expect("Error running cargo-build-bpf"); .expect("Error running cargo-build-sbf");
if !output.status.success() { if !output.status.success() {
eprintln!("--- stdout ---"); eprintln!("--- stdout ---");
io::stderr().write_all(&output.stdout).unwrap(); io::stderr().write_all(&output.stdout).unwrap();
@ -51,7 +51,7 @@ fn test_build() {
fn test_dump() { fn test_dump() {
// This test requires rustfilt. // This test requires rustfilt.
assert!(Command::new("cargo") assert!(Command::new("cargo")
.args(&["install", "rustfilt"]) .args(&["install", "-f", "rustfilt"])
.status() .status()
.expect("Unable to install rustfilt required for --dump option") .expect("Unable to install rustfilt required for --dump option")
.success()); .success());
@ -71,7 +71,7 @@ fn test_dump() {
#[test] #[test]
#[serial] #[serial]
fn test_out_dir() { fn test_out_dir() {
let output = run_cargo_build("noop", &["--bpf-out-dir", "tmp_out"]); let output = run_cargo_build("noop", &["--sbf-out-dir", "tmp_out"]);
assert!(output.status.success()); assert!(output.status.success());
let cwd = env::current_dir().expect("Unable to get current working directory"); let cwd = env::current_dir().expect("Unable to get current working directory");
let dir = cwd.join("tmp_out"); let dir = cwd.join("tmp_out");
@ -89,7 +89,7 @@ fn test_generate_child_script_on_failre() {
.join("tests") .join("tests")
.join("crates") .join("crates")
.join("fail") .join("fail")
.join("cargo-build-bpf-child-script-cargo.sh"); .join("cargo-build-sbf-child-script-cargo.sh");
assert!(scr.exists()); assert!(scr.exists());
fs::remove_file(scr).expect("Failed to remove script"); fs::remove_file(scr).expect("Failed to remove script");
} }

View File

@ -1,7 +1,7 @@
[package] [package]
name = "fail" name = "fail"
version = "1.11.0" version = "1.11.0"
description = "Solana BPF test program written in Rust" description = "Solana SBF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.foundation>"] authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"

View File

@ -1,4 +1,4 @@
//! Example Rust-based BPF noop program //! Example Rust-based SBF noop program
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};

View File

@ -1,7 +1,7 @@
[package] [package]
name = "noop" name = "noop"
version = "1.11.0" version = "1.11.0"
description = "Solana BPF test program written in Rust" description = "Solana SBF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.foundation>"] authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"

View File

@ -1,4 +1,4 @@
//! Example Rust-based BPF noop program //! Example Rust-based SBF noop program
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};

View File

@ -0,0 +1,18 @@
[package]
name = "solana-cargo-test-bpf"
version = "1.11.0"
description = "Execute all unit and integration tests after building with the Solana SBF SDK"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/"
license = "Apache-2.0"
edition = "2021"
publish = false
[dependencies]
cargo_metadata = "0.14.2"
clap = { version = "3.1.5", features = ["cargo"] }
[[bin]]
name = "cargo-test-bpf"
path = "src/main.rs"

View File

@ -0,0 +1,61 @@
use std::{
env,
path::PathBuf,
process::{exit, Command, Stdio},
};
fn main() {
println!("Warning: cargo-test-bpf is deprecated. Please, use cargo-test-sbf");
let mut args = env::args()
.map(|x| {
let s = x;
s.replace("--bpf", "--sbf")
})
.collect::<Vec<_>>();
if let Ok(cargo_build_bpf) = env::var("CARGO_BUILD_BPF") {
let cargo_build_sbf = cargo_build_bpf.replace("build-bpf", "build-sbf");
env::set_var("CARGO_BUILD_SBF", cargo_build_sbf);
}
let program = if let Some(arg0) = args.get(0) {
let cargo_test_sbf = arg0.replace("test-bpf", "test-sbf");
let cargo_build_sbf = cargo_test_sbf.replace("test-sbf", "build-sbf");
env::set_var("CARGO_BUILD_SBF", cargo_build_sbf);
args.remove(0);
PathBuf::from(cargo_test_sbf)
} else {
PathBuf::from("cargo-test-sbf")
};
// When run as a cargo subcommand, the first program argument is the subcommand name.
// Remove it
if let Some(arg1) = args.get(1) {
if arg1 == "test-bpf" {
args.remove(1);
}
}
print!("cargo-test-bpf child: {}", program.display());
for a in &args {
print!(" {}", a);
}
println!();
let child = Command::new(&program)
.args(&args)
.stdout(Stdio::piped())
.spawn()
.unwrap_or_else(|err| {
eprintln!("Failed to execute {}: {}", program.display(), err);
exit(1);
});
let output = child.wait_with_output().expect("failed to wait on child");
println!(
"{}",
output
.stdout
.as_slice()
.iter()
.map(|&c| c as char)
.collect::<String>()
);
let code = output.status.code().unwrap_or(1);
exit(code);
}

View File

@ -1,7 +1,7 @@
[package] [package]
name = "solana-cargo-test-bpf" name = "solana-cargo-test-sbf"
version = "1.11.0" version = "1.11.0"
description = "Execute all unit and integration tests after building with the Solana BPF SDK" description = "Execute all unit and integration tests after building with the Solana SBF SDK"
authors = ["Solana Maintainers <maintainers@solana.foundation>"] authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@ -14,5 +14,5 @@ cargo_metadata = "0.14.2"
clap = { version = "3.1.5", features = ["cargo"] } clap = { version = "3.1.5", features = ["cargo"] }
[[bin]] [[bin]]
name = "cargo-test-bpf" name = "cargo-test-sbf"
path = "src/main.rs" path = "src/main.rs"

View File

@ -11,10 +11,10 @@ use {
}; };
struct Config { struct Config {
bpf_sdk: Option<String>, sbf_sdk: Option<String>,
bpf_out_dir: Option<String>, sbf_out_dir: Option<String>,
cargo: PathBuf, cargo: PathBuf,
cargo_build_bpf: PathBuf, cargo_build_sbf: PathBuf,
extra_cargo_test_args: Vec<String>, extra_cargo_test_args: Vec<String>,
features: Vec<String>, features: Vec<String>,
generate_child_script_on_failure: bool, generate_child_script_on_failure: bool,
@ -30,10 +30,10 @@ struct Config {
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
bpf_sdk: None, sbf_sdk: None,
bpf_out_dir: None, sbf_out_dir: None,
cargo: PathBuf::from("cargo"), cargo: PathBuf::from("cargo"),
cargo_build_bpf: PathBuf::from("cargo-build-bpf"), cargo_build_sbf: PathBuf::from("cargo-build-sbf"),
extra_cargo_test_args: vec![], extra_cargo_test_args: vec![],
features: vec![], features: vec![],
generate_child_script_on_failure: false, generate_child_script_on_failure: false,
@ -54,7 +54,7 @@ where
S: AsRef<OsStr>, S: AsRef<OsStr>,
{ {
let args = args.into_iter().collect::<Vec<_>>(); let args = args.into_iter().collect::<Vec<_>>();
print!("cargo-test-bpf child: {}", program.display()); print!("cargo-test-sbf child: {}", program.display());
for arg in args.iter() { for arg in args.iter() {
print!(" {}", arg.as_ref().to_str().unwrap_or("?")); print!(" {}", arg.as_ref().to_str().unwrap_or("?"));
} }
@ -73,9 +73,9 @@ where
if !generate_child_script_on_failure { if !generate_child_script_on_failure {
exit(1); exit(1);
} }
eprintln!("cargo-test-bpf exited on command execution failure"); eprintln!("cargo-test-sbf exited on command execution failure");
let script_name = format!( let script_name = format!(
"cargo-test-bpf-child-script-{}.sh", "cargo-test-sbf-child-script-{}.sh",
program.file_name().unwrap().to_str().unwrap(), program.file_name().unwrap().to_str().unwrap(),
); );
let file = File::create(&script_name).unwrap(); let file = File::create(&script_name).unwrap();
@ -97,11 +97,9 @@ where
} }
} }
fn test_bpf_package(config: &Config, target_directory: &Path, package: &cargo_metadata::Package) { fn test_sbf_package(config: &Config, target_directory: &Path, package: &cargo_metadata::Package) {
let set_test_bpf_feature = package.features.contains_key("test-bpf"); let sbf_out_dir = config
.sbf_out_dir
let bpf_out_dir = config
.bpf_out_dir
.as_ref() .as_ref()
.cloned() .cloned()
.unwrap_or_else(|| format!("{}", target_directory.join("deploy").display())); .unwrap_or_else(|| format!("{}", target_directory.join("deploy").display()));
@ -123,22 +121,22 @@ fn test_bpf_package(config: &Config, target_directory: &Path, package: &cargo_me
cargo_args.push(jobs); cargo_args.push(jobs);
} }
let mut build_bpf_args = cargo_args.clone(); let mut build_sbf_args = cargo_args.clone();
if let Some(bpf_sdk) = config.bpf_sdk.as_ref() { if let Some(sbf_sdk) = config.sbf_sdk.as_ref() {
build_bpf_args.push("--bpf-sdk"); build_sbf_args.push("--sbf-sdk");
build_bpf_args.push(bpf_sdk); build_sbf_args.push(sbf_sdk);
} }
build_bpf_args.push("--bpf-out-dir"); build_sbf_args.push("--sbf-out-dir");
build_bpf_args.push(&bpf_out_dir); build_sbf_args.push(&sbf_out_dir);
spawn( spawn(
&config.cargo_build_bpf, &config.cargo_build_sbf,
&build_bpf_args, &build_sbf_args,
config.generate_child_script_on_failure, config.generate_child_script_on_failure,
); );
// Pass --bpf-out-dir along to the solana-program-test crate // Pass --sbf-out-dir along to the solana-program-test crate
env::set_var("BPF_OUT_DIR", bpf_out_dir); env::set_var("SBF_OUT_DIR", sbf_out_dir);
cargo_args.insert(0, "test"); cargo_args.insert(0, "test");
@ -151,9 +149,13 @@ fn test_bpf_package(config: &Config, target_directory: &Path, package: &cargo_me
cargo_args.push("--no-run"); cargo_args.push("--no-run");
} }
// If the program crate declares the "test-bpf" feature, pass it along to the tests so they can // If the program crate declares the "test-sbf" feature, pass it along to the tests so they can
// distinguish between `cargo test` and `cargo test-bpf` // distinguish between `cargo test` and `cargo test-sbf`
if set_test_bpf_feature { if package.features.contains_key("test-sbf") {
cargo_args.push("--features");
cargo_args.push("test-sbf");
}
if package.features.contains_key("test-bpf") {
cargo_args.push("--features"); cargo_args.push("--features");
cargo_args.push("test-bpf"); cargo_args.push("test-bpf");
} }
@ -167,7 +169,7 @@ fn test_bpf_package(config: &Config, target_directory: &Path, package: &cargo_me
); );
} }
fn test_bpf(config: Config, manifest_path: Option<PathBuf>) { fn test_sbf(config: Config, manifest_path: Option<PathBuf>) {
let mut metadata_command = cargo_metadata::MetadataCommand::new(); let mut metadata_command = cargo_metadata::MetadataCommand::new();
if let Some(manifest_path) = manifest_path.as_ref() { if let Some(manifest_path) = manifest_path.as_ref() {
metadata_command.manifest_path(manifest_path); metadata_command.manifest_path(manifest_path);
@ -183,12 +185,12 @@ fn test_bpf(config: Config, manifest_path: Option<PathBuf>) {
if let Some(root_package) = metadata.root_package() { if let Some(root_package) = metadata.root_package() {
if !config.workspace { if !config.workspace {
test_bpf_package(&config, metadata.target_directory.as_ref(), root_package); test_sbf_package(&config, metadata.target_directory.as_ref(), root_package);
return; return;
} }
} }
let all_bpf_packages = metadata let all_sbf_packages = metadata
.packages .packages
.iter() .iter()
.filter(|package| { .filter(|package| {
@ -203,8 +205,8 @@ fn test_bpf(config: Config, manifest_path: Option<PathBuf>) {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for package in all_bpf_packages { for package in all_sbf_packages {
test_bpf_package(&config, metadata.target_directory.as_ref(), package); test_sbf_package(&config, metadata.target_directory.as_ref(), package);
} }
} }
@ -213,7 +215,7 @@ fn main() {
// When run as a cargo subcommand, the first program argument is the subcommand name. // When run as a cargo subcommand, the first program argument is the subcommand name.
// Remove it // Remove it
if let Some(arg1) = args.get(1) { if let Some(arg1) = args.get(1) {
if arg1 == "test-bpf" { if arg1 == "test-sbf" {
args.remove(1); args.remove(1);
} }
} }
@ -226,11 +228,11 @@ fn main() {
.version(crate_version!()) .version(crate_version!())
.trailing_var_arg(true) .trailing_var_arg(true)
.arg( .arg(
Arg::new("bpf_sdk") Arg::new("sbf_sdk")
.long("bpf-sdk") .long("sbf-sdk")
.value_name("PATH") .value_name("PATH")
.takes_value(true) .takes_value(true)
.help("Path to the Solana BPF SDK"), .help("Path to the Solana SBF SDK"),
) )
.arg( .arg(
Arg::new("features") Arg::new("features")
@ -262,11 +264,11 @@ fn main() {
.help("Path to Cargo.toml"), .help("Path to Cargo.toml"),
) )
.arg( .arg(
Arg::new("bpf_out_dir") Arg::new("sbf_out_dir")
.long("bpf-out-dir") .long("sbf-out-dir")
.value_name("DIRECTORY") .value_name("DIRECTORY")
.takes_value(true) .takes_value(true)
.help("Place final BPF build artifacts in this directory"), .help("Place final SBF build artifacts in this directory"),
) )
.arg( .arg(
Arg::new("no_run") Arg::new("no_run")
@ -298,7 +300,7 @@ fn main() {
.long("workspace") .long("workspace")
.takes_value(false) .takes_value(false)
.alias("all") .alias("all")
.help("Test all BPF packages in the workspace"), .help("Test all SBF packages in the workspace"),
) )
.arg( .arg(
Arg::new("jobs") Arg::new("jobs")
@ -320,8 +322,8 @@ fn main() {
.get_matches_from(args); .get_matches_from(args);
let mut config = Config { let mut config = Config {
bpf_sdk: matches.value_of_t("bpf_sdk").ok(), sbf_sdk: matches.value_of_t("sbf_sdk").ok(),
bpf_out_dir: matches.value_of_t("bpf_out_dir").ok(), sbf_out_dir: matches.value_of_t("sbf_out_dir").ok(),
extra_cargo_test_args: matches extra_cargo_test_args: matches
.values_of_t("extra_cargo_test_args") .values_of_t("extra_cargo_test_args")
.ok() .ok()
@ -338,22 +340,22 @@ fn main() {
..Config::default() ..Config::default()
}; };
if let Ok(cargo_build_bpf) = env::var("CARGO_BUILD_BPF") { if let Ok(cargo_build_sbf) = env::var("CARGO_BUILD_SBF") {
config.cargo_build_bpf = PathBuf::from(cargo_build_bpf); config.cargo_build_sbf = PathBuf::from(cargo_build_sbf);
} }
if let Ok(cargo_build_bpf) = env::var("CARGO") { if let Ok(cargo_build_sbf) = env::var("CARGO") {
config.cargo = PathBuf::from(cargo_build_bpf); config.cargo = PathBuf::from(cargo_build_sbf);
} }
// clap.rs swallows "--" in the case when the user provides it as the first `extra_cargo_test_args` // clap.rs swallows "--" in the case when the user provides it as the first `extra_cargo_test_args`
// //
// For example, this command-line "cargo-test-bpf -- --nocapture" results in `extra_cargo_test_args` only // For example, this command-line "cargo-test-sbf -- --nocapture" results in `extra_cargo_test_args` only
// containing "--nocapture". This is a problem because `cargo test` will never see the `--`. // containing "--nocapture". This is a problem because `cargo test` will never see the `--`.
// //
// Whereas "cargo-test-bpf testname -- --nocapture" correctly produces a `extra_cargo_test_args` // Whereas "cargo-test-sbf testname -- --nocapture" correctly produces a `extra_cargo_test_args`
// with "testname -- --nocapture". // with "testname -- --nocapture".
// //
// So if the original cargo-test-bpf arguments contain "--" but `extra_cargo_test_args` does // So if the original cargo-test-sbf arguments contain "--" but `extra_cargo_test_args` does
// not, then prepend "--". // not, then prepend "--".
// //
if args_contain_dashash && !config.extra_cargo_test_args.contains(&em_dash) { if args_contain_dashash && !config.extra_cargo_test_args.contains(&em_dash) {
@ -361,5 +363,5 @@ fn main() {
} }
let manifest_path: Option<PathBuf> = matches.value_of_t("manifest_path").ok(); let manifest_path: Option<PathBuf> = matches.value_of_t("manifest_path").ok();
test_bpf(config, manifest_path); test_sbf(config, manifest_path);
} }