diff --git a/.gitignore b/.gitignore index 9f81952..1b8b34a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ crates/shader-crate-template/shaders tmp/* crates/shader-crate-template/manifest.json crates/shader-crate-template/rust_gpu_shader_crate_template.spv + +.idea diff --git a/Cargo.lock b/Cargo.lock index bd63d76..992488f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -52,19 +52,20 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "autocfg" @@ -74,60 +75,81 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" -version = "2.6.0" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" dependencies = [ "serde", ] [[package]] -name = "bytes" -version = "1.9.0" +name = "camino" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] [[package]] name = "cargo-gpu" version = "0.1.0" dependencies = [ "anyhow", - "chrono", + "cargo_metadata", "clap", "crossterm", "directories", "env_logger 0.10.2", - "http", "log", "relative-path", + "semver", "serde", "serde_json", - "spirv-builder-cli", + "spirv-builder", "test-log", - "toml", - "version_check", ] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "cargo-platform" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] [[package]] -name = "chrono" -version = "0.4.38" +name = "cargo_metadata" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ - "num-traits", + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.12", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "clap" -version = "4.4.8" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -135,9 +157,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -147,9 +169,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck", "proc-macro2", @@ -159,9 +181,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" @@ -175,7 +197,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags", + "bitflags 2.9.0", "crossterm_winapi", "mio", "parking_lot", @@ -217,19 +239,13 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", ] -[[package]] -name = "env_home" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" - [[package]] name = "env_logger" version = "0.10.2" @@ -245,9 +261,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", @@ -257,25 +273,40 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "filetime" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] [[package]] name = "fuchsia-cprng" @@ -285,9 +316,9 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -296,58 +327,76 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" [[package]] -name = "http" -version = "1.2.0" +name = "humantime" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ - "bytes", - "fnv", - "itoa", + "equivalent", + "hashbrown", ] [[package]] -name = "humantime" -version = "2.1.0" +name = "inotify" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] [[package]] -name = "indexmap" -version = "2.6.0" +name = "inotify-sys" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" dependencies = [ - "equivalent", - "hashbrown", + "libc", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", ] [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -358,9 +407,29 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] [[package]] name = "lazy_static" @@ -370,9 +439,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libredox" @@ -380,15 +449,16 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags", + "bitflags 2.9.0", "libc", + "redox_syscall", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "lock_api" @@ -402,9 +472,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "matchers" @@ -434,29 +504,48 @@ dependencies = [ ] [[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "notify" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "c533b4c39709f9ba5005d8002048266593c1cfaf3c5f0739d5b8ab0c6c504009" dependencies = [ - "overload", - "winapi", + "bitflags 2.9.0", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "notify-types", + "walkdir", + "windows-sys 0.52.0", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "notify-types" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "585d3cb5e12e01aed9e8a1f70d5c6b5e86fe2a6e48fc8cd0b3e0b8df6f6eb174" dependencies = [ - "autocfg", + "instant", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -495,24 +584,24 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -545,6 +634,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +[[package]] +name = "raw-string" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0501e134c6905fee1f10fed25b0a7e1261bf676cffac9543a7d0730dec01af2" + [[package]] name = "rdrand" version = "0.4.0" @@ -556,11 +651,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ - "bitflags", + "bitflags 2.9.0", ] [[package]] @@ -571,7 +666,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -582,7 +677,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -597,9 +692,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -633,13 +728,40 @@ dependencies = [ "winapi", ] +[[package]] +name = "rspirv" +version = "0.12.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cf3a93856b6e5946537278df0d3075596371b1950ccff012f02b0f7eafec8d" +dependencies = [ + "rustc-hash", + "spirv", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_codegen_spirv-types" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu.git?rev=6d7c1cd6c0920500a3fa8c01c23e7b74302c15c4#6d7c1cd6c0920500a3fa8c01c23e7b74302c15c4" +dependencies = [ + "rspirv", + "serde", + "serde_json", + "spirv", +] + [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys", @@ -648,9 +770,18 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "scopeguard" @@ -658,20 +789,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +dependencies = [ + "serde", +] + [[package]] name = "serde" -version = "1.0.214" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -680,9 +820,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -731,18 +871,18 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "spirv" @@ -750,35 +890,37 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags", + "bitflags 2.9.0", "serde", ] [[package]] -name = "spirv-builder-cli" -version = "0.1.0" +name = "spirv-builder" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu.git?rev=6d7c1cd6c0920500a3fa8c01c23e7b74302c15c4#6d7c1cd6c0920500a3fa8c01c23e7b74302c15c4" dependencies = [ "clap", - "env_home", - "env_logger 0.10.2", - "log", + "memchr", + "notify", + "raw-string", + "rustc_codegen_spirv-types", + "semver", "serde", "serde_json", - "spirv", - "toml", + "thiserror 2.0.12", ] [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -806,20 +948,20 @@ dependencies = [ [[package]] name = "test-log" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" +checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f" dependencies = [ - "env_logger 0.11.5", + "env_logger 0.11.8", "test-log-macros", "tracing-subscriber", ] [[package]] name = "test-log-macros" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" +checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", @@ -828,18 +970,38 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] name = "thiserror-impl" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -858,9 +1020,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -870,26 +1032,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "tracing" version = "0.1.41" @@ -940,9 +1109,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "utf8parse" @@ -952,15 +1121,19 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] -name = "version_check" -version = "0.9.5" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "wasi" @@ -1149,9 +1322,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 3d16813..c266e87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,30 +1,24 @@ [workspace] members = [ - "crates/cargo-gpu", - "crates/xtask", + "crates/cargo-gpu", + "crates/xtask", ] exclude = [ - # Can't be included because it depends on a specific Rust toolchain and considering that - # the reason it exists is to prevent Rust toolchain requirements from polluting workspaces - # then let's just not try to workaround it. - "crates/spirv-builder-cli", - - # This currently needs to be excluded because it depends on a version of `rust-gpu` that - # uses a toolchain whose Cargo version doesn't recognise version 4 of `Cargo.lock`. - "crates/shader-crate-template" + # This currently needs to be excluded because it depends on a version of `rust-gpu` that + # uses a toolchain whose Cargo version doesn't recognise version 4 of `Cargo.lock`. + "crates/shader-crate-template" ] resolver = "2" [workspace.dependencies] +spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu.git", rev = "6d7c1cd6c0920500a3fa8c01c23e7b74302c15c4", default-features = false } anyhow = "1.0.94" -clap = { version = "4.4.8", features = ["derive"] } -chrono = { version = "0.4.38", default-features = false, features = ["std"] } +clap = { version = "4.5.37", features = ["derive"] } crossterm = "0.28.1" directories = "5.0.1" env_logger = "0.10" -http = "1.2.0" log = "0.4" relative-path = "1.9.3" serde = { version = "1.0.214", features = ["derive"] } @@ -32,6 +26,8 @@ serde_json = "1.0.132" toml = "0.8.19" tempdir = "0.3.7" test-log = "0.2.16" +cargo_metadata = "0.19.2" +semver = "1.0.26" [workspace.lints.rust] missing_docs = "warn" diff --git a/README.md b/README.md index 39f303b..9065311 100644 --- a/README.md +++ b/README.md @@ -64,159 +64,226 @@ for an example. build Compile a shader crate to SPIR-V show Show some useful values help Print this message or the help of the given subcommand(s) - + Options: -h, --help Print help - + -V, --version Print version * Install Install rust-gpu compiler artifacts - + Usage: cargo-gpu install [OPTIONS] - + Options: --shader-crate Directory containing the shader crate to compile - + [default: ./] - + --spirv-builder-source Source of `spirv-builder` dependency Eg: "https://github.com/Rust-GPU/rust-gpu" - + --spirv-builder-version Version of `spirv-builder` dependency. * If `--spirv-builder-source` is not set, then this is assumed to be a crates.io semantic version such as "0.9.0". * If `--spirv-builder-source` is set, then this is assumed to be a Git "commitsh", such as a Git commit hash or a Git tag, therefore anything that `git checkout` can resolve. - - --rust-toolchain - Rust toolchain channel to use to build `spirv-builder`. - - This must be compatible with the `spirv_builder` argument as defined in the `rust-gpu` repo. - - --force-spirv-cli-rebuild - Force `spirv-builder-cli` and `rustc_codegen_spirv` to be rebuilt - + + --rebuild-codegen + Force `rustc_codegen_spirv` to be rebuilt + --auto-install-rust-toolchain Assume "yes" to "Install Rust toolchain: [y/n]" prompt - + + --no-clear-target + Clear target dir of `rustc_codegen_spirv` build after a successful build, saves about 200MiB of disk space + + --force-overwrite-lockfiles-v4-to-v3 + There is a tricky situation where a shader crate that depends on workspace config can have + a different `Cargo.lock` lockfile version from the the workspace's `Cargo.lock`. This can + prevent builds when an old Rust toolchain doesn't recognise the newer lockfile version. + + The ideal way to resolve this would be to match the shader crate's toolchain with the + workspace's toolchain. However, that is not always possible. Another solution is to + `exclude = [...]` the problematic shader crate from the workspace. This also may not be a + suitable solution if there are a number of shader crates all sharing similar config and + you don't want to have to copy/paste and maintain that config across all the shaders. + + So a somewhat hacky workaround is to have `cargo gpu` overwrite lockfile versions. Enabling + this flag will only come into effect if there are a mix of v3/v4 lockfiles. It will also + only overwrite versions for the duration of a build. It will attempt to return the versions + to their original values once the build is finished. However, of course, unexpected errors + can occur and the overwritten values can remain. Hence why this behaviour is not enabled by + default. + + This hack is possible because the change from v3 to v4 only involves a minor change to the + way source URLs are encoded. See these PRs for more details: + * + * + -h, --help Print help (see a summary with '-h') * Build Compile a shader crate to SPIR-V - + Usage: cargo-gpu build [OPTIONS] - + Options: --shader-crate Directory containing the shader crate to compile - + [default: ./] - + --spirv-builder-source Source of `spirv-builder` dependency Eg: "https://github.com/Rust-GPU/rust-gpu" - + --spirv-builder-version Version of `spirv-builder` dependency. * If `--spirv-builder-source` is not set, then this is assumed to be a crates.io semantic version such as "0.9.0". * If `--spirv-builder-source` is set, then this is assumed to be a Git "commitsh", such as a Git commit hash or a Git tag, therefore anything that `git checkout` can resolve. - - --rust-toolchain - Rust toolchain channel to use to build `spirv-builder`. - - This must be compatible with the `spirv_builder` argument as defined in the `rust-gpu` repo. - - --force-spirv-cli-rebuild - Force `spirv-builder-cli` and `rustc_codegen_spirv` to be rebuilt - + + --rebuild-codegen + Force `rustc_codegen_spirv` to be rebuilt + --auto-install-rust-toolchain Assume "yes" to "Install Rust toolchain: [y/n]" prompt - + + --no-clear-target + Clear target dir of `rustc_codegen_spirv` build after a successful build, saves about 200MiB of disk space + + --force-overwrite-lockfiles-v4-to-v3 + There is a tricky situation where a shader crate that depends on workspace config can have + a different `Cargo.lock` lockfile version from the the workspace's `Cargo.lock`. This can + prevent builds when an old Rust toolchain doesn't recognise the newer lockfile version. + + The ideal way to resolve this would be to match the shader crate's toolchain with the + workspace's toolchain. However, that is not always possible. Another solution is to + `exclude = [...]` the problematic shader crate from the workspace. This also may not be a + suitable solution if there are a number of shader crates all sharing similar config and + you don't want to have to copy/paste and maintain that config across all the shaders. + + So a somewhat hacky workaround is to have `cargo gpu` overwrite lockfile versions. Enabling + this flag will only come into effect if there are a mix of v3/v4 lockfiles. It will also + only overwrite versions for the duration of a build. It will attempt to return the versions + to their original values once the build is finished. However, of course, unexpected errors + can occur and the overwritten values can remain. Hence why this behaviour is not enabled by + default. + + This hack is possible because the change from v3 to v4 only involves a minor change to the + way source URLs are encoded. See these PRs for more details: + * + * + -o, --output-dir Path to the output directory for the compiled shaders - + [default: ./] - - --no-default-features - Set cargo default-features - - --features - Set cargo features - + + -w, --watch + Watch the shader crate directory and automatically recompile on changes + + --debug + Build in release. Defaults to true + --target - `rust-gpu` compile target - + The target triple, eg. `spirv-unknown-vulkan1.2` + [default: spirv-unknown-vulkan1.2] - - --shader-target - Shader target - - [default: spirv-unknown-vulkan1.2] - + + --no-default-features + Set --default-features for the target shader crate + + --features + Set --features for the target shader crate + --deny-warnings - Treat warnings as errors during compilation - - --debug - Compile shaders in debug mode - - --capability - Enables the provided SPIR-V capabilities. See: `impl core::str::FromStr for spirv_builder::Capability` - - --extension - Enables the provided SPIR-V extensions. See for all extensions - + Deny any warnings, as they may never be printed when building within a build script. Defaults to false + --multimodule - Compile one .spv file per entry point - + Splits the resulting SPIR-V file into one module per entry point. This is useful in cases where ecosystem tooling has bugs around multiple entry points per module - having all entry points bundled into a single file is the preferred system + --spirv-metadata - Set the level of metadata included in the SPIR-V binary - + Sets the level of metadata (primarily `OpName` and `OpLine`) included in the SPIR-V binary. Including metadata significantly increases binary size + [default: none] - + + Possible values: + - none: Strip all names and other debug information from SPIR-V output + - name-variables: Only include `OpName`s for public interface variables (uniforms and the like), to allow shader reflection + - full: Include all `OpName`s for everything, and `OpLine`s. Significantly increases binary size + + --capabilities + Adds a capability to the SPIR-V module. Checking if a capability is enabled in code can be done via `#[cfg(target_feature = "TheCapability")]` + + --extensions + Adds an extension to the SPIR-V module. Checking if an extension is enabled in code can be done via `#[cfg(target_feature = "ext:the_extension")]` + --relax-struct-store - Allow store from one struct type to a different type with compatible layout and members - + Record whether or not the validator should relax the rules on types for stores to structs. When relaxed, it will allow a type mismatch as long as the types are structs with the same layout. Two structs have the same layout if + + 1) the members of the structs are either the same type or are structs with same layout, and + + 2) the decorations that affect the memory layout are identical for both types. Other decorations are not relevant. + --relax-logical-pointer - Allow allocating an object of a pointer type and returning a pointer value from a function in logical addressing mode - - --relax-block-layout - Enable `VK_KHR_relaxed_block_layout` when checking standard uniform, storage buffer, and push constant layouts. This is the default when targeting Vulkan 1.1 or later - + Records whether or not the validator should relax the rules on pointer usage in logical addressing mode. + + When relaxed, it will allow the following usage cases of pointers: 1) `OpVariable` allocating an object whose type is a pointer type 2) `OpReturnValue` returning a pointer value + + --relax-block-layout + Records whether the validator should use "relaxed" block layout rules. Relaxed layout rules are described by Vulkan extension `VK_KHR_relaxed_block_layout`, and they affect uniform blocks, storage blocks, and push constants. + + This is enabled by default when targeting Vulkan 1.1 or later. Relaxed layout is more permissive than the default rules in Vulkan 1.0. + + [default: false] + [possible values: true, false] + --uniform-buffer-standard-layout - Enable `VK_KHR_uniform_buffer_standard_layout` when checking standard uniform buffer layouts - + Records whether the validator should use standard block layout rules for uniform blocks + --scalar-block-layout - Enable `VK_EXT_scalar_block_layout` when checking standard uniform, storage buffer, and push constant layouts. Scalar layout rules are more permissive than relaxed block layout so in effect this will override the --relax-block-layout option - + Records whether the validator should use "scalar" block layout rules. Scalar layout rules are more permissive than relaxed block layout. + + See Vulkan extnesion `VK_EXT_scalar_block_layout`. The scalar alignment is defined as follows: - scalar alignment of a scalar is the scalar size - scalar alignment of a vector is the scalar alignment of its component - scalar alignment of a matrix is the scalar alignment of its component - scalar alignment of an array is the scalar alignment of its element - scalar alignment of a struct is the max scalar alignment among its members + + For a struct in Uniform, `StorageClass`, or `PushConstant`: - a member Offset must be a multiple of the member's scalar alignment - `ArrayStride` or `MatrixStride` must be a multiple of the array or matrix scalar alignment + --skip-block-layout - Skip checking standard uniform / storage buffer layout. Overrides any --relax-block-layout or --scalar-block-layout option - + Records whether or not the validator should skip validating standard uniform/storage block layout + --preserve-bindings - Preserve unused descriptor bindings. Useful for reflection - + Records whether all bindings within the module should be preserved + + -m, --manifest-file + Renames the manifest.json file to the given name + + [default: manifest.json] + -h, --help Print help (see a summary with '-h') * Show Show some useful values - + Usage: cargo-gpu show - + Commands: cache-directory Displays the location of the cache directory spirv-source The source location of spirv-std + commitsh The git commitsh of this cli tool + capabilities All the available SPIR-V capabilities that can be set with `--capabilities` help Print this message or the help of the given subcommand(s) - + Options: -h, --help Print help @@ -224,9 +291,9 @@ for an example. * Cache-directory Displays the location of the cache directory - + Usage: cargo-gpu show cache-directory - + Options: -h, --help Print help @@ -234,15 +301,35 @@ for an example. * Spirv-source The source location of spirv-std - + Usage: cargo-gpu show spirv-source [OPTIONS] - + Options: --shader-crate The location of the shader-crate to inspect to determine its spirv-std dependency - + [default: ./] + + -h, --help + Print help + + + * Commitsh + The git commitsh of this cli tool + + Usage: cargo-gpu show commitsh + + Options: + -h, --help + Print help + + * Capabilities + All the available SPIR-V capabilities that can be set with `--capabilities` + + Usage: cargo-gpu show capabilities + + Options: -h, --help Print help ```` diff --git a/crates/cargo-gpu/Cargo.toml b/crates/cargo-gpu/Cargo.toml index 8373ef4..49ea815 100644 --- a/crates/cargo-gpu/Cargo.toml +++ b/crates/cargo-gpu/Cargo.toml @@ -7,11 +7,13 @@ repository = "https://github.com/Rust-GPU/cargo-gpu" readme = "../../README.md" keywords = ["gpu", "compiler"] build = "build.rs" +default-run = "cargo-gpu" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +cargo_metadata.workspace = true anyhow.workspace = true -spirv-builder-cli = { path = "../spirv-builder-cli", default-features = false, features = ["rspirv-latest"] } +spirv-builder = { workspace = true, features = ["clap", "watch"] } clap.workspace = true directories.workspace = true env_logger.workspace = true @@ -19,29 +21,11 @@ log.workspace = true relative-path.workspace = true serde.workspace = true serde_json.workspace = true -toml.workspace = true -chrono.workspace = true -http.workspace = true crossterm.workspace = true -version_check = "0.9.5" +semver.workspace = true [dev-dependencies] test-log.workspace = true -# Enable incremental by default in release mode. -[profile.release] -incremental = true -# HACK(eddyb) this is the default but without explicitly specifying it, Cargo -# will treat the identical settings in `[profile.release.build-override]` below -# as different sets of `rustc` flags and will not reuse artifacts between them. -codegen-units = 256 - -# Compile build-dependencies in release mode with the same settings -# as regular dependencies (including the incremental enabled above). -[profile.release.build-override] -opt-level = 3 -incremental = true -codegen-units = 256 - [lints] workspace = true diff --git a/crates/cargo-gpu/src/args.rs b/crates/cargo-gpu/src/args.rs new file mode 100644 index 0000000..346d857 --- /dev/null +++ b/crates/cargo-gpu/src/args.rs @@ -0,0 +1,106 @@ +//! Args for building and installing. + +use spirv_builder::SpirvBuilder; + +/// All args for a build and install +#[derive(clap::Parser, Debug, Clone, serde::Deserialize, serde::Serialize)] +pub struct AllArgs { + /// build args + #[clap(flatten)] + pub build: BuildArgs, + + /// install args + #[clap(flatten)] + pub install: InstallArgs, +} + +/// Args for just a build +#[derive(clap::Parser, Debug, Clone, serde::Deserialize, serde::Serialize)] +pub struct BuildArgs { + /// Path to the output directory for the compiled shaders. + #[clap(long, short, default_value = "./")] + pub output_dir: std::path::PathBuf, + + /// Watch the shader crate directory and automatically recompile on changes. + #[clap(long, short, action)] + pub watch: bool, + + /// the flattened [`SpirvBuilder`] + #[clap(flatten)] + #[serde(flatten)] + pub spirv_builder: SpirvBuilder, + + ///Renames the manifest.json file to the given name + #[clap(long, short, default_value = "manifest.json")] + pub manifest_file: String, +} + +/// Args for an install +#[derive(clap::Parser, Debug, Clone, serde::Deserialize, serde::Serialize)] +#[expect( + clippy::struct_excessive_bools, + reason = "cmdline args have many bools" +)] +pub struct InstallArgs { + /// path to the `rustc_codegen_spirv` dylib + #[clap(long, hide(true), default_value = "INTERNALLY_SET")] + pub dylib_path: std::path::PathBuf, + + /// Directory containing the shader crate to compile. + #[clap(long, default_value = "./")] + pub shader_crate: std::path::PathBuf, + + #[expect( + clippy::doc_markdown, + reason = "The URL should appear literally like this. But Clippy wants a markdown clickable link" + )] + /// Source of `spirv-builder` dependency + /// Eg: "https://github.com/Rust-GPU/rust-gpu" + #[clap(long)] + pub spirv_builder_source: Option, + + /// Version of `spirv-builder` dependency. + /// * If `--spirv-builder-source` is not set, then this is assumed to be a crates.io semantic + /// version such as "0.9.0". + /// * If `--spirv-builder-source` is set, then this is assumed to be a Git "commitsh", such + /// as a Git commit hash or a Git tag, therefore anything that `git checkout` can resolve. + #[clap(long, verbatim_doc_comment)] + pub spirv_builder_version: Option, + + /// Force `rustc_codegen_spirv` to be rebuilt. + #[clap(long)] + pub rebuild_codegen: bool, + + /// Assume "yes" to "Install Rust toolchain: [y/n]" prompt. + #[clap(long, action)] + pub auto_install_rust_toolchain: bool, + + /// Clear target dir of `rustc_codegen_spirv` build after a successful build, saves about + /// 200MiB of disk space. + #[clap(long = "no-clear-target", default_value = "true", action = clap::ArgAction::SetFalse)] + pub clear_target: bool, + + /// There is a tricky situation where a shader crate that depends on workspace config can have + /// a different `Cargo.lock` lockfile version from the the workspace's `Cargo.lock`. This can + /// prevent builds when an old Rust toolchain doesn't recognise the newer lockfile version. + /// + /// The ideal way to resolve this would be to match the shader crate's toolchain with the + /// workspace's toolchain. However, that is not always possible. Another solution is to + /// `exclude = [...]` the problematic shader crate from the workspace. This also may not be a + /// suitable solution if there are a number of shader crates all sharing similar config and + /// you don't want to have to copy/paste and maintain that config across all the shaders. + /// + /// So a somewhat hacky workaround is to have `cargo gpu` overwrite lockfile versions. Enabling + /// this flag will only come into effect if there are a mix of v3/v4 lockfiles. It will also + /// only overwrite versions for the duration of a build. It will attempt to return the versions + /// to their original values once the build is finished. However, of course, unexpected errors + /// can occur and the overwritten values can remain. Hence why this behaviour is not enabled by + /// default. + /// + /// This hack is possible because the change from v3 to v4 only involves a minor change to the + /// way source URLs are encoded. See these PRs for more details: + /// * + /// * + #[clap(long, action, verbatim_doc_comment)] + pub force_overwrite_lockfiles_v4_to_v3: bool, +} diff --git a/crates/cargo-gpu/src/build.rs b/crates/cargo-gpu/src/build.rs index d32dd24..b77e5a2 100644 --- a/crates/cargo-gpu/src/build.rs +++ b/crates/cargo-gpu/src/build.rs @@ -2,14 +2,16 @@ #![allow(clippy::unwrap_used, reason = "this is basically a test")] //! `cargo gpu build`, analogous to `cargo build` +use crate::args::BuildArgs; +use crate::linkage::Linkage; +use crate::lockfile::LockfileMismatchHandler; +use crate::{install::Install, target_spec_dir}; use anyhow::Context as _; +use spirv_builder::{CompileResult, ModuleResult}; use std::io::Write as _; -use crate::{install::Install, target_spec_dir}; -use spirv_builder_cli::{args::BuildArgs, Linkage, ShaderModule}; - /// `cargo build` subcommands -#[derive(clap::Parser, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Clone, clap::Parser, Debug, serde::Deserialize, serde::Serialize)] pub struct Build { /// CLI args for install the `rust-gpu` compiler and components #[clap(flatten)] @@ -22,9 +24,25 @@ pub struct Build { impl Build { /// Entrypoint - #[expect(clippy::too_many_lines, reason = "It's not too confusing")] pub fn run(&mut self) -> anyhow::Result<()> { - let spirv_builder_cli_path = self.install.run()?; + let (rustc_codegen_spirv_location, toolchain_channel) = self.install.run()?; + + let _lockfile_mismatch_handler = LockfileMismatchHandler::new( + &self.install.spirv_install.shader_crate, + &toolchain_channel, + self.install + .spirv_install + .force_overwrite_lockfiles_v4_to_v3, + )?; + + let builder = &mut self.build_args.spirv_builder; + builder.rustc_codegen_spirv_location = Some(rustc_codegen_spirv_location); + builder.toolchain_overwrite = Some(toolchain_channel); + builder.path_to_crate = Some(self.install.spirv_install.shader_crate.clone()); + builder.path_to_target_spec = Some(target_spec_dir()?.join(format!( + "{}.json", + builder.target.as_ref().context("expect target to be set")? + ))); // Ensure the shader output dir exists log::debug!( @@ -46,87 +64,74 @@ impl Build { std::env::current_dir()?.display() ); - if !self.build_args.watch { - self.build_args.shader_target = target_spec_dir()? - .join(format!("{}.json", self.build_args.shader_target)) - .display() - .to_string(); - } - - let args_as_json = serde_json::json!({ - "install": self.install.spirv_install, - "build": self.build_args - }); - let arg = serde_json::to_string_pretty(&args_as_json)?; - log::info!("using spirv-builder-cli arg: {arg}"); - - if !self.build_args.watch { + if self.build_args.watch { + let this = self.clone(); + self.build_args + .spirv_builder + .watch(move |result, accept| { + let result1 = this.parse_compilation_result(&result); + if let Some(accept) = accept { + accept.submit(result1); + } + })? + .context("unreachable")??; + std::thread::park(); + } else { crate::user_output!( - "Running `spirv-builder-cli` to compile shader at {}...\n", + "Compiling shaders at {}...\n", self.install.spirv_install.shader_crate.display() ); + let result = self.build_args.spirv_builder.build()?; + self.parse_compilation_result(&result)?; } + Ok(()) + } - // Call spirv-builder-cli to compile the shaders. - let output = std::process::Command::new(spirv_builder_cli_path) - .arg(arg) - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) - .output()?; - anyhow::ensure!(output.status.success(), "build failed"); - - let spirv_manifest = self.build_args.output_dir.join("spirv-manifest.json"); - if spirv_manifest.is_file() { - log::debug!( - "successfully built shaders, raw manifest is at '{}'", - spirv_manifest.display() - ); - } else { - log::error!("missing raw manifest '{}'", spirv_manifest.display()); - anyhow::bail!("missing raw manifest"); - } - - let shaders: Vec = - serde_json::from_reader(std::fs::File::open(&spirv_manifest)?)?; - + /// Parses compilation result from `SpirvBuilder` and writes it out to a file + fn parse_compilation_result(&self, result: &CompileResult) -> anyhow::Result<()> { + let shaders = match &result.module { + ModuleResult::MultiModule(modules) => { + anyhow::ensure!(!modules.is_empty(), "No shader modules were compiled"); + modules.iter().collect::>() + } + ModuleResult::SingleModule(filepath) => result + .entry_points + .iter() + .map(|entry| (entry, filepath)) + .collect::>(), + }; let mut linkage: Vec = shaders .into_iter() - .map( - |ShaderModule { - entry, - path: filepath, - }| - -> anyhow::Result { - use relative_path::PathExt as _; - let path = self.build_args.output_dir.join( - filepath - .file_name() - .context("Couldn't parse file name from shader module path")?, - ); - log::debug!("copying {} to {}", filepath.display(), path.display()); - std::fs::copy(&filepath, &path)?; - log::debug!( - "linkage of {} relative to {}", - path.display(), - self.install.spirv_install.shader_crate.display() - ); - let spv_path = path - .relative_to(&self.install.spirv_install.shader_crate) - .map_or(path, |path_relative_to_shader_crate| { - path_relative_to_shader_crate.to_path("") - }); - Ok(Linkage::new(entry, spv_path)) - }, - ) + .map(|(entry, filepath)| -> anyhow::Result { + use relative_path::PathExt as _; + let path = self.build_args.output_dir.join( + filepath + .file_name() + .context("Couldn't parse file name from shader module path")?, + ); + log::debug!("copying {} to {}", filepath.display(), path.display()); + std::fs::copy(filepath, &path)?; + log::debug!( + "linkage of {} relative to {}", + path.display(), + self.install.spirv_install.shader_crate.display() + ); + let spv_path = path + .relative_to(&self.install.spirv_install.shader_crate) + .map_or(path, |path_relative_to_shader_crate| { + path_relative_to_shader_crate.to_path("") + }); + Ok(Linkage::new(entry, spv_path)) + }) .collect::>>()?; + // Sort the contents so the output is deterministic + linkage.sort(); // Write the shader manifest json file let manifest_path = self .build_args .output_dir .join(&self.build_args.manifest_file); - // Sort the contents so the output is deterministic - linkage.sort(); let json = serde_json::to_string_pretty(&linkage)?; let mut file = std::fs::File::create(&manifest_path).with_context(|| { format!( @@ -142,14 +147,6 @@ impl Build { })?; log::info!("wrote manifest to '{}'", manifest_path.display()); - - if spirv_manifest.is_file() { - log::debug!( - "removing spirv-manifest.json file '{}'", - spirv_manifest.display() - ); - std::fs::remove_file(spirv_manifest)?; - } Ok(()) } } diff --git a/crates/cargo-gpu/src/config.rs b/crates/cargo-gpu/src/config.rs index 15337d3..ad86402 100644 --- a/crates/cargo-gpu/src/config.rs +++ b/crates/cargo-gpu/src/config.rs @@ -140,7 +140,7 @@ mod test { ], ) .unwrap(); - assert!(args.build_args.debug); + assert!(!args.build_args.spirv_builder.release); assert!(args.install.spirv_install.auto_install_rust_toolchain); } @@ -151,7 +151,7 @@ mod test { file.write_all( [ "[package.metadata.rust-gpu.build]", - "debug = true", + "release = false", "[package.metadata.rust-gpu.install]", "auto-install-rust-toolchain = true", ] @@ -161,7 +161,7 @@ mod test { .unwrap(); let args = Config::clap_command_with_cargo_config(&shader_crate_path, vec![]).unwrap(); - assert!(args.build_args.debug); + assert!(!args.build_args.spirv_builder.release); assert!(args.install.spirv_install.auto_install_rust_toolchain); } @@ -225,7 +225,7 @@ mod test { file.write_all( [ "[package.metadata.rust-gpu.build]", - "capability = [\"AtomicStorage\", \"Matrix\"]", + "capabilities = [\"AtomicStorage\", \"Matrix\"]", ] .join("\n") .as_bytes(), @@ -234,10 +234,10 @@ mod test { let args = Config::clap_command_with_cargo_config(&shader_crate_path, vec![]).unwrap(); assert_eq!( - args.build_args.capability, + args.build_args.spirv_builder.capabilities, vec![ - spirv_builder_cli::spirv::Capability::AtomicStorage, - spirv_builder_cli::spirv::Capability::Matrix + spirv_builder::Capability::AtomicStorage, + spirv_builder::Capability::Matrix ] ); } diff --git a/crates/cargo-gpu/src/install.rs b/crates/cargo-gpu/src/install.rs index 9977227..0b6f5fd 100644 --- a/crates/cargo-gpu/src/install.rs +++ b/crates/cargo-gpu/src/install.rs @@ -1,102 +1,18 @@ //! Install a dedicated per-shader crate that has the `rust-gpu` compiler in it. -use std::io::Write as _; - +use crate::args::InstallArgs; +use crate::spirv_source::{ + get_channel_from_rustc_codegen_spirv_build_script, get_package_from_crate, +}; +use crate::{cache_dir, spirv_source::SpirvSource, target_spec_dir}; use anyhow::Context as _; - -use crate::{cache_dir, spirv_cli::SpirvCli, spirv_source::SpirvSource, target_spec_dir}; -use spirv_builder_cli::args::InstallArgs; - -/// These are the files needed to create the dedicated, per-shader `rust-gpu` builder create. -const SPIRV_BUILDER_FILES: &[(&str, &str)] = &[ - ( - "Cargo.toml", - include_str!("../../spirv-builder-cli/Cargo.toml"), - ), - ( - "Cargo.lock", - include_str!("../../spirv-builder-cli/Cargo.lock"), - ), - ( - "src/main.rs", - include_str!("../../spirv-builder-cli/src/main.rs"), - ), - ( - "src/lib.rs", - include_str!("../../spirv-builder-cli/src/lib.rs"), - ), - ( - "src/args.rs", - include_str!("../../spirv-builder-cli/src/args.rs"), - ), -]; - -/// Metadata for the compile targets supported by `rust-gpu` -const TARGET_SPECS: &[(&str, &str)] = &[ - ( - "spirv-unknown-opengl4.0.json", - include_str!("../target-specs/spirv-unknown-opengl4.0.json"), - ), - ( - "spirv-unknown-opengl4.1.json", - include_str!("../target-specs/spirv-unknown-opengl4.1.json"), - ), - ( - "spirv-unknown-opengl4.2.json", - include_str!("../target-specs/spirv-unknown-opengl4.2.json"), - ), - ( - "spirv-unknown-opengl4.3.json", - include_str!("../target-specs/spirv-unknown-opengl4.3.json"), - ), - ( - "spirv-unknown-opengl4.5.json", - include_str!("../target-specs/spirv-unknown-opengl4.5.json"), - ), - ( - "spirv-unknown-spv1.0.json", - include_str!("../target-specs/spirv-unknown-spv1.0.json"), - ), - ( - "spirv-unknown-spv1.1.json", - include_str!("../target-specs/spirv-unknown-spv1.1.json"), - ), - ( - "spirv-unknown-spv1.2.json", - include_str!("../target-specs/spirv-unknown-spv1.2.json"), - ), - ( - "spirv-unknown-spv1.3.json", - include_str!("../target-specs/spirv-unknown-spv1.3.json"), - ), - ( - "spirv-unknown-spv1.4.json", - include_str!("../target-specs/spirv-unknown-spv1.4.json"), - ), - ( - "spirv-unknown-spv1.5.json", - include_str!("../target-specs/spirv-unknown-spv1.5.json"), - ), - ( - "spirv-unknown-vulkan1.0.json", - include_str!("../target-specs/spirv-unknown-vulkan1.0.json"), - ), - ( - "spirv-unknown-vulkan1.1.json", - include_str!("../target-specs/spirv-unknown-vulkan1.1.json"), - ), - ( - "spirv-unknown-vulkan1.1spv1.4.json", - include_str!("../target-specs/spirv-unknown-vulkan1.1spv1.4.json"), - ), - ( - "spirv-unknown-vulkan1.2.json", - include_str!("../target-specs/spirv-unknown-vulkan1.2.json"), - ), -]; +use log::trace; +use spirv_builder::TARGET_SPECS; +use std::io::Write as _; +use std::path::{Path, PathBuf}; /// `cargo gpu install` -#[derive(clap::Parser, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Clone, clap::Parser, Debug, serde::Deserialize, serde::Serialize)] pub struct Install { /// CLI arguments for installing the Rust toolchain and components #[clap(flatten)] @@ -104,69 +20,57 @@ pub struct Install { } impl Install { - /// Returns a [`SpirvCLI`] instance, responsible for ensuring the right version of the `spirv-builder-cli` crate. - fn spirv_cli(&self, shader_crate_path: &std::path::Path) -> anyhow::Result { - SpirvCli::new( - shader_crate_path, - self.spirv_install.spirv_builder_source.clone(), - self.spirv_install.spirv_builder_version.clone(), - self.spirv_install.rust_toolchain.clone(), - self.spirv_install.auto_install_rust_toolchain, - self.spirv_install.force_overwrite_lockfiles_v4_to_v3, - ) - } - - /// Create the `spirv-builder-cli` crate. - fn write_source_files(&self) -> anyhow::Result<()> { - let spirv_cli = self - .spirv_cli(&self.spirv_install.shader_crate) - .context("running spirv cli")?; - let checkout = spirv_cli - .cached_checkout_path() - .context("getting cached checkout path")?; - std::fs::create_dir_all(checkout.join("src")).context("creating directory for 'src'")?; - for (filename, contents) in SPIRV_BUILDER_FILES { - log::debug!("writing {filename}"); - let path = checkout.join(filename); - let mut file = std::fs::File::create(&path) - .with_context(|| format!("creating a file at [{}]", path.display()))?; - let mut replaced_contents = contents.replace("${CHANNEL}", &spirv_cli.channel); - if filename == &"Cargo.toml" { - replaced_contents = Self::update_cargo_toml(&replaced_contents, &spirv_cli.source); - } - file.write_all(replaced_contents.as_bytes()) - .context("writing to file")?; + /// Create the `rustc_codegen_spirv_dummy` crate that depends on `rustc_codegen_spirv` + fn write_source_files(source: &SpirvSource, checkout: &Path) -> anyhow::Result<()> { + // skip writing a dummy project if we use a local rust-gpu checkout + if matches!(source, SpirvSource::Path { .. }) { + return Ok(()); } - Ok(()) - } - - /// Update the `Cargo.toml` file in the `spirv-builder-cli` crate so that it contains - /// the correct version of `spirv-builder-cli`. - fn update_cargo_toml(contents: &str, spirv_source: &SpirvSource) -> String { - let updated = contents.lines().map(|line| { - if line.contains("${AUTO-REPLACE-SOURCE}") { - let replaced_line = match spirv_source { - SpirvSource::CratesIO(_) => String::new(), - SpirvSource::Git { url, .. } => format!("git = \"{url}\""), - SpirvSource::Path((path, _)) => format!("path = \"{path}\""), - }; - return format!("{replaced_line}\n"); - } - - if line.contains("${AUTO-REPLACE-VERSION}") { - let replaced_line = match spirv_source { - SpirvSource::CratesIO(version) | SpirvSource::Path((_, version)) => { - format!("version = \"{}\"", version.replace('v', "")) - } - SpirvSource::Git { rev, .. } => format!("rev = \"{rev}\""), - }; - return format!("{replaced_line}\n"); - } + log::debug!( + "writing `rustc_codegen_spirv_dummy` source files into '{}'", + checkout.display() + ); - format!("{line}\n") - }); + { + trace!("writing dummy main.rs"); + let main = "fn main() {}"; + let src = checkout.join("src"); + std::fs::create_dir_all(&src).context("creating directory for 'src'")?; + std::fs::write(src.join("main.rs"), main).context("writing 'main.rs'")?; + }; - updated.collect() + { + trace!("writing dummy Cargo.toml"); + let version_spec = match &source { + SpirvSource::CratesIO(version) => { + format!("version = \"{version}\"") + } + SpirvSource::Git { url, rev } => format!("git = \"{url}\"\nrev = \"{rev}\""), + SpirvSource::Path { + rust_gpu_repo_root: rust_gpu_path, + version, + } => { + let mut new_path = rust_gpu_path.to_owned(); + new_path.push("crates/spirv-builder"); + format!("path = \"{new_path}\"\nversion = \"{version}\"") + } + }; + let cargo_toml = format!( + r#" +[package] +name = "rustc_codegen_spirv_dummy" +version = "0.1.0" +edition = "2021" + +[dependencies.spirv-builder] +package = "rustc_codegen_spirv" +{version_spec} + "# + ); + std::fs::write(checkout.join("Cargo.toml"), cargo_toml) + .context("writing 'Cargo.toml'")?; + }; + Ok(()) } /// Add the target spec files to the crate. @@ -175,7 +79,7 @@ impl Install { let path = target_spec_dir() .context("creating target spec dir")? .join(filename); - if !path.is_file() || self.spirv_install.force_spirv_cli_rebuild { + if !path.is_file() || self.spirv_install.rebuild_codegen { let mut file = std::fs::File::create(&path) .with_context(|| format!("creating file at [{}]", path.display()))?; file.write_all(contents.as_bytes()) @@ -185,8 +89,9 @@ impl Install { Ok(()) } - /// Install the binary pair and return the paths, (dylib, cli). - pub fn run(&mut self) -> anyhow::Result { + /// Install the binary pair and return the `(dylib_path, toolchain_channel)`. + #[expect(clippy::too_many_lines, reason = "it's fine")] + pub fn run(&mut self) -> anyhow::Result<(PathBuf, String)> { // Ensure the cache dir exists let cache_dir = cache_dir()?; log::info!("cache directory is '{}'", cache_dir.display()); @@ -194,66 +99,79 @@ impl Install { format!("could not create cache directory '{}'", cache_dir.display()) })?; - let spirv_version = self - .spirv_cli(&self.spirv_install.shader_crate) - .context("running spirv cli")?; - spirv_version - .ensure_toolchain_and_components_exist() - .context("ensuring toolchain and components exist")?; - - let checkout = spirv_version - .cached_checkout_path() - .context("getting cached checkout path")?; - let release = checkout.join("target").join("release"); + let source = SpirvSource::new( + &self.spirv_install.shader_crate, + self.spirv_install.spirv_builder_source.as_deref(), + self.spirv_install.spirv_builder_version.as_deref(), + )?; + let source_is_path = matches!(source, SpirvSource::Path { .. }); + let checkout = source.install_dir()?; let dylib_filename = format!( "{}rustc_codegen_spirv{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_SUFFIX ); - let dylib_path = release.join(&dylib_filename); - let dest_dylib_path = checkout.join(&dylib_filename); - let dest_cli_path = checkout.join("spirv-builder-cli"); - if dest_dylib_path.is_file() && dest_cli_path.is_file() { - log::info!( - "cargo-gpu artifacts are already installed in '{}'", - checkout.display() - ); + + let dest_dylib_path; + if source_is_path { + dest_dylib_path = checkout + .join("target") + .join("release") + .join(&dylib_filename); + } else { + dest_dylib_path = checkout.join(&dylib_filename); + if dest_dylib_path.is_file() { + log::info!( + "cargo-gpu artifacts are already installed in '{}'", + checkout.display() + ); + } } - if dest_dylib_path.is_file() - && dest_cli_path.is_file() - && !self.spirv_install.force_spirv_cli_rebuild - { + let skip_rebuild = + !source_is_path && dest_dylib_path.is_file() && !self.spirv_install.rebuild_codegen; + if skip_rebuild { log::info!("...and so we are aborting the install step."); } else { - log::debug!( - "writing spirv-builder-cli source files into '{}'", - checkout.display() - ); - self.write_source_files().context("writing source files")?; - self.write_target_spec_files() - .context("writing target spec files")?; + Self::write_source_files(&source, &checkout).context("writing source files")?; + } - crate::user_output!( - "Compiling shader-specific `spirv-builder-cli` for {}\n", - self.spirv_install.shader_crate.display() - ); + // TODO cache toolchain channel in a file? + log::debug!("resolving toolchain version to use"); + let rustc_codegen_spirv = get_package_from_crate(&checkout, "rustc_codegen_spirv") + .context("get `rustc_codegen_spirv` metadata")?; + let toolchain_channel = + get_channel_from_rustc_codegen_spirv_build_script(&rustc_codegen_spirv) + .context("read toolchain from `rustc_codegen_spirv`'s build.rs")?; + log::info!("selected toolchain channel `{toolchain_channel:?}`"); + + if !skip_rebuild { + log::debug!("ensure_toolchain_and_components_exist"); + crate::install_toolchain::ensure_toolchain_and_components_exist( + &toolchain_channel, + self.spirv_install.auto_install_rust_toolchain, + ) + .context("ensuring toolchain and components exist")?; + + // to prevent unsupported version errors when using older toolchains + if !source_is_path { + log::debug!("remove Cargo.lock"); + std::fs::remove_file(checkout.join("Cargo.lock")).context("remove Cargo.lock")?; + } + crate::user_output!("Compiling `rustc_codegen_spirv` from source {}\n", source,); let mut build_command = std::process::Command::new("cargo"); build_command .current_dir(&checkout) - .arg(format!("+{}", spirv_version.channel)) + .arg(format!("+{toolchain_channel}")) .args(["build", "--release"]) - .args(["--no-default-features"]); - - build_command.args([ - "--features", - &Self::get_required_spirv_builder_version(spirv_version.date) - .context("getting required spirv builder version")?, - ]); + .env_remove("RUSTC"); + if source_is_path { + build_command.args(["-p", "rustc_codegen_spirv", "--lib"]); + } - log::debug!("building artifacts with `{:?}`", build_command); + log::debug!("building artifacts with `{build_command:?}`"); build_command .stdout(std::process::Stdio::inherit()) @@ -269,54 +187,30 @@ impl Install { }) .context("running build command")?; + let target = checkout.join("target"); + let dylib_path = target.join("release").join(&dylib_filename); if dylib_path.is_file() { log::info!("successfully built {}", dylib_path.display()); - std::fs::rename(&dylib_path, &dest_dylib_path).context("renaming dylib path")?; + if !source_is_path { + std::fs::rename(&dylib_path, &dest_dylib_path) + .context("renaming dylib path")?; + + if self.spirv_install.clear_target { + log::warn!("clearing target dir {}", target.display()); + std::fs::remove_dir_all(&target).context("clearing target dir")?; + } + } } else { log::error!("could not find {}", dylib_path.display()); - anyhow::bail!("spirv-builder-cli build failed"); + anyhow::bail!("`rustc_codegen_spirv` build failed"); } - let cli_path = if cfg!(target_os = "windows") { - release.join("spirv-builder-cli").with_extension("exe") - } else { - release.join("spirv-builder-cli") - }; - if cli_path.is_file() { - log::info!("successfully built {}", cli_path.display()); - std::fs::rename(&cli_path, &dest_cli_path).context("renaming cli path")?; - } else { - log::error!("could not find {}", cli_path.display()); - log::debug!("contents of '{}':", release.display()); - for maybe_entry in std::fs::read_dir(&release).context("reading release dir")? { - let entry = maybe_entry?; - log::debug!("{}", entry.file_name().to_string_lossy()); - } - anyhow::bail!("spirv-builder-cli build failed"); - } + log::debug!("write_target_spec_files"); + self.write_target_spec_files() + .context("writing target spec files")?; } - self.spirv_install.dylib_path = dest_dylib_path; - - Ok(dest_cli_path) - } - - /// The `spirv-builder` crate from the main `rust-gpu` repo hasn't always been setup to - /// interact with `cargo-gpu`. Older versions don't have the same `SpirvBuilder` interface. So - /// here we choose the right Cargo feature to enable/disable code in `spirv-builder-cli`. - /// - /// TODO: - /// * Warn the user that certain `cargo-gpu` features aren't available when building with - /// older versions of `spirv-builder`, eg setting the target spec. - fn get_required_spirv_builder_version(date: chrono::NaiveDate) -> anyhow::Result { - let parse_date = chrono::NaiveDate::parse_from_str; - let pre_cli_date = parse_date("2024-04-24", "%Y-%m-%d")?; - - Ok(if date < pre_cli_date { - "spirv-builder-pre-cli" - } else { - "spirv-builder-0_10" - } - .into()) + self.spirv_install.dylib_path.clone_from(&dest_dylib_path); + Ok((dest_dylib_path, toolchain_channel)) } } diff --git a/crates/cargo-gpu/src/install_toolchain.rs b/crates/cargo-gpu/src/install_toolchain.rs new file mode 100644 index 0000000..027a90d --- /dev/null +++ b/crates/cargo-gpu/src/install_toolchain.rs @@ -0,0 +1,134 @@ +//! toolchain installation logic + +use anyhow::Context as _; + +/// Use `rustup` to install the toolchain and components, if not already installed. +/// +/// Pretty much runs: +/// +/// * rustup toolchain add nightly-2024-04-24 +/// * rustup component add --toolchain nightly-2024-04-24 rust-src rustc-dev llvm-tools +pub fn ensure_toolchain_and_components_exist( + channel: &str, + skip_toolchain_install_consent: bool, +) -> anyhow::Result<()> { + // Check for the required toolchain + let output_toolchain_list = std::process::Command::new("rustup") + .args(["toolchain", "list"]) + .output() + .context("running rustup command")?; + anyhow::ensure!( + output_toolchain_list.status.success(), + "could not list installed toolchains" + ); + let string_toolchain_list = String::from_utf8_lossy(&output_toolchain_list.stdout); + if string_toolchain_list + .split_whitespace() + .any(|toolchain| toolchain.starts_with(channel)) + { + log::debug!("toolchain {channel} is already installed"); + } else { + let message = format!("Rust {channel} with `rustup`"); + get_consent_for_toolchain_install( + format!("Install {message}").as_ref(), + skip_toolchain_install_consent, + )?; + crate::user_output!("Installing {message}\n"); + + let output_toolchain_add = std::process::Command::new("rustup") + .args(["toolchain", "add"]) + .arg(channel) + .stdout(std::process::Stdio::inherit()) + .stderr(std::process::Stdio::inherit()) + .output() + .context("adding toolchain")?; + anyhow::ensure!( + output_toolchain_add.status.success(), + "could not install required toolchain" + ); + } + + // Check for the required components + let output_component_list = std::process::Command::new("rustup") + .args(["component", "list", "--toolchain"]) + .arg(channel) + .output() + .context("getting toolchain list")?; + anyhow::ensure!( + output_component_list.status.success(), + "could not list installed components" + ); + let string_component_list = String::from_utf8_lossy(&output_component_list.stdout); + let required_components = ["rust-src", "rustc-dev", "llvm-tools"]; + let installed_components = string_component_list.lines().collect::>(); + let all_components_installed = required_components.iter().all(|component| { + installed_components.iter().any(|installed_component| { + let is_component = installed_component.starts_with(component); + let is_installed = installed_component.ends_with("(installed)"); + is_component && is_installed + }) + }); + if all_components_installed { + log::debug!("all required components are installed"); + } else { + let message = "toolchain components [rust-src, rustc-dev, llvm-tools] with `rustup`"; + get_consent_for_toolchain_install( + format!("Install {message}").as_ref(), + skip_toolchain_install_consent, + )?; + crate::user_output!("Installing {message}\n"); + + let output_component_add = std::process::Command::new("rustup") + .args(["component", "add", "--toolchain"]) + .arg(channel) + .args(["rust-src", "rustc-dev", "llvm-tools"]) + .stdout(std::process::Stdio::inherit()) + .stderr(std::process::Stdio::inherit()) + .output() + .context("adding rustup component")?; + anyhow::ensure!( + output_component_add.status.success(), + "could not install required components" + ); + } + + Ok(()) +} + +/// Prompt user if they want to install a new Rust toolchain. +fn get_consent_for_toolchain_install( + prompt: &str, + skip_toolchain_install_consent: bool, +) -> anyhow::Result<()> { + if skip_toolchain_install_consent { + return Ok(()); + } + log::debug!("asking for consent to install the required toolchain"); + crossterm::terminal::enable_raw_mode().context("enabling raw mode")?; + crate::user_output!("{prompt} [y/n]: \n"); + let mut input = crossterm::event::read().context("reading crossterm event")?; + + if let crossterm::event::Event::Key(crossterm::event::KeyEvent { + code: crossterm::event::KeyCode::Enter, + kind: crossterm::event::KeyEventKind::Release, + .. + }) = input + { + // In Powershell, programs will potentially observe the Enter key release after they started + // (see crossterm#124). If that happens, re-read the input. + input = crossterm::event::read().context("re-reading crossterm event")?; + } + crossterm::terminal::disable_raw_mode().context("disabling raw mode")?; + + if let crossterm::event::Event::Key(crossterm::event::KeyEvent { + code: crossterm::event::KeyCode::Char('y'), + .. + }) = input + { + Ok(()) + } else { + crate::user_output!("Exiting...\n"); + #[expect(clippy::exit, reason = "user requested abort")] + std::process::exit(0); + } +} diff --git a/crates/cargo-gpu/src/linkage.rs b/crates/cargo-gpu/src/linkage.rs new file mode 100644 index 0000000..346bdaf --- /dev/null +++ b/crates/cargo-gpu/src/linkage.rs @@ -0,0 +1,30 @@ +//! Mainly for the Linkage struct, which is written to a json file. + +/// Shader source and entry point that can be used to create shader linkage. +#[derive(serde::Serialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Linkage { + /// File path to the entry point's source file + pub source_path: String, + /// Name of the entry point for spirv and vulkan + pub entry_point: String, + /// Name of the entry point for wgsl, where `::` characters have been removed + pub wgsl_entry_point: String, +} + +impl Linkage { + /// Make a new `Linkage` from an entry point and source path + #[expect(clippy::impl_trait_in_params, reason = "just a struct new")] + pub fn new(entry_point: impl AsRef, source_path: impl AsRef) -> Self { + Self { + // Force a forward slash convention here so it works on all OSs + source_path: source_path + .as_ref() + .components() + .map(|comp| comp.as_os_str().to_string_lossy()) + .collect::>() + .join("/"), + wgsl_entry_point: entry_point.as_ref().replace("::", ""), + entry_point: entry_point.as_ref().to_owned(), + } + } +} diff --git a/crates/cargo-gpu/src/lockfile.rs b/crates/cargo-gpu/src/lockfile.rs new file mode 100644 index 0000000..bce1487 --- /dev/null +++ b/crates/cargo-gpu/src/lockfile.rs @@ -0,0 +1,274 @@ +//! Handles lockfile version conflicts and downgrades. Stable uses lockfile v4, but rust-gpu +//! v0.9.0 uses an old toolchain requiring v3 and will refuse to build with a v4 lockfile being +//! present. This module takes care of warning the user and potentially downgrading the lockfile. + +use anyhow::Context as _; +use semver::Version; +use spirv_builder::query_rustc_version; +use std::io::Write as _; + +/// `Cargo.lock` manifest version 4 became the default in Rust 1.83.0. Conflicting manifest +/// versions between the workspace and the shader crate, can cause problems. +const RUST_VERSION_THAT_USES_V4_CARGO_LOCKS: Version = Version::new(1, 83, 0); + +/// Cargo dependency for `spirv-builder` and the rust toolchain channel. +#[derive(Debug, Clone)] +pub struct LockfileMismatchHandler { + /// `Cargo.lock`s that have had their manifest versions changed by us and need changing back. + pub cargo_lock_files_with_changed_manifest_versions: Vec, +} + +impl LockfileMismatchHandler { + /// Create instance + pub fn new( + shader_crate_path: &std::path::Path, + toolchain_channel: &str, + is_force_overwrite_lockfiles_v4_to_v3: bool, + ) -> anyhow::Result { + let mut cargo_lock_files_with_changed_manifest_versions = vec![]; + + let maybe_shader_crate_lock = + Self::ensure_workspace_rust_version_doesnt_conflict_with_shader( + shader_crate_path, + is_force_overwrite_lockfiles_v4_to_v3, + ) + .context("ensure_workspace_rust_version_doesnt_conflict_with_shader")?; + + if let Some(shader_crate_lock) = maybe_shader_crate_lock { + cargo_lock_files_with_changed_manifest_versions.push(shader_crate_lock); + } + + let maybe_workspace_crate_lock = + Self::ensure_shader_rust_version_doesnt_conflict_with_any_cargo_locks( + shader_crate_path, + toolchain_channel, + is_force_overwrite_lockfiles_v4_to_v3, + ) + .context("ensure_shader_rust_version_doesnt_conflict_with_any_cargo_locks")?; + + if let Some(workspace_crate_lock) = maybe_workspace_crate_lock { + cargo_lock_files_with_changed_manifest_versions.push(workspace_crate_lock); + } + + Ok(Self { + cargo_lock_files_with_changed_manifest_versions, + }) + } + + /// See docs for `force_overwrite_lockfiles_v4_to_v3` flag for why we do this. + fn ensure_workspace_rust_version_doesnt_conflict_with_shader( + shader_crate_path: &std::path::Path, + is_force_overwrite_lockfiles_v4_to_v3: bool, + ) -> anyhow::Result> { + log::debug!("Ensuring no v3/v4 `Cargo.lock` conflicts from workspace Rust..."); + let workspace_rust_version = query_rustc_version(None).context("reading rustc version")?; + if workspace_rust_version >= RUST_VERSION_THAT_USES_V4_CARGO_LOCKS { + log::debug!( + "user's Rust is v{workspace_rust_version}, so no v3/v4 conflicts possible." + ); + return Ok(None); + } + + Self::handle_conflicting_cargo_lock_v4( + shader_crate_path, + is_force_overwrite_lockfiles_v4_to_v3, + ) + .context("handling v4/v3 conflict")?; + + if is_force_overwrite_lockfiles_v4_to_v3 { + Ok(Some(shader_crate_path.join("Cargo.lock"))) + } else { + Ok(None) + } + } + + /// See docs for `force_overwrite_lockfiles_v4_to_v3` flag for why we do this. + fn ensure_shader_rust_version_doesnt_conflict_with_any_cargo_locks( + shader_crate_path: &std::path::Path, + channel: &str, + is_force_overwrite_lockfiles_v4_to_v3: bool, + ) -> anyhow::Result> { + log::debug!("Ensuring no v3/v4 `Cargo.lock` conflicts from shader's Rust..."); + let shader_rust_version = + query_rustc_version(Some(channel)).context("getting rustc version")?; + if shader_rust_version >= RUST_VERSION_THAT_USES_V4_CARGO_LOCKS { + log::debug!("shader's Rust is v{shader_rust_version}, so no v3/v4 conflicts possible."); + return Ok(None); + } + + log::debug!( + "shader's Rust is v{shader_rust_version}, so checking both shader and workspace `Cargo.lock` manifest versions..." + ); + + if shader_crate_path.join("Cargo.lock").exists() { + // Note that we don't return the `Cargo.lock` here (so that it's marked for reversion + // after the build), because we can be sure that updating it now is actually updating it + // to the state it should have been all along. Therefore it doesn't need reverting once + // fixed. + Self::handle_conflicting_cargo_lock_v4( + shader_crate_path, + is_force_overwrite_lockfiles_v4_to_v3, + ) + .context("handling v4/v3 conflict")?; + } + + if let Some(workspace_root) = + Self::get_workspace_root(shader_crate_path).context("reading workspace root")? + { + Self::handle_conflicting_cargo_lock_v4( + workspace_root, + is_force_overwrite_lockfiles_v4_to_v3, + ) + .context("handling conflicting cargo v4")?; + return Ok(Some(workspace_root.join("Cargo.lock"))); + } + + Ok(None) + } + + /// Get the path to the shader crate's workspace, if it has one. We can't use the traditional + /// `cargo metadata` because if the workspace has a conflicting `Cargo.lock` manifest version + /// then that command won't work. Instead we do an old school recursive file tree walk. + fn get_workspace_root( + shader_crate_path: &std::path::Path, + ) -> anyhow::Result> { + let shader_cargo_toml = std::fs::read_to_string(shader_crate_path.join("Cargo.toml")) + .with_context(|| format!("reading Cargo.toml at {}", shader_crate_path.display()))?; + if !shader_cargo_toml.contains("workspace = true") { + return Ok(None); + } + + let mut current_path = shader_crate_path; + #[expect(clippy::default_numeric_fallback, reason = "It's just a loop")] + for _ in 0..15 { + if let Some(parent_path) = current_path.parent() { + if parent_path.join("Cargo.lock").exists() { + return Ok(Some(parent_path)); + } + current_path = parent_path; + } else { + break; + } + } + + Ok(None) + } + + /// When Rust < 1.83.0 is being used an error will occur if it tries to parse `Cargo.lock` + /// files that use lockfile manifest version 4. Here we check and handle that. + fn handle_conflicting_cargo_lock_v4( + folder: &std::path::Path, + is_force_overwrite_lockfiles_v4_to_v3: bool, + ) -> anyhow::Result<()> { + let shader_cargo_lock_path = folder.join("Cargo.lock"); + let shader_cargo_lock = std::fs::read_to_string(shader_cargo_lock_path.clone()) + .context("reading shader cargo lock")?; + let third_line = shader_cargo_lock.lines().nth(2).context("no third line")?; + if third_line.contains("version = 4") { + Self::handle_v3v4_conflict( + &shader_cargo_lock_path, + is_force_overwrite_lockfiles_v4_to_v3, + ) + .context("handling v4/v3 conflict")?; + return Ok(()); + } + if third_line.contains("version = 3") { + return Ok(()); + } + anyhow::bail!( + "Unrecognized `Cargo.lock` manifest version at: {}", + folder.display() + ) + } + + /// Handle conflicting `Cargo.lock` manifest versions by either overwriting the manifest + /// version or exiting with advice on how to handle the conflict. + fn handle_v3v4_conflict( + offending_cargo_lock: &std::path::Path, + is_force_overwrite_lockfiles_v4_to_v3: bool, + ) -> anyhow::Result<()> { + if !is_force_overwrite_lockfiles_v4_to_v3 { + Self::exit_with_v3v4_hack_suggestion(); + } + + Self::replace_cargo_lock_manifest_version(offending_cargo_lock, "4", "3") + .context("replacing version 4 -> 3")?; + + Ok(()) + } + + /// Once all install and builds have completed put their manifest versions back to how they + /// were. + pub fn revert_cargo_lock_manifest_versions(&self) -> anyhow::Result<()> { + for offending_cargo_lock in &self.cargo_lock_files_with_changed_manifest_versions { + log::debug!("Reverting: {}", offending_cargo_lock.display()); + Self::replace_cargo_lock_manifest_version(offending_cargo_lock, "3", "4") + .context("replacing version 3 -> 4")?; + } + + Ok(()) + } + + /// Replace the manifest version, eg `version = 4`, in a `Cargo.lock` file. + fn replace_cargo_lock_manifest_version( + offending_cargo_lock: &std::path::Path, + from_version: &str, + to_version: &str, + ) -> anyhow::Result<()> { + log::warn!( + "Replacing manifest version 'version = {}' with 'version = {}' in: {}", + from_version, + to_version, + offending_cargo_lock.display() + ); + let old_contents = std::fs::read_to_string(offending_cargo_lock) + .context("reading offending Cargo.lock")?; + let new_contents = old_contents.replace( + &format!("\nversion = {from_version}\n"), + &format!("\nversion = {to_version}\n"), + ); + + let mut file = std::fs::OpenOptions::new() + .write(true) + .truncate(true) + .open(offending_cargo_lock) + .context("opening offending Cargo.lock")?; + file.write_all(new_contents.as_bytes())?; + + Ok(()) + } + + /// Exit and give the user advice on how to deal with the infamous v3/v4 Cargo lockfile version + /// problem. + #[expect(clippy::non_ascii_literal, reason = "It's CLI output")] + fn exit_with_v3v4_hack_suggestion() { + crate::user_output!( + "Conflicting `Cargo.lock` versions detected ⚠️\n\ + Because `cargo gpu` uses a dedicated Rust toolchain for compiling shaders\n\ + it's possible that the `Cargo.lock` manifest version of the shader crate\n\ + does not match the `Cargo.lock` manifest version of the workspace. This is\n\ + due to a change in the defaults introduced in Rust 1.83.0.\n\ + \n\ + One way to resolve this is to force the workspace to use the same version\n\ + of Rust as required by the shader. However that is not often ideal or even\n\ + possible. Another way is to exlude the shader from the workspace. This is\n\ + also not ideal if you have many shaders sharing config from the workspace.\n\ + \n\ + Therefore `cargo gpu build/install` offers a workaround with the argument:\n\ + --force-overwrite-lockfiles-v4-to-v3\n\ + \n\ + See `cargo gpu build --help` for more information.\n\ + " + ); + std::process::exit(1); + } +} + +impl Drop for LockfileMismatchHandler { + fn drop(&mut self) { + let result = self.revert_cargo_lock_manifest_versions(); + if let Err(error) = result { + log::error!("Couldn't revert some or all of the shader `Cargo.lock` files: {error}"); + } + } +} diff --git a/crates/cargo-gpu/src/main.rs b/crates/cargo-gpu/src/main.rs index 6997386..852766f 100644 --- a/crates/cargo-gpu/src/main.rs +++ b/crates/cargo-gpu/src/main.rs @@ -1,50 +1,48 @@ //! Rust GPU shader crate builder. //! -//! This program manages installations of `spirv-builder-cli` and `rustc_codegen_spirv`. -//! It uses these tools to compile Rust code into SPIR-V. +//! This program and library allows you to easily compile your rust-gpu shaders, +//! without requiring you to fix your entire project to a specific toolchain. //! //! # How it works //! -//! In order to build shader crates, we must invoke cargo/rustc with a special backend -//! that performs the SPIR-V code generation. This backend is a dynamic library known -//! by its project name `rustc_codegen_spirv`. The name of the artifact itself is -//! OS-dependent. +//! This program primarily manages installations of `rustc_codegen_spirv`, the +//! codegen backend of rust-gpu to generate SPIR-V shader binaries. The codegen +//! backend builds on internal, ever-changing interfaces of rustc, which requires +//! fixing a version of rust-gpu to a specific version of the rustc compiler. +//! Usually, this would require you to fix your entire project to that specific +//! toolchain, but this project loosens that requirement by managing installations +//! of `rustc_codegen_spirv` and their associated toolchains for you. //! -//! There are a lot of special flags to wrangle and so we use a command line program -//! that wraps `cargo` to perform the building of shader crates. This cli program is -//! called `spirv-builder-cli`, which itself is a cli wrapper around the `spirv-builder` -//! library. +//! We continue to use rust-gpu's `spirv_builder` crate to pass the many additional +//! parameters required to configure rustc and our codegen backend, but provide you +//! with a toolchain agnostic version that you may use from stable rustc. And a +//! `cargo gpu` cmdline utility to simplify shader building even more. //! //! ## Where the binaries are //! -//! `cargo-gpu` maintains different versions `spirv-builder-cli` and `rustc_codegen_spirv` -//! in a cache dir. The location is OS-dependent, for example on macOS it's in -//! `~/Library/Caches/rust-gpu`. Specific versions live inside the cache dir, prefixed -//! by their `spirv-builder` cargo dependency and rust toolchain pair. +//! We store our prebuild `rustc_spirv_builder` binaries in the default cache +//! directory of your OS: +//! * Windows: `C:/users//AppData/Local/rust-gpu` +//! * Mac: `~/Library/Caches/rust-gpu` +//! * Linux: `~/.cache/rust-gpu` //! -//! Building a specific "binary pair" of `spirv-builder-cli` and `rustc_codegen_spirv` -//! happens when there is no existing pair that matches the computed prefix, or if -//! a force rebuild is specified on the command line. +//! ## How we build the backend //! -//! ## Building the "binary pairs" -//! -//! The source of `spirv-builder-cli` lives alongside this source file, in crate that -//! is not included in the workspace. That same source code is also included statically -//! in **this** source file. -//! -//! When `spirv-builder-cli` needs to be built, a new directory is created in the cache -//! where the source to `spirv-builder-cli` is copied into, containing the specific cargo -//! dependency for `spirv-builder` and the matching rust toolchain channel. -//! -//! Then `cargo` is invoked in that cache directory to build the pair of artifacts, which -//! are then put into the top level of that cache directory. -//! -//! This pair of artifacts is then used to build shader crates. +//! * retrieve the version of rust-gpu you want to use based on the version of the +//! `spirv-std` dependency in your shader crate. +//! * create a dummy project at `/codegen//` that depends on +//! `rustc_codegen_spirv` +//! * use `cargo metadata` to `cargo update` the dummy project, which downloads the +//! `rustc_codegen_spirv` crate into cargo's cache, and retrieve the path to the +//! download location. +//! * search for the required toolchain in `build.rs` of `rustc_codegen_spirv` +//! * build it with the required toolchain version +//! * copy out the binary and clean the target dir //! //! ## Building shader crates //! //! `cargo-gpu` takes a path to a shader crate to build, as well as a path to a directory -//! to put the compiled `spv` source files. It also takes a path to an output mainifest +//! to put the compiled `spv` source files. It also takes a path to an output manifest //! file where all shader entry points will be mapped to their `spv` source files. This //! manifest file can be used by build scripts (`build.rs` files) to generate linkage or //! conduct other post-processing, like converting the `spv` files into `wgsl` files, @@ -57,12 +55,15 @@ use clap::Parser as _; use install::Install; use show::Show; +mod args; mod build; mod config; mod install; +mod install_toolchain; +mod linkage; +mod lockfile; mod metadata; mod show; -mod spirv_cli; mod spirv_source; /// Central function to write to the user. @@ -163,10 +164,10 @@ fn run() -> anyhow::Result<()> { #[derive(clap::Subcommand)] enum Command { /// Install rust-gpu compiler artifacts. - Install(Install), + Install(Box), /// Compile a shader crate to SPIR-V. - Build(Build), + Build(Box), /// Show some useful values. Show(Show), diff --git a/crates/cargo-gpu/src/metadata.rs b/crates/cargo-gpu/src/metadata.rs index 0d6b164..0b330fb 100644 --- a/crates/cargo-gpu/src/metadata.rs +++ b/crates/cargo-gpu/src/metadata.rs @@ -1,5 +1,6 @@ //! Get config from the shader crate's `Cargo.toml` `[*.metadata.rust-gpu.*]` +use cargo_metadata::MetadataCommand; use serde_json::Value; /// `Metadata` refers to the `[metadata.*]` section of `Cargo.toml` that `cargo` formally @@ -15,43 +16,23 @@ impl Metadata { /// First we generate the CLI arg defaults as JSON. Then on top of those we merge any config /// from the workspace `Cargo.toml`, then on top of those we merge any config from the shader /// crate's `Cargo.toml`. - pub fn as_json(path: &std::path::PathBuf) -> anyhow::Result { + pub fn as_json(path: &std::path::PathBuf) -> anyhow::Result { let cargo_json = Self::get_cargo_toml_as_json(path)?; let config = Self::merge_configs(&cargo_json, path)?; Ok(config) } - /// Convert JSON keys from kebab case to snake case. Eg: `a-b` to `a_b`. - /// - /// Detection of keys for serde deserialization must match the case in the Rust structs. - /// However clap defaults to detecting CLI args in kebab case. So here we do the conversion. - fn keys_to_snake_case(json: &mut serde_json::Value) { - let serde_json::Value::Object(object) = json else { - return; - }; - - *object = core::mem::take(object) - .into_iter() - .map(|(key, mut value)| { - if let serde_json::Value::Object(_) = value { - Self::keys_to_snake_case(&mut value); - } - (key.replace('-', "_"), value) - }) - .collect(); - } - /// Merge the various source of config: defaults, workspace and shader crate. fn merge_configs( - cargo_json: &serde_json::Value, + cargo_json: &cargo_metadata::Metadata, path: &std::path::Path, - ) -> anyhow::Result { + ) -> anyhow::Result { let mut metadata = crate::config::Config::defaults_as_json()?; crate::config::Config::json_merge( &mut metadata, { log::debug!("looking for workspace metadata"); - let ws_meta = Self::get_workspace_metadata(cargo_json); + let ws_meta = Self::get_rust_gpu_from_metadata(&cargo_json.workspace_metadata); log::trace!("workspace_metadata: {ws_meta:#?}"); ws_meta }, @@ -64,7 +45,7 @@ impl Metadata { let mut crate_meta = Self::get_crate_metadata(cargo_json, path)?; log::trace!("crate_metadata: {crate_meta:#?}"); if let Some(output_path) = crate_meta.pointer_mut("/build/output_dir") { - log::debug!("found output-dir path in crate metadata: {:?}", output_path); + log::debug!("found output-dir path in crate metadata: {output_path:?}"); if let Some(output_dir) = output_path.clone().as_str() { let new_output_path = path.join(output_dir); *output_path = Value::String(format!("{}", new_output_path.display())); @@ -83,76 +64,59 @@ impl Metadata { } /// Convert a `Cargo.toml` to JSON - // - // TODO: reuse for getting the default `rust-gpu` source and toolchain. - fn get_cargo_toml_as_json(path: &std::path::PathBuf) -> anyhow::Result { - let cargo_toml_path = path.join("Cargo.toml"); - if !cargo_toml_path.exists() { - anyhow::bail!("{path:?} must be a shader crate directory"); - } - - log::debug!("Querying Cargo metadata for {cargo_toml_path:?}"); - let output_cargo = std::process::Command::new("cargo") - .args([ - "metadata", - "--no-deps", - "--manifest-path", - cargo_toml_path.display().to_string().as_ref(), - ]) - .output()?; - anyhow::ensure!( - output_cargo.status.success(), - "could not run `cargo metadata` on {cargo_toml_path:?}" - ); - - Ok(serde_json::from_slice(&output_cargo.stdout)?) - } - - /// Get any `rust-gpu` metadata set in the root workspace `Cargo.toml` - fn get_workspace_metadata(json: &serde_json::Value) -> serde_json::Value { - let empty_json_object = serde_json::json!({}); - let mut metadata = json - .pointer("/metadata/rust-gpu") - .unwrap_or(&empty_json_object) - .clone(); - - Self::keys_to_snake_case(&mut metadata); - metadata.clone() + fn get_cargo_toml_as_json( + path: &std::path::PathBuf, + ) -> anyhow::Result { + Ok(MetadataCommand::new().current_dir(path).exec()?) } /// Get any `rust-gpu` metadata set in the crate's `Cargo.toml` fn get_crate_metadata( - json: &serde_json::Value, + json: &cargo_metadata::Metadata, path: &std::path::Path, - ) -> anyhow::Result { - let empty_json_object = serde_json::json!({}); - if let Some(serde_json::Value::Array(packages)) = json.pointer("/packages") { - for package in packages { - if let Some(serde_json::Value::String(manifest_path_dirty)) = - package.pointer("/manifest_path") - { - let mut shader_crate_path = std::fs::canonicalize(path)? - .join("Cargo.toml") - .display() - .to_string(); - - // Windows prefixs paths with `\\?\` - shader_crate_path = shader_crate_path.replace(r"\\?\", ""); - let manifest_path = manifest_path_dirty.replace(r"\\?\", ""); - log::debug!("Matching shader crate path with manifest path: {shader_crate_path} == {manifest_path}?"); - if manifest_path == shader_crate_path { - log::debug!("...matches! Getting metadata"); - let mut metadata = package - .pointer("/metadata/rust-gpu") - .unwrap_or(&empty_json_object) - .clone(); - Self::keys_to_snake_case(&mut metadata); - return Ok(metadata); - } - } + ) -> anyhow::Result { + let shader_crate_path = std::fs::canonicalize(path)?.join("Cargo.toml"); + + for package in &json.packages { + let manifest_path = std::fs::canonicalize(package.manifest_path.as_std_path())?; + log::debug!( + "Matching shader crate path with manifest path: '{}' == '{}'?", + shader_crate_path.display(), + manifest_path.display() + ); + if manifest_path == shader_crate_path { + log::debug!("...matches! Getting metadata"); + return Ok(Self::get_rust_gpu_from_metadata(&package.metadata)); } } - Ok(empty_json_object) + Ok(serde_json::json!({})) + } + + /// Get `rust-gpu` value from some metadata + fn get_rust_gpu_from_metadata(metadata: &Value) -> Value { + Self::keys_to_snake_case( + metadata + .pointer("/rust-gpu") + .cloned() + .unwrap_or(Value::Null), + ) + } + + /// Convert JSON keys from kebab case to snake case. Eg: `a-b` to `a_b`. + /// + /// Detection of keys for serde deserialization must match the case in the Rust structs. + /// However clap defaults to detecting CLI args in kebab case. So here we do the conversion. + #[expect(clippy::wildcard_enum_match_arm, reason = "we only want objects")] + fn keys_to_snake_case(json: Value) -> Value { + match json { + Value::Object(object) => Value::Object( + object + .into_iter() + .map(|(key, value)| (key.replace('-', "_"), Self::keys_to_snake_case(value))) + .collect(), + ), + other => other, + } } } @@ -163,59 +127,73 @@ impl Metadata { #[cfg(test)] mod test { use super::*; + use std::path::Path; #[test_log::test] fn generates_defaults() { - let json = serde_json::json!({}); - let configs = Metadata::merge_configs(&json, std::path::Path::new("./")).unwrap(); - assert_eq!(configs["build"]["debug"], serde_json::Value::Bool(false)); + let mut metadata = MetadataCommand::new() + .current_dir(env!("CARGO_MANIFEST_DIR")) + .exec() + .unwrap(); + metadata.packages.first_mut().unwrap().metadata = serde_json::json!({}); + let configs = Metadata::merge_configs(&metadata, Path::new("./")).unwrap(); + assert_eq!(configs["build"]["release"], Value::Bool(true)); assert_eq!( configs["install"]["auto_install_rust_toolchain"], - serde_json::Value::Bool(false) + Value::Bool(false) ); } #[test_log::test] fn can_override_config_from_workspace_toml() { - let json = serde_json::json!( - { "metadata": { "rust-gpu": { + let mut metadata = MetadataCommand::new() + .current_dir(env!("CARGO_MANIFEST_DIR")) + .exec() + .unwrap(); + metadata.workspace_metadata = serde_json::json!({ + "rust-gpu": { "build": { - "debug": true + "release": false }, "install": { "auto-install-rust-toolchain": true } - }}} - ); - let configs = Metadata::merge_configs(&json, std::path::Path::new("./")).unwrap(); - assert_eq!(configs["build"]["debug"], serde_json::Value::Bool(true)); + } + }); + let configs = Metadata::merge_configs(&metadata, Path::new("./")).unwrap(); + assert_eq!(configs["build"]["release"], Value::Bool(false)); assert_eq!( configs["install"]["auto_install_rust_toolchain"], - serde_json::Value::Bool(true) + Value::Bool(true) ); } #[test_log::test] fn can_override_config_from_crate_toml() { - let marker = std::path::Path::new("./Cargo.toml"); - let json = serde_json::json!( - { "packages": [{ - "metadata": { "rust-gpu": { - "build": { - "debug": true - }, - "install": { - "auto-install-rust-toolchain": true - } - }}, - "manifest_path": std::fs::canonicalize(marker).unwrap() - }]} - ); - let configs = Metadata::merge_configs(&json, marker.parent().unwrap()).unwrap(); - assert_eq!(configs["build"]["debug"], serde_json::Value::Bool(true)); + let mut metadata = MetadataCommand::new() + .current_dir(env!("CARGO_MANIFEST_DIR")) + .exec() + .unwrap(); + let cargo_gpu = metadata + .packages + .iter_mut() + .find(|package| package.name.contains("cargo-gpu")) + .unwrap(); + cargo_gpu.metadata = serde_json::json!({ + "rust-gpu": { + "build": { + "release": false + }, + "install": { + "auto-install-rust-toolchain": true + } + } + }); + let configs = Metadata::merge_configs(&metadata, Path::new(".")).unwrap(); + assert_eq!(configs["build"]["release"], Value::Bool(false)); assert_eq!( configs["install"]["auto_install_rust_toolchain"], - serde_json::Value::Bool(true) + Value::Bool(true) ); } } diff --git a/crates/cargo-gpu/src/show.rs b/crates/cargo-gpu/src/show.rs index 61202cb..3b0e2f8 100644 --- a/crates/cargo-gpu/src/show.rs +++ b/crates/cargo-gpu/src/show.rs @@ -19,7 +19,7 @@ pub enum Info { SpirvSource(SpirvSourceDep), /// The git commitsh of this cli tool. Commitsh, - /// All the available SPIR-V capabilities that can be set with `--capability` + /// All the available SPIR-V capabilities that can be set with `--capabilities` Capabilities, } @@ -47,16 +47,14 @@ impl Show { } Info::SpirvSource(SpirvSourceDep { shader_crate }) => { let rust_gpu_source = - crate::spirv_source::SpirvSource::get_spirv_std_dep_definition(&shader_crate)?; - { - println!("{rust_gpu_source}\n"); - } + crate::spirv_source::SpirvSource::get_rust_gpu_deps_from_shader(&shader_crate)?; + println!("{rust_gpu_source}\n"); } Info::Commitsh => { println!("{}", std::env!("GIT_HASH")); } Info::Capabilities => { - println!("All available options to the `cargo gpu build --capability` argument:"); + println!("All available options to the `cargo gpu build --capabilities` argument:"); #[expect( clippy::use_debug, reason = "It's easier to just use `Debug` formatting than implementing `Display`" @@ -71,11 +69,11 @@ impl Show { } /// Iterator over all `Capability` variants. - fn capability_variants_iter() -> impl Iterator { + fn capability_variants_iter() -> impl Iterator { // Since spirv::Capability is repr(u32) we can iterate over // u32s until some maximum #[expect(clippy::as_conversions, reason = "We know all variants are repr(u32)")] - let last_capability = spirv_builder_cli::spirv::Capability::CacheControlsINTEL as u32; - (0..=last_capability).filter_map(spirv_builder_cli::spirv::Capability::from_u32) + let last_capability = spirv_builder::Capability::CacheControlsINTEL as u32; + (0..=last_capability).filter_map(spirv_builder::Capability::from_u32) } } diff --git a/crates/cargo-gpu/src/spirv_cli.rs b/crates/cargo-gpu/src/spirv_cli.rs deleted file mode 100644 index 8a905d1..0000000 --- a/crates/cargo-gpu/src/spirv_cli.rs +++ /dev/null @@ -1,512 +0,0 @@ -//! Query the shader crate to find what version of `rust-gpu` it depends on. -//! Then ensure that the relevant Rust toolchain and components are installed. - -use std::io::Write as _; - -use anyhow::Context as _; - -use crate::spirv_source::SpirvSource; - -/// `Cargo.lock` manifest version 4 became the default in Rust 1.83.0. Conflicting manifest -/// versions between the workspace and the shader crate, can cause problems. -const RUST_VERSION_THAT_USES_V4_CARGO_LOCKS: &str = "1.83.0"; - -/// Cargo dependency for `spirv-builder` and the rust toolchain channel. -#[derive(Debug, Clone)] -pub struct SpirvCli { - #[expect( - clippy::doc_markdown, - reason = "The URL should appear literally like this. But Clippy wants it to be a in markdown clickable link" - )] - /// The source and version of `rust-gpu`. - /// Eg: - /// * From crates.io with version "0.10.0" - /// * From Git with: - /// - a repo of "https://github.com/Rust-GPU/rust-gpu.git" - /// - a revision of "abc213" - pub source: SpirvSource, - /// The toolchain channel that `rust-gpu` uses, eg "nightly-2024-04-24" - pub channel: String, - /// The date of the pinned version of `rust-gpu` - pub date: chrono::NaiveDate, - /// `Cargo.lock`s that have had their manifest versions changed by us and need changing back. - pub cargo_lock_files_with_changed_manifest_versions: Vec, - /// Has the user overridden the toolchain consent prompt - is_toolchain_install_consent: bool, -} - -impl core::fmt::Display for SpirvCli { - #[expect( - clippy::min_ident_chars, - reason = "It's a core library trait implementation" - )] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - format!("{}+{}", self.source, self.channel).fmt(f) - } -} - -impl SpirvCli { - /// Create instance - pub fn new( - shader_crate_path: &std::path::Path, - maybe_rust_gpu_source: Option, - maybe_rust_gpu_version: Option, - maybe_rust_gpu_channel: Option, - is_toolchain_install_consent: bool, - is_force_overwrite_lockfiles_v4_to_v3: bool, - ) -> anyhow::Result { - let mut cargo_lock_files_with_changed_manifest_versions = vec![]; - - let maybe_shader_crate_lock = - Self::ensure_workspace_rust_version_doesnt_conflict_with_shader( - shader_crate_path, - is_force_overwrite_lockfiles_v4_to_v3, - ) - .context("ensure_workspace_rust_version_doesnt_conflict_with_shader")?; - - if let Some(shader_crate_lock) = maybe_shader_crate_lock { - cargo_lock_files_with_changed_manifest_versions.push(shader_crate_lock); - } - - let (default_rust_gpu_source, rust_gpu_date, default_rust_gpu_channel) = - SpirvSource::get_rust_gpu_deps_from_shader(shader_crate_path) - .context("get_rust_gpu_deps_from_shader")?; - - let maybe_workspace_crate_lock = - Self::ensure_shader_rust_version_doesnt_conflict_with_any_cargo_locks( - shader_crate_path, - default_rust_gpu_channel.clone(), - is_force_overwrite_lockfiles_v4_to_v3, - ) - .context("ensure_shader_rust_version_doesnt_conflict_with_any_cargo_locks")?; - - if let Some(workspace_crate_lock) = maybe_workspace_crate_lock { - cargo_lock_files_with_changed_manifest_versions.push(workspace_crate_lock); - } - - let mut maybe_spirv_source: Option = None; - if let Some(rust_gpu_version) = maybe_rust_gpu_version { - let mut source = SpirvSource::CratesIO(rust_gpu_version.clone()); - if let Some(rust_gpu_source) = maybe_rust_gpu_source { - source = SpirvSource::Git { - url: rust_gpu_source, - rev: rust_gpu_version, - }; - } - maybe_spirv_source = Some(source); - } - - Ok(Self { - source: maybe_spirv_source.unwrap_or(default_rust_gpu_source), - channel: maybe_rust_gpu_channel.unwrap_or(default_rust_gpu_channel), - date: rust_gpu_date, - is_toolchain_install_consent, - cargo_lock_files_with_changed_manifest_versions, - }) - } - - /// Create and/or return the cache directory - pub fn cached_checkout_path(&self) -> anyhow::Result { - let checkout_dir = crate::cache_dir() - .context("reading cache dir")? - .join("spirv-builder-cli") - .join(crate::to_dirname(self.to_string().as_ref())); - std::fs::create_dir_all(&checkout_dir) - .with_context(|| format!("could not create checkout dir '{}'", checkout_dir.display())) - .context("crating directory in cahce dir")?; - - Ok(checkout_dir) - } - - /// Use `rustup` to install the toolchain and components, if not already installed. - /// - /// Pretty much runs: - /// - /// * rustup toolchain add nightly-2024-04-24 - /// * rustup component add --toolchain nightly-2024-04-24 rust-src rustc-dev llvm-tools - pub fn ensure_toolchain_and_components_exist(&self) -> anyhow::Result<()> { - // Check for the required toolchain - let output_toolchain_list = std::process::Command::new("rustup") - .args(["toolchain", "list"]) - .output() - .context("running rustup command")?; - anyhow::ensure!( - output_toolchain_list.status.success(), - "could not list installed toolchains" - ); - let string_toolchain_list = String::from_utf8_lossy(&output_toolchain_list.stdout); - if string_toolchain_list - .split_whitespace() - .any(|toolchain| toolchain.starts_with(&self.channel)) - { - log::debug!("toolchain {} is already installed", self.channel); - } else { - let message = format!("Rust {} with `rustup`", self.channel); - self.get_consent_for_toolchain_install(format!("Install {message}").as_ref())?; - crate::user_output!("Installing {message}\n"); - - let output_toolchain_add = std::process::Command::new("rustup") - .args(["toolchain", "add"]) - .arg(&self.channel) - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) - .output() - .context("adding toolchain")?; - anyhow::ensure!( - output_toolchain_add.status.success(), - "could not install required toolchain" - ); - } - - // Check for the required components - let output_component_list = std::process::Command::new("rustup") - .args(["component", "list", "--toolchain"]) - .arg(&self.channel) - .output() - .context("getting toolchain list")?; - anyhow::ensure!( - output_component_list.status.success(), - "could not list installed components" - ); - let string_component_list = String::from_utf8_lossy(&output_component_list.stdout); - let required_components = ["rust-src", "rustc-dev", "llvm-tools"]; - let installed_components = string_component_list.lines().collect::>(); - let all_components_installed = required_components.iter().all(|component| { - installed_components.iter().any(|installed_component| { - let is_component = installed_component.starts_with(component); - let is_installed = installed_component.ends_with("(installed)"); - is_component && is_installed - }) - }); - if all_components_installed { - log::debug!("all required components are installed"); - } else { - let message = "toolchain components (rust-src, rustc-dev, llvm-tools) with `rustup`"; - self.get_consent_for_toolchain_install(format!("Install {message}").as_ref())?; - crate::user_output!("Installing {message}\n"); - - let output_component_add = std::process::Command::new("rustup") - .args(["component", "add", "--toolchain"]) - .arg(&self.channel) - .args(["rust-src", "rustc-dev", "llvm-tools"]) - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) - .output() - .context("adding rustup component")?; - anyhow::ensure!( - output_component_add.status.success(), - "could not install required components" - ); - } - - Ok(()) - } - - /// Prompt user if they want to install a new Rust toolchain. - fn get_consent_for_toolchain_install(&self, prompt: &str) -> anyhow::Result<()> { - if self.is_toolchain_install_consent { - return Ok(()); - } - log::debug!("asking for consent to install the required toolchain"); - crossterm::terminal::enable_raw_mode().context("enabling raw mode")?; - crate::user_output!("{prompt} [y/n]: \n"); - let mut input = crossterm::event::read().context("reading crossterm event")?; - - if let crossterm::event::Event::Key(crossterm::event::KeyEvent { - code: crossterm::event::KeyCode::Enter, - kind: crossterm::event::KeyEventKind::Release, - .. - }) = input - { - // In Powershell, programs will potentially observe the Enter key release after they started - // (see crossterm#124). If that happens, re-read the input. - input = crossterm::event::read().context("re-reading crossterm event")?; - } - crossterm::terminal::disable_raw_mode().context("disabling raw mode")?; - - if let crossterm::event::Event::Key(crossterm::event::KeyEvent { - code: crossterm::event::KeyCode::Char('y'), - .. - }) = input - { - Ok(()) - } else { - crate::user_output!("Exiting...\n"); - std::process::exit(0); - } - } - - /// See docs for `force_overwrite_lockfiles_v4_to_v3` flag for why we do this. - fn ensure_workspace_rust_version_doesnt_conflict_with_shader( - shader_crate_path: &std::path::Path, - is_force_overwrite_lockfiles_v4_to_v3: bool, - ) -> anyhow::Result> { - log::debug!("Ensuring no v3/v4 `Cargo.lock` conflicts from workspace Rust..."); - let workspace_rust_version = - Self::get_rustc_version(None).context("reading rustc version")?; - if version_check::Version::at_least( - &workspace_rust_version, - RUST_VERSION_THAT_USES_V4_CARGO_LOCKS, - ) { - log::debug!( - "user's Rust is v{}, so no v3/v4 conflicts possible.", - workspace_rust_version - ); - return Ok(None); - } - - Self::handle_conflicting_cargo_lock_v4( - shader_crate_path, - is_force_overwrite_lockfiles_v4_to_v3, - ) - .context("handling v4/v3 conflict")?; - - if is_force_overwrite_lockfiles_v4_to_v3 { - Ok(Some(shader_crate_path.join("Cargo.lock"))) - } else { - Ok(None) - } - } - - /// See docs for `force_overwrite_lockfiles_v4_to_v3` flag for why we do this. - fn ensure_shader_rust_version_doesnt_conflict_with_any_cargo_locks( - shader_crate_path: &std::path::Path, - channel: String, - is_force_overwrite_lockfiles_v4_to_v3: bool, - ) -> anyhow::Result> { - log::debug!("Ensuring no v3/v4 `Cargo.lock` conflicts from shader's Rust..."); - let shader_rust_version = - Self::get_rustc_version(Some(channel)).context("getting rustc version")?; - if version_check::Version::at_least( - &shader_rust_version, - RUST_VERSION_THAT_USES_V4_CARGO_LOCKS, - ) { - log::debug!( - "shader's Rust is v{}, so no v3/v4 conflicts possible.", - shader_rust_version - ); - return Ok(None); - } - - log::debug!( - "shader's Rust is v{}, so checking both shader and workspace `Cargo.lock` manifest versions...", - shader_rust_version - ); - - if shader_crate_path.join("Cargo.lock").exists() { - // Note that we don't return the `Cargo.lock` here (so that it's marked for reversion - // after the build), because we can be sure that updating it now is actually updating it - // to the state it should have been all along. Therefore it doesn't need reverting once - // fixed. - Self::handle_conflicting_cargo_lock_v4( - shader_crate_path, - is_force_overwrite_lockfiles_v4_to_v3, - ) - .context("handling v4/v3 conflict")?; - } - - if let Some(workspace_root) = - Self::get_workspace_root(shader_crate_path).context("reading workspace root")? - { - Self::handle_conflicting_cargo_lock_v4( - workspace_root, - is_force_overwrite_lockfiles_v4_to_v3, - ) - .context("handling conflicting cargo v4")?; - return Ok(Some(workspace_root.join("Cargo.lock"))); - } - - Ok(None) - } - - /// Get the path to the shader crate's workspace, if it has one. We can't use the traditional - /// `cargo metadata` because if the workspace has a conflicting `Cargo.lock` manifest version - /// then that command won't work. Instead we do an old school recursive file tree walk. - fn get_workspace_root( - shader_crate_path: &std::path::Path, - ) -> anyhow::Result> { - let shader_cargo_toml = std::fs::read_to_string(shader_crate_path.join("Cargo.toml")) - .with_context(|| format!("reading Cargo.toml at {}", shader_crate_path.display()))?; - if !shader_cargo_toml.contains("workspace = true") { - return Ok(None); - } - - let mut current_path = shader_crate_path; - #[expect(clippy::default_numeric_fallback, reason = "It's just a loop")] - for _ in 0..15 { - if let Some(parent_path) = current_path.parent() { - if parent_path.join("Cargo.lock").exists() { - return Ok(Some(parent_path)); - } - current_path = parent_path; - } else { - break; - } - } - - Ok(None) - } - - /// When Rust < 1.83.0 is being used an error will occur if it tries to parse `Cargo.lock` - /// files that use lockfile manifest version 4. Here we check and handle that. - fn handle_conflicting_cargo_lock_v4( - folder: &std::path::Path, - is_force_overwrite_lockfiles_v4_to_v3: bool, - ) -> anyhow::Result<()> { - let shader_cargo_lock_path = folder.join("Cargo.lock"); - let shader_cargo_lock = std::fs::read_to_string(shader_cargo_lock_path.clone()) - .context("reading shader cargo lock")?; - let third_line = shader_cargo_lock.lines().nth(2).context("no third line")?; - if third_line.contains("version = 4") { - Self::handle_v3v4_conflict( - &shader_cargo_lock_path, - is_force_overwrite_lockfiles_v4_to_v3, - ) - .context("handling v4/v3 conflict")?; - return Ok(()); - } - if third_line.contains("version = 3") { - return Ok(()); - } - anyhow::bail!( - "Unrecognized `Cargo.lock` manifest version at: {}", - folder.display() - ) - } - - /// Handle conflicting `Cargo.lock` manifest versions by either overwriting the manifest - /// version or exiting with advice on how to handle the conflict. - fn handle_v3v4_conflict( - offending_cargo_lock: &std::path::Path, - is_force_overwrite_lockfiles_v4_to_v3: bool, - ) -> anyhow::Result<()> { - if !is_force_overwrite_lockfiles_v4_to_v3 { - Self::exit_with_v3v4_hack_suggestion(); - } - - Self::replace_cargo_lock_manifest_version(offending_cargo_lock, "4", "3") - .context("replacing version 4 -> 3")?; - - Ok(()) - } - - /// Once all install and builds have completed put their manifest versions back to how they - /// were. - pub fn revert_cargo_lock_manifest_versions(&self) -> anyhow::Result<()> { - for offending_cargo_lock in &self.cargo_lock_files_with_changed_manifest_versions { - log::debug!("Reverting: {}", offending_cargo_lock.display()); - Self::replace_cargo_lock_manifest_version(offending_cargo_lock, "3", "4") - .context("replacing version 3 -> 4")?; - } - - Ok(()) - } - - /// Replace the manifest version, eg `version = 4`, in a `Cargo.lock` file. - fn replace_cargo_lock_manifest_version( - offending_cargo_lock: &std::path::Path, - from_version: &str, - to_version: &str, - ) -> anyhow::Result<()> { - log::warn!( - "Replacing manifest version 'version = {}' with 'version = {}' in: {}", - from_version, - to_version, - offending_cargo_lock.display() - ); - let old_contents = std::fs::read_to_string(offending_cargo_lock) - .context("reading offending Cargo.lock")?; - let new_contents = old_contents.replace( - &format!("\nversion = {from_version}\n"), - &format!("\nversion = {to_version}\n"), - ); - - let mut file = std::fs::OpenOptions::new() - .write(true) - .truncate(true) - .open(offending_cargo_lock) - .context("opening offending Cargo.lock")?; - file.write_all(new_contents.as_bytes())?; - - Ok(()) - } - - /// Exit and give the user advice on how to deal with the infamous v3/v4 Cargo lockfile version - /// problem. - #[expect(clippy::non_ascii_literal, reason = "It's CLI output")] - fn exit_with_v3v4_hack_suggestion() { - crate::user_output!( - "Conflicting `Cargo.lock` versions detected ⚠️\n\ - Because `cargo gpu` uses a dedicated Rust toolchain for compiling shaders\n\ - it's possible that the `Cargo.lock` manifest version of the shader crate\n\ - does not match the `Cargo.lock` manifest version of the workspace. This is\n\ - due to a change in the defaults introduced in Rust 1.83.0.\n\ - \n\ - One way to resolve this is to force the workspace to use the same version\n\ - of Rust as required by the shader. However that is not often ideal or even\n\ - possible. Another way is to exlude the shader from the workspace. This is\n\ - also not ideal if you have many shaders sharing config from the workspace.\n\ - \n\ - Therefore `cargo gpu build/install` offers a workaround with the argument:\n\ - --force-overwrite-lockfiles-v4-to-v3\n\ - \n\ - See `cargo gpu build --help` for more information.\n\ - " - ); - std::process::exit(1); - } - - /// Get the version of `rustc`. - fn get_rustc_version( - maybe_toolchain: Option, - ) -> anyhow::Result { - let mut maybe_current_env_toolchain: Option = None; - if let Some(toolchain) = maybe_toolchain { - maybe_current_env_toolchain = std::env::var_os("RUSTUP_TOOLCHAIN"); - std::env::set_var("RUSTUP_TOOLCHAIN", toolchain); - } - - let Some(version) = version_check::Version::read() else { - anyhow::bail!("Couldn't get `rustc --version`"); - }; - - if let Some(current_env_toolchain) = maybe_current_env_toolchain { - std::env::set_var("RUSTUP_TOOLCHAIN", current_env_toolchain); - } - - Ok(version) - } -} - -impl Drop for SpirvCli { - fn drop(&mut self) { - let result = self.revert_cargo_lock_manifest_versions(); - if let Err(error) = result { - log::error!("Couldn't revert some or all of the shader `Cargo.lock` files: {error}"); - } - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test_log::test] - fn cached_checkout_dir_sanity() { - let shader_template_path = crate::test::shader_crate_template_path(); - // TODO: This downloads the `rust-gpu` repo which slows the test down. Can we avoid that - // just to get the sanity check? - let spirv = SpirvCli::new(&shader_template_path, None, None, None, true, false).unwrap(); - let dir = spirv.cached_checkout_path().unwrap(); - let name = dir - .file_name() - .unwrap() - .to_str() - .map(std::string::ToString::to_string) - .unwrap(); - assert_eq!( - "https___github_com_Rust-GPU_rust-gpu+82a0f69+nightly-2024-04-24", - &name - ); - } -} diff --git a/crates/cargo-gpu/src/spirv_source.rs b/crates/cargo-gpu/src/spirv_source.rs index c1815d6..32fde8d 100644 --- a/crates/cargo-gpu/src/spirv_source.rs +++ b/crates/cargo-gpu/src/spirv_source.rs @@ -5,20 +5,28 @@ //! From there we can look at the source code to get the required Rust toolchain. use anyhow::Context as _; - -/// The canonical `rust-gpu` URI -const RUST_GPU_REPO: &str = "https://github.com/Rust-GPU/rust-gpu"; - -/// The various sources that the `rust-gpu` repo can have. -/// Most commonly it will simply be the canonical version on crates.io. But it could also be the -/// Git version, or a fork. +use cargo_metadata::camino::{Utf8Path, Utf8PathBuf}; +use cargo_metadata::semver::Version; +use cargo_metadata::{MetadataCommand, Package}; +use std::fs; +use std::path::{Path, PathBuf}; + +#[expect( + clippy::doc_markdown, + reason = "The URL should appear literally like this. But Clippy wants a markdown clickable link" +)] +/// The source and version of `rust-gpu`. +/// Eg: +/// * From crates.io with version "0.10.0" +/// * From Git with: +/// - a repo of "https://github.com/Rust-GPU/rust-gpu.git" +/// - a revision of "abc213" +/// * a local Path #[derive(Eq, PartialEq, Clone, Debug)] pub enum SpirvSource { /// If the shader specifies a simple version like `spirv-std = "0.9.0"` then the source of /// `rust-gpu` is the conventional crates.io version. - /// - /// `String` is the simple version like, "0.9.0" - CratesIO(String), + CratesIO(Version), /// If the shader specifies a version like: /// `spirv-std = { git = "https://github.com..." ... }` /// then the source of `rust-gpu` is `Git`. @@ -31,7 +39,12 @@ pub enum SpirvSource { /// If the shader specifies a version like: /// `spirv-std = { path = "/path/to/rust-gpu" ... }` /// then the source of `rust-gpu` is `Path`. - Path((String, String)), + Path { + /// File path of rust-gpu repository + rust_gpu_repo_root: Utf8PathBuf, + /// Version of specified rust-gpu repository + version: Version, + }, } impl core::fmt::Display for SpirvSource { @@ -41,328 +54,190 @@ impl core::fmt::Display for SpirvSource { )] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - Self::CratesIO(version) => f.write_str(version), - Self::Git { url, rev } => f.write_str(&format!("{url}+{rev}")), - Self::Path((a, b)) => f.write_str(&format!("{a}+{b}")), + Self::CratesIO(version) => version.fmt(f), + Self::Git { url, rev } => { + // shorten rev to 8 chars, prevents windows compile errors due to too long paths... seriously + if let Some(short_rev) = rev.get(..8) { + write!(f, "{url}+{short_rev}") + } else { + write!(f, "{url}+{rev}") + } + } + Self::Path { + rust_gpu_repo_root, + version, + } => write!(f, "{rust_gpu_repo_root}+{version}"), } } } impl SpirvSource { - /// Look into the shader crate to get the version of `rust-gpu` it's using. - pub fn get_rust_gpu_deps_from_shader>( - shader_crate_path: F, - ) -> anyhow::Result<(Self, chrono::NaiveDate, String)> { - let rust_gpu_source = Self::get_spirv_std_dep_definition(shader_crate_path.as_ref())?; - rust_gpu_source.ensure_repo_is_installed()?; - rust_gpu_source.checkout()?; - - let date = rust_gpu_source.get_version_date()?; - let channel = Self::get_channel_from_toolchain_toml(&rust_gpu_source.to_dirname()?)?; + /// Figures out which source of `rust-gpu` to use + pub fn new( + shader_crate_path: &Path, + maybe_rust_gpu_source: Option<&str>, + maybe_rust_gpu_version: Option<&str>, + ) -> anyhow::Result { + let source = if let Some(rust_gpu_version) = maybe_rust_gpu_version { + if let Some(rust_gpu_source) = maybe_rust_gpu_source { + Self::Git { + url: rust_gpu_source.to_owned(), + rev: rust_gpu_version.to_owned(), + } + } else { + Self::CratesIO(Version::parse(rust_gpu_version)?) + } + } else { + Self::get_rust_gpu_deps_from_shader(shader_crate_path) + .context("get_rust_gpu_deps_from_shader")? + }; + Ok(source) + } + /// Look into the shader crate to get the version of `rust-gpu` it's using. + pub fn get_rust_gpu_deps_from_shader(shader_crate_path: &Path) -> anyhow::Result { + let spirv_std_package = get_package_from_crate(shader_crate_path, "spirv-std")?; + let spirv_source = Self::parse_spirv_std_source_and_version(&spirv_std_package)?; log::debug!( - "Parsed version, date and toolchain channel from shader-defined `rust-gpu`: \ - {rust_gpu_source:?}, {date}, {channel}" + "Parsed `SpirvSource` from crate `{}`: \ + {spirv_source:?}", + shader_crate_path.display(), ); - - Ok((rust_gpu_source, date, channel)) - } - - /// Convert the source to just its version. - pub fn to_version(&self) -> String { - match self { - Self::CratesIO(version) | Self::Path((_, version)) => version.to_string(), - Self::Git { rev, .. } => rev.to_string(), - } - } - - /// Convert the source to just its repo or path. - fn to_repo(&self) -> String { - match self { - Self::CratesIO(_) => RUST_GPU_REPO.to_owned(), - Self::Git { url, .. } => url.to_owned(), - Self::Path((path, _)) => path.to_owned(), - } + Ok(spirv_source) } - /// Convert the `rust-gpu` source into a string that can be used as a directory. + /// Convert the `SpirvSource` to a cache directory in which we can build it. /// It needs to be dynamically created because an end-user might want to swap out the source, /// maybe using their own fork for example. - fn to_dirname(&self) -> anyhow::Result { - let dir = crate::to_dirname(self.to_string().as_ref()); - Ok(crate::cache_dir()?.join("rust-gpu-repo").join(dir)) - } - - /// Make sure shader crate path is absolute and canonical. - fn shader_crate_path_canonical( - shader_crate_path: &mut std::path::PathBuf, - ) -> anyhow::Result<()> { - let cwd = std::env::current_dir().context("no cwd")?; - let mut canonical_path = shader_crate_path.clone(); - - if !canonical_path.is_absolute() { - canonical_path = cwd.join(canonical_path); - } - canonical_path - .canonicalize() - .context("could not get absolute path to shader crate")?; - - if !canonical_path.is_dir() { - log::error!("{shader_crate_path:?} is not a directory, aborting"); - anyhow::bail!("{shader_crate_path:?} is not a directory"); + pub fn install_dir(&self) -> anyhow::Result { + match self { + Self::Path { + rust_gpu_repo_root, .. + } => Ok(rust_gpu_repo_root.as_std_path().to_owned()), + Self::CratesIO { .. } | Self::Git { .. } => { + let dir = crate::to_dirname(self.to_string().as_ref()); + Ok(crate::cache_dir()?.join("codegen").join(dir)) + } } - - *shader_crate_path = canonical_path; - - Ok(()) - } - - /// Checkout the `rust-gpu` repo to the requested version. - fn checkout(&self) -> anyhow::Result<()> { - log::debug!( - "Checking out `rust-gpu` repo at {} to {}", - self.to_dirname()?.display(), - self.to_version() - ); - let output_checkout = std::process::Command::new("git") - .current_dir(self.to_dirname()?) - .args(["checkout", self.to_version().as_ref()]) - .output()?; - anyhow::ensure!( - output_checkout.status.success(), - "couldn't checkout revision '{}' of `rust-gpu` at {}", - self.to_version(), - self.to_dirname()?.to_string_lossy() - ); - - Ok(()) - } - - /// Get the date of the version of `rust-gpu` used by the shader. This allows us to know what - /// features we can use in the `spirv-builder` crate. - fn get_version_date(&self) -> anyhow::Result { - let date_format = "%Y-%m-%d"; - - log::debug!( - "Getting `rust-gpu` version date from {}", - self.to_dirname()?.display(), - ); - let output_date = std::process::Command::new("git") - .current_dir(self.to_dirname()?) - .args([ - "show", - "--no-patch", - "--format=%cd", - format!("--date=format:'{date_format}'").as_ref(), - self.to_version().as_ref(), - ]) - .output()?; - anyhow::ensure!( - output_date.status.success(), - "couldn't get `rust-gpu` version date at for {} at {}", - self.to_version(), - self.to_dirname()?.to_string_lossy() - ); - let date_string = String::from_utf8_lossy(&output_date.stdout) - .to_string() - .trim() - .replace('\'', ""); - - log::debug!( - "Parsed date for version {}: {date_string}", - self.to_version() - ); - - Ok(chrono::NaiveDate::parse_from_str( - &date_string, - date_format, - )?) - } - - /// Parse the `rust-toolchain.toml` in the working tree of the checked-out version of the `rust-gpu` repo. - fn get_channel_from_toolchain_toml(path: &std::path::PathBuf) -> anyhow::Result { - log::debug!("Parsing `rust-toolchain.toml` at {path:?} for the used toolchain"); - - let contents = std::fs::read_to_string(path.join("rust-toolchain.toml"))?; - let toml: toml::Table = toml::from_str(&contents)?; - let Some(toolchain) = toml.get("toolchain") else { - anyhow::bail!( - "Couldn't find `[toolchain]` section in `rust-toolchain.toml` at {path:?}" - ); - }; - let Some(channel) = toolchain.get("channel") else { - anyhow::bail!("Couldn't find `channel` field in `rust-toolchain.toml` at {path:?}"); - }; - - Ok(channel.to_string().replace('"', "")) - } - - /// Get the shader crate's resolved `spirv_std = ...` definition in its `Cargo.toml`/`Cargo.lock` - pub fn get_spirv_std_dep_definition( - shader_crate_path: &std::path::Path, - ) -> anyhow::Result { - let canonical_shader_path = shader_crate_path.to_path_buf(); - Self::shader_crate_path_canonical(&mut canonical_shader_path.clone())?; - - log::debug!( - "Running `cargo tree` on {}", - canonical_shader_path.display() - ); - let output_cargo_tree = std::process::Command::new("cargo") - .current_dir(canonical_shader_path.clone()) - .args(["tree", "--workspace", "--prefix", "none"]) - .output()?; - anyhow::ensure!( - output_cargo_tree.status.success(), - format!( - "could not query shader's `Cargo.toml` for `spirv-std` dependency: {}", - String::from_utf8(output_cargo_tree.stderr)? - ) - ); - let cargo_tree_string = String::from_utf8_lossy(&output_cargo_tree.stdout); - - let maybe_spirv_std_def = cargo_tree_string - .lines() - .find(|line| line.contains("spirv-std")); - log::trace!(" found {maybe_spirv_std_def:?}"); - - let Some(spirv_std_def) = maybe_spirv_std_def else { - anyhow::bail!("`spirv-std` not found in shader's `Cargo.toml` at {canonical_shader_path:?}:\n{cargo_tree_string}"); - }; - - Self::parse_spirv_std_source_and_version(spirv_std_def) } /// Parse a string like: /// `spirv-std v0.9.0 (https://github.com/Rust-GPU/rust-gpu?rev=54f6978c#54f6978c) (*)` /// Which would return: /// `SpirvSource::Git("https://github.com/Rust-GPU/rust-gpu", "54f6978c")` - fn parse_spirv_std_source_and_version(spirv_std_def: &str) -> anyhow::Result { - log::trace!("parsing spirv-std source and version from def: '{spirv_std_def}'"); - let parts: Vec = spirv_std_def.split_whitespace().map(String::from).collect(); - let version = parts - .get(1) - .context("Couldn't find `spirv_std` version in shader crate")? - .to_owned(); - let mut source = Self::CratesIO(version.clone()); - - if parts.len() > 2 { - let mut source_string = parts - .get(2) - .context("Couldn't get Uri from dependency string")? + fn parse_spirv_std_source_and_version(spirv_std_package: &Package) -> anyhow::Result { + log::trace!("parsing spirv-std source and version from package: '{spirv_std_package:?}'"); + + let result = if let Some(source) = &spirv_std_package.source { + let is_git = source.repr.starts_with("git+"); + let is_crates_io = source.is_crates_io(); + + match (is_git, is_crates_io) { + (true, true) => anyhow::bail!("parsed both git and crates.io?"), + (true, false) => { + let parse_git = || { + let link = &source.repr.get(4..)?; + let sharp_index = link.find('#')?; + let question_mark_index = link.find('?')?; + let url = link.get(..question_mark_index)?.to_owned(); + let rev = link.get(sharp_index + 1..)?.to_owned(); + Some(Self::Git { url, rev }) + }; + parse_git() + .with_context(|| format!("Failed to parse git url {}", &source.repr))? + } + (false, true) => Self::CratesIO(spirv_std_package.version.clone()), + (false, false) => { + anyhow::bail!("Metadata of spirv-std package uses unknown url format!") + } + } + } else { + let rust_gpu_repo_root = spirv_std_package + .manifest_path // rust-gpu/crates/spirv-std/Cargo.toml + .parent() // rust-gpu/crates/spirv-std + .and_then(Utf8Path::parent) // rust-gpu/crates + .and_then(Utf8Path::parent) // rust-gpu + .context("selecting rust-gpu workspace root dir in local path")? .to_owned(); - source_string = source_string.replace(['(', ')'], ""); - - // Unfortunately Uri ignores the fragment/hash portion of the Uri. - // - // There's been a ticket open for years: - // - // - // So here we'll parse the fragment out of the source string by hand - let uri = source_string.parse::()?; - let maybe_hash = if source_string.contains('#') { - let mut splits = source_string.split('#'); - splits.next_back().map(std::borrow::ToOwned::to_owned) - } else { - None - }; - if uri.scheme().is_some() { - source = Self::parse_git_source(version, &uri, maybe_hash)?; - } else { - source = Self::Path((source_string, version)); + if !rust_gpu_repo_root.is_dir() { + anyhow::bail!("path {rust_gpu_repo_root} is not a directory"); } - } + let version = spirv_std_package.version.clone(); + Self::Path { + rust_gpu_repo_root, + version, + } + }; - log::debug!("Parsed `rust-gpu` source and version: {source:?}"); + log::debug!("Parsed `rust-gpu` source and version: {result:?}"); - Ok(source) + Ok(result) } +} - /// Parse a Git source like: `https://github.com/Rust-GPU/rust-gpu?rev=54f6978c#54f6978c` - fn parse_git_source( - version: String, - uri: &http::Uri, - fragment: Option, - ) -> anyhow::Result { - log::trace!( - "parsing git source from version: '{version}' and uri: '{uri}' and fragment: {}", - fragment.as_deref().unwrap_or("?") - ); - let repo = format!( - "{}://{}{}", - uri.scheme().context("Couldn't parse scheme from Uri")?, - uri.host().context("Couldn't parse host from Uri")?, - uri.path() - ); - - let rev = Self::parse_git_revision(uri.query(), fragment, version); +/// Make sure shader crate path is absolute and canonical. +fn crate_path_canonical(shader_crate_path: &Path) -> anyhow::Result { + let mut canonical_path = shader_crate_path.to_path_buf(); - Ok(Self::Git { url: repo, rev }) + if !canonical_path.is_absolute() { + let cwd = std::env::current_dir().context("no cwd")?; + canonical_path = cwd.join(canonical_path); } + canonical_path = canonical_path + .canonicalize() + .context("could not get absolute path to shader crate")?; - /// Decide the Git revision to use. - fn parse_git_revision( - maybe_query: Option<&str>, - maybe_fragment: Option, - version: String, - ) -> String { - let marker = "rev="; - let maybe_sane_query = maybe_query.and_then(|query| { - // TODO: This might seem a little crude, but it saves adding a whole query parsing dependency. - let sanity_check = query.contains(marker) && query.split('=').count() == 2; - sanity_check.then_some(query) - }); - - if let Some(query) = maybe_sane_query { - return query.replace(marker, ""); - } - - if let Some(fragment) = maybe_fragment { - return fragment; - } - - version + if !canonical_path.is_dir() { + log::error!("{shader_crate_path:?} is not a directory, aborting"); + anyhow::bail!("{shader_crate_path:?} is not a directory"); } + Ok(canonical_path) +} - /// `git clone` the `rust-gpu` repo. We use it to get the required Rust toolchain to compile - /// the shader. - fn ensure_repo_is_installed(&self) -> anyhow::Result<()> { - if self.to_dirname()?.exists() { - log::debug!( - "Not cloning `rust-gpu` repo ({}) as it already exists at {}", - self.to_repo(), - self.to_dirname()?.to_string_lossy().as_ref(), - ); - return Ok(()); - } - - log::debug!( - "Cloning `rust-gpu` repo {} to {}", - self.to_repo(), - self.to_dirname()?.to_string_lossy().as_ref(), - ); - - crate::user_output!("Cloning `rust-gpu` repo...\n"); - - // TODO: do something else when testing, to help speed things up. - let output_clone = std::process::Command::new("git") - .args([ - "clone", - self.to_repo().as_ref(), - self.to_dirname()?.to_string_lossy().as_ref(), - ]) - .output()?; - - anyhow::ensure!( - output_clone.status.success(), - "couldn't clone `rust-gpu` {} to {}\n{}", - self.to_repo(), - self.to_dirname()?.to_string_lossy(), - String::from_utf8_lossy(&output_clone.stderr) - ); +/// get the Package metadata from some crate +pub fn get_package_from_crate(crate_path: &Path, crate_name: &str) -> anyhow::Result { + let canonical_crate_path = crate_path_canonical(crate_path)?; + + log::debug!( + "Running `cargo metadata` on `{}` to query for package `{crate_name}`", + canonical_crate_path.display() + ); + let metadata = MetadataCommand::new() + .current_dir(&canonical_crate_path) + .exec()?; + + let Some(package) = metadata + .packages + .into_iter() + .find(|package| package.name.eq(crate_name)) + else { + anyhow::bail!("`{crate_name}` not found in `Cargo.toml` at `{canonical_crate_path:?}`"); + }; + log::trace!(" found `{}` version `{}`", package.name, package.version); + Ok(package) +} - Ok(()) - } +/// Parse the `rust-toolchain.toml` in the working tree of the checked-out version of the `rust-gpu` repo. +pub fn get_channel_from_rustc_codegen_spirv_build_script( + rustc_codegen_spirv_package: &Package, +) -> anyhow::Result { + let path = rustc_codegen_spirv_package + .manifest_path + .parent() + .context("finding `rustc_codegen_spirv` crate root")?; + let build_rs = path.join("build.rs"); + + log::debug!("Parsing `build.rs` at {build_rs:?} for the used toolchain"); + let contents = fs::read_to_string(&build_rs)?; + let channel_start = "channel = \""; + let channel_line = contents + .lines() + .find_map(|line| line.strip_prefix(channel_start)) + .context(format!("Can't find `{channel_start}` line in {build_rs:?}"))?; + let channel = channel_line + .get(..channel_line.find('"').context("ending \" missing")?) + .context("can't slice version")?; + Ok(channel.to_owned()) } #[cfg(test)] @@ -372,39 +247,12 @@ mod test { #[test_log::test] fn parsing_spirv_std_dep_for_shader_template() { let shader_template_path = crate::test::shader_crate_template_path(); - let source = SpirvSource::get_spirv_std_dep_definition(&shader_template_path).unwrap(); + let source = SpirvSource::get_rust_gpu_deps_from_shader(&shader_template_path).unwrap(); assert_eq!( source, SpirvSource::Git { url: "https://github.com/Rust-GPU/rust-gpu".to_owned(), - rev: "82a0f69".to_owned() - } - ); - } - - #[test_log::test] - fn parsing_spirv_std_dep_for_git_source() { - let definition = - "spirv-std v9.9.9 (https://github.com/Rust-GPU/rust-gpu?rev=82a0f69#82a0f69) (*)"; - let source = SpirvSource::parse_spirv_std_source_and_version(definition).unwrap(); - assert_eq!( - source, - SpirvSource::Git { - url: "https://github.com/Rust-GPU/rust-gpu".to_owned(), - rev: "82a0f69".to_owned() - } - ); - } - - #[test_log::test] - fn parsing_spirv_std_dep_for_git_source_hash() { - let definition = "spirv-std v9.9.9 (https://github.com/Rust-GPU/rust-gpu#82a0f69) (*)"; - let source = SpirvSource::parse_spirv_std_source_and_version(definition).unwrap(); - assert_eq!( - source, - SpirvSource::Git { - url: "https://github.com/Rust-GPU/rust-gpu".to_owned(), - rev: "82a0f69".to_owned() + rev: "82a0f69008414f51d59184763146caa6850ac588".to_owned() } ); } @@ -414,4 +262,18 @@ mod test { let path = std::path::PathBuf::from("./"); assert!(path.is_relative()); } + + #[test_log::test] + fn cached_checkout_dir_sanity() { + let shader_template_path = crate::test::shader_crate_template_path(); + let source = SpirvSource::get_rust_gpu_deps_from_shader(&shader_template_path).unwrap(); + let dir = source.install_dir().unwrap(); + let name = dir + .file_name() + .unwrap() + .to_str() + .map(std::string::ToString::to_string) + .unwrap(); + assert_eq!("https___github_com_Rust-GPU_rust-gpu+82a0f690", &name); + } } diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.0.json b/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.0.json deleted file mode 100644 index 9fa58d8..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.0.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "opengl4.0", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-opengl4.0", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.1.json b/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.1.json deleted file mode 100644 index 13d6872..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.1.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "opengl4.1", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-opengl4.1", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.2.json b/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.2.json deleted file mode 100644 index d131262..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.2.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "opengl4.2", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-opengl4.2", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.3.json b/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.3.json deleted file mode 100644 index 7a52159..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.3.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "opengl4.3", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-opengl4.3", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.5.json b/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.5.json deleted file mode 100644 index ba509ed..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-opengl4.5.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "opengl4.5", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-opengl4.5", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.0.json b/crates/cargo-gpu/target-specs/spirv-unknown-spv1.0.json deleted file mode 100644 index d9e2166..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.0.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "spv1.0", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-spv1.0", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.1.json b/crates/cargo-gpu/target-specs/spirv-unknown-spv1.1.json deleted file mode 100644 index 8fc1bca..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.1.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "spv1.1", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-spv1.1", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.2.json b/crates/cargo-gpu/target-specs/spirv-unknown-spv1.2.json deleted file mode 100644 index 0037561..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.2.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "spv1.2", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-spv1.2", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.3.json b/crates/cargo-gpu/target-specs/spirv-unknown-spv1.3.json deleted file mode 100644 index 645848c..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.3.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "spv1.3", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-spv1.3", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.4.json b/crates/cargo-gpu/target-specs/spirv-unknown-spv1.4.json deleted file mode 100644 index 43ab248..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.4.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "spv1.4", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-spv1.4", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.5.json b/crates/cargo-gpu/target-specs/spirv-unknown-spv1.5.json deleted file mode 100644 index e339e11..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-spv1.5.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "spv1.5", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-spv1.5", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.0.json b/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.0.json deleted file mode 100644 index a15b45b..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.0.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "vulkan1.0", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-vulkan1.0", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.1.json b/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.1.json deleted file mode 100644 index b71dd7b..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.1.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "vulkan1.1", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-vulkan1.1", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.1spv1.4.json b/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.1spv1.4.json deleted file mode 100644 index 82634e6..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.1spv1.4.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "vulkan1.1spv1.4", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-vulkan1.1spv1.4", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.2.json b/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.2.json deleted file mode 100644 index 7952bae..0000000 --- a/crates/cargo-gpu/target-specs/spirv-unknown-vulkan1.2.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "allows-weak-linkage": false, - "arch": "spirv", - "crt-objects-fallback": "false", - "crt-static-allows-dylibs": true, - "data-layout": "e-m:e-p:32:32:32-i64:64-n8:16:32:64", - "dll-prefix": "", - "dll-suffix": ".spv.json", - "dynamic-linking": true, - "emit-debug-gdb-scripts": false, - "env": "vulkan1.2", - "linker-flavor": "unix", - "linker-is-gnu": false, - "llvm-target": "spirv-unknown-vulkan1.2", - "main-needs-argc-argv": false, - "metadata": { - "description": null, - "host_tools": null, - "std": null, - "tier": null - }, - "os": "unknown", - "panic-strategy": "abort", - "simd-types-indirect": false, - "target-pointer-width": "32" -} diff --git a/crates/shader-crate-template/Cargo.toml b/crates/shader-crate-template/Cargo.toml index fb72e0e..faae1f2 100644 --- a/crates/shader-crate-template/Cargo.toml +++ b/crates/shader-crate-template/Cargo.toml @@ -24,24 +24,24 @@ glam = { version = "0.29", features = ["std"] } # TODO: Should it default to the root of the shader crate? output-dir = "./" # Set shader crate's cargo default-features -no_default_features = false +default_features = true # Set shader crate's cargo features. features = [] # The compile target. # TODO: `cargo gpu show targets` for all available options. -shader-target = "spirv-unknown-vulkan1.2" +target = "spirv-unknown-vulkan1.2" # Treat warnings as errors during compilation. deny-warnings = false # Compile shaders in debug mode. -debug = false +release = true # Enables the provided SPIR-V capabilities. # See: `impl core::str::FromStr for spirv_builder::Capability`. # TODO: `cargo gpu show capabilities` for all available options. -capability = [] +capabilities = [] # Enables the provided SPIR-V extensions. # See https://github.com/KhronosGroup/SPIRV-Registry for all extensions # TODO: `cargo gpu show extensions` for all available options. -extension = [] +extensions = [] # Compile one .spv file per shader entry point. multimodule = false # Set the level of metadata included in the SPIR-V binary. @@ -84,14 +84,10 @@ manifest-file = "manifest.json" # as a Git commit hash or a Git tag, therefore anything that `git checkout` can resolve. # spirv_builder_version = "" -# Rust toolchain channel to use to build `spirv-builder`. -# Eg: "nightly-2024-04-24" -# rust_toolchain = "" - # Whether to assume "yes" to the "Install Rust toolchain: [y/n]" prompt. auto-install-rust-toolchain = false -# Force `spirv-builder-cli` and `rustc_codegen_spirv` to be rebuilt. -force-spirv-cli-rebuild = false +# Force `rustc_codegen_spirv` to be rebuilt. +rebuild_codegen = false # There is a tricky situation where a shader crate that depends on workspace config can have # a different `Cargo.lock` lockfile version from the the workspace's `Cargo.lock`. This can # prevent builds when an old Rust toolchain doesn't recognise the newer lockfile version. diff --git a/crates/spirv-builder-cli/Cargo.lock b/crates/spirv-builder-cli/Cargo.lock deleted file mode 100644 index 1058571..0000000 --- a/crates/spirv-builder-cli/Cargo.lock +++ /dev/null @@ -1,1260 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" -dependencies = [ - "anstyle", - "once_cell", - "windows-sys 0.59.0", -] - -[[package]] -name = "ar" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" -dependencies = [ - "serde", -] - -[[package]] -name = "bytemuck" -version = "1.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.96", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "crossbeam-channel" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.96", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "elsa" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" -dependencies = [ - "indexmap 2.7.0", - "stable_deref_trait", -] - -[[package]] -name = "env_home" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" - -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - -[[package]] -name = "fsevent-sys" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" -dependencies = [ - "libc", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", -] - -[[package]] -name = "inotify" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" -dependencies = [ - "bitflags 1.3.2", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - -[[package]] -name = "internal-iterator" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969ee3fc68ec2e88eb21434ce4d9b7e1600d1ce92ff974560a6c4a304f5124b9" - -[[package]] -name = "is-terminal" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "kqueue" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" -dependencies = [ - "kqueue-sys", - "libc", -] - -[[package]] -name = "kqueue-sys" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" -dependencies = [ - "bitflags 1.3.2", - "libc", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", - "redox_syscall", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "longest-increasing-subsequence" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "notify" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486" -dependencies = [ - "bitflags 1.3.2", - "crossbeam-channel", - "filetime", - "fsevent-sys", - "inotify", - "kqueue", - "libc", - "mio", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "proc-macro2" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "raw-string" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0501e134c6905fee1f10fed25b0a7e1261bf676cffac9543a7d0730dec01af2" - -[[package]] -name = "redox_syscall" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rspirv" -version = "0.11.0+1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1503993b59ca9ae4127365c3293517576d7ce56be9f3d8abb1625c85ddc583ba" -dependencies = [ - "fxhash", - "num-traits", - "spirv 0.2.0+1.5.4", -] - -[[package]] -name = "rspirv" -version = "0.12.0+sdk-1.3.268.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cf3a93856b6e5946537278df0d3075596371b1950ccff012f02b0f7eafec8d" -dependencies = [ - "rustc-hash", - "spirv 0.3.0+sdk-1.3.268.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_codegen_spirv" -version = "0.9.0" -source = "git+https://github.com/Rust-GPU/rust-gpu?rev=4c633aec#4c633aec182300d9f85460ffd5a6ba7904ff5f74" -dependencies = [ - "ar", - "either", - "hashbrown 0.11.2", - "indexmap 1.9.3", - "itertools", - "lazy_static", - "libc", - "num-traits", - "once_cell", - "regex", - "rspirv 0.11.0+1.5.4", - "rustc-demangle", - "rustc_codegen_spirv-types 0.9.0 (git+https://github.com/Rust-GPU/rust-gpu?rev=4c633aec)", - "sanitize-filename", - "serde", - "serde_json", - "smallvec", - "spirt 0.3.0", - "spirv-tools", - "syn 1.0.109", -] - -[[package]] -name = "rustc_codegen_spirv" -version = "0.9.0" -source = "git+https://github.com/Rust-GPU/rust-gpu?rev=60dcb82#60dcb82613b0de4bbcf9701a288b4202d486427f" -dependencies = [ - "ar", - "either", - "hashbrown 0.11.2", - "indexmap 1.9.3", - "itertools", - "lazy_static", - "libc", - "num-traits", - "once_cell", - "regex", - "rspirv 0.12.0+sdk-1.3.268.0", - "rustc-demangle", - "rustc_codegen_spirv-types 0.9.0 (git+https://github.com/Rust-GPU/rust-gpu?rev=60dcb82)", - "sanitize-filename", - "smallvec", - "spirt 0.4.0", - "spirv-tools", - "syn 1.0.109", -] - -[[package]] -name = "rustc_codegen_spirv-types" -version = "0.9.0" -source = "git+https://github.com/Rust-GPU/rust-gpu?rev=4c633aec#4c633aec182300d9f85460ffd5a6ba7904ff5f74" -dependencies = [ - "rspirv 0.11.0+1.5.4", - "serde", -] - -[[package]] -name = "rustc_codegen_spirv-types" -version = "0.9.0" -source = "git+https://github.com/Rust-GPU/rust-gpu?rev=60dcb82#60dcb82613b0de4bbcf9701a288b4202d486427f" -dependencies = [ - "rspirv 0.12.0+sdk-1.3.268.0", - "serde", - "serde_json", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "sanitize-filename" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c502bdb638f1396509467cb0580ef3b29aa2a45c5d43e5d84928241280296c" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "semver" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" - -[[package]] -name = "serde" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", -] - -[[package]] -name = "serde_json" -version = "1.0.135" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -dependencies = [ - "serde", -] - -[[package]] -name = "spirt" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e1f7903720ff818d6da824edf2c4082c6e7a029a99317fd10c39dd7c40c7ff" -dependencies = [ - "arrayvec", - "bytemuck", - "derive_more", - "elsa", - "indexmap 1.9.3", - "internal-iterator", - "itertools", - "lazy_static", - "longest-increasing-subsequence", - "rustc-hash", - "serde", - "serde_json", - "smallvec", -] - -[[package]] -name = "spirt" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d5968bd2a36466468aac637b355776f080edfb0c6f769b2b99b9708260c42a" -dependencies = [ - "arrayvec", - "bytemuck", - "derive_more", - "elsa", - "indexmap 2.7.0", - "internal-iterator", - "itertools", - "lazy_static", - "longest-increasing-subsequence", - "rustc-hash", - "serde", - "serde_json", - "smallvec", -] - -[[package]] -name = "spirv" -version = "0.2.0+1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" -dependencies = [ - "bitflags 1.3.2", - "num-traits", - "serde", -] - -[[package]] -name = "spirv" -version = "0.3.0+sdk-1.3.268.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" -dependencies = [ - "bitflags 2.7.0", - "serde", -] - -[[package]] -name = "spirv-builder" -version = "0.9.0" -source = "git+https://github.com/Rust-GPU/rust-gpu?rev=4c633aec#4c633aec182300d9f85460ffd5a6ba7904ff5f74" -dependencies = [ - "memchr", - "notify", - "raw-string", - "rustc_codegen_spirv 0.9.0 (git+https://github.com/Rust-GPU/rust-gpu?rev=4c633aec)", - "rustc_codegen_spirv-types 0.9.0 (git+https://github.com/Rust-GPU/rust-gpu?rev=4c633aec)", - "serde", - "serde_json", -] - -[[package]] -name = "spirv-builder" -version = "0.9.0" -source = "git+https://github.com/Rust-GPU/rust-gpu?rev=60dcb82#60dcb82613b0de4bbcf9701a288b4202d486427f" -dependencies = [ - "memchr", - "notify", - "raw-string", - "rustc_codegen_spirv 0.9.0 (git+https://github.com/Rust-GPU/rust-gpu?rev=60dcb82)", - "rustc_codegen_spirv-types 0.9.0 (git+https://github.com/Rust-GPU/rust-gpu?rev=60dcb82)", - "serde", - "serde_json", -] - -[[package]] -name = "spirv-builder-cli" -version = "0.1.0" -dependencies = [ - "clap", - "env_home", - "env_logger", - "log", - "serde", - "serde_json", - "spirv 0.2.0+1.5.4", - "spirv 0.3.0+sdk-1.3.268.0", - "spirv-builder 0.9.0 (git+https://github.com/Rust-GPU/rust-gpu?rev=4c633aec)", - "spirv-builder 0.9.0 (git+https://github.com/Rust-GPU/rust-gpu?rev=60dcb82)", - "toml", -] - -[[package]] -name = "spirv-tools" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcb3b0832881834994b7ec82b709ec5491043ceb4bf8101e27da6b5234b24261" -dependencies = [ - "spirv-tools-sys", -] - -[[package]] -name = "spirv-tools-sys" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e68b55a97aa6856e010a6f2477425875a97873e147bb0232160e73c45bdae7" -dependencies = [ - "cc", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" -dependencies = [ - "indexmap 2.7.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] diff --git a/crates/spirv-builder-cli/Cargo.toml b/crates/spirv-builder-cli/Cargo.toml deleted file mode 100644 index 2cbd135..0000000 --- a/crates/spirv-builder-cli/Cargo.toml +++ /dev/null @@ -1,61 +0,0 @@ -[package] -name = "spirv-builder-cli" -version = "0.1.0" -edition = "2021" - -[dependencies] -# `clap = "=4.4.8"` pin is needed to support older Rust toolchains. -# If `clap` gets too old, then it can be split into 2 versions, gated by a feature, like `spirv` is. -# Or more generally we should think about how to deprecate supporting old version of `rust-gpu`. -clap = { version = "=4.4.8", features = ["derive"] } -env_home = "0.1.0" -env_logger = "0.10" -log = "0.4" -serde = "1.0.214" -serde_json = "1.0.132" -toml = "0.8.19" - -[features] -default = ["spirv-builder-0_10"] -# The `spirv-builder` before `cargo gpu` existed. It has an incompatible `SpirvBuilder` interface. -spirv-builder-pre-cli = ["dep:spirv-builder-pre-cli", "dep:spirv_0_2"] -# The first version that introduced `cargo gpu`. It has some extra `.builder()` args that make -# dynamically changing build dependencies easier. -spirv-builder-0_10 = ["dep:spirv-builder-0_10", "dep:spirv_0_3"] -# -rspirv-latest = ["dep:spirv_0_3"] - -[dependencies.spirv_0_2] -package = "spirv" -version = "0.2.0" -features = [ "deserialize", "serialize" ] -optional = true - -[dependencies.spirv_0_3] -package = "spirv" -version = "0.3.0" -features = [ "deserialize", "serialize" ] -optional = true - -# NB: All the `${AUTO-REPLACE*}` tokens in each feature get replaced with the same values. -# This is because only one feature can ever be used at once and it makes it easier to just -# replace each token rather than figure out to what feature each token belongs. - -[dependencies.spirv-builder-pre-cli] -package = "spirv-builder" -features = [ "watch" ] -optional = true -git = "https://github.com/Rust-GPU/rust-gpu" # ${AUTO-REPLACE-SOURCE} -rev = "4c633aec" # ${AUTO-REPLACE-VERSION} - -[dependencies.spirv-builder-0_10] -package = "spirv-builder" -features = [ "watch" ] -optional = true -git = "https://github.com/Rust-GPU/rust-gpu" # ${AUTO-REPLACE-SOURCE} -rev = "60dcb82" # ${AUTO-REPLACE-VERSION} - -[lints.rust] -# This crate is most often run by end users compiling their shaders so it's not so relevant -# for them to see warnings. -warnings = "allow" diff --git a/crates/spirv-builder-cli/README.md b/crates/spirv-builder-cli/README.md deleted file mode 100644 index ad609e9..0000000 --- a/crates/spirv-builder-cli/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# SPIR-V Builder CLI Template - -> [!CAUTION] -> This may look like a typical crate, but it is in fact more like a crate _template_. -> It is intended to be primarily called by `cargo gpu`, which has these files embedded -> into its binary and so can copy and edit them to automatically compile end-user -> shaders. diff --git a/crates/spirv-builder-cli/rust-toolchain.toml b/crates/spirv-builder-cli/rust-toolchain.toml deleted file mode 100644 index 6148ea9..0000000 --- a/crates/spirv-builder-cli/rust-toolchain.toml +++ /dev/null @@ -1,5 +0,0 @@ -# This is just a placeholder for development. In actual usage the toolchain -# is set dynamically. -[toolchain] -channel = "nightly-2024-04-24" -components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/crates/spirv-builder-cli/src/args.rs b/crates/spirv-builder-cli/src/args.rs deleted file mode 100644 index dad50d6..0000000 --- a/crates/spirv-builder-cli/src/args.rs +++ /dev/null @@ -1,203 +0,0 @@ -#[cfg(feature = "spirv-builder-pre-cli")] -use spirv_0_2 as spirv; - -#[cfg(any(feature = "spirv-builder-0_10", feature = "rspirv-latest"))] -use spirv_0_3 as spirv; - -use std::str::FromStr as _; - -#[derive(clap::Parser, Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct AllArgs { - #[clap(flatten)] - pub build: BuildArgs, - - #[clap(flatten)] - pub install: InstallArgs, -} - -/// Options for the `--spirv-metadata` command -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] -pub enum SpirvMetadata { - /// Don't log any metadata (the default) - None, - /// Only log named variables - NameVariables, - /// Log all metadata - Full, -} - -#[derive(clap::Parser, Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct BuildArgs { - /// Path to the output directory for the compiled shaders. - #[clap(long, short, default_value = "./")] - pub output_dir: std::path::PathBuf, - - /// Watch the shader crate directory and automatically recompile on changes. - #[clap(long, short, action)] - pub watch: bool, - - /// Set shader crate's cargo default-features. - #[clap(long)] - pub no_default_features: bool, - - /// Set shader crate's cargo features. - #[clap(long)] - pub features: Vec, - - /// `rust-gpu` compile target. - /// TODO: deprecate completely - #[arg(hide(true), default_value = "spirv-unknown-vulkan1.2")] - pub target: String, - - /// Shader target. - // TODO: how to list the available options? Would be nice to have a command like: - // `cargo gpu show targets` - #[clap(long, default_value = "spirv-unknown-vulkan1.2")] - pub shader_target: String, - - /// Treat warnings as errors during compilation. - #[arg(long, default_value = "false")] - pub deny_warnings: bool, - - /// Compile shaders in debug mode. - #[arg(long, default_value = "false")] - pub debug: bool, - - /// Enables the provided SPIR-V capabilities. - /// See: `cargo gpu show capabilities` - #[arg(long, value_parser=Self::spirv_capability)] - pub capability: Vec, - - /// Enables the provided SPIR-V extensions. - /// See for all extensions - #[arg(long)] - pub extension: Vec, - - /// Compile one .spv file per entry point. - #[arg(long, default_value = "false")] - pub multimodule: bool, - - /// Set the level of metadata included in the SPIR-V binary. - #[arg(long, value_parser=Self::spirv_metadata, default_value = "none")] - pub spirv_metadata: SpirvMetadata, - - /// Allow store from one struct type to a different type with compatible layout and members. - #[arg(long, default_value = "false")] - pub relax_struct_store: bool, - - /// Allow allocating an object of a pointer type and returning a pointer value from a function - /// in logical addressing mode. - #[arg(long, default_value = "false")] - pub relax_logical_pointer: bool, - - /// Enable `VK_KHR_relaxed_block_layout` when checking standard uniform, - /// storage buffer, and push constant layouts. - /// This is the default when targeting Vulkan 1.1 or later. - #[arg(long, default_value = "false")] - pub relax_block_layout: bool, - - /// Enable `VK_KHR_uniform_buffer_standard_layout` when checking standard uniform buffer layouts. - #[arg(long, default_value = "false")] - pub uniform_buffer_standard_layout: bool, - - /// Enable `VK_EXT_scalar_block_layout` when checking standard uniform, storage buffer, and push - /// constant layouts. - /// Scalar layout rules are more permissive than relaxed block layout so in effect this will - /// override the --relax-block-layout option. - #[arg(long, default_value = "false")] - pub scalar_block_layout: bool, - - /// Skip checking standard uniform / storage buffer layout. Overrides any --relax-block-layout - /// or --scalar-block-layout option. - #[arg(long, default_value = "false")] - pub skip_block_layout: bool, - - /// Preserve unused descriptor bindings. Useful for reflection. - #[arg(long, default_value = "false")] - pub preserve_bindings: bool, - - ///Renames the manifest.json file to the given name - #[clap(long, short, default_value = "manifest.json")] - pub manifest_file: String, -} - -impl BuildArgs { - /// Clap value parser for `SpirvMetadata`. - fn spirv_metadata(metadata: &str) -> Result { - match metadata { - "none" => Ok(SpirvMetadata::None), - "name-variables" => Ok(SpirvMetadata::NameVariables), - "full" => Ok(SpirvMetadata::Full), - _ => Err(clap::Error::new(clap::error::ErrorKind::InvalidValue)), - } - } - - /// Clap value parser for `Capability`. - fn spirv_capability(capability: &str) -> Result { - spirv::Capability::from_str(capability).map_or_else( - |()| Err(clap::Error::new(clap::error::ErrorKind::InvalidValue)), - Ok, - ) - } -} - -#[derive(clap::Parser, Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct InstallArgs { - #[clap(long, hide(true), default_value = "INTERNALLY_SET")] - pub dylib_path: std::path::PathBuf, - - /// Directory containing the shader crate to compile. - #[clap(long, default_value = "./")] - pub shader_crate: std::path::PathBuf, - - /// Source of `spirv-builder` dependency - /// Eg: "https://github.com/Rust-GPU/rust-gpu" - #[clap(long)] - pub spirv_builder_source: Option, - - /// Version of `spirv-builder` dependency. - /// * If `--spirv-builder-source` is not set, then this is assumed to be a crates.io semantic - /// version such as "0.9.0". - /// * If `--spirv-builder-source` is set, then this is assumed to be a Git "commitsh", such - /// as a Git commit hash or a Git tag, therefore anything that `git checkout` can resolve. - #[clap(long, verbatim_doc_comment)] - pub spirv_builder_version: Option, - - /// Rust toolchain channel to use to build `spirv-builder`. - /// - /// This must be compatible with the `spirv_builder` argument as defined in the `rust-gpu` repo. - #[clap(long)] - pub rust_toolchain: Option, - - /// Force `spirv-builder-cli` and `rustc_codegen_spirv` to be rebuilt. - #[clap(long)] - pub force_spirv_cli_rebuild: bool, - - /// Assume "yes" to "Install Rust toolchain: [y/n]" prompt. - #[clap(long, action)] - pub auto_install_rust_toolchain: bool, - - /// There is a tricky situation where a shader crate that depends on workspace config can have - /// a different `Cargo.lock` lockfile version from the the workspace's `Cargo.lock`. This can - /// prevent builds when an old Rust toolchain doesn't recognise the newer lockfile version. - /// - /// The ideal way to resolve this would be to match the shader crate's toolchain with the - /// workspace's toolchain. However, that is not always possible. Another solution is to - /// `exclude = [...]` the problematic shader crate from the workspace. This also may not be a - /// suitable solution if there are a number of shader crates all sharing similar config and - /// you don't want to have to copy/paste and maintain that config across all the shaders. - /// - /// So a somewhat hacky workaround is to have `cargo gpu` overwrite lockfile versions. Enabling - /// this flag will only come into effect if there are a mix of v3/v4 lockfiles. It will also - /// only overwrite versions for the duration of a build. It will attempt to return the versions - /// to their original values once the build is finished. However, of course, unexpected errors - /// can occur and the overwritten values can remain. Hence why this behaviour is not enabled by - /// default. - /// - /// This hack is possible because the change from v3 to v4 only involves a minor change to the - /// way source URLs are encoded. See these PRs for more details: - /// * https://github.com/rust-lang/cargo/pull/12280 - /// * https://github.com/rust-lang/cargo/pull/14595 - #[clap(long, action, verbatim_doc_comment)] - pub force_overwrite_lockfiles_v4_to_v3: bool, -} diff --git a/crates/spirv-builder-cli/src/lib.rs b/crates/spirv-builder-cli/src/lib.rs deleted file mode 100644 index 70d83e4..0000000 --- a/crates/spirv-builder-cli/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -pub mod args; - -#[cfg(feature = "spirv-builder-pre-cli")] -pub use spirv_0_2 as spirv; - -#[cfg(any(feature = "spirv-builder-0_10", feature = "rspirv-latest"))] -pub use spirv_0_3 as spirv; - -/// Shader source and entry point that can be used to create shader linkage. -#[derive(serde::Serialize, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Linkage { - pub source_path: String, - pub entry_point: String, - pub wgsl_entry_point: String, -} - -impl Linkage { - pub fn new(entry_point: impl AsRef, source_path: impl AsRef) -> Self { - Self { - // Force a forward slash convention here so it works on all OSs - source_path: source_path - .as_ref() - .components() - .map(|c| c.as_os_str().to_string_lossy()) - .collect::>() - .join("/"), - wgsl_entry_point: entry_point.as_ref().replace("::", ""), - entry_point: entry_point.as_ref().to_string(), - } - } - - pub fn fn_name(&self) -> &str { - self.entry_point.split("::").last().unwrap() - } -} - -/// A built shader entry-point, used in `spirv-builder-cli` to generate -/// a `build-manifest.json` used by `cargo-gpu`. -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct ShaderModule { - pub entry: String, - pub path: std::path::PathBuf, -} - -impl ShaderModule { - pub fn new(entry: impl AsRef, path: impl AsRef) -> Self { - Self { - entry: entry.as_ref().into(), - path: path.as_ref().into(), - } - } -} diff --git a/crates/spirv-builder-cli/src/main.rs b/crates/spirv-builder-cli/src/main.rs deleted file mode 100644 index 2a17938..0000000 --- a/crates/spirv-builder-cli/src/main.rs +++ /dev/null @@ -1,155 +0,0 @@ -/// NB: For developing this file it will probably help to temporarily move the `"crates/spirv-builder-cli"` -/// line from the `exclude` to `members` section of the root `Cargo.toml` file. This will allow -/// `rust-analyzer` to run on the file. We can't permanently keep it there because each of the -/// `spirv-builder-*` features depends on a different Rust toolchain which `cargo check/clippy` -/// can't build all at once. -pub mod args; - -#[cfg(feature = "spirv-builder-pre-cli")] -use spirv_builder_pre_cli as spirv_builder; - -#[cfg(feature = "spirv-builder-0_10")] -use spirv_builder_0_10 as spirv_builder; - -use spirv_builder::{CompileResult, MetadataPrintout, ModuleResult, SpirvBuilder}; -use spirv_builder_cli::ShaderModule; - -const RUSTC_NIGHTLY_CHANNEL: &str = "${CHANNEL}"; - -fn set_rustup_toolchain() { - log::trace!( - "setting RUSTUP_TOOLCHAIN = '{}'", - RUSTC_NIGHTLY_CHANNEL.trim_matches('"') - ); - std::env::set_var("RUSTUP_TOOLCHAIN", RUSTC_NIGHTLY_CHANNEL.trim_matches('"')); -} - -/// Get the OS-dependent ENV variable name for the list of paths pointing to .so/.dll files -const fn dylib_path_envvar() -> &'static str { - if cfg!(windows) { - "PATH" - } else if cfg!(target_os = "macos") { - "DYLD_FALLBACK_LIBRARY_PATH" - } else { - "LD_LIBRARY_PATH" - } -} - -fn set_codegen_spirv_location(dylib_path: std::path::PathBuf) { - let env_var = dylib_path_envvar(); - let existing_paths_str = std::env::var(env_var).unwrap(); - let mut dylib_paths = std::env::split_paths(&existing_paths_str).collect::>(); - - let dylib_path = dylib_path.parent().unwrap().to_path_buf(); - dylib_paths.insert(0, dylib_path); - - let path = std::env::join_paths(dylib_paths).unwrap().into_string().unwrap(); - - log::debug!("Setting OS-dependent DLL ENV path ({env_var}) to: {path}"); - std::env::set_var(env_var, path); -} - -fn handle_compile_result(result: &CompileResult, args: &args::AllArgs) { - log::debug!("found entry points: {:#?}", result.entry_points); - - let dir = &args.build.output_dir; - let mut shaders = vec![]; - match &result.module { - ModuleResult::MultiModule(modules) => { - assert!(!modules.is_empty(), "No shader modules to compile"); - for (entry, filepath) in modules.clone().into_iter() { - log::debug!("compiled {entry} {}", filepath.display()); - shaders.push(ShaderModule::new(entry, filepath)); - } - } - ModuleResult::SingleModule(filepath) => { - for entry in result.entry_points.clone() { - shaders.push(ShaderModule::new(entry, filepath.clone())); - } - } - } - - use std::io::Write; - let mut file = std::fs::File::create(dir.join("spirv-manifest.json")).unwrap(); - file.write_all(&serde_json::to_vec(&shaders).unwrap()) - .unwrap(); -} - -pub fn main() { - env_logger::builder().init(); - - set_rustup_toolchain(); - - let args = std::env::args().collect::>(); - log::debug!( - "running spirv-builder-cli from '{}'", - std::env::current_dir().unwrap().display() - ); - log::debug!("with args: {args:#?}"); - let args: args::AllArgs = serde_json::from_str(&args[1]).unwrap(); - let args_for_result = args.clone(); - - let spirv_metadata = match args.build.spirv_metadata { - args::SpirvMetadata::None => spirv_builder::SpirvMetadata::None, - args::SpirvMetadata::NameVariables => spirv_builder::SpirvMetadata::NameVariables, - args::SpirvMetadata::Full => spirv_builder::SpirvMetadata::Full, - }; - - let mut builder = SpirvBuilder::new(args.install.shader_crate, &args.build.target) - .deny_warnings(args.build.deny_warnings) - .release(!args.build.debug) - .multimodule(args.build.multimodule) - .spirv_metadata(spirv_metadata) - .relax_struct_store(args.build.relax_struct_store) - .relax_logical_pointer(args.build.relax_logical_pointer) - .relax_block_layout(args.build.relax_block_layout) - .uniform_buffer_standard_layout(args.build.uniform_buffer_standard_layout) - .scalar_block_layout(args.build.scalar_block_layout) - .skip_block_layout(args.build.skip_block_layout) - .preserve_bindings(args.build.preserve_bindings) - .print_metadata(spirv_builder::MetadataPrintout::None); - - for capability in &args.build.capability { - builder = builder.capability(*capability); - } - - for extension in &args.build.extension { - builder = builder.extension(extension); - } - - #[cfg(feature = "spirv-builder-pre-cli")] - { - log::debug!("using spirv-builder-pre-cli"); - set_codegen_spirv_location(args.install.dylib_path); - } - - #[cfg(feature = "spirv-builder-0_10")] - { - log::debug!("using spirv-builder-0_10"); - builder = builder - .rustc_codegen_spirv_location(args.install.dylib_path) - .target_spec(args.build.shader_target); - - if args.build.no_default_features { - log::info!("setting cargo --no-default-features"); - builder = builder.shader_crate_default_features(false); - } - if !args.build.features.is_empty() { - log::info!("setting --features {:?}", args.build.features); - builder = builder.shader_crate_features(args.build.features); - } - } - - log::debug!("Calling `rust-gpu`'s `spirv-builder` library"); - - if args.build.watch { - println!("🦀 Watching and recompiling shader on changes..."); - builder.watch(move |compile_result| { - handle_compile_result(&compile_result, &args_for_result); - }); - std::thread::park(); - } else { - let result = builder.build().unwrap(); - handle_compile_result(&result, &args_for_result); - } -} diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs index 3f4d090..d767a2c 100644 --- a/crates/xtask/src/main.rs +++ b/crates/xtask/src/main.rs @@ -151,18 +151,7 @@ fn main() { log::info!("installing cargo gpu"); cmd(["cargo", "install", "--path", "crates/cargo-gpu"]).unwrap(); - log::info!("installing cargo gpu artifacts"); - cmd([ - "cargo", - "gpu", - "install", - "--shader-crate", - SHADER_CRATE_PATH, - "--auto-install-rust-toolchain", - "--force-overwrite-lockfiles-v4-to-v3", - ]) - .unwrap(); - + log::info!("setup project"); let dir = tempdir::TempDir::new("test-shader-output").unwrap(); let mut overwriter = ShaderCrateTemplateCargoTomlWriter::new(); overwriter.replace_output_dir(dir.path()).unwrap(); @@ -175,6 +164,7 @@ fn main() { } } + log::info!("building with auto-install"); cmd([ "cargo", "gpu", @@ -182,7 +172,7 @@ fn main() { "--shader-crate", SHADER_CRATE_PATH, "--auto-install-rust-toolchain", - "--force-spirv-cli-rebuild", + "--rebuild-codegen", "--force-overwrite-lockfiles-v4-to-v3", ]) .unwrap();