如何在 Unix 系统上直接执行 Rust 代码? (使用 shebang)
How to execute Rust code directly on Unix systems? (using the shebang)
从阅读 this thread 来看,似乎可以使用 shebang 来 运行 Rust *.
#!/usr/bin/env rustc
fn main() {
println!("Hello World!");
}
使此可执行文件和 运行ning 编译,但 运行 代码不编译。
chmod +x hello_world.rs
./hello_world.rs
然而,这只会将代码编译成 hello_world
。
是否可以直接执行*.rs
个文件,类似于shell脚本?
* 这引用了 rustx,我对此进行了调查,但它是一个 bash 脚本,它每次都编译脚本(没有缓存)并且从不从临时目录中删除文件,尽管这可以改进。它还具有不能使用板条箱的重大限制。
这似乎有效:
#!/bin/sh
//usr/bin/env rustc [=10=] -o a.out && ./a.out && rm ./a.out ; exit
fn main() {
println!("Hello World!");
}
有cargo-script
。这也让您可以使用依赖项。
通过 cargo install cargo-script
安装 cargo-script
后,您可以像这样创建脚本文件 (hello.rs
):
#!/usr/bin/env run-cargo-script
fn main() {
println!("Hello World!");
}
要执行它,您需要:
$ chmod +x hello.rs
$ ./hello.rs
Compiling hello v0.1.0 (file://~/.cargo/.cargo/script-cache/file-hello-d746fc676c0590b)
Finished release [optimized] target(s) in 0.80 secs
Hello World!
要使用 crates.io 中的 crate,请参阅上面链接的 README 中的教程。
我专门为此编写了一个工具:Scriptisto。它是一个完全与语言无关的工具,它可以与其他编译语言或具有昂贵验证步骤的语言一起使用(Python with mypy)。
对于 Rust,它还可以获取 dependencies behind the scenes or build entirely in Docker 而无需安装 Rust 编译器。 scriptisto
将这些模板嵌入到二进制文件中,因此您可以 bootstrap 轻松地:
$ scriptisto new rust > ./script.rs
$ chmod +x ./script.rs
$ ./script.rs
您可以 new docker-rust
而不是 new rust
并且构建不需要在您的主机系统上安装 Rust 编译器。
#!/bin/sh
#![allow()] /*
exec cargo-play --cached --release [=10=] -- "$@"
*/
需要货运。你可以看到一个不需要任何东西的解决方案here:
#!/bin/sh
#![allow()] /*
# rust self-compiler by Mahmoud Al-Qudsi, Copyright NeoSmart Technologies 2020
# See <https://neosmart.net/blog/self-compiling-rust-code/> for info & updates.
#
# This code is freely released to the public domain. In case a public domain
# license is insufficient for your legal department, this code is also licensed
# under the MIT license.
# Get an output path that is derived from the complete path to this self script.
# - `realpath` makes sure if you have two separate `script.rs` files in two
# different directories, they get mapped to different binaries.
# - `which` makes that work even if you store this script in $PATH and execute
# it by its filename alone.
# - `cut` is used to print only the hash and not the filename, which `md5sum`
# always includes in its output.
OUT=/tmp/$(printf "%s" $(realpath $(which "[=11=]")) | md5sum | cut -d' ' -f1)
# Calculate hash of the current contents of the script, so we can avoid
# recompiling if it hasn't changed.
MD5=$(md5sum "[=11=]" | cut -d' ' -f1)
# Check if we have a previously compiled output for this exact source code.
if !(test -f "${OUT}.md5" && test "${MD5}" = "$(cat ${OUT}.md5)"); then
# The script has been modified or is otherwise not cached.
# Check if the script already contains an `fn main()` entry point.
if grep -Eq '^\s*(\[.*?\])*\s*fn\s*main\b*' "[=11=]"; then
# Compile the input script as-is to the previously determined location.
rustc "[=11=]" -o ${OUT}
# Save rustc's exit code so we can compare against it later.
RUSTC_STATUS=$?
else
# The script does not contain an `fn main()` entry point, so add one.
# We don't use `printf 'fn main() { %s }' because the shebang must
# come at the beginning of the line, and we don't use `tail` to skip
# it because that would result in incorrect line numbers in any errors
# reported by rustc, instead we just comment out the shebang but leave
# it on the same line as `fn main() {`.
printf "fn main() {//%s\n}" "$(cat [=11=])" | rustc - -o ${OUT}
# Save rustc's exit code so we can compare against it later.
RUSTC_STATUS=$?
fi
# Check if we compiled the script OK, or exit bubbling up the return code.
if test "${RUSTC_STATUS}" -ne 0; then
exit ${RUSTC_STATUS}
fi
# Save the MD5 of the current version of the script so we can compare
# against it next time.
printf "%s" ${MD5} > ${OUT}.md5
fi
# Execute the compiled output. This also ends execution of the shell script,
# as it actually replaces its process with ours; see exec(3) for more on this.
exec ${OUT} $@
# At this point, it's OK to write raw rust code as the shell interpreter
# never gets this far. But we're actually still in the rust comment we opened
# on line 2, so close that: */
从阅读 this thread 来看,似乎可以使用 shebang 来 运行 Rust *.
#!/usr/bin/env rustc
fn main() {
println!("Hello World!");
}
使此可执行文件和 运行ning 编译,但 运行 代码不编译。
chmod +x hello_world.rs
./hello_world.rs
然而,这只会将代码编译成 hello_world
。
是否可以直接执行*.rs
个文件,类似于shell脚本?
* 这引用了 rustx,我对此进行了调查,但它是一个 bash 脚本,它每次都编译脚本(没有缓存)并且从不从临时目录中删除文件,尽管这可以改进。它还具有不能使用板条箱的重大限制。
这似乎有效:
#!/bin/sh
//usr/bin/env rustc [=10=] -o a.out && ./a.out && rm ./a.out ; exit
fn main() {
println!("Hello World!");
}
有cargo-script
。这也让您可以使用依赖项。
通过 cargo install cargo-script
安装 cargo-script
后,您可以像这样创建脚本文件 (hello.rs
):
#!/usr/bin/env run-cargo-script
fn main() {
println!("Hello World!");
}
要执行它,您需要:
$ chmod +x hello.rs
$ ./hello.rs
Compiling hello v0.1.0 (file://~/.cargo/.cargo/script-cache/file-hello-d746fc676c0590b)
Finished release [optimized] target(s) in 0.80 secs
Hello World!
要使用 crates.io 中的 crate,请参阅上面链接的 README 中的教程。
我专门为此编写了一个工具:Scriptisto。它是一个完全与语言无关的工具,它可以与其他编译语言或具有昂贵验证步骤的语言一起使用(Python with mypy)。
对于 Rust,它还可以获取 dependencies behind the scenes or build entirely in Docker 而无需安装 Rust 编译器。 scriptisto
将这些模板嵌入到二进制文件中,因此您可以 bootstrap 轻松地:
$ scriptisto new rust > ./script.rs
$ chmod +x ./script.rs
$ ./script.rs
您可以 new docker-rust
而不是 new rust
并且构建不需要在您的主机系统上安装 Rust 编译器。
#!/bin/sh
#![allow()] /*
exec cargo-play --cached --release [=10=] -- "$@"
*/
需要货运。你可以看到一个不需要任何东西的解决方案here:
#!/bin/sh
#![allow()] /*
# rust self-compiler by Mahmoud Al-Qudsi, Copyright NeoSmart Technologies 2020
# See <https://neosmart.net/blog/self-compiling-rust-code/> for info & updates.
#
# This code is freely released to the public domain. In case a public domain
# license is insufficient for your legal department, this code is also licensed
# under the MIT license.
# Get an output path that is derived from the complete path to this self script.
# - `realpath` makes sure if you have two separate `script.rs` files in two
# different directories, they get mapped to different binaries.
# - `which` makes that work even if you store this script in $PATH and execute
# it by its filename alone.
# - `cut` is used to print only the hash and not the filename, which `md5sum`
# always includes in its output.
OUT=/tmp/$(printf "%s" $(realpath $(which "[=11=]")) | md5sum | cut -d' ' -f1)
# Calculate hash of the current contents of the script, so we can avoid
# recompiling if it hasn't changed.
MD5=$(md5sum "[=11=]" | cut -d' ' -f1)
# Check if we have a previously compiled output for this exact source code.
if !(test -f "${OUT}.md5" && test "${MD5}" = "$(cat ${OUT}.md5)"); then
# The script has been modified or is otherwise not cached.
# Check if the script already contains an `fn main()` entry point.
if grep -Eq '^\s*(\[.*?\])*\s*fn\s*main\b*' "[=11=]"; then
# Compile the input script as-is to the previously determined location.
rustc "[=11=]" -o ${OUT}
# Save rustc's exit code so we can compare against it later.
RUSTC_STATUS=$?
else
# The script does not contain an `fn main()` entry point, so add one.
# We don't use `printf 'fn main() { %s }' because the shebang must
# come at the beginning of the line, and we don't use `tail` to skip
# it because that would result in incorrect line numbers in any errors
# reported by rustc, instead we just comment out the shebang but leave
# it on the same line as `fn main() {`.
printf "fn main() {//%s\n}" "$(cat [=11=])" | rustc - -o ${OUT}
# Save rustc's exit code so we can compare against it later.
RUSTC_STATUS=$?
fi
# Check if we compiled the script OK, or exit bubbling up the return code.
if test "${RUSTC_STATUS}" -ne 0; then
exit ${RUSTC_STATUS}
fi
# Save the MD5 of the current version of the script so we can compare
# against it next time.
printf "%s" ${MD5} > ${OUT}.md5
fi
# Execute the compiled output. This also ends execution of the shell script,
# as it actually replaces its process with ours; see exec(3) for more on this.
exec ${OUT} $@
# At this point, it's OK to write raw rust code as the shell interpreter
# never gets this far. But we're actually still in the rust comment we opened
# on line 2, so close that: */