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]]
name = "solana-cargo-build-bpf"
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 = [
"bzip2",
"cargo_metadata",
"clap 3.1.8",
"log",
"regex",
"serial_test",
"solana-download-utils",
@ -4514,6 +4524,14 @@ dependencies = [
"clap 3.1.8",
]
[[package]]
name = "solana-cargo-test-sbf"
version = "1.11.0"
dependencies = [
"cargo_metadata",
"clap 3.1.8",
]
[[package]]
name = "solana-clap-utils"
version = "1.11.0"

View File

@ -66,7 +66,9 @@ members = [
"runtime/store-tool",
"sdk",
"sdk/cargo-build-bpf",
"sdk/cargo-build-sbf",
"sdk/cargo-test-bpf",
"sdk/cargo-test-sbf",
"sdk/gen-headers",
"send-transaction-service",
"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")
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf"
maybe_sbf_sdk="--sbf-sdk $here/sdk/bpf"
for a in "$@"; do
if [[ $a = --bpf-sdk ]]; then
maybe_bpf_sdk=
if [[ $a = --sbf-sdk ]]; then
maybe_sbf_sdk=
fi
done
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
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")
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf"
maybe_sbf_sdk="--sbf-sdk $here/sdk/bpf"
for a in "$@"; do
if [[ $a = --bpf-sdk ]]; then
maybe_bpf_sdk=
if [[ $a = --sbf-sdk ]]; then
maybe_sbf_sdk=
fi
done
export CARGO_BUILD_BPF="$here"/cargo-build-bpf
export CARGO_BUILD_SBF="$here"/cargo-build-sbf
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
cargo_build_bpf_main="${here}/../sdk/cargo-build-bpf/src/main.rs"
if [[ -f "${cargo_build_bpf_main}" ]]; then
version=$(sed -e 's/^.*bpf_tools_version\s*=\s*"\(v[0-9.]\+\)".*/\1/;t;d' "${cargo_build_bpf_main}")
cargo_build_sbf_main="${here}/../sdk/cargo-build-sbf/src/main.rs"
if [[ -f "${cargo_build_sbf_main}" ]]; then
version=$(sed -e 's/^.*sbf_tools_version\s*=\s*"\(v[0-9.]\+\)".*/\1/;t;d' "${cargo_build_sbf_main}")
if [[ ${version} != '' ]]; then
SBF_TOOLS_VERSION="${version}"
else
echo '--- unable to parse SBF_TOOLS_VERSION'
fi
else
echo "--- '${cargo_build_bpf_main}' not present"
echo "--- '${cargo_build_sbf_main}' not present"
fi
echo SBF_TOOLS_VERSION="${SBF_TOOLS_VERSION}"

View File

@ -78,7 +78,7 @@ test-stable-bpf)
bpf_dump_archive="bpf-dumps.tar.bz2"
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
;;
test-stable-perf)

View File

@ -401,6 +401,8 @@ fn default_shared_object_dirs() -> Vec<PathBuf> {
let mut search_path = vec![];
if let Ok(bpf_out_dir) = std::env::var("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"));
if let Ok(dir) = std::env::current_dir() {
@ -450,7 +452,8 @@ impl Default for ProgramTest {
solana_runtime::system_instruction_processor=trace,\
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 {
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]
name = "solana-cargo-build-bpf"
name = "solana-cargo-build-sbf"
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>"]
repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/"
@ -13,6 +13,7 @@ publish = false
bzip2 = "0.4.3"
cargo_metadata = "0.14.2"
clap = { version = "3.1.5", features = ["cargo", "env"] }
log = { version = "0.4.14", features = ["std"] }
regex = "1.5.6"
solana-download-utils = { path = "../../download-utils", version = "=1.11.0" }
solana-sdk = { path = "..", version = "=1.11.0" }
@ -25,5 +26,5 @@ serial_test = "*"
program = []
[[bin]]
name = "cargo-build-bpf"
name = "cargo-build-sbf"
path = "src/main.rs"

View File

@ -1,6 +1,7 @@
use {
bzip2::bufread::BzDecoder,
clap::{crate_description, crate_name, crate_version, Arg},
log::*,
regex::Regex,
solana_download_utils::download_file,
solana_sdk::signature::{write_keypair_file, Keypair},
@ -19,9 +20,9 @@ use {
struct Config<'a> {
cargo_args: Option<Vec<&'a str>>,
bpf_out_dir: Option<PathBuf>,
bpf_sdk: PathBuf,
bpf_tools_version: &'a str,
sbf_out_dir: Option<PathBuf>,
sbf_sdk: PathBuf,
sbf_tools_version: &'a str,
dump: bool,
features: Vec<String>,
generate_child_script_on_failure: bool,
@ -36,15 +37,15 @@ impl Default for Config<'_> {
fn default() -> Self {
Self {
cargo_args: None,
bpf_sdk: env::current_exe()
sbf_sdk: env::current_exe()
.expect("Unable to get current executable")
.parent()
.expect("Unable to get parent directory")
.to_path_buf()
.join("sdk")
.join("bpf"),
bpf_out_dir: None,
bpf_tools_version: "(unknown)",
sbf_out_dir: None,
sbf_tools_version: "(unknown)",
dump: false,
features: vec![],
generate_child_script_on_failure: false,
@ -63,18 +64,18 @@ where
S: AsRef<OsStr>,
{
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() {
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)
.args(&args)
.stdout(Stdio::piped())
.spawn()
.unwrap_or_else(|err| {
eprintln!("Failed to execute {}: {}", program.display(), err);
error!("Failed to execute {}: {}", program.display(), err);
exit(1);
});
@ -83,9 +84,9 @@ where
if !generate_child_script_on_failure {
exit(1);
}
eprintln!("cargo-build-bpf exited on command execution failure");
error!("cargo-build-sbf exited on command execution failure");
let script_name = format!(
"cargo-build-bpf-child-script-{}.sh",
"cargo-build-sbf-child-script-{}.sh",
program.file_name().unwrap().to_str().unwrap(),
);
let file = File::create(&script_name).unwrap();
@ -99,7 +100,7 @@ where
}
writeln!(out).unwrap();
out.flush().unwrap();
eprintln!(
error!(
"To rerun the failed command for debugging use {}",
script_name,
);
@ -123,7 +124,7 @@ fn install_if_missing(
) -> Result<(), String> {
// Check whether the target path is an empty directory. This can
// 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.
if target_path.is_dir()
&& target_path
@ -149,7 +150,7 @@ fn install_if_missing(
fs::create_dir_all(&target_path).map_err(|err| err.to_string())?;
let mut url = String::from(url);
url.push('/');
url.push_str(config.bpf_tools_version);
url.push_str(config.sbf_tools_version);
url.push('/');
url.push_str(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())?;
}
// Make a symbolic link source_path -> target_path in the
// sdk/bpf/dependencies directory if no valid link found.
let source_base = config.bpf_sdk.join("dependencies");
// sdk/sbf/dependencies directory if no valid link found.
let source_base = config.sbf_sdk.join("dependencies");
if !source_base.exists() {
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
// not known to the runtime and warn about them if any.
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) {
Ok(x) => x,
_ => 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 +(.+)")
.unwrap();
let readelf = config
.bpf_sdk
.sbf_sdk
.join("dependencies")
.join("bpf-tools")
.join("sbf-tools")
.join("llvm")
.join("bin")
.join("llvm-readelf");
@ -322,7 +323,7 @@ fn check_undefined_symbols(config: &Config, program: &Path) {
config.generate_child_script_on_failure,
);
if config.verbose {
println!("{}", output);
debug!("{}", output);
}
let mut unresolved_symbols: Vec<String> = Vec::new();
for line in output.lines() {
@ -336,20 +337,20 @@ fn check_undefined_symbols(config: &Config, program: &Path) {
}
}
if !unresolved_symbols.is_empty() {
println!(
"Warning: the following functions are undefined and not known syscalls {:?}.",
warn!(
"The following functions are undefined and not known syscalls {:?}.",
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.
fn link_bpf_toolchain(config: &Config) {
// check whether custom SBF toolchain is linked, and link it if it is not.
fn link_sbf_toolchain(config: &Config) {
let toolchain_path = config
.bpf_sdk
.sbf_sdk
.join("dependencies")
.join("bpf-tools")
.join("sbf-tools")
.join("rust");
let rustup = PathBuf::from("rustup");
let rustup_args = vec!["toolchain", "list", "-v"];
@ -359,23 +360,23 @@ fn link_bpf_toolchain(config: &Config) {
config.generate_child_script_on_failure,
);
if config.verbose {
println!("{}", rustup_output);
debug!("{}", rustup_output);
}
let mut do_link = true;
for line in rustup_output.lines() {
if line.starts_with("bpf") {
if line.starts_with("sbf") {
let mut it = line.split_whitespace();
let _ = it.next();
let path = it.next();
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(
&rustup,
&rustup_args,
config.generate_child_script_on_failure,
);
if config.verbose {
println!("{}", output);
debug!("{}", output);
}
} else {
do_link = false;
@ -384,19 +385,19 @@ fn link_bpf_toolchain(config: &Config) {
}
}
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(
&rustup,
&rustup_args,
config.generate_child_script_on_failure,
);
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 cdylib_targets = package
.targets
@ -412,7 +413,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
match cdylib_targets.len() {
0 => {
println!(
warn!(
"Note: {} crate does not contain a cdylib target",
package.name
);
@ -420,7 +421,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
}
1 => Some(cdylib_targets[0].replace('-', "_")),
_ => {
eprintln!(
error!(
"{} crate contains multiple 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 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);
});
let bpf_out_dir = config
.bpf_out_dir
let sbf_out_dir = config
.sbf_out_dir
.as_ref()
.cloned()
.unwrap_or_else(|| target_directory.join("deploy"));
let target_build_directory = target_directory
.join("bpfel-unknown-unknown")
.join("release");
let target_build_directory = target_directory.join("sbf-solana-solana").join("release");
env::set_current_dir(&root_package_dir).unwrap_or_else(|err| {
eprintln!(
error!(
"Unable to set current directory to {}: {}",
root_package_dir, err
);
exit(1);
});
println!("BPF SDK: {}", config.bpf_sdk.display());
info!("SBF SDK: {}", config.sbf_sdk.display());
if config.no_default_features {
println!("No default features");
info!("No default features");
}
if !config.features.is_empty() {
println!("Features: {}", config.features.join(" "));
info!("Features: {}", config.features.join(" "));
}
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") {
"solana-bpf-tools-windows.tar.bz2"
let sbf_tools_download_file_name = if cfg!(target_os = "windows") {
"solana-sbf-tools-windows.tar.bz2"
} else if cfg!(target_os = "macos") {
"solana-bpf-tools-osx.tar.bz2"
"solana-sbf-tools-osx.tar.bz2"
} 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| {
eprintln!("Can't get home directory path: {}", err);
error!("Can't get home directory path: {}", err);
exit(1);
}));
let package = "bpf-tools";
let package = "sbf-tools";
let target_path = home_dir
.join(".cache")
.join("solana")
.join(config.bpf_tools_version)
.join(config.sbf_tools_version)
.join(package);
install_if_missing(
config,
package,
"https://github.com/solana-labs/bpf-tools/releases/download",
bpf_tools_download_file_name,
sbf_tools_download_file_name,
&target_path,
)
.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.
let target_path_parent = target_path.parent().expect("Invalid package path");
fs::remove_dir_all(&target_path_parent).unwrap_or_else(|err| {
eprintln!(
error!(
"Failed to remove {} while recovering from installation failure: {}",
target_path_parent.to_string_lossy(),
err,
);
exit(1);
});
eprintln!("Failed to install bpf-tools: {}", err);
error!("Failed to install sbf-tools: {}", err);
exit(1);
});
link_bpf_toolchain(config);
link_sbf_toolchain(config);
let llvm_bin = config
.bpf_sdk
.sbf_sdk
.join("dependencies")
.join("bpf-tools")
.join("sbf-tools")
.join("llvm")
.join("bin");
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"));
if config.verbose {
println!(
debug!(
"RUSTFLAGS={}",
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 mut cargo_build_args = vec![
"+bpf",
"+sbf",
"build",
"--target",
"bpfel-unknown-unknown",
"sbf-solana-solana",
"--release",
];
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,
);
if config.verbose {
println!("{}", output);
debug!("{}", output);
}
if let Some(program_name) = 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_so = bpf_out_dir.join(&format!("{}.so", program_name));
let program_keypair = bpf_out_dir.join(&format!("{}-keypair.json", program_name));
let program_dump = sbf_out_dir.join(&format!("{}-dump.txt", program_name));
let program_so = sbf_out_dir.join(&format!("{}.so", 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 {
let prerequisite_metadata = fs::metadata(prerequisite_file).unwrap_or_else(|err| {
eprintln!(
error!(
"Unable to get file metadata for {}: {}",
prerequisite_file.display(),
err
@ -592,7 +591,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
if !program_keypair.exists() {
write_keypair_file(&Keypair::new(), &program_keypair).unwrap_or_else(|err| {
eprintln!(
error!(
"Unable to get create {}: {}",
program_keypair.display(),
err
@ -614,21 +613,21 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m
);
#[cfg(not(windows))]
let output = spawn(
&config.bpf_sdk.join("scripts").join("strip.sh"),
&config.sbf_sdk.join("scripts").join("strip.sh"),
&[&program_unstripped_so, &program_so],
config.generate_child_script_on_failure,
);
if config.verbose {
println!("{}", output);
debug!("{}", output);
}
}
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)]
{
eprintln!("Using Bash scripts from within a program is not supported on Windows, skipping `--dump`.");
eprintln!(
error!("Using Bash scripts from within a program is not supported on Windows, skipping `--dump`.");
error!(
"Please run \"{} {} {}\" from a Bash-supporting shell, then re-run this command to see the processed program dump.",
&dump_script.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,
);
if config.verbose {
println!("{}", output);
debug!("{}", output);
}
}
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);
println!();
println!("To deploy this program:");
println!(" $ solana program deploy {}", program_so.display());
println!("The program address will default to this keypair (override with --program-id):");
println!(" {}", program_keypair.display());
info!("To deploy this program:");
info!(" $ solana program deploy {}", program_so.display());
info!("The program address will default to this keypair (override with --program-id):");
info!(" {}", program_keypair.display());
} 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();
if let Some(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| {
eprintln!("Failed to obtain package metadata: {}", err);
error!("Failed to obtain package metadata: {}", err);
exit(1);
});
if let Some(root_package) = metadata.root_package() {
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;
}
}
let all_bpf_packages = metadata
let all_sbf_packages = metadata
.packages
.iter()
.filter(|package| {
@ -696,47 +694,47 @@ fn build_bpf(config: Config, manifest_path: Option<PathBuf>) {
})
.collect::<Vec<_>>();
for package in all_bpf_packages {
build_bpf_package(&config, metadata.target_directory.as_ref(), package);
for package in all_sbf_packages {
build_sbf_package(&config, metadata.target_directory.as_ref(), package);
}
}
fn main() {
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<_>>();
// 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" {
if arg1 == "build-sbf" {
args.remove(1);
}
}
// The following line is scanned by CI configuration script to
// separate cargo caches according to the version of sbf-tools.
let bpf_tools_version = "v1.27";
let version = format!("{}\nbpf-tools {}", crate_version!(), bpf_tools_version);
let sbf_tools_version = "v1.27";
let version = format!("{}\nsbf-tools {}", crate_version!(), sbf_tools_version);
let matches = clap::Command::new(crate_name!())
.about(crate_description!())
.version(version.as_str())
.arg(
Arg::new("bpf_out_dir")
.env("BPF_OUT_PATH")
.long("bpf-out-dir")
Arg::new("sbf_out_dir")
.env("SBF_OUT_PATH")
.long("sbf-out-dir")
.value_name("DIRECTORY")
.takes_value(true)
.help("Place final BPF build artifacts in this directory"),
.help("Place final SBF build artifacts in this directory"),
)
.arg(
Arg::new("bpf_sdk")
.env("BPF_SDK_PATH")
.long("bpf-sdk")
Arg::new("sbf_sdk")
.env("SBF_SDK_PATH")
.long("sbf-sdk")
.value_name("PATH")
.takes_value(true)
.default_value(&default_bpf_sdk)
.help("Path to the Solana BPF SDK"),
.default_value(&default_sbf_sdk)
.help("Path to the Solana SBF SDK"),
)
.arg(
Arg::new("cargo_args")
@ -797,7 +795,7 @@ fn main() {
.long("workspace")
.takes_value(false)
.alias("all")
.help("Build all BPF packages in the workspace"),
.help("Build all SBF packages in the workspace"),
)
.arg(
Arg::new("jobs")
@ -810,31 +808,31 @@ fn main() {
)
.get_matches_from(args);
let bpf_sdk: PathBuf = matches.value_of_t_or_exit("bpf_sdk");
let bpf_out_dir: Option<PathBuf> = matches.value_of_t("bpf_out_dir").ok();
let sbf_sdk: PathBuf = matches.value_of_t_or_exit("sbf_sdk");
let sbf_out_dir: Option<PathBuf> = matches.value_of_t("sbf_out_dir").ok();
let config = Config {
cargo_args: matches
.values_of("cargo_args")
.map(|vals| vals.collect::<Vec<_>>()),
bpf_sdk: fs::canonicalize(&bpf_sdk).unwrap_or_else(|err| {
eprintln!(
"BPF SDK path does not exist: {}: {}",
bpf_sdk.display(),
sbf_sdk: fs::canonicalize(&sbf_sdk).unwrap_or_else(|err| {
error!(
"SBF SDK path does not exist: {}: {}",
sbf_sdk.display(),
err
);
exit(1);
}),
bpf_out_dir: bpf_out_dir.map(|bpf_out_dir| {
if bpf_out_dir.is_absolute() {
bpf_out_dir
sbf_out_dir: sbf_out_dir.map(|sbf_out_dir| {
if sbf_out_dir.is_absolute() {
sbf_out_dir
} else {
env::current_dir()
.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"),
features: matches.values_of_t("features").ok().unwrap_or_default(),
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(),
};
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("Cargo.toml");
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 {
args.push(arg);
}
let cargo_build_bpf = root.join("target").join("debug").join("cargo-build-bpf");
let output = Command::new(cargo_build_bpf)
let cargo_build_sbf = root.join("target").join("debug").join("cargo-build-sbf");
let output = Command::new(cargo_build_sbf)
.args(&args)
.output()
.expect("Error running cargo-build-bpf");
.expect("Error running cargo-build-sbf");
if !output.status.success() {
eprintln!("--- stdout ---");
io::stderr().write_all(&output.stdout).unwrap();
@ -51,7 +51,7 @@ fn test_build() {
fn test_dump() {
// This test requires rustfilt.
assert!(Command::new("cargo")
.args(&["install", "rustfilt"])
.args(&["install", "-f", "rustfilt"])
.status()
.expect("Unable to install rustfilt required for --dump option")
.success());
@ -71,7 +71,7 @@ fn test_dump() {
#[test]
#[serial]
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());
let cwd = env::current_dir().expect("Unable to get current working directory");
let dir = cwd.join("tmp_out");
@ -89,7 +89,7 @@ fn test_generate_child_script_on_failre() {
.join("tests")
.join("crates")
.join("fail")
.join("cargo-build-bpf-child-script-cargo.sh");
.join("cargo-build-sbf-child-script-cargo.sh");
assert!(scr.exists());
fs::remove_file(scr).expect("Failed to remove script");
}

View File

@ -1,7 +1,7 @@
[package]
name = "fail"
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>"]
repository = "https://github.com/solana-labs/solana"
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};

View File

@ -1,7 +1,7 @@
[package]
name = "noop"
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>"]
repository = "https://github.com/solana-labs/solana"
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};

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]
name = "solana-cargo-test-bpf"
name = "solana-cargo-test-sbf"
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>"]
repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/"
@ -14,5 +14,5 @@ cargo_metadata = "0.14.2"
clap = { version = "3.1.5", features = ["cargo"] }
[[bin]]
name = "cargo-test-bpf"
name = "cargo-test-sbf"
path = "src/main.rs"

View File

@ -11,10 +11,10 @@ use {
};
struct Config {
bpf_sdk: Option<String>,
bpf_out_dir: Option<String>,
sbf_sdk: Option<String>,
sbf_out_dir: Option<String>,
cargo: PathBuf,
cargo_build_bpf: PathBuf,
cargo_build_sbf: PathBuf,
extra_cargo_test_args: Vec<String>,
features: Vec<String>,
generate_child_script_on_failure: bool,
@ -30,10 +30,10 @@ struct Config {
impl Default for Config {
fn default() -> Self {
Self {
bpf_sdk: None,
bpf_out_dir: None,
sbf_sdk: None,
sbf_out_dir: None,
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![],
features: vec![],
generate_child_script_on_failure: false,
@ -54,7 +54,7 @@ where
S: AsRef<OsStr>,
{
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() {
print!(" {}", arg.as_ref().to_str().unwrap_or("?"));
}
@ -73,9 +73,9 @@ where
if !generate_child_script_on_failure {
exit(1);
}
eprintln!("cargo-test-bpf exited on command execution failure");
eprintln!("cargo-test-sbf exited on command execution failure");
let script_name = format!(
"cargo-test-bpf-child-script-{}.sh",
"cargo-test-sbf-child-script-{}.sh",
program.file_name().unwrap().to_str().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) {
let set_test_bpf_feature = package.features.contains_key("test-bpf");
let bpf_out_dir = config
.bpf_out_dir
fn test_sbf_package(config: &Config, target_directory: &Path, package: &cargo_metadata::Package) {
let sbf_out_dir = config
.sbf_out_dir
.as_ref()
.cloned()
.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);
}
let mut build_bpf_args = cargo_args.clone();
if let Some(bpf_sdk) = config.bpf_sdk.as_ref() {
build_bpf_args.push("--bpf-sdk");
build_bpf_args.push(bpf_sdk);
let mut build_sbf_args = cargo_args.clone();
if let Some(sbf_sdk) = config.sbf_sdk.as_ref() {
build_sbf_args.push("--sbf-sdk");
build_sbf_args.push(sbf_sdk);
}
build_bpf_args.push("--bpf-out-dir");
build_bpf_args.push(&bpf_out_dir);
build_sbf_args.push("--sbf-out-dir");
build_sbf_args.push(&sbf_out_dir);
spawn(
&config.cargo_build_bpf,
&build_bpf_args,
&config.cargo_build_sbf,
&build_sbf_args,
config.generate_child_script_on_failure,
);
// Pass --bpf-out-dir along to the solana-program-test crate
env::set_var("BPF_OUT_DIR", bpf_out_dir);
// Pass --sbf-out-dir along to the solana-program-test crate
env::set_var("SBF_OUT_DIR", sbf_out_dir);
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");
}
// If the program crate declares the "test-bpf" feature, pass it along to the tests so they can
// distinguish between `cargo test` and `cargo test-bpf`
if set_test_bpf_feature {
// 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-sbf`
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("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();
if let Some(manifest_path) = manifest_path.as_ref() {
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 !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;
}
}
let all_bpf_packages = metadata
let all_sbf_packages = metadata
.packages
.iter()
.filter(|package| {
@ -203,8 +205,8 @@ fn test_bpf(config: Config, manifest_path: Option<PathBuf>) {
})
.collect::<Vec<_>>();
for package in all_bpf_packages {
test_bpf_package(&config, metadata.target_directory.as_ref(), package);
for package in all_sbf_packages {
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.
// Remove it
if let Some(arg1) = args.get(1) {
if arg1 == "test-bpf" {
if arg1 == "test-sbf" {
args.remove(1);
}
}
@ -226,11 +228,11 @@ fn main() {
.version(crate_version!())
.trailing_var_arg(true)
.arg(
Arg::new("bpf_sdk")
.long("bpf-sdk")
Arg::new("sbf_sdk")
.long("sbf-sdk")
.value_name("PATH")
.takes_value(true)
.help("Path to the Solana BPF SDK"),
.help("Path to the Solana SBF SDK"),
)
.arg(
Arg::new("features")
@ -262,11 +264,11 @@ fn main() {
.help("Path to Cargo.toml"),
)
.arg(
Arg::new("bpf_out_dir")
.long("bpf-out-dir")
Arg::new("sbf_out_dir")
.long("sbf-out-dir")
.value_name("DIRECTORY")
.takes_value(true)
.help("Place final BPF build artifacts in this directory"),
.help("Place final SBF build artifacts in this directory"),
)
.arg(
Arg::new("no_run")
@ -298,7 +300,7 @@ fn main() {
.long("workspace")
.takes_value(false)
.alias("all")
.help("Test all BPF packages in the workspace"),
.help("Test all SBF packages in the workspace"),
)
.arg(
Arg::new("jobs")
@ -320,8 +322,8 @@ fn main() {
.get_matches_from(args);
let mut config = Config {
bpf_sdk: matches.value_of_t("bpf_sdk").ok(),
bpf_out_dir: matches.value_of_t("bpf_out_dir").ok(),
sbf_sdk: matches.value_of_t("sbf_sdk").ok(),
sbf_out_dir: matches.value_of_t("sbf_out_dir").ok(),
extra_cargo_test_args: matches
.values_of_t("extra_cargo_test_args")
.ok()
@ -338,22 +340,22 @@ fn main() {
..Config::default()
};
if let Ok(cargo_build_bpf) = env::var("CARGO_BUILD_BPF") {
config.cargo_build_bpf = PathBuf::from(cargo_build_bpf);
if let Ok(cargo_build_sbf) = env::var("CARGO_BUILD_SBF") {
config.cargo_build_sbf = PathBuf::from(cargo_build_sbf);
}
if let Ok(cargo_build_bpf) = env::var("CARGO") {
config.cargo = PathBuf::from(cargo_build_bpf);
if let Ok(cargo_build_sbf) = env::var("CARGO") {
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`
//
// 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 `--`.
//
// 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".
//
// 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 "--".
//
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();
test_bpf(config, manifest_path);
test_sbf(config, manifest_path);
}