2020-12-16 10:31:49 -08:00
|
|
|
use {
|
2021-03-16 08:32:42 -07:00
|
|
|
bzip2::bufread::BzDecoder,
|
2022-03-07 07:25:01 -08:00
|
|
|
clap::{crate_description, crate_name, crate_version, Arg},
|
2021-04-09 02:44:19 -07:00
|
|
|
regex::Regex,
|
2021-05-26 13:26:07 -07:00
|
|
|
solana_download_utils::download_file,
|
2020-12-16 10:31:49 -08:00
|
|
|
solana_sdk::signature::{write_keypair_file, Keypair},
|
|
|
|
std::{
|
2021-06-10 15:23:09 -07:00
|
|
|
collections::{HashMap, HashSet},
|
2020-12-16 10:31:49 -08:00
|
|
|
env,
|
|
|
|
ffi::OsStr,
|
2021-03-16 08:32:42 -07:00
|
|
|
fs::{self, File},
|
2021-04-09 02:44:19 -07:00
|
|
|
io::{prelude::*, BufReader, BufWriter},
|
2020-12-16 10:31:49 -08:00
|
|
|
path::{Path, PathBuf},
|
2021-12-03 09:00:31 -08:00
|
|
|
process::{exit, Command, Stdio},
|
2021-04-09 02:44:19 -07:00
|
|
|
str::FromStr,
|
2020-12-16 10:31:49 -08:00
|
|
|
},
|
2021-03-16 08:32:42 -07:00
|
|
|
tar::Archive,
|
2020-10-20 17:50:20 -07:00
|
|
|
};
|
|
|
|
|
2021-06-17 18:27:13 -07:00
|
|
|
struct Config<'a> {
|
|
|
|
cargo_args: Option<Vec<&'a str>>,
|
2020-11-04 13:52:03 -08:00
|
|
|
bpf_out_dir: Option<PathBuf>,
|
2020-11-04 18:29:26 -08:00
|
|
|
bpf_sdk: PathBuf,
|
2021-12-22 15:10:25 -08:00
|
|
|
bpf_tools_version: &'a str,
|
2020-10-20 17:50:20 -07:00
|
|
|
dump: bool,
|
|
|
|
features: Vec<String>,
|
2021-07-14 18:02:42 -07:00
|
|
|
generate_child_script_on_failure: bool,
|
2020-10-20 17:50:20 -07:00
|
|
|
no_default_features: bool,
|
2020-11-12 16:39:33 -08:00
|
|
|
offline: bool,
|
2020-11-04 18:29:26 -08:00
|
|
|
verbose: bool,
|
2020-11-06 10:50:28 -08:00
|
|
|
workspace: bool,
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|
|
|
|
|
2021-06-17 18:27:13 -07:00
|
|
|
impl Default for Config<'_> {
|
2020-10-20 17:50:20 -07:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2021-06-17 18:27:13 -07:00
|
|
|
cargo_args: None,
|
2020-10-20 17:50:20 -07:00
|
|
|
bpf_sdk: env::current_exe()
|
2020-10-22 17:10:42 -07:00
|
|
|
.expect("Unable to get current executable")
|
2020-10-20 17:50:20 -07:00
|
|
|
.parent()
|
|
|
|
.expect("Unable to get parent directory")
|
|
|
|
.to_path_buf()
|
2021-06-21 11:53:34 -07:00
|
|
|
.join("sdk")
|
|
|
|
.join("bpf"),
|
2020-11-04 13:52:03 -08:00
|
|
|
bpf_out_dir: None,
|
2021-12-22 15:10:25 -08:00
|
|
|
bpf_tools_version: "(unknown)",
|
2020-11-04 18:29:26 -08:00
|
|
|
dump: false,
|
2020-10-20 17:50:20 -07:00
|
|
|
features: vec![],
|
2021-07-14 18:02:42 -07:00
|
|
|
generate_child_script_on_failure: false,
|
2020-10-20 17:50:20 -07:00
|
|
|
no_default_features: false,
|
2020-11-12 16:39:33 -08:00
|
|
|
offline: false,
|
2020-11-04 18:29:26 -08:00
|
|
|
verbose: false,
|
2020-11-06 10:50:28 -08:00
|
|
|
workspace: false,
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-14 18:02:42 -07:00
|
|
|
fn spawn<I, S>(program: &Path, args: I, generate_child_script_on_failure: bool) -> String
|
2020-10-20 17:50:20 -07:00
|
|
|
where
|
|
|
|
I: IntoIterator<Item = S>,
|
|
|
|
S: AsRef<OsStr>,
|
|
|
|
{
|
|
|
|
let args = args.into_iter().collect::<Vec<_>>();
|
2021-07-14 18:02:42 -07:00
|
|
|
print!("cargo-build-bpf child: {}", program.display());
|
2020-10-20 17:50:20 -07:00
|
|
|
for arg in args.iter() {
|
|
|
|
print!(" {}", arg.as_ref().to_str().unwrap_or("?"));
|
|
|
|
}
|
|
|
|
println!();
|
|
|
|
|
2021-03-16 08:32:42 -07:00
|
|
|
let child = Command::new(program)
|
2020-10-20 17:50:20 -07:00
|
|
|
.args(&args)
|
2021-03-16 08:32:42 -07:00
|
|
|
.stdout(Stdio::piped())
|
2020-10-20 17:50:20 -07:00
|
|
|
.spawn()
|
|
|
|
.unwrap_or_else(|err| {
|
|
|
|
eprintln!("Failed to execute {}: {}", program.display(), err);
|
|
|
|
exit(1);
|
|
|
|
});
|
|
|
|
|
2021-03-16 08:32:42 -07:00
|
|
|
let output = child.wait_with_output().expect("failed to wait on child");
|
|
|
|
if !output.status.success() {
|
2021-07-14 18:02:42 -07:00
|
|
|
if !generate_child_script_on_failure {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
eprintln!("cargo-build-bpf exited on command execution failure");
|
|
|
|
let script_name = format!(
|
|
|
|
"cargo-build-bpf-child-script-{}.sh",
|
|
|
|
program.file_name().unwrap().to_str().unwrap(),
|
|
|
|
);
|
|
|
|
let file = File::create(&script_name).unwrap();
|
|
|
|
let mut out = BufWriter::new(file);
|
|
|
|
for (key, value) in env::vars() {
|
|
|
|
writeln!(out, "{}=\"{}\" \\", key, value).unwrap();
|
|
|
|
}
|
|
|
|
write!(out, "{}", program.display()).unwrap();
|
|
|
|
for arg in args.iter() {
|
|
|
|
write!(out, " {}", arg.as_ref().to_str().unwrap_or("?")).unwrap();
|
|
|
|
}
|
|
|
|
writeln!(out).unwrap();
|
|
|
|
out.flush().unwrap();
|
|
|
|
eprintln!(
|
|
|
|
"To rerun the failed command for debugging use {}",
|
|
|
|
script_name,
|
|
|
|
);
|
2020-10-20 17:50:20 -07:00
|
|
|
exit(1);
|
|
|
|
}
|
2021-03-16 08:32:42 -07:00
|
|
|
output
|
|
|
|
.stdout
|
|
|
|
.as_slice()
|
|
|
|
.iter()
|
|
|
|
.map(|&c| c as char)
|
|
|
|
.collect::<String>()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether a package is installed and install it if missing.
|
|
|
|
fn install_if_missing(
|
|
|
|
config: &Config,
|
|
|
|
package: &str,
|
|
|
|
url: &str,
|
2021-09-06 01:59:58 -07:00
|
|
|
download_file_name: &str,
|
2021-11-03 14:06:14 -07:00
|
|
|
target_path: &Path,
|
2021-03-16 08:32:42 -07:00
|
|
|
) -> Result<(), String> {
|
2021-11-02 15:41:06 -07:00
|
|
|
// 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
|
|
|
|
// case.
|
|
|
|
if target_path.is_dir()
|
|
|
|
&& target_path
|
|
|
|
.read_dir()
|
|
|
|
.map_err(|err| err.to_string())?
|
|
|
|
.next()
|
|
|
|
.is_none()
|
|
|
|
{
|
|
|
|
fs::remove_dir(&target_path).map_err(|err| err.to_string())?;
|
|
|
|
}
|
|
|
|
|
2021-11-03 14:06:14 -07:00
|
|
|
// Check whether the package is already in ~/.cache/solana.
|
|
|
|
// Download it and place in the proper location if not found.
|
cargo-build-bpf: allow sdk path to be set by environment variables
In many Linux distros such as NixOS, the directory in which packages are
installed is assumed to be read-only. To work around this, it is
expected that the filepaths which packaged CLI tools take in are able to
be freely configured through either 1) command-line flags, 2)
environment variables, or 3) a configuration file.
In this commit, environment variables 'BPF_SDK_PATH' and 'BPF_OUT_PATH',
which map respectively to command-line flags '--bpf-sdk-path' and
'--bpf-out-dir', are now handled in cargo-build-bpf.
Additionally, given that arbitrary filepaths may now be set in which the
BPF SDK is located, the requirement in which
'$BPF_SDK_PATH/dependencies/bpf-tools' must strictly be a symbolic link
to the directory '$HOME/.cache/solana/${bpf-tools.version}/bpf-tools has
been relaxed.
Ideally, the directory in which bpf-tools is expected to be downloaded
to and stored should be configurable. Though, this commit serves as a
temporary fix which enables NixOS users to now start being able to build
applications with the Solana SDK.
2021-08-30 10:27:20 -07:00
|
|
|
if !target_path.is_dir()
|
|
|
|
&& !target_path
|
|
|
|
.symlink_metadata()
|
|
|
|
.map(|metadata| metadata.file_type().is_symlink())
|
|
|
|
.unwrap_or(false)
|
|
|
|
{
|
2021-03-16 08:32:42 -07:00
|
|
|
if target_path.exists() {
|
|
|
|
fs::remove_file(&target_path).map_err(|err| err.to_string())?;
|
|
|
|
}
|
2021-09-06 01:59:58 -07:00
|
|
|
fs::create_dir_all(&target_path).map_err(|err| err.to_string())?;
|
2021-03-16 08:32:42 -07:00
|
|
|
let mut url = String::from(url);
|
|
|
|
url.push('/');
|
2021-12-22 15:10:25 -08:00
|
|
|
url.push_str(config.bpf_tools_version);
|
2021-03-16 08:32:42 -07:00
|
|
|
url.push('/');
|
2021-09-06 01:59:58 -07:00
|
|
|
url.push_str(download_file_name);
|
|
|
|
let download_file_path = target_path.join(download_file_name);
|
|
|
|
if download_file_path.exists() {
|
|
|
|
fs::remove_file(&download_file_path).map_err(|err| err.to_string())?;
|
|
|
|
}
|
|
|
|
download_file(url.as_str(), &download_file_path, true, &mut None)?;
|
|
|
|
let zip = File::open(&download_file_path).map_err(|err| err.to_string())?;
|
2021-03-16 08:32:42 -07:00
|
|
|
let tar = BzDecoder::new(BufReader::new(zip));
|
|
|
|
let mut archive = Archive::new(tar);
|
|
|
|
archive
|
|
|
|
.unpack(&target_path)
|
|
|
|
.map_err(|err| err.to_string())?;
|
2021-09-06 01:59:58 -07:00
|
|
|
fs::remove_file(download_file_path).map_err(|err| err.to_string())?;
|
2021-03-16 08:32:42 -07:00
|
|
|
}
|
cargo-build-bpf: allow sdk path to be set by environment variables
In many Linux distros such as NixOS, the directory in which packages are
installed is assumed to be read-only. To work around this, it is
expected that the filepaths which packaged CLI tools take in are able to
be freely configured through either 1) command-line flags, 2)
environment variables, or 3) a configuration file.
In this commit, environment variables 'BPF_SDK_PATH' and 'BPF_OUT_PATH',
which map respectively to command-line flags '--bpf-sdk-path' and
'--bpf-out-dir', are now handled in cargo-build-bpf.
Additionally, given that arbitrary filepaths may now be set in which the
BPF SDK is located, the requirement in which
'$BPF_SDK_PATH/dependencies/bpf-tools' must strictly be a symbolic link
to the directory '$HOME/.cache/solana/${bpf-tools.version}/bpf-tools has
been relaxed.
Ideally, the directory in which bpf-tools is expected to be downloaded
to and stored should be configurable. Though, this commit serves as a
temporary fix which enables NixOS users to now start being able to build
applications with the Solana SDK.
2021-08-30 10:27:20 -07:00
|
|
|
// Make a symbolic link source_path -> target_path in the
|
2021-03-16 08:32:42 -07:00
|
|
|
// sdk/bpf/dependencies directory if no valid link found.
|
|
|
|
let source_base = config.bpf_sdk.join("dependencies");
|
|
|
|
if !source_base.exists() {
|
|
|
|
fs::create_dir_all(&source_base).map_err(|err| err.to_string())?;
|
|
|
|
}
|
|
|
|
let source_path = source_base.join(package);
|
|
|
|
// Check whether the correct symbolic link exists.
|
2021-09-06 01:59:58 -07:00
|
|
|
let invalid_link = if let Ok(link_target) = source_path.read_link() {
|
2021-11-03 14:06:14 -07:00
|
|
|
if link_target.ne(target_path) {
|
2021-09-06 01:59:58 -07:00
|
|
|
fs::remove_file(&source_path).map_err(|err| err.to_string())?;
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
};
|
|
|
|
if invalid_link {
|
2021-03-16 08:32:42 -07:00
|
|
|
#[cfg(unix)]
|
|
|
|
std::os::unix::fs::symlink(target_path, source_path).map_err(|err| err.to_string())?;
|
|
|
|
#[cfg(windows)]
|
|
|
|
std::os::windows::fs::symlink_dir(target_path, source_path)
|
|
|
|
.map_err(|err| err.to_string())?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-04-09 02:44:19 -07:00
|
|
|
// Process dump file attributing call instructions with callee function names
|
|
|
|
fn postprocess_dump(program_dump: &Path) {
|
|
|
|
if !program_dump.exists() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let postprocessed_dump = program_dump.with_extension("postprocessed");
|
2021-05-11 02:24:12 -07:00
|
|
|
let head_re = Regex::new(r"^([0-9a-f]{16}) (.+)").unwrap();
|
2021-04-09 02:44:19 -07:00
|
|
|
let insn_re = Regex::new(r"^ +([0-9]+)((\s[0-9a-f]{2})+)\s.+").unwrap();
|
|
|
|
let call_re = Regex::new(r"^ +([0-9]+)(\s[0-9a-f]{2})+\scall (-?)0x([0-9a-f]+)").unwrap();
|
|
|
|
let relo_re = Regex::new(r"^([0-9a-f]{16}) [0-9a-f]{16} R_BPF_64_32 +0{16} (.+)").unwrap();
|
|
|
|
let mut a2n: HashMap<i64, String> = HashMap::new();
|
|
|
|
let mut rel: HashMap<u64, String> = HashMap::new();
|
|
|
|
let mut name = String::from("");
|
|
|
|
let mut state = 0;
|
|
|
|
let file = match File::open(program_dump) {
|
|
|
|
Ok(x) => x,
|
|
|
|
_ => return,
|
|
|
|
};
|
|
|
|
for line_result in BufReader::new(file).lines() {
|
|
|
|
let line = line_result.unwrap();
|
|
|
|
let line = line.trim_end();
|
|
|
|
if line == "Disassembly of section .text" {
|
|
|
|
state = 1;
|
|
|
|
}
|
|
|
|
if state == 0 {
|
|
|
|
if relo_re.is_match(line) {
|
|
|
|
let captures = relo_re.captures(line).unwrap();
|
|
|
|
let address = u64::from_str_radix(&captures[1], 16).unwrap();
|
|
|
|
let symbol = captures[2].to_string();
|
|
|
|
rel.insert(address, symbol);
|
|
|
|
}
|
|
|
|
} else if state == 1 {
|
|
|
|
if head_re.is_match(line) {
|
|
|
|
state = 2;
|
|
|
|
let captures = head_re.captures(line).unwrap();
|
|
|
|
name = captures[2].to_string();
|
|
|
|
}
|
|
|
|
} else if state == 2 {
|
|
|
|
state = 1;
|
|
|
|
if insn_re.is_match(line) {
|
|
|
|
let captures = insn_re.captures(line).unwrap();
|
|
|
|
let address = i64::from_str(&captures[1]).unwrap();
|
|
|
|
a2n.insert(address, name.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let file = match File::create(&postprocessed_dump) {
|
|
|
|
Ok(x) => x,
|
|
|
|
_ => return,
|
|
|
|
};
|
|
|
|
let mut out = BufWriter::new(file);
|
|
|
|
let file = match File::open(program_dump) {
|
|
|
|
Ok(x) => x,
|
|
|
|
_ => return,
|
|
|
|
};
|
|
|
|
let mut pc = 0u64;
|
|
|
|
let mut step = 0u64;
|
|
|
|
for line_result in BufReader::new(file).lines() {
|
|
|
|
let line = line_result.unwrap();
|
|
|
|
let line = line.trim_end();
|
|
|
|
if head_re.is_match(line) {
|
|
|
|
let captures = head_re.captures(line).unwrap();
|
|
|
|
pc = u64::from_str_radix(&captures[1], 16).unwrap();
|
|
|
|
writeln!(out, "{}", line).unwrap();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if insn_re.is_match(line) {
|
|
|
|
let captures = insn_re.captures(line).unwrap();
|
|
|
|
step = if captures[2].len() > 24 { 16 } else { 8 };
|
|
|
|
}
|
|
|
|
if call_re.is_match(line) {
|
|
|
|
if rel.contains_key(&pc) {
|
|
|
|
writeln!(out, "{} ; {}", line, rel[&pc]).unwrap();
|
|
|
|
} else {
|
|
|
|
let captures = call_re.captures(line).unwrap();
|
|
|
|
let pc = i64::from_str(&captures[1]).unwrap().checked_add(1).unwrap();
|
|
|
|
let offset = i64::from_str_radix(&captures[4], 16).unwrap();
|
|
|
|
let offset = if &captures[3] == "-" {
|
|
|
|
offset.checked_neg().unwrap()
|
|
|
|
} else {
|
|
|
|
offset
|
|
|
|
};
|
|
|
|
let address = pc.checked_add(offset).unwrap();
|
|
|
|
if a2n.contains_key(&address) {
|
|
|
|
writeln!(out, "{} ; {}", line, a2n[&address]).unwrap();
|
|
|
|
} else {
|
|
|
|
writeln!(out, "{}", line).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
writeln!(out, "{}", line).unwrap();
|
|
|
|
}
|
|
|
|
pc = pc.checked_add(step).unwrap();
|
|
|
|
}
|
|
|
|
fs::rename(postprocessed_dump, program_dump).unwrap();
|
|
|
|
}
|
|
|
|
|
2021-06-10 15:23:09 -07:00
|
|
|
// 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) {
|
2021-06-12 19:54:44 -07:00
|
|
|
let syscalls_txt = config.bpf_sdk.join("syscalls.txt");
|
|
|
|
let file = match File::open(syscalls_txt) {
|
|
|
|
Ok(x) => x,
|
|
|
|
_ => return,
|
|
|
|
};
|
|
|
|
let mut syscalls = HashSet::new();
|
|
|
|
for line_result in BufReader::new(file).lines() {
|
|
|
|
let line = line_result.unwrap();
|
|
|
|
let line = line.trim_end();
|
|
|
|
syscalls.insert(line.to_string());
|
|
|
|
}
|
2021-06-10 15:23:09 -07:00
|
|
|
let entry =
|
|
|
|
Regex::new(r"^ *[0-9]+: [0-9a-f]{16} +[0-9a-f]+ +NOTYPE +GLOBAL +DEFAULT +UND +(.+)")
|
|
|
|
.unwrap();
|
|
|
|
let readelf = config
|
|
|
|
.bpf_sdk
|
|
|
|
.join("dependencies")
|
|
|
|
.join("bpf-tools")
|
|
|
|
.join("llvm")
|
|
|
|
.join("bin")
|
|
|
|
.join("llvm-readelf");
|
|
|
|
let mut readelf_args = vec!["--dyn-symbols"];
|
|
|
|
readelf_args.push(program.to_str().unwrap());
|
2021-07-14 18:02:42 -07:00
|
|
|
let output = spawn(
|
|
|
|
&readelf,
|
|
|
|
&readelf_args,
|
|
|
|
config.generate_child_script_on_failure,
|
|
|
|
);
|
2021-06-10 15:23:09 -07:00
|
|
|
if config.verbose {
|
|
|
|
println!("{}", output);
|
|
|
|
}
|
|
|
|
let mut unresolved_symbols: Vec<String> = Vec::new();
|
|
|
|
for line in output.lines() {
|
|
|
|
let line = line.trim_end();
|
|
|
|
if entry.is_match(line) {
|
|
|
|
let captures = entry.captures(line).unwrap();
|
|
|
|
let symbol = captures[1].to_string();
|
|
|
|
if !syscalls.contains(&symbol) {
|
|
|
|
unresolved_symbols.push(symbol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !unresolved_symbols.is_empty() {
|
|
|
|
println!(
|
|
|
|
"Warning: the following functions are undefined and not known syscalls {:?}.",
|
|
|
|
unresolved_symbols
|
|
|
|
);
|
|
|
|
println!(" Calling them will trigger a run-time error.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-16 08:32:42 -07:00
|
|
|
// check whether custom BPF toolchain is linked, and link it if it is not.
|
|
|
|
fn link_bpf_toolchain(config: &Config) {
|
|
|
|
let toolchain_path = config
|
|
|
|
.bpf_sdk
|
|
|
|
.join("dependencies")
|
|
|
|
.join("bpf-tools")
|
|
|
|
.join("rust");
|
|
|
|
let rustup = PathBuf::from("rustup");
|
|
|
|
let rustup_args = vec!["toolchain", "list", "-v"];
|
2021-07-14 18:02:42 -07:00
|
|
|
let rustup_output = spawn(
|
|
|
|
&rustup,
|
|
|
|
&rustup_args,
|
|
|
|
config.generate_child_script_on_failure,
|
|
|
|
);
|
2021-06-08 13:55:33 -07:00
|
|
|
if config.verbose {
|
|
|
|
println!("{}", rustup_output);
|
|
|
|
}
|
2021-03-16 08:32:42 -07:00
|
|
|
let mut do_link = true;
|
|
|
|
for line in rustup_output.lines() {
|
|
|
|
if line.starts_with("bpf") {
|
|
|
|
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"];
|
2021-07-14 18:02:42 -07:00
|
|
|
let output = spawn(
|
|
|
|
&rustup,
|
|
|
|
&rustup_args,
|
|
|
|
config.generate_child_script_on_failure,
|
|
|
|
);
|
2021-06-08 13:55:33 -07:00
|
|
|
if config.verbose {
|
|
|
|
println!("{}", output);
|
|
|
|
}
|
2021-03-16 08:32:42 -07:00
|
|
|
} else {
|
|
|
|
do_link = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if do_link {
|
|
|
|
let rustup_args = vec!["toolchain", "link", "bpf", toolchain_path.to_str().unwrap()];
|
2021-07-14 18:02:42 -07:00
|
|
|
let output = spawn(
|
|
|
|
&rustup,
|
|
|
|
&rustup_args,
|
|
|
|
config.generate_child_script_on_failure,
|
|
|
|
);
|
2021-06-08 13:55:33 -07:00
|
|
|
if config.verbose {
|
|
|
|
println!("{}", output);
|
|
|
|
}
|
2021-03-16 08:32:42 -07:00
|
|
|
}
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|
|
|
|
|
2021-01-23 11:55:15 -08:00
|
|
|
fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_metadata::Package) {
|
2020-10-20 17:50:20 -07:00
|
|
|
let program_name = {
|
2020-11-06 10:50:28 -08:00
|
|
|
let cdylib_targets = package
|
2020-10-20 17:50:20 -07:00
|
|
|
.targets
|
|
|
|
.iter()
|
|
|
|
.filter_map(|target| {
|
|
|
|
if target.crate_types.contains(&"cdylib".to_string()) {
|
|
|
|
Some(&target.name)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
match cdylib_targets.len() {
|
|
|
|
0 => {
|
|
|
|
println!(
|
|
|
|
"Note: {} crate does not contain a cdylib target",
|
2020-11-06 10:50:28 -08:00
|
|
|
package.name
|
2020-10-20 17:50:20 -07:00
|
|
|
);
|
|
|
|
None
|
|
|
|
}
|
2022-01-21 16:01:22 -08:00
|
|
|
1 => Some(cdylib_targets[0].replace('-', "_")),
|
2020-10-20 17:50:20 -07:00
|
|
|
_ => {
|
|
|
|
eprintln!(
|
|
|
|
"{} crate contains multiple cdylib targets: {:?}",
|
2020-11-06 10:50:28 -08:00
|
|
|
package.name, cdylib_targets
|
2020-10-20 17:50:20 -07:00
|
|
|
);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-06 10:50:28 -08:00
|
|
|
let legacy_program_feature_present = package.name == "solana-sdk";
|
|
|
|
let root_package_dir = &package.manifest_path.parent().unwrap_or_else(|| {
|
2021-06-16 10:50:22 -07:00
|
|
|
eprintln!("Unable to get directory of {}", package.manifest_path);
|
2020-10-20 17:50:20 -07:00
|
|
|
exit(1);
|
|
|
|
});
|
|
|
|
|
2020-11-04 13:52:03 -08:00
|
|
|
let bpf_out_dir = config
|
|
|
|
.bpf_out_dir
|
2020-11-06 10:50:28 -08:00
|
|
|
.as_ref()
|
|
|
|
.cloned()
|
|
|
|
.unwrap_or_else(|| target_directory.join("deploy"));
|
2020-11-04 13:52:03 -08:00
|
|
|
|
2021-02-18 23:23:04 -08:00
|
|
|
let target_build_directory = target_directory
|
|
|
|
.join("bpfel-unknown-unknown")
|
|
|
|
.join("release");
|
2020-10-20 17:50:20 -07:00
|
|
|
|
|
|
|
env::set_current_dir(&root_package_dir).unwrap_or_else(|err| {
|
|
|
|
eprintln!(
|
|
|
|
"Unable to set current directory to {}: {}",
|
2021-06-16 10:50:22 -07:00
|
|
|
root_package_dir, err
|
2020-10-20 17:50:20 -07:00
|
|
|
);
|
|
|
|
exit(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
println!("BPF SDK: {}", config.bpf_sdk.display());
|
|
|
|
if config.no_default_features {
|
|
|
|
println!("No default features");
|
|
|
|
}
|
|
|
|
if !config.features.is_empty() {
|
|
|
|
println!("Features: {}", config.features.join(" "));
|
|
|
|
}
|
|
|
|
if legacy_program_feature_present {
|
|
|
|
println!("Legacy program feature detected");
|
|
|
|
}
|
2021-12-28 15:37:35 -08:00
|
|
|
let bpf_tools_download_file_name = if cfg!(target_os = "windows") {
|
|
|
|
"solana-bpf-tools-windows.tar.bz2"
|
|
|
|
} else if cfg!(target_os = "macos") {
|
2021-03-16 08:32:42 -07:00
|
|
|
"solana-bpf-tools-osx.tar.bz2"
|
|
|
|
} else {
|
|
|
|
"solana-bpf-tools-linux.tar.bz2"
|
|
|
|
};
|
2021-11-03 14:06:14 -07:00
|
|
|
|
|
|
|
let home_dir = PathBuf::from(env::var("HOME").unwrap_or_else(|err| {
|
|
|
|
eprintln!("Can't get home directory path: {}", err);
|
|
|
|
exit(1);
|
|
|
|
}));
|
|
|
|
let package = "bpf-tools";
|
|
|
|
let target_path = home_dir
|
|
|
|
.join(".cache")
|
|
|
|
.join("solana")
|
2021-12-22 15:10:25 -08:00
|
|
|
.join(config.bpf_tools_version)
|
2021-11-03 14:06:14 -07:00
|
|
|
.join(package);
|
2021-03-16 08:32:42 -07:00
|
|
|
install_if_missing(
|
2021-06-18 06:34:46 -07:00
|
|
|
config,
|
2021-11-03 14:06:14 -07:00
|
|
|
package,
|
2021-03-16 08:32:42 -07:00
|
|
|
"https://github.com/solana-labs/bpf-tools/releases/download",
|
2021-09-06 01:59:58 -07:00
|
|
|
bpf_tools_download_file_name,
|
2021-11-03 14:06:14 -07:00
|
|
|
&target_path,
|
2021-03-16 08:32:42 -07:00
|
|
|
)
|
2021-11-03 14:06:14 -07:00
|
|
|
.unwrap_or_else(|err| {
|
|
|
|
// The package version directory doesn't contain a valid
|
|
|
|
// 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!(
|
|
|
|
"Failed to remove {} while recovering from installation failure: {}",
|
|
|
|
target_path_parent.to_string_lossy(),
|
|
|
|
err,
|
|
|
|
);
|
|
|
|
exit(1);
|
|
|
|
});
|
|
|
|
eprintln!("Failed to install bpf-tools: {}", err);
|
|
|
|
exit(1);
|
|
|
|
});
|
2021-06-18 06:34:46 -07:00
|
|
|
link_bpf_toolchain(config);
|
2020-10-20 17:50:20 -07:00
|
|
|
|
2021-03-16 08:32:42 -07:00
|
|
|
let llvm_bin = config
|
|
|
|
.bpf_sdk
|
|
|
|
.join("dependencies")
|
|
|
|
.join("bpf-tools")
|
|
|
|
.join("llvm")
|
|
|
|
.join("bin");
|
|
|
|
env::set_var("CC", llvm_bin.join("clang"));
|
|
|
|
env::set_var("AR", llvm_bin.join("llvm-ar"));
|
|
|
|
env::set_var("OBJDUMP", llvm_bin.join("llvm-objdump"));
|
|
|
|
env::set_var("OBJCOPY", llvm_bin.join("llvm-objcopy"));
|
2022-01-05 14:16:50 -08:00
|
|
|
|
2022-01-06 12:41:13 -08:00
|
|
|
if config.verbose {
|
|
|
|
println!(
|
|
|
|
"RUSTFLAGS={}",
|
|
|
|
env::var("RUSTFLAGS").ok().as_deref().unwrap_or("")
|
|
|
|
);
|
2021-06-11 10:23:15 -07:00
|
|
|
};
|
2022-01-05 14:16:50 -08:00
|
|
|
|
2021-03-16 08:32:42 -07:00
|
|
|
let cargo_build = PathBuf::from("cargo");
|
|
|
|
let mut cargo_build_args = vec![
|
|
|
|
"+bpf",
|
|
|
|
"build",
|
|
|
|
"--target",
|
|
|
|
"bpfel-unknown-unknown",
|
|
|
|
"--release",
|
|
|
|
];
|
2020-10-20 17:50:20 -07:00
|
|
|
if config.no_default_features {
|
2021-03-16 08:32:42 -07:00
|
|
|
cargo_build_args.push("--no-default-features");
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|
|
|
|
for feature in &config.features {
|
2021-03-16 08:32:42 -07:00
|
|
|
cargo_build_args.push("--features");
|
|
|
|
cargo_build_args.push(feature);
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|
|
|
|
if legacy_program_feature_present {
|
|
|
|
if !config.no_default_features {
|
2021-03-16 08:32:42 -07:00
|
|
|
cargo_build_args.push("--no-default-features");
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|
2021-03-16 08:32:42 -07:00
|
|
|
cargo_build_args.push("--features=program");
|
2020-11-04 18:29:26 -08:00
|
|
|
}
|
|
|
|
if config.verbose {
|
2021-03-16 08:32:42 -07:00
|
|
|
cargo_build_args.push("--verbose");
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|
2021-06-17 18:27:13 -07:00
|
|
|
if let Some(args) = &config.cargo_args {
|
|
|
|
for arg in args {
|
|
|
|
cargo_build_args.push(arg);
|
|
|
|
}
|
|
|
|
}
|
2021-07-14 18:02:42 -07:00
|
|
|
let output = spawn(
|
|
|
|
&cargo_build,
|
|
|
|
&cargo_build_args,
|
|
|
|
config.generate_child_script_on_failure,
|
|
|
|
);
|
2021-06-08 13:55:33 -07:00
|
|
|
if config.verbose {
|
|
|
|
println!("{}", output);
|
|
|
|
}
|
2020-10-20 17:50:20 -07:00
|
|
|
|
|
|
|
if let Some(program_name) = program_name {
|
|
|
|
let program_unstripped_so = target_build_directory.join(&format!("{}.so", program_name));
|
2020-11-04 13:52:03 -08:00
|
|
|
let program_dump = bpf_out_dir.join(&format!("{}-dump.txt", program_name));
|
|
|
|
let program_so = bpf_out_dir.join(&format!("{}.so", program_name));
|
2020-12-16 10:31:49 -08:00
|
|
|
let program_keypair = bpf_out_dir.join(&format!("{}-keypair.json", program_name));
|
2020-10-20 17:50:20 -07:00
|
|
|
|
2020-11-05 08:56:35 -08:00
|
|
|
fn file_older_or_missing(prerequisite_file: &Path, target_file: &Path) -> bool {
|
|
|
|
let prerequisite_metadata = fs::metadata(prerequisite_file).unwrap_or_else(|err| {
|
|
|
|
eprintln!(
|
|
|
|
"Unable to get file metadata for {}: {}",
|
|
|
|
prerequisite_file.display(),
|
|
|
|
err
|
|
|
|
);
|
|
|
|
exit(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Ok(target_metadata) = fs::metadata(target_file) {
|
|
|
|
use std::time::UNIX_EPOCH;
|
|
|
|
prerequisite_metadata.modified().unwrap_or(UNIX_EPOCH)
|
|
|
|
> target_metadata.modified().unwrap_or(UNIX_EPOCH)
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-16 10:31:49 -08:00
|
|
|
if !program_keypair.exists() {
|
|
|
|
write_keypair_file(&Keypair::new(), &program_keypair).unwrap_or_else(|err| {
|
|
|
|
eprintln!(
|
|
|
|
"Unable to get create {}: {}",
|
|
|
|
program_keypair.display(),
|
|
|
|
err
|
|
|
|
);
|
|
|
|
exit(1);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-05 08:56:35 -08:00
|
|
|
if file_older_or_missing(&program_unstripped_so, &program_so) {
|
2021-12-28 15:37:35 -08:00
|
|
|
#[cfg(windows)]
|
|
|
|
let output = spawn(
|
|
|
|
&llvm_bin.join("llvm-objcopy"),
|
|
|
|
&[
|
|
|
|
"--strip-all".as_ref(),
|
|
|
|
program_unstripped_so.as_os_str(),
|
|
|
|
program_so.as_os_str(),
|
|
|
|
],
|
|
|
|
config.generate_child_script_on_failure,
|
|
|
|
);
|
|
|
|
#[cfg(not(windows))]
|
2021-06-08 13:55:33 -07:00
|
|
|
let output = spawn(
|
2021-02-18 23:23:04 -08:00
|
|
|
&config.bpf_sdk.join("scripts").join("strip.sh"),
|
2020-11-05 08:56:35 -08:00
|
|
|
&[&program_unstripped_so, &program_so],
|
2021-07-14 18:02:42 -07:00
|
|
|
config.generate_child_script_on_failure,
|
2020-11-05 08:56:35 -08:00
|
|
|
);
|
2021-06-08 13:55:33 -07:00
|
|
|
if config.verbose {
|
|
|
|
println!("{}", output);
|
|
|
|
}
|
2020-11-05 08:56:35 -08:00
|
|
|
}
|
2020-10-20 17:50:20 -07:00
|
|
|
|
2020-11-05 08:56:35 -08:00
|
|
|
if config.dump && file_older_or_missing(&program_unstripped_so, &program_dump) {
|
2021-12-28 15:37:35 -08:00
|
|
|
let dump_script = config.bpf_sdk.join("scripts").join("dump.sh");
|
|
|
|
#[cfg(windows)]
|
|
|
|
{
|
|
|
|
eprintln!("Using Bash scripts from within a program is not supported on Windows, skipping `--dump`.");
|
|
|
|
eprintln!(
|
|
|
|
"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(),
|
|
|
|
&program_dump.display());
|
|
|
|
}
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
{
|
|
|
|
let output = spawn(
|
|
|
|
&dump_script,
|
|
|
|
&[&program_unstripped_so, &program_dump],
|
|
|
|
config.generate_child_script_on_failure,
|
|
|
|
);
|
|
|
|
if config.verbose {
|
|
|
|
println!("{}", output);
|
|
|
|
}
|
2021-06-08 13:55:33 -07:00
|
|
|
}
|
2021-04-09 02:44:19 -07:00
|
|
|
postprocess_dump(&program_dump);
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|
2020-11-04 13:52:03 -08:00
|
|
|
|
2021-06-18 06:34:46 -07:00
|
|
|
check_undefined_symbols(config, &program_so);
|
2021-06-10 15:23:09 -07:00
|
|
|
|
2020-11-04 13:52:03 -08:00
|
|
|
println!();
|
|
|
|
println!("To deploy this program:");
|
2020-12-21 13:02:53 -08:00
|
|
|
println!(" $ solana program deploy {}", program_so.display());
|
2021-08-24 10:05:54 -07:00
|
|
|
println!("The program address will default to this keypair (override with --program-id):");
|
|
|
|
println!(" {}", program_keypair.display());
|
2020-10-20 17:50:20 -07:00
|
|
|
} else if config.dump {
|
|
|
|
println!("Note: --dump is only available for crates with a cdylib target");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-06 10:50:28 -08:00
|
|
|
fn build_bpf(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);
|
|
|
|
}
|
2020-11-12 16:39:33 -08:00
|
|
|
if config.offline {
|
|
|
|
metadata_command.other_options(vec!["--offline".to_string()]);
|
|
|
|
}
|
2020-11-06 10:50:28 -08:00
|
|
|
|
|
|
|
let metadata = metadata_command.exec().unwrap_or_else(|err| {
|
|
|
|
eprintln!("Failed to obtain package metadata: {}", err);
|
|
|
|
exit(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(root_package) = metadata.root_package() {
|
|
|
|
if !config.workspace {
|
2021-06-18 06:34:46 -07:00
|
|
|
build_bpf_package(&config, metadata.target_directory.as_ref(), root_package);
|
2020-11-06 10:50:28 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let all_bpf_packages = metadata
|
|
|
|
.packages
|
|
|
|
.iter()
|
|
|
|
.filter(|package| {
|
2021-04-07 17:22:55 -07:00
|
|
|
if metadata.workspace_members.contains(&package.id) {
|
|
|
|
for target in package.targets.iter() {
|
|
|
|
if target.kind.contains(&"cdylib".to_string()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
2020-11-06 10:50:28 -08:00
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
for package in all_bpf_packages {
|
2021-06-18 06:34:46 -07:00
|
|
|
build_bpf_package(&config, metadata.target_directory.as_ref(), package);
|
2020-11-06 10:50:28 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:50:20 -07:00
|
|
|
fn main() {
|
2020-10-22 17:10:42 -07:00
|
|
|
let default_config = Config::default();
|
|
|
|
let default_bpf_sdk = format!("{}", default_config.bpf_sdk.display());
|
2020-10-20 17:50:20 -07:00
|
|
|
|
|
|
|
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" {
|
|
|
|
args.remove(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-08 14:35:50 -08:00
|
|
|
// The following line is scanned by CI configuration script to
|
|
|
|
// separate cargo caches according to the version of sbf-tools.
|
2022-03-30 10:19:04 -07:00
|
|
|
let bpf_tools_version = "v1.24";
|
2021-12-22 15:10:25 -08:00
|
|
|
let version = format!("{}\nbpf-tools {}", crate_version!(), bpf_tools_version);
|
2022-03-07 07:25:01 -08:00
|
|
|
let matches = clap::Command::new(crate_name!())
|
2020-10-20 17:50:20 -07:00
|
|
|
.about(crate_description!())
|
2021-12-22 15:10:25 -08:00
|
|
|
.version(version.as_str())
|
2021-06-21 11:53:34 -07:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("bpf_out_dir")
|
cargo-build-bpf: allow sdk path to be set by environment variables
In many Linux distros such as NixOS, the directory in which packages are
installed is assumed to be read-only. To work around this, it is
expected that the filepaths which packaged CLI tools take in are able to
be freely configured through either 1) command-line flags, 2)
environment variables, or 3) a configuration file.
In this commit, environment variables 'BPF_SDK_PATH' and 'BPF_OUT_PATH',
which map respectively to command-line flags '--bpf-sdk-path' and
'--bpf-out-dir', are now handled in cargo-build-bpf.
Additionally, given that arbitrary filepaths may now be set in which the
BPF SDK is located, the requirement in which
'$BPF_SDK_PATH/dependencies/bpf-tools' must strictly be a symbolic link
to the directory '$HOME/.cache/solana/${bpf-tools.version}/bpf-tools has
been relaxed.
Ideally, the directory in which bpf-tools is expected to be downloaded
to and stored should be configurable. Though, this commit serves as a
temporary fix which enables NixOS users to now start being able to build
applications with the Solana SDK.
2021-08-30 10:27:20 -07:00
|
|
|
.env("BPF_OUT_PATH")
|
2021-06-21 11:53:34 -07:00
|
|
|
.long("bpf-out-dir")
|
|
|
|
.value_name("DIRECTORY")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Place final BPF build artifacts in this directory"),
|
|
|
|
)
|
2020-10-20 17:50:20 -07:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("bpf_sdk")
|
cargo-build-bpf: allow sdk path to be set by environment variables
In many Linux distros such as NixOS, the directory in which packages are
installed is assumed to be read-only. To work around this, it is
expected that the filepaths which packaged CLI tools take in are able to
be freely configured through either 1) command-line flags, 2)
environment variables, or 3) a configuration file.
In this commit, environment variables 'BPF_SDK_PATH' and 'BPF_OUT_PATH',
which map respectively to command-line flags '--bpf-sdk-path' and
'--bpf-out-dir', are now handled in cargo-build-bpf.
Additionally, given that arbitrary filepaths may now be set in which the
BPF SDK is located, the requirement in which
'$BPF_SDK_PATH/dependencies/bpf-tools' must strictly be a symbolic link
to the directory '$HOME/.cache/solana/${bpf-tools.version}/bpf-tools has
been relaxed.
Ideally, the directory in which bpf-tools is expected to be downloaded
to and stored should be configurable. Though, this commit serves as a
temporary fix which enables NixOS users to now start being able to build
applications with the Solana SDK.
2021-08-30 10:27:20 -07:00
|
|
|
.env("BPF_SDK_PATH")
|
2020-10-20 17:50:20 -07:00
|
|
|
.long("bpf-sdk")
|
|
|
|
.value_name("PATH")
|
|
|
|
.takes_value(true)
|
|
|
|
.default_value(&default_bpf_sdk)
|
|
|
|
.help("Path to the Solana BPF SDK"),
|
|
|
|
)
|
2021-06-21 11:53:34 -07:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("cargo_args")
|
2021-06-21 11:53:34 -07:00
|
|
|
.help("Arguments passed directly to `cargo build`")
|
2022-03-07 07:25:01 -08:00
|
|
|
.multiple_occurrences(true)
|
|
|
|
.multiple_values(true)
|
2021-06-21 11:53:34 -07:00
|
|
|
.last(true),
|
|
|
|
)
|
2020-10-20 17:50:20 -07:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("dump")
|
2020-10-20 17:50:20 -07:00
|
|
|
.long("dump")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Dump ELF information to a text file on success"),
|
|
|
|
)
|
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("features")
|
2020-10-20 17:50:20 -07:00
|
|
|
.long("features")
|
|
|
|
.value_name("FEATURES")
|
|
|
|
.takes_value(true)
|
2022-03-07 07:25:01 -08:00
|
|
|
.multiple_occurrences(true)
|
|
|
|
.multiple_values(true)
|
2020-10-20 17:50:20 -07:00
|
|
|
.help("Space-separated list of features to activate"),
|
|
|
|
)
|
2021-07-14 18:02:42 -07:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("generate_child_script_on_failure")
|
2021-07-14 18:02:42 -07:00
|
|
|
.long("generate-child-script-on-failure")
|
|
|
|
.takes_value(false)
|
2021-07-14 20:31:33 -07:00
|
|
|
.help("Generate a shell script to rerun a failed subcommand"),
|
2021-07-14 18:02:42 -07:00
|
|
|
)
|
2021-06-21 11:53:34 -07:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("manifest_path")
|
2021-06-21 11:53:34 -07:00
|
|
|
.long("manifest-path")
|
|
|
|
.value_name("PATH")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Path to Cargo.toml"),
|
|
|
|
)
|
2020-10-20 17:50:20 -07:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("no_default_features")
|
2020-10-20 17:50:20 -07:00
|
|
|
.long("no-default-features")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Do not activate the `default` feature"),
|
|
|
|
)
|
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("offline")
|
2021-06-21 11:53:34 -07:00
|
|
|
.long("offline")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Run without accessing the network"),
|
2020-10-20 17:50:20 -07:00
|
|
|
)
|
2020-10-22 17:10:42 -07:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("verbose")
|
|
|
|
.short('v')
|
2021-06-21 11:53:34 -07:00
|
|
|
.long("verbose")
|
|
|
|
.takes_value(false)
|
|
|
|
.help("Use verbose output"),
|
2020-10-22 17:10:42 -07:00
|
|
|
)
|
2020-11-06 10:50:28 -08:00
|
|
|
.arg(
|
2022-03-07 07:25:01 -08:00
|
|
|
Arg::new("workspace")
|
2020-11-06 10:50:28 -08:00
|
|
|
.long("workspace")
|
|
|
|
.takes_value(false)
|
|
|
|
.alias("all")
|
|
|
|
.help("Build all BPF packages in the workspace"),
|
|
|
|
)
|
2020-10-20 17:50:20 -07:00
|
|
|
.get_matches_from(args);
|
|
|
|
|
2022-03-07 07:25:01 -08:00
|
|
|
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();
|
2020-10-20 17:50:20 -07:00
|
|
|
|
|
|
|
let config = Config {
|
2021-06-17 18:27:13 -07:00
|
|
|
cargo_args: matches
|
|
|
|
.values_of("cargo_args")
|
|
|
|
.map(|vals| vals.collect::<Vec<_>>()),
|
2020-10-20 17:50:20 -07:00
|
|
|
bpf_sdk: fs::canonicalize(&bpf_sdk).unwrap_or_else(|err| {
|
|
|
|
eprintln!(
|
|
|
|
"BPF SDK path does not exist: {}: {}",
|
|
|
|
bpf_sdk.display(),
|
|
|
|
err
|
|
|
|
);
|
|
|
|
exit(1);
|
|
|
|
}),
|
2020-11-04 13:52:03 -08:00
|
|
|
bpf_out_dir: bpf_out_dir.map(|bpf_out_dir| {
|
|
|
|
if bpf_out_dir.is_absolute() {
|
|
|
|
bpf_out_dir
|
|
|
|
} else {
|
|
|
|
env::current_dir()
|
|
|
|
.expect("Unable to get current working directory")
|
|
|
|
.join(bpf_out_dir)
|
|
|
|
}
|
|
|
|
}),
|
2021-12-22 15:10:25 -08:00
|
|
|
bpf_tools_version,
|
2020-10-20 17:50:20 -07:00
|
|
|
dump: matches.is_present("dump"),
|
2022-03-07 07:25:01 -08:00
|
|
|
features: matches.values_of_t("features").ok().unwrap_or_default(),
|
2021-07-14 18:02:42 -07:00
|
|
|
generate_child_script_on_failure: matches.is_present("generate_child_script_on_failure"),
|
2020-10-20 17:50:20 -07:00
|
|
|
no_default_features: matches.is_present("no_default_features"),
|
2020-11-12 16:39:33 -08:00
|
|
|
offline: matches.is_present("offline"),
|
2020-11-04 18:29:26 -08:00
|
|
|
verbose: matches.is_present("verbose"),
|
2020-11-06 10:50:28 -08:00
|
|
|
workspace: matches.is_present("workspace"),
|
2020-10-20 17:50:20 -07:00
|
|
|
};
|
2022-03-07 07:25:01 -08:00
|
|
|
let manifest_path: Option<PathBuf> = matches.value_of_t("manifest_path").ok();
|
2020-11-06 10:50:28 -08:00
|
|
|
build_bpf(config, manifest_path);
|
2020-10-20 17:50:20 -07:00
|
|
|
}
|