-
Notifications
You must be signed in to change notification settings - Fork 145
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added new command to quill, and minimal docs.
- Loading branch information
1 parent
e4791aa
commit 178c5da
Showing
4 changed files
with
274 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# cargo-quill | ||
We have created an extension to cargo, that provides utilities for creating, | ||
building, and testing feather plugins written in rust. This utility is called | ||
cargo-quill. | ||
|
||
The sourcecode for cargo-quill can be found in /feather/quill/cargo-quill. | ||
If there is a bug, or some missing feature, this is were to look. | ||
|
||
# How to install: | ||
Install cargo-quill by running the following command from the main folder. | ||
> cargo install --path quill/cargo-quill | ||
## How to create a new plugin | ||
This command works similar to | ||
> cargo-quill new 'name' | ||
## build | ||
> cargo-quill build | ||
Builds the source and puts a '.plugin' file in the target folder. Just like the | ||
regular cargo build you can choose the compilation to be in '--release' mode or not. | ||
> cargo-quill build --release | ||
A command option you might not have considerd is that you can use '--native' if the | ||
plugin should be compiled to native code instead of web assembly. | ||
|
||
> cargo-quill build --native | ||
You can also add some compression to the plugin. | ||
|
||
> cargo-quill build --release --compression (0 to 9) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
/** | ||
This file contains code for the build command. | ||
'cargo build --release? --native?' | ||
*/ | ||
use anyhow::{bail, Context}; | ||
use argh::FromArgs; | ||
use cargo_metadata::Metadata; | ||
use heck::CamelCase; | ||
use quill_plugin_format::{PluginFile, PluginMetadata, PluginTarget, Triple}; | ||
use std::{ | ||
fs, | ||
path::PathBuf, | ||
process::{Command, Stdio}, | ||
}; | ||
|
||
use crate::{WASM_TARGET, WASM_TARGET_FEATURES}; | ||
|
||
#[derive(Debug, FromArgs)] | ||
#[argh(subcommand, name = "build")] | ||
/// Build a Quill plugin. | ||
pub(crate) struct Build { | ||
#[argh(switch)] | ||
/// whether to build in release mode | ||
release: bool, | ||
#[argh(switch)] | ||
/// whether to compile to a native shared library | ||
/// instead of a WebAssembly module | ||
native: bool, | ||
#[argh(option, default = "6")] | ||
/// the compression level to compress the plugin | ||
/// binary. 0 is worst and 9 is best. | ||
compression_level: u32, | ||
} | ||
|
||
impl Build { | ||
pub fn module_extension(&self) -> &'static str { | ||
if !self.native { | ||
"wasm" | ||
} else if cfg!(windows) { | ||
"dll" | ||
} else if cfg!(target_vendor = "apple") { | ||
"dylib" | ||
} else { | ||
// assume Linux / other Unix | ||
"so" | ||
} | ||
} | ||
|
||
pub fn target_dir(&self, cargo_meta: &Metadata) -> PathBuf { | ||
let mut target_dir = cargo_meta.target_directory.clone(); | ||
if !self.native { | ||
target_dir.push(WASM_TARGET); | ||
} | ||
|
||
if self.release { | ||
target_dir.push("release"); | ||
} else { | ||
target_dir.push("debug"); | ||
} | ||
|
||
target_dir | ||
} | ||
|
||
pub fn module_path(&self, cargo_meta: &Metadata, plugin_meta: &PluginMetadata) -> PathBuf { | ||
let target_dir = self.target_dir(cargo_meta); | ||
let module_filename = plugin_meta.identifier.replace("-", "_"); | ||
|
||
let module_extension = self.module_extension(); | ||
let lib_prefix = if self.native && cfg!(unix) { "lib" } else { "" }; | ||
|
||
target_dir.join(format!( | ||
"{}{}.{}", | ||
lib_prefix, module_filename, module_extension | ||
)) | ||
} | ||
} | ||
|
||
pub(crate) fn build(args: Build) -> anyhow::Result<()> { | ||
let cargo_meta = get_cargo_metadata()?; | ||
validate_cargo_metadata(&cargo_meta)?; | ||
|
||
let mut command = cargo_build_command(&args); | ||
let status = command.spawn()?.wait()?; | ||
if !status.success() { | ||
bail!("build failed"); | ||
} | ||
|
||
let meta = find_metadata(&cargo_meta, &args)?; | ||
let module_path = args.module_path(&cargo_meta, &meta); | ||
let module = fs::read(&module_path) | ||
.with_context(|| format!("failed to read {}", module_path.display()))?; | ||
|
||
let file = PluginFile::new(module, meta.clone()); | ||
let target_path = module_path | ||
.parent() | ||
.unwrap() | ||
.join(format!("{}.plugin", meta.identifier)); | ||
fs::write(&target_path, file.encode(args.compression_level))?; | ||
|
||
println!("Wrote plugin file to {}", target_path.display()); | ||
Ok(()) | ||
} | ||
|
||
fn cargo_build_command(args: &Build) -> Command { | ||
let mut cmd = Command::new("cargo"); | ||
cmd.arg("rustc"); | ||
if args.release { | ||
cmd.arg("--release"); | ||
} | ||
|
||
if !args.native { | ||
cmd.args(&["--target", WASM_TARGET]); | ||
cmd.args(&["--", "-C", WASM_TARGET_FEATURES]); | ||
} | ||
|
||
cmd.stdout(Stdio::piped()); | ||
|
||
cmd | ||
} | ||
|
||
fn get_cargo_metadata() -> anyhow::Result<Metadata> { | ||
let cmd = cargo_metadata::MetadataCommand::new(); | ||
let cargo_meta = cmd.exec()?; | ||
Ok(cargo_meta) | ||
} | ||
|
||
fn validate_cargo_metadata(cargo_meta: &Metadata) -> anyhow::Result<()> { | ||
let package = cargo_meta.root_package().context("missing root package")?; | ||
if !package | ||
.targets | ||
.iter() | ||
.any(|t| t.crate_types.contains(&"cdylib".to_owned())) | ||
{ | ||
bail!("crate-type = [\"cdylib\"] must be set in the plugin Cargo.toml"); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn find_metadata(cargo_meta: &Metadata, args: &Build) -> anyhow::Result<PluginMetadata> { | ||
let package = cargo_meta.root_package().context("missing root package")?; | ||
|
||
let quill_dependency = package | ||
.dependencies | ||
.iter() | ||
.find(|d| d.name == "quill") | ||
.context("plugin does not depend on the `quill` crate")?; | ||
|
||
let target = if args.native { | ||
PluginTarget::Native { | ||
target_triple: Triple::host(), | ||
} | ||
} else { | ||
PluginTarget::Wasm | ||
}; | ||
|
||
let plugin_meta = PluginMetadata { | ||
name: package.name.to_camel_case(), | ||
identifier: package.name.clone(), | ||
version: package.version.to_string(), | ||
api_version: quill_dependency.req.to_string(), | ||
description: package.description.clone(), | ||
authors: package.authors.clone(), | ||
target, | ||
}; | ||
|
||
Ok(plugin_meta) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.