#build #copy #cargo #output #tool #generalized

omnicopy_to_output

Generalized post build copy to place files in output directory

2 releases

0.1.1 Jan 14, 2024
0.1.0 Dec 20, 2023

#696 in Filesystem

32 downloads per month

MIT/Apache

13KB

Omnicopy_to_output

Provides a generalized implementation for a "post build copy" operation, which isn't well-supported in rust at time of writing. This crate is inspired by https://github.com/prenwyn/copy_to_output, but implements more managed helpers + addresses some of the missing scenarios (again, at time of writing).

If any scenarios are missing, please contribute!

See docs.rs for full details.

License

This project is licensed under either of

at your option.

The SPDX license identifier for this project is MIT OR Apache-2.0.


lib.rs:

githubcrates-iodocs-rs


Provides a generalized implementation for a "post build copy" operation, which isn't well-supported in rust at time of writing. This crate is inspired by https://github.com/prenwyn/copy_to_output, but implements more managed helpers + addresses some of the missing scenarios (again, at time of writing).

As the name implies, the goal here is to provide coverage for all possible build scenarios as a stand-in until (if) there is a native solution in the rust tooling. If anything is missing, please contribute!

Examples

  • Use in build.rs with automatic discovery.

    Path is relative to project root. If your resources are in your project, cargo will automatically detect changes and invalidate the cache as needed.

    use omnicopy_to_output::copy_to_output;
    
    fn main() {
        // Copy everything recursively from the res folder and place into output.
        copy_to_output("res").expect("Could not copy");
    }
    
  • Use in build.rs with custom target (e.g. if your have different shared libraries for debug).

    Note, if you used both your builds will fail. Each target directory only exists when that build is run. A full example would have conditional logic.

    use omnicopy_to_output::copy_to_output_for_build_type;
    
    fn main() {
        // Manually specify the profile (i.e. env:PROFILE)
        copy_to_output_for_build_type("res/foo.dll", "release").expect("Could not copy");
        copy_to_output_for_build_type("res/food.dll", "debug").expect("Could not copy");
        
    }
    
  • Invalidate Cache for external resources

    Large resources may not exist in your project. We can still copy those to output, but cargo will not detect changes and invalidate the cache. Emitting cargo:rerun-if-changed instructions will inform cargo these files exist, but then will change cache invalidation to only what you specify. We can use the helper cargo_rerun_if_project_changed to restore the default behavior along with the helper cargo_rerun_if_changed to include the out of project resources.

    use omnicopy_to_output::{copy_to_output, cargo_rerun_if_project_changed, cargo_rerun_if_changed};
    
    fn main() {
        cargo_rerun_if_project_changed().expect("Could not determine project root");
        let path_to_large_resources = "/path/to/large/resources";
        cargo_rerun_if_changed(path_to_large_resources);
        copy_to_output(path_to_large_resources).expect("Could not copy");
    }
    
    

Scenario Coverage

Key motivations for the original fork were supporting workspaces + managed experience for cargo cache instructions.

We support accommodating: - Build types (e.g retail vs test; integration tests see files) - Target - Cross compilation (special case target) - Workspace or single crate build

Considerations

This is in lieu of a better solution from cargo directly. In particular, it's worth noting that build scripts should not modify any files outside of the OUT_DIR directory. We're not modifying, but it's still not necessarily in the "spirit" of the instructions.

How it Works

To locate the target directory, we must know the project root and the target.

  1. Project root (to support workspaces) is determined using project_root
  2. From the root, the next path element is always /target
  3. Next is either /{profile} if no specific target selector was provided or /{target}/{profile} if one is provided a. Get {profile} from env:PROFILE b. Get {target} from build_target::target_triple c. Determine which scheme is in use by testing if env:OUT_DIR contains target/{target}

Dependencies

~250KB