1Shared scratch for build scripts 2================================ 3 4[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/scratch-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/scratch) 5[<img alt="crates.io" src="https://img.shields.io/crates/v/scratch.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/scratch) 6[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-scratch-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/scratch) 7[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/scratch/CI/master?style=for-the-badge" height="20">](https://github.com/dtolnay/scratch/actions?query=branch%3Amaster) 8 9This crate exposes a compile-time temporary directory sharable by multiple 10crates in a build graph and erased by `cargo clean`. 11 12The intended usage is from a build.rs Cargo build script, or more likely from a 13library which is called by other crates' build scripts. 14 15```toml 16# Cargo.toml 17 18[build-dependencies] 19scratch = "1.0" 20``` 21 22```rust 23// build.rs 24 25fn main() { 26 let dir = scratch::path("mycrate"); 27 // ... write or read inside of that path 28} 29``` 30 31<br> 32 33## Comparisons 34 35Comparison to **`std::env::var_os("OUT_DIR")`**: 36 37- This functionality is different from OUT\_DIR in that the same directory path 38 will be seen by *all* crates whose build passes a matching `suffix` argument, 39 and each crate can see content placed into the directory by those other 40 crates' build scripts that have already run. 41 42- This functionality is similar to OUT\_DIR in that both are erased when a 43 `cargo clean` is executed. 44 45Comparison to **`std::env::temp_dir()`**: 46 47- This functionality is similar to temp\_dir() in that stuff that goes in is 48 visible to subsequently running build scripts. 49 50- This functionality is different from temp\_dir() in that `cargo clean` cleans 51 up the contents. 52 53<br> 54 55## Tips 56 57You'll want to consider what happens when Cargo runs multiple build scripts 58concurrently that access the same scratch dir. In some use cases you likely want 59some synchronization over the contents of the scratch directory, such as by an 60advisory [file lock]. On Unix-like and Windows host systems the simplest way to 61sequence the build scripts such that each one gets exclusive access one after 62the other is something like: 63 64[file lock]: https://man7.org/linux/man-pages/man2/flock.2.html 65 66```rust 67use std::fs::{self, File}; 68use std::io; 69 70fn main() -> io::Result<()> { 71 let dir = scratch::path("demo"); 72 let flock = File::create(dir.join(".lock"))?; 73 fs2::FileExt::lock_exclusive(&flock)?; 74 75 // ... now do work 76} 77``` 78 79This simplest approach is fine for a cache which is slow to fill (maybe a large 80download) but fast/almost immediate to use. On the other hand if the build 81scripts using your cache will take a while to complete even if they only read 82from the scratch directory, a different approach which allows readers to make 83progress in parallel would perform better. 84 85```rust 86use std::fs::{self, File}; 87use std::io; 88 89fn main() -> io::Result<()> { 90 let dir = scratch::path("demo"); 91 let flock = File::create(dir.join(".lock"))?; 92 let sdk = dir.join("thing.sdk"); 93 94 if !sdk.exists() { 95 fs2::FileExt::lock_exclusive(&flock)?; 96 if !sdk.exists() { 97 let download_location = sdk.with_file_name("thing.sdk.partial"); 98 download_sdk_to(&download_location)?; 99 fs::rename(&download_location, &sdk)?; 100 } 101 fs2::FileExt::unlock(&flock)?; 102 } 103 104 // ... now use the SDK 105} 106``` 107 108For use cases that are not just a matter of the first build script writing to 109the directory and the rest reading, more elaborate schemes involving 110`lock_shared` might be something to consider. 111 112<br> 113 114#### License 115 116<sup> 117Licensed under either of <a href="LICENSE-APACHE">Apache License, Version 1182.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. 119</sup> 120 121<br> 122 123<sub> 124Unless you explicitly state otherwise, any contribution intentionally submitted 125for inclusion in this crate by you, as defined in the Apache-2.0 license, shall 126be dual licensed as above, without any additional terms or conditions. 127</sub> 128