如何在Unix系统上直接执行Rust代码? (使用shebang)

时间:2016-12-25 15:17:05

标签: rust shebang

从阅读this thread开始,看起来可以使用shebang来运行Rust *。

#!/usr/bin/env rustc

fn main() {
    println!("Hello World!");
}

使这个可执行文件运行并编译,但不运行代码。

chmod +x hello_world.rs
./hello_world.rs

但是,这只会将代码编译为hello_world

可以直接执行*.rs个文件,类似于shell脚本吗?

*这引用了rustx,我调查了这个,但它是一个bash脚本,每次都编译脚本(没有缓存)并且永远不会从temp目录中删除文件,尽管这可以改进。它也有很大的局限性,它不能使用板条箱。

4 个答案:

答案 0 :(得分:14)

cargo-script。这也允许你使用依赖。

通过cargo-script安装cargo install 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中的crates,请参阅上面链接的README中的教程。

答案 1 :(得分:1)

这似乎有效:

#!/bin/sh
//usr/bin/env rustc $0 -o a.out && ./a.out && rm ./a.out ; exit

fn main() {
    println!("Hello World!");
}

答案 2 :(得分:0)

我为此专门编写了一个工具:Scriptisto。这是一个完全与语言无关的工具,可与其他编译语言或具有昂贵验证步骤的语言(带有mypy的Python)一起使用。

对于Rust,它也可以在后台获取dependencies或完全在Docker中构建,而无需安装Rust编译器。 scriptisto将这些模板嵌入二进制文件中,以便您轻松引导:

$ scriptisto new rust > ./script.rs
$ chmod +x ./script.rs
$ ./script.rs

您可以执行new rust而不是new docker-rust,并且该构建不需要主机系统上的Rust编译器。

答案 3 :(得分:0)

#!/bin/sh
#![allow()] /*
            exec cargo-play --cached --release $0 -- "$@"
                        */

需要货运。您可以看到不需要任何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 "$0")) | 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 "$0" | 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*' "$0"; then
        # Compile the input script as-is to the previously determined location.
        rustc "$0" -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 $0)" | 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: */