DanielKeep/cargo-script

Can't start the script + internal error

vi opened this issue · 11 comments

vi commented
$ cat time.rs
// cargo-deps: time="0.1.34"
extern crate time;

pub fn main() {
  let ::time::Timespec { sec: s, nsec: ns } = ::time::get_time();
  let time = s as f64 + 0.001*0.001*0.001 * (ns as f64);
  println!("{}", time);
}
$ cargo script time.rs
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading libc v0.2.19
   Compiling libc v0.2.19
   Compiling winapi v0.2.8
   Compiling winapi-build v0.1.1
   Compiling kernel32-sys v0.2.2
   Compiling time v0.1.35
   Compiling time v0.1.0 (file:///home/vi/.multirust/toolchains/nightly/cargo/.cargo/script-cache/file-time-081628d1e4f892f1)
    Finished release [optimized] target(s) in 10.8 secs
internal error: No such file or directory (os error 2)

Probable cause: overridden default target for Cargo:

$ cat ~/.cargo/config 
[build]
target = "x86_64-unknown-linux-gnu"

So it's in /home/vi/.multirust/toolchains/nightly/cargo/.cargo/binary-cache/x86_64-unknown-linux-gnu/release/time instead of just /home/vi/.multirust/toolchains/nightly/cargo/.cargo/binary-cache/release/time.

Sorry for taking so long to look at this.

I don't know that I can really fix this. Insofar as I'm aware, there's no way to get Cargo to tell me where it writes executables. Currently, cargo-script has to guess where the output executable is going to be. If Cargo puts it somewhere else, there's nothing cargo-script can do.

Technically, I could switch to using cargo run instead of running the executable directly. However, this has two problems. First, I've already had people complaining about seeing the output from Cargo during builds, and using cargo run would make this worse. Secondly, there are some cases where cargo-script specifically avoids invoking Cargo in order to avoid spurious recompiles.

As such, I'm going to close this for now with a note in the readme that cargo-script does not support this.

vi commented

What needs to be changed in Cargo for this to work?

Something like:

  • cargo build --output ... - explicitly setting where to put result.
  • cargo install --path ... . - telling cargo intsall to build and install current crate.
vi commented

Actually cargo install works for this:

rust@vi-notebook:~$ cargo new --bin qqq
     Created binary (application) `qqq` project
rust@vi-notebook:~$ cd qqq
rust@vi-notebook:~/qqq$ mkdir im
rust@vi-notebook:~/qqq$ cargo install --root `pwd`/im
  Installing qqq v0.1.0 (file:///home/rust/qqq)
   Compiling qqq v0.1.0 (file:///home/rust/qqq)
    Finished release [optimized] target(s) in 4.80 secs
  Installing /home/rust/qqq/im/bin/qqq
warning: be sure to add `/home/rust/qqq/im/bin` to your PATH to be able to run the installed binaries
rust@vi-notebook:~/qqq$ ls /home/rust/qqq/im/bin/
qqq
rust@vi-notebook:~/qqq$ 

Update: re-read and realized it's about target...

vi commented

It can also be done the JSON way:

rust@vi-notebook:~/qqq$ eval "ls -lh $(cargo build --message-format=json  | rq -j 'map(x)=>{x.filenames[0]}')"
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
-rwxrwxr-x 2 rust rust 3.6M Jul 25 12:45 /home/rust/qqq/target/debug/qqq

Ok, so. First problem with that is that it requires asking Cargo to build the package to find out where the output is. This is a problem because there's a fair amount of logic in cargo-script specifically to avoid calling Cargo at all. If we have to call Cargo to find the executable, it becomes something of a case of cutting your hand off to get a paper-cut on your finger to stop hurting.

Another problem is that we want the messages as text: they get output to the user if compilation is taking a while or something goes wrong.

I can think of one way of making this work, though: when we do invoke Cargo to build a package, we invoke it again immediately afterwards to get the output filename, and then cache that somewhere.

That said, there's something that's only just now started bothering me about this: why do you have an overridden default target? If you're almost always building for that target, why aren't you using a compiler that has that target by default?

vi commented

Options:

  • When calling Cargo to build, remember and cache the path of executable;
  • After calling Cargo to build, move the executable to some deditated cargo-script's bin directory.

No need to call Cargo more than before.

when we do invoke Cargo to build a package, ...

..., we inkove it with --message-format=json, so we have information about executable's location from the first hands.

vi commented

why do you have an overridden default target

Previously rust toolchain was not installed from rustup.rs and was 32-bit. My system got more 64-bit, so I have changed default output to be 64-bit (while still using 32-bit Rust toolchain). Now It's all 64-bit, but the setting remained.

Anyway, cargo-script should not guess Cargo's output location, but make Cargo just tell it during the build. Today the problem is the setting in Cargo's config, tomorrow it will be some hypothetical new feature of Cargo (that changes directory structure). Currently it's like relying on that gcc or clang's default program name will always remain a.out.

I implemented this, but with a catch: it requires the version of Cargo that shipped with Rust 1.17 or higher. If you're using a version of Cargo prior to that one, you'll get the old guessing behaviour.

FYI; 0.2.2 has been released with this.

vi commented
$ cargo install -f cargo-script
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading cargo-script v0.2.1
  Installing cargo-script v0.2.1
^C

v0.2.1

Sorry, it's 0.2.1. I always bump the manifest version immediately after a release, so I had 0.2.2 on my mind.