xtask: build/run
This commit is contained in:
parent
138e77bb4c
commit
7ab8bcf308
|
@ -1,8 +1,7 @@
|
|||
[alias]
|
||||
xtask = "run --package xtask --release --"
|
||||
xtask = "run --package xtask --"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
lto = false
|
||||
|
||||
[profile.release]
|
||||
|
|
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -4344,11 +4344,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.120"
|
||||
version = "1.0.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
@ -4507,6 +4508,28 @@ version = "0.11.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
@ -5832,11 +5855,32 @@ version = "0.8.20"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193"
|
||||
|
||||
[[package]]
|
||||
name = "xshell"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437"
|
||||
dependencies = [
|
||||
"xshell-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xshell-macros"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo_metadata",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"log",
|
||||
"nih_plug_xtask",
|
||||
"strum",
|
||||
"xshell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -6,4 +6,10 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.15", features = ["derive"] }
|
||||
strum = { version = "0.26.3", features = ["derive"] }
|
||||
xshell = "0.2.6"
|
||||
cargo_metadata = "0.18.1"
|
||||
nih_plug_xtask = { workspace = true }
|
||||
log = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
|
|
57
xtask/src/args.rs
Normal file
57
xtask/src/args.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use clap::Parser;
|
||||
|
||||
use crate::types::*;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
#[command(subcommand)]
|
||||
pub command: Commands,
|
||||
|
||||
#[arg(long)]
|
||||
/// Defaults to CARGO_WORKSPACE_DIR/build, unless XTASK_TARGET_DIR is set.
|
||||
pub target_dir: Option<std::path::PathBuf>,
|
||||
|
||||
#[arg(long)]
|
||||
/// Build in debug mode instead of release mode
|
||||
pub debug: bool,
|
||||
}
|
||||
|
||||
#[derive(clap::Subcommand, Debug)]
|
||||
pub enum Commands {
|
||||
#[command(allow_external_subcommands = true)]
|
||||
Bundle,
|
||||
#[command(allow_external_subcommands = true)]
|
||||
BundleUniversal,
|
||||
Build(BuildArgs),
|
||||
#[command(allow_external_subcommands = true)]
|
||||
Run(RunArgs),
|
||||
}
|
||||
|
||||
#[derive(clap::Args, Debug)]
|
||||
#[command(group(clap::ArgGroup::new("platforms").args(["platform","all_platforms"]).required(true)))]
|
||||
#[command(group(clap::ArgGroup::new("binaries").args(["binary","all_binaries"]).required(true)))]
|
||||
pub struct BuildArgs {
|
||||
#[arg(long, short)]
|
||||
pub platform: Vec<Platform>,
|
||||
#[arg(long)]
|
||||
pub all_platforms: bool,
|
||||
|
||||
#[arg(long, short)]
|
||||
pub binary: Vec<Binary>,
|
||||
#[arg(long)]
|
||||
pub all_binaries: bool,
|
||||
|
||||
#[arg(long, short)]
|
||||
pub renderer: Vec<Renderer>,
|
||||
}
|
||||
|
||||
#[derive(clap::Args, Debug)]
|
||||
pub struct RunArgs {
|
||||
#[arg(long, short)]
|
||||
pub platform: Option<Platform>,
|
||||
#[arg(long, short)]
|
||||
pub binary: Option<Binary>,
|
||||
#[arg(long, short)]
|
||||
pub renderer: Option<Renderer>,
|
||||
}
|
|
@ -1,3 +1,264 @@
|
|||
fn main() -> nih_plug_xtask::Result<()> {
|
||||
nih_plug_xtask::main()
|
||||
use clap::Parser;
|
||||
use strum::IntoEnumIterator;
|
||||
use xshell::Shell;
|
||||
|
||||
use args::*;
|
||||
use types::*;
|
||||
mod args;
|
||||
mod types;
|
||||
|
||||
static METADATA: std::sync::OnceLock<cargo_metadata::Metadata> = std::sync::OnceLock::new();
|
||||
static OUTPUT_DIR: std::sync::OnceLock<std::path::PathBuf> = std::sync::OnceLock::new();
|
||||
|
||||
fn executable_dir(binary: Binary, platform: Platform, renderer: Renderer) -> String {
|
||||
format!(
|
||||
"{}_{}_{}",
|
||||
binary.name(),
|
||||
platform.as_target(),
|
||||
renderer.as_feature()
|
||||
)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
if std::env::var("RUST_LOG").is_err() {
|
||||
std::env::set_var("RUST_LOG", "info");
|
||||
}
|
||||
env_logger::init();
|
||||
let args = Args::parse();
|
||||
|
||||
let metadata = cargo_metadata::MetadataCommand::new().exec()?;
|
||||
|
||||
let target_dir = args
|
||||
.target_dir
|
||||
.or(std::env::var("XTASK_TARGET_DIR")
|
||||
.ok()
|
||||
.map(std::path::PathBuf::from))
|
||||
.unwrap_or_else(|| std::path::PathBuf::from(&metadata.target_directory).join("xbuild"));
|
||||
|
||||
OUTPUT_DIR.set(target_dir).map_err(|_| CouldntSetOnceLock)?;
|
||||
METADATA.set(metadata).map_err(|_| CouldntSetOnceLock)?;
|
||||
|
||||
match args.command {
|
||||
Commands::Bundle | Commands::BundleUniversal => {
|
||||
let args = std::env::args().skip(1).collect::<Vec<_>>();
|
||||
nih_plug_xtask::main_with_args("cargo xtask", args.into_iter())?;
|
||||
Ok(())
|
||||
}
|
||||
Commands::Build(build_args) => build(build_args, args.debug),
|
||||
Commands::Run(run_args) => run(run_args, args.debug),
|
||||
}
|
||||
}
|
||||
|
||||
fn build(args: BuildArgs, debug: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let platforms = if args.all_platforms {
|
||||
Platform::iter().collect()
|
||||
} else {
|
||||
args.platform
|
||||
};
|
||||
log::info!("platforms: {platforms:?}");
|
||||
|
||||
let binaries = if args.all_binaries {
|
||||
Binary::iter().collect()
|
||||
} else {
|
||||
args.binary
|
||||
};
|
||||
log::info!("binaries: {binaries:?}");
|
||||
|
||||
let renderers = if args.renderer.is_empty() {
|
||||
vec![Renderer::Wgpu]
|
||||
} else {
|
||||
args.renderer
|
||||
};
|
||||
log::info!("renderers: {renderers:?}");
|
||||
|
||||
for binary in binaries {
|
||||
for platform in &platforms {
|
||||
for renderer in &renderers {
|
||||
build_binary(binary, *platform, *renderer, debug)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(args: RunArgs, debug: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let platform = args.platform.unwrap_or(Platform::host_platform());
|
||||
let binary = args.binary.unwrap_or(Binary::get_default());
|
||||
let renderer = args.renderer.unwrap_or(Renderer::Wgpu);
|
||||
match binary {
|
||||
Binary::Gui => run_gui(platform, renderer, debug),
|
||||
Binary::Cli => run_cli(platform, renderer, debug),
|
||||
Binary::Vst => {
|
||||
eprintln!("twinc_emu_vst doesn't support standalone usage!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_binary(
|
||||
binary: Binary,
|
||||
platform: Platform,
|
||||
renderer: Renderer,
|
||||
debug: bool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let output_dir = OUTPUT_DIR
|
||||
.get()
|
||||
.unwrap()
|
||||
.join(executable_dir(binary, platform, renderer));
|
||||
|
||||
std::fs::create_dir_all(&output_dir)?;
|
||||
match binary {
|
||||
Binary::Gui => build_gui(output_dir, platform, renderer, debug),
|
||||
Binary::Cli => build_cli(output_dir, platform, renderer, debug),
|
||||
Binary::Vst => build_vst(platform, renderer, debug),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_gui(
|
||||
output_dir: std::path::PathBuf,
|
||||
platform: Platform,
|
||||
renderer: Renderer,
|
||||
debug: bool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let ui = platform.ui();
|
||||
|
||||
run_build(
|
||||
"gui",
|
||||
platform,
|
||||
renderer,
|
||||
debug,
|
||||
Some(["-F", ui].into_iter().map(String::from).collect()),
|
||||
output_dir,
|
||||
)
|
||||
}
|
||||
|
||||
fn run_gui(
|
||||
platform: Platform,
|
||||
renderer: Renderer,
|
||||
debug: bool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let ui = platform.ui();
|
||||
|
||||
let _ = cargo_exec(
|
||||
"run",
|
||||
"gui",
|
||||
platform,
|
||||
renderer,
|
||||
debug,
|
||||
Some(["-F", ui].into_iter().map(String::from).collect()),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_cli(
|
||||
output_dir: std::path::PathBuf,
|
||||
platform: Platform,
|
||||
renderer: Renderer,
|
||||
debug: bool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
run_build("cli", platform, renderer, debug, None, output_dir)
|
||||
}
|
||||
|
||||
fn run_cli(
|
||||
platform: Platform,
|
||||
renderer: Renderer,
|
||||
debug: bool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = std::env::args().skip(1).collect::<Vec<_>>();
|
||||
let additional_flags = args
|
||||
.iter()
|
||||
.position(|arg| arg == "--")
|
||||
.map(|extra_args_index| args[extra_args_index..].to_vec());
|
||||
|
||||
let _ = cargo_exec("run", "cli", platform, renderer, debug, additional_flags)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_build(
|
||||
package: &str,
|
||||
platform: Platform,
|
||||
renderer: Renderer,
|
||||
debug: bool,
|
||||
additional_flags: Option<Vec<String>>,
|
||||
output_dir: std::path::PathBuf,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
for (name, executable_path) in cargo_exec(
|
||||
"build",
|
||||
package,
|
||||
platform,
|
||||
renderer,
|
||||
debug,
|
||||
additional_flags,
|
||||
)?
|
||||
.filter_map(|m| as_artifact(m.ok()?))
|
||||
.filter_map(|a| a.executable.map(|e| (a.target.name, e)))
|
||||
{
|
||||
std::fs::copy(executable_path, output_dir.join(name))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cargo_exec(
|
||||
verb: &str,
|
||||
package: &str,
|
||||
platform: Platform,
|
||||
renderer: Renderer,
|
||||
debug: bool,
|
||||
additional_flags: Option<Vec<String>>,
|
||||
) -> Result<
|
||||
impl Iterator<Item = std::io::Result<cargo_metadata::Message>>,
|
||||
Box<dyn std::error::Error>,
|
||||
> {
|
||||
let sh = Shell::new()?;
|
||||
let target = platform.as_target();
|
||||
let release = if debug { "" } else { "--release" };
|
||||
|
||||
let renderer = renderer.as_feature();
|
||||
let args=format!("{verb} -p {package} --target {target} {release} --no-default-features -F {renderer} --message-format=json");
|
||||
let args = args.split_whitespace().map(|s| s.to_string());
|
||||
let args = if let Some(additional_flags) = additional_flags {
|
||||
args.chain(additional_flags).collect::<Vec<_>>()
|
||||
} else {
|
||||
args.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let output = sh.cmd("cargo").args(args).read()?;
|
||||
|
||||
Ok(cargo_metadata::Message::parse_stream(std::io::Cursor::new(
|
||||
output,
|
||||
)))
|
||||
}
|
||||
|
||||
fn as_artifact(message: cargo_metadata::Message) -> Option<cargo_metadata::Artifact> {
|
||||
if let cargo_metadata::Message::CompilerArtifact(a) = message {
|
||||
Some(a)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn build_vst(
|
||||
platform: Platform,
|
||||
renderer: Renderer,
|
||||
debug: bool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut args = if platform == Platform::Mac {
|
||||
vec!["bundle-universal"]
|
||||
} else {
|
||||
vec!["bundle", "--target", platform.as_target()]
|
||||
};
|
||||
if !debug {
|
||||
args.push("--release");
|
||||
}
|
||||
let more_args = "-p twinc_emu_vst --no-default-features -F plugin";
|
||||
for arg in more_args.split_whitespace() {
|
||||
args.push(arg);
|
||||
}
|
||||
args.push("-F");
|
||||
args.push(renderer.as_feature());
|
||||
|
||||
nih_plug_xtask::main_with_args("cargo xtask", args.into_iter().map(String::from))?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
96
xtask/src/types.rs
Normal file
96
xtask/src/types.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
#[derive(clap::ValueEnum, Clone, Copy, Debug, strum::EnumIter, PartialEq, Eq)]
|
||||
pub enum Platform {
|
||||
Windows,
|
||||
Linux,
|
||||
Mac,
|
||||
}
|
||||
|
||||
impl Platform {
|
||||
pub fn as_target(&self) -> &str {
|
||||
match self {
|
||||
Platform::Windows => "x86_64-pc-windows-gnu",
|
||||
Platform::Linux => "x86_64-unknown-linux-gnu",
|
||||
Platform::Mac => "aarch64-apple-darwin",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui(&self) -> &str {
|
||||
match self {
|
||||
Platform::Windows | Platform::Linux => "crossplatform-ui",
|
||||
Platform::Mac => "macos-ui",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn host_platform() -> Self {
|
||||
if cfg!(target_os = "windows") {
|
||||
Self::Windows
|
||||
} else if cfg!(target_os = "macos") {
|
||||
Self::Mac
|
||||
} else if cfg!(target_os = "linux") {
|
||||
Self::Linux
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(clap::ValueEnum, Clone, Copy, Debug, strum::EnumIter, PartialEq, Eq)]
|
||||
pub enum Binary {
|
||||
Gui,
|
||||
Cli,
|
||||
Vst,
|
||||
}
|
||||
|
||||
impl Binary {
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
Binary::Gui => "gui",
|
||||
Binary::Cli => "cli",
|
||||
Binary::Vst => "vst",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_default() -> Self {
|
||||
Self::Cli
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(clap::ValueEnum, Clone, Copy, Debug, strum::EnumIter, PartialEq, Eq)]
|
||||
pub enum Renderer {
|
||||
Wgpu,
|
||||
Vulkan,
|
||||
Pixels,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn as_feature(&self) -> &str {
|
||||
match self {
|
||||
Renderer::Wgpu => "wgpu",
|
||||
Renderer::Vulkan => "vulkan",
|
||||
Renderer::Pixels => "pixels",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CouldntSetOnceLock;
|
||||
|
||||
impl std::fmt::Display for CouldntSetOnceLock {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(&self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for CouldntSetOnceLock {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"description() is deprecated; use Display"
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn std::error::Error> {
|
||||
self.source()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue