| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| //! While fargo is mainly intended to be a command line tool, this library |
| //! exposes one function, `run_cargo`, that could be integrated directly into |
| //! Rust programs that want to cross compile cargo crates on Fuchsia. |
| |
| #![deny(warnings)] |
| |
| mod build_rustc; |
| pub mod command_line; |
| mod cross; |
| mod device; |
| mod linking; |
| mod manifest; |
| mod package; |
| mod sdk; |
| mod utils; |
| |
| pub use crate::sdk::{FuchsiaConfig, TargetOptions}; |
| |
| use crate::cross::{pkg_config_path, run_configure}; |
| use crate::device::{enable_networking, shell}; |
| use crate::package::make_package; |
| use crate::sdk::{ |
| cargo_path, clang_archiver_path, clang_c_compiler_path, clang_cpp_compiler_path, |
| clang_ranlib_path, clang_resource_dir, rustc_path, rustdoc_path, shared_libraries_path, |
| sysroot_path, target_out_dir, zircon_build_path, |
| }; |
| use manifest::Manifest; |
| |
| use failure::{bail, err_msg, Error, ResultExt}; |
| use std::fs; |
| use std::fs::File; |
| use std::io::Write; |
| use std::path::{Path, PathBuf}; |
| use std::process::Command; |
| use std::time::SystemTime; |
| |
| fn run_program_on_target( |
| filename: &str, |
| verbose: bool, |
| nocapture: bool, |
| target_options: &TargetOptions<'_, '_>, |
| run_mode: RunMode, |
| run_cargo_options: &RunCargoOptions, |
| story_name: &str, |
| mod_name: &str, |
| app_dir: &str, |
| app_name: &str, |
| params: &[&str], |
| test_args: Option<&str>, |
| ) -> Result<(), Error> { |
| let source_path = PathBuf::from(&filename); |
| |
| let target_string = |
| make_package(verbose, target_options, &run_cargo_options, &source_path, app_dir, app_name)?; |
| |
| let mut command_string = match run_mode { |
| RunMode::Tiles => "tiles_ctl add ".to_string(), |
| RunMode::SessionCtl => { |
| format!("sessionctl --story_name={} --mod_name={} --mod_url=", story_name, mod_name) |
| } |
| RunMode::Run => "run ".to_string(), |
| }; |
| command_string.push_str(&target_string); |
| |
| match run_mode { |
| RunMode::SessionCtl => { |
| command_string.push_str(" add_mod"); |
| } |
| _ => (), |
| } |
| |
| if nocapture { |
| command_string.push_str(" --"); |
| command_string.push_str(NOCAPTURE); |
| } |
| |
| for param in params { |
| command_string.push(' '); |
| command_string.push_str(param); |
| } |
| |
| if let Some(test_args_str) = test_args { |
| command_string.push_str(" -- "); |
| command_string.push_str(test_args_str); |
| } |
| |
| if verbose { |
| println!("running {}", command_string); |
| } |
| |
| shell(verbose, target_options, &command_string).context("ssh failed")?; |
| Ok(()) |
| } |
| |
| extern crate notify; |
| |
| use notify::{RecommendedWatcher, RecursiveMode, Watcher}; |
| use std::sync::mpsc::channel; |
| use std::time::Duration; |
| |
| fn autotest( |
| run_cargo_options: &RunCargoOptions, |
| target_options: &TargetOptions<'_, '_>, |
| ) -> Result<(), Error> { |
| let (tx, rx) = channel(); |
| let mut watcher: RecommendedWatcher = |
| Watcher::new(tx, Duration::from_secs(1)).context("autotest: watcher creation failed")?; |
| |
| let cwd = std::fs::canonicalize(std::env::current_dir()?) |
| .context("autotest: canonicalize working directory")?; |
| let tgt = cwd.join("target"); |
| let git = cwd.join(".git"); |
| |
| watcher.watch(&cwd, RecursiveMode::Recursive).context("autotest: watch failed")?; |
| |
| println!("autotest: started"); |
| loop { |
| let event = rx.recv().context("autotest: watch recv failed")?; |
| match event { |
| notify::DebouncedEvent::Create(path) |
| | notify::DebouncedEvent::Write(path) |
| | notify::DebouncedEvent::Chmod(path) |
| | notify::DebouncedEvent::Remove(path) |
| | notify::DebouncedEvent::Rename(path, _) => { |
| // TODO(raggi): provide a fuller ignore flag/pattern match solution here. |
| if !path.starts_with(&tgt) && !path.starts_with(&git) { |
| println!("autotest: running tests because {:?}", path); |
| run_tests(run_cargo_options, false, false, target_options, &[], None).ok(); |
| } |
| } |
| _ => {} |
| } |
| } |
| } |
| |
| fn run_tests( |
| run_cargo_options: &RunCargoOptions, |
| no_run: bool, |
| doc: bool, |
| target_options: &TargetOptions<'_, '_>, |
| params: &[&str], |
| target_params: Option<&str>, |
| ) -> Result<(), Error> { |
| let mut args = vec!["-Zdoctest-xcompile"]; |
| |
| if no_run { |
| args.push("--no-run"); |
| } |
| |
| if doc { |
| args.push("--doc"); |
| } |
| |
| for param in params { |
| args.push(param); |
| } |
| |
| if let Some(target_params) = target_params { |
| let formatted_target_params = format!("--args={}", target_params); |
| run_cargo( |
| &run_cargo_options, |
| TEST, |
| &args, |
| target_options, |
| None, |
| Some(&formatted_target_params), |
| )?; |
| } else { |
| run_cargo(&run_cargo_options, "test", &args, target_options, None, None)?; |
| } |
| |
| Ok(()) |
| } |
| |
| fn build_binary( |
| run_cargo_options: &RunCargoOptions, |
| target_options: &TargetOptions<'_, '_>, |
| params: &[&str], |
| ) -> Result<(), Error> { |
| run_cargo(run_cargo_options, BUILD, params, target_options, None, None) |
| } |
| |
| fn check_binary( |
| run_cargo_options: &RunCargoOptions, |
| target_options: &TargetOptions<'_, '_>, |
| params: &[&str], |
| ) -> Result<(), Error> { |
| run_cargo(run_cargo_options, "check", params, target_options, None, None) |
| } |
| |
| fn run_binary( |
| run_cargo_options: &RunCargoOptions, |
| target_options: &TargetOptions<'_, '_>, |
| params: &[&str], |
| ) -> Result<(), Error> { |
| run_cargo(run_cargo_options, RUN, params, target_options, None, None)?; |
| Ok(()) |
| } |
| |
| fn build_doc( |
| run_cargo_options: &RunCargoOptions, |
| target_options: &TargetOptions<'_, '_>, |
| no_deps: bool, |
| open: bool, |
| ) -> Result<(), Error> { |
| let mut args = vec![]; |
| if no_deps { |
| args.push("--no-deps"); |
| } |
| if open { |
| args.push("--open"); |
| } |
| run_cargo(run_cargo_options, "doc", &args, &target_options, None, None) |
| } |
| |
| #[derive(Clone, Copy, Debug)] |
| pub enum RunMode { |
| Run, |
| Tiles, |
| SessionCtl, |
| } |
| |
| impl Default for RunMode { |
| fn default() -> Self { |
| RunMode::Run |
| } |
| } |
| fn run_switches_to_mode(tiles: bool, session_ctl: bool) -> RunMode { |
| if tiles { |
| RunMode::Tiles |
| } else if session_ctl { |
| RunMode::SessionCtl |
| } else { |
| RunMode::Run |
| } |
| } |
| |
| fn random_story_name() -> String { |
| let secs = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { |
| Ok(n) => n.as_secs(), |
| Err(_) => panic!("SystemTime before UNIX EPOCH!"), |
| }; |
| format!("fargo-story-{}", secs) |
| } |
| |
| #[derive(Debug, Clone, Default)] |
| pub struct RunCargoOptions { |
| pub fargo_manifest: Manifest, |
| pub verbose: bool, |
| pub release: bool, |
| pub run_mode: RunMode, |
| pub story_name: Option<String>, |
| pub mod_name: Option<String>, |
| pub disable_cross: bool, |
| pub nocapture: bool, |
| pub manifest_path: Option<PathBuf>, |
| pub cmx_path: Option<PathBuf>, |
| pub app_dir: Option<String>, |
| pub app_name: Option<String>, |
| } |
| |
| impl RunCargoOptions { |
| pub fn new(verbose: bool, release: bool) -> RunCargoOptions { |
| Self { verbose, release, ..Self::default() } |
| } |
| |
| pub fn disable_cross(&self, disable_cross: bool) -> RunCargoOptions { |
| Self { disable_cross, ..self.clone() } |
| } |
| |
| pub fn release(&self, release: bool) -> RunCargoOptions { |
| Self { release, ..self.clone() } |
| } |
| |
| pub fn nocapture(&self, nocapture: bool) -> RunCargoOptions { |
| Self { nocapture, ..self.clone() } |
| } |
| |
| pub fn run_mode(&self, run_mode: RunMode) -> RunCargoOptions { |
| Self { run_mode, ..self.clone() } |
| } |
| |
| pub fn story_name(&self, story_name: &Option<&str>) -> RunCargoOptions { |
| Self { story_name: story_name.map(|name| name.to_string()), ..self.clone() } |
| } |
| |
| pub fn mod_name(&self, mod_name: &Option<&str>) -> RunCargoOptions { |
| Self { mod_name: mod_name.map(|name| name.to_string()), ..self.clone() } |
| } |
| |
| pub fn manifest_path(&self, manifest_path: Option<PathBuf>) -> RunCargoOptions { |
| Self { manifest_path, ..self.clone() } |
| } |
| |
| pub fn cmx_path(&self, cmx_path: Option<PathBuf>) -> RunCargoOptions { |
| Self { cmx_path, ..self.clone() } |
| } |
| |
| pub fn app_dir(&self, app_dir: &Option<&str>) -> RunCargoOptions { |
| Self { app_dir: app_dir.map(|name| name.to_string()), ..self.clone() } |
| } |
| |
| pub fn app_name(&self, app_name: &Option<&str>) -> RunCargoOptions { |
| Self { app_name: app_name.map(|name| name.to_string()), ..self.clone() } |
| } |
| |
| pub fn get_story_name(&self) -> String { |
| if let Some(ref name) = self.story_name { |
| name.clone() |
| } else { |
| random_story_name() |
| } |
| } |
| |
| pub fn get_mod_name(&self) -> String { |
| if let Some(ref name) = self.mod_name { |
| name.clone() |
| } else { |
| DEFAULT_MOD_NAME.to_string() |
| } |
| } |
| } |
| |
| pub fn get_triple_cpu(target_options: &TargetOptions<'_, '_>) -> String { |
| if (target_options.config.fuchsia_arch) == X64 { "x86_64" } else { "aarch64" }.to_string() |
| } |
| |
| pub fn get_target_triple(target_options: &TargetOptions<'_, '_>) -> String { |
| let triple_cpu = get_triple_cpu(target_options); |
| |
| format!("{}-fuchsia", triple_cpu) |
| } |
| |
| fn get_rustflags( |
| run_cargo_options: &RunCargoOptions, |
| target_options: &TargetOptions<'_, '_>, |
| sysroot_as_path: &PathBuf, |
| linking: bool, |
| ) -> Result<String, Error> { |
| let target_triple = get_target_triple(target_options); |
| let sysroot_lib_pathbuf = sysroot_as_path.join("lib"); |
| let sysroot_lib = sysroot_lib_pathbuf.to_string_lossy(); |
| let shared_lib_path = shared_libraries_path(target_options)?; |
| let clang_resource_lib = clang_resource_dir(&target_triple)?.join(&target_triple).join("lib"); |
| |
| let mut rust_flags = vec![ |
| "-L".to_string(), |
| sysroot_lib.to_string(), |
| "-Cpanic=abort".to_string(), |
| "-Zpanic_abort_tests".to_string(), |
| // Add an extra config to let crates like scoped_task know we're compiling with |
| // panic=abort. This matches |
| // http://fuchsia.googlesource.com/fuchsia/+/08dce526941ac5be23cec1b50f841aad5ed37ea1/build/config/BUILD.gn#547 |
| "--cfg=rust_panic=\"abort\"".to_string(), |
| "-Clink-arg=--pack-dyn-relocs=relr".to_string(), |
| format!("-Clink-arg=-L{}", sysroot_lib), |
| format!("-Clink-arg=-L{}/gen/zircon/public/lib/fdio", shared_lib_path.to_string_lossy(),), |
| format!("-Clink-arg=-L{}/gen/zircon/public/lib/syslog", shared_lib_path.to_string_lossy(),), |
| format!( |
| "-Clink-arg=-L{}/gen/zircon/public/lib/trace-engine", |
| shared_lib_path.to_string_lossy(), |
| ), |
| format!("-Clink-arg=-L{}", clang_resource_lib.to_string_lossy()), |
| format!("-Clink-arg=--sysroot={}", sysroot_as_path.to_string_lossy()), |
| format!("-Lnative={}", shared_libraries_path(target_options)?.to_string_lossy()), |
| ]; |
| |
| if get_triple_cpu(target_options) == "aarch64" { |
| rust_flags.push("-Clink-arg=--fix-cortex-a53-843419".to_string()); |
| } |
| |
| for search_path in &run_cargo_options.fargo_manifest.library_search_paths { |
| let full_search_path = target_out_dir(&target_options.config)?.join(search_path); |
| let arg = format!("-Lnative={}", full_search_path.to_string_lossy()); |
| rust_flags.push(arg); |
| } |
| |
| if linking { |
| for additional_lib in &run_cargo_options.fargo_manifest.additional_static_libraries { |
| let arg = format!("-l{}", additional_lib); |
| rust_flags.push(arg); |
| } |
| } |
| |
| Ok(rust_flags.join(" ")) |
| } |
| |
| fn make_fargo_command( |
| runner: Option<PathBuf>, |
| options: &RunCargoOptions, |
| nocapture: bool, |
| target_options: &TargetOptions<'_, '_>, |
| additional_target_args: Option<&str>, |
| ) -> Result<String, Error> { |
| let cmx_path; |
| let tiles_arg = format!("--{}", RUN_WITH_TILES); |
| let session_ctl_arg = format!( |
| "--{} --story-name={} --mod-name={}", |
| RUN_WITH_SESSIONCTL, |
| options.get_story_name(), |
| options.get_mod_name() |
| ); |
| let manifest_path_string; |
| let cmx_arg = format!("--{}", CMX_PATH); |
| let app_dir_arg = format!("--{}", APP_DIR); |
| let app_name_arg = format!("--{}", APP_NAME); |
| let run_arg = format!("--{}", RUN_WITH_RUN); |
| let nocapture_arg = format!("--{}", NOCAPTURE); |
| |
| let fargo_path = if let Some(runner) = runner { |
| runner |
| } else { |
| fs::canonicalize(std::env::current_exe()?)? |
| }; |
| |
| let mut runner_args = vec![fargo_path |
| .to_str() |
| .ok_or_else(|| err_msg("unable to convert path to utf8 encoding"))?]; |
| |
| if options.verbose { |
| runner_args.push("-v"); |
| } |
| |
| if let Some(manifest_path) = options.manifest_path.as_ref() { |
| manifest_path_string = manifest_path.to_string_lossy(); |
| runner_args.push("--manifest-path"); |
| runner_args.push(&manifest_path_string); |
| } |
| |
| if let Some(device_name) = target_options.device_name { |
| runner_args.push("--device-name"); |
| runner_args.push(device_name); |
| } |
| |
| runner_args.push(RUN_ON_TARGET); |
| |
| if let Some(ref passed_path) = options.cmx_path { |
| cmx_path = passed_path.to_string_lossy().to_string(); |
| runner_args.push(&cmx_arg); |
| runner_args.push(&cmx_path); |
| } |
| |
| if nocapture { |
| runner_args.push(&nocapture_arg); |
| } |
| |
| match options.run_mode { |
| RunMode::Tiles => runner_args.push(&tiles_arg), |
| RunMode::SessionCtl => { |
| println!("***** Warning: sessionctl is no longer supported in many Fuchsia configurations. *****"); |
| runner_args.push(&session_ctl_arg) |
| } |
| RunMode::Run => runner_args.push(&run_arg), |
| } |
| |
| if let Some(args_for_target) = additional_target_args { |
| runner_args.push(&args_for_target); |
| } |
| |
| if let Some(app_dir) = options.app_dir.as_ref() { |
| runner_args.push(&app_dir_arg); |
| runner_args.push(&app_dir); |
| } |
| |
| if let Some(app_name) = options.app_name.as_ref() { |
| runner_args.push(&app_name_arg); |
| runner_args.push(&app_name); |
| } |
| |
| Ok(runner_args.join(" ")) |
| } |
| |
| fn format_project(manifest_path: Option<PathBuf>) -> Result<(), Error> { |
| let mut cmd = Command::new(cargo_path()?); |
| if let Some(ref manifest_path) = manifest_path { |
| let parent = |
| manifest_path.parent().expect(&format!("Can't get parent of {:#?}", manifest_path)); |
| cmd.current_dir(parent); |
| } |
| cmd.arg(FORMAT); |
| let cargo_status = cmd.status()?; |
| if !cargo_status.success() { |
| bail!("cargo exited with status {:?}", cargo_status,); |
| } |
| Ok(()) |
| } |
| |
| /// Runs the cargo tool configured to target Fuchsia. When used as a library, |
| /// the runner options must contain the path to fargo or some other program |
| /// that implements the `run-on-target` subcommand in a way compatible with |
| /// fargo. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use fargo::{run_cargo, FuchsiaConfig, RunCargoOptions, RunMode, TargetOptions}; |
| /// |
| /// let config = FuchsiaConfig::default(); |
| /// let target_options = TargetOptions::new(&config, None); |
| /// run_cargo( |
| /// &RunCargoOptions { |
| /// verbose: false, |
| /// release: true, |
| /// nocapture: false, |
| /// run_mode: RunMode::Run, |
| /// ..RunCargoOptions::default() |
| /// }, |
| /// "help", |
| /// &[], |
| /// &target_options, |
| /// None, |
| /// None, |
| /// ); |
| /// ``` |
| pub fn run_cargo( |
| options: &RunCargoOptions, |
| subcommand: &str, |
| args: &[&str], |
| target_options: &TargetOptions<'_, '_>, |
| runner: Option<PathBuf>, |
| additional_target_args: Option<&str>, |
| ) -> Result<(), Error> { |
| if options.verbose { |
| println!("target_options = {:?}", target_options); |
| } |
| |
| let triple_cpu = get_triple_cpu(target_options); |
| let target_triple = get_target_triple(target_options); |
| let mut target_args = vec!["--target", &target_triple]; |
| |
| if options.release { |
| target_args.push("--release"); |
| } |
| |
| if options.verbose { |
| println!("target_options.target_cpu = {:?}", target_options.config.fuchsia_arch); |
| println!("triple_cpu = {:?}", triple_cpu); |
| println!("target_triple = {:?}", target_triple); |
| println!("target_args = {:?}", target_args); |
| println!("options = {:?}", options); |
| } |
| |
| let linking = match subcommand { |
| RUN | TEST | BUILD => true, |
| _ => false, |
| }; |
| |
| let target_triple_uc = format!("{}_fuchsia", triple_cpu).to_uppercase(); |
| |
| let fargo_command = make_fargo_command( |
| runner, |
| &options, |
| options.nocapture, |
| target_options, |
| additional_target_args, |
| )?; |
| |
| if options.verbose { |
| println!("fargo_command: {:?}", fargo_command); |
| } |
| |
| let pkg_path = pkg_config_path(target_options)?; |
| let mut cmd = Command::new(cargo_path()?); |
| let sysroot_as_path = sysroot_path(target_options)?; |
| let sysroot_as_str = sysroot_as_path.to_string_lossy(); |
| |
| let args: Vec<&str> = args.iter().map(|a| if *a == "++" { "--" } else { *a }).collect(); |
| |
| let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target_triple_uc); |
| let rustflags_env_name = format!("CARGO_TARGET_{}_RUSTFLAGS", target_triple_uc); |
| let rustflags = get_rustflags(options, target_options, &sysroot_as_path, linking)?; |
| |
| if options.verbose { |
| println!("runner_env_name: {:?}", runner_env_name); |
| println!("rustflags_env_name: {:?}", rustflags_env_name); |
| println!("rustc_path: {:?}", rustc_path()?.to_string_lossy()); |
| println!("cargo_path: {:?}", cargo_path()?.to_string_lossy()); |
| println!("rustdoc_path: {:?}", rustdoc_path()?); |
| println!("rustflags: {:?}", &rustflags); |
| } |
| |
| cmd.env(runner_env_name, fargo_command) |
| .env(rustflags_env_name, &rustflags) |
| .env("RUSTC", rustc_path()?.to_string_lossy().as_ref()) |
| .env("RUSTDOC", rustdoc_path()?.to_string_lossy().as_ref()) |
| .env("RUSTDOCFLAGS", &rustflags) |
| .env("FUCHSIA_SHARED_ROOT", shared_libraries_path(target_options)?) |
| .env("ZIRCON_BUILD_ROOT", zircon_build_path(&target_options.config)?) |
| .arg(subcommand) |
| .args(target_args) |
| .args(args); |
| |
| if let Some(ref manifest_path) = options.manifest_path { |
| let manifest_args: Vec<&str> = vec![ |
| "--manifest-path", |
| manifest_path.to_str().expect("path to string failed for manifest_path"), |
| ]; |
| cmd.args(manifest_args); |
| } |
| |
| if !options.disable_cross { |
| let cc_env_name = format!("CC_{}", target_triple_uc); |
| let cxx_env_name = format!("CXX_{}", target_triple_uc); |
| let cflags_env_name = format!("CFLAGS_{}", target_triple_uc); |
| let ar_env_name = format!("AR_{}", target_triple_uc); |
| cmd.env(cc_env_name, clang_c_compiler_path()?.to_string_lossy().as_ref()) |
| .env(cxx_env_name, clang_cpp_compiler_path()?.to_string_lossy().as_ref()) |
| .env(cflags_env_name, format!("--sysroot={}", sysroot_as_str)) |
| .env(ar_env_name, clang_archiver_path()?.to_string_lossy().as_ref()) |
| .env("RANLIB", clang_ranlib_path()?.to_string_lossy().as_ref()) |
| .env("PKG_CONFIG_ALL_STATIC", "1") |
| .env("PKG_CONFIG_ALLOW_CROSS", "1") |
| .env("PKG_CONFIG_PATH", "") |
| .env("PKG_CONFIG_LIBDIR", pkg_path); |
| } |
| |
| if options.verbose { |
| println!("cargo cmd: {:?}", cmd); |
| } |
| |
| let cargo_status = cmd.status()?; |
| if !cargo_status.success() { |
| bail!("cargo exited with status {:?}", cargo_status,); |
| } |
| |
| Ok(()) |
| } |
| |
| fn write_config( |
| options: &RunCargoOptions, |
| target_options: &TargetOptions<'_, '_>, |
| ) -> Result<(), Error> { |
| let cargo_dir_path = Path::new(".cargo"); |
| if cargo_dir_path.exists() { |
| if !cargo_dir_path.is_dir() { |
| bail!( |
| "fargo wants to create a directory {:#?}, but there is an existing file in the way", |
| cargo_dir_path |
| ); |
| } |
| } else { |
| fs::create_dir(cargo_dir_path)?; |
| } |
| |
| let mut config = File::create(".cargo/config")?; |
| |
| let sysroot_as_path = sysroot_path(target_options)?; |
| writeln!(config, "[target.{}]", get_target_triple(target_options))?; |
| writeln!( |
| config, |
| "rustflags = {}", |
| toml::ser::to_string(&get_rustflags(options, target_options, &sysroot_as_path, false)?)? |
| )?; |
| writeln!( |
| config, |
| "runner = \"{}\"", |
| make_fargo_command(None, options, true, target_options, None)? |
| )?; |
| writeln!(config, "")?; |
| writeln!(config, "[build]")?; |
| writeln!(config, "rustc = \"{}\"", rustc_path()?.to_string_lossy())?; |
| writeln!(config, "rustdoc = \"{}\"", rustdoc_path()?.to_string_lossy())?; |
| writeln!(config, "target = \"{}\"", get_target_triple(target_options))?; |
| Ok(()) |
| } |
| |
| const RUN: &str = "run"; |
| const RUN_WITH_TILES: &str = "run-with-tiles"; |
| const RUN_WITH_RUN: &str = "run-with-run"; |
| const RUN_WITH_SESSIONCTL: &str = "run-with-sessionctl"; |
| const DEFAULT_MOD_NAME: &str = "fargo"; |
| const APP_DIR: &str = "app-dir"; |
| const APP_NAME: &str = "app-name"; |
| |
| const BUILD: &str = "build"; |
| const TEST: &str = "test"; |
| |
| const NOCAPTURE: &str = "nocapture"; |
| |
| const X64: &str = "x64"; |
| |
| const CMX_PATH: &str = "cmx-path"; |
| |
| const RUN_ON_TARGET: &str = "run-on-target"; |
| |
| const FORMAT: &str = "fmt"; |