`cargo run` slow on MacOS when binary already built

When the binary is considerably large, the cargo run takes long time on MacOS even though it has nothing to do.

Example binary -- very quick to run:

$ time ./target/debug/datafusion-cli --version
datafusion-cli 41.0.0

real	0m0.022s

cargo build alone is quick, since there is nothing to do:

$ time cargo build --offline --bin datafusion-cli
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s

real	0m0.234s

but cargo run is slow

$ time cargo run --offline --bin datafusion-cli -- --version
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/datafusion-cli --version`
datafusion-cli 41.0.0

real	0m2.599s

When the system is under heavy load, a "Verifying 'datafusion-cli'" popup can be seen.
Normally it doesn't show up, but over 2s are spend on something.

The binary is almost 200M in size. It's mtime does not change when running build or run

ll target/debug/datafusion-cli
-rwxr-xr-x 1 findepi staff 199M Sep 12 12:18 target/debug/datafusion-cli

Those 2 seconds (or more on bigger binary, or when CPU is already busy with something) affect developing experience in an IDE. VS Code and RustRover both invoke cargo run and not the binary directly.

~How to speed up running the binary when it is already built?~
How to speed up running the binary via IDE when it is already built?

Just run the binary directly from the target/ subdirectory.

Yes, i know I can do that, especially when invoking from terminal.
But my IDE (both i tried) delegates build commands to cargo (which not unwise in general), which then incurs this few sec delay.
Even if i forgo using any IDE and switch over to any other text editor, I would still want to invoke cargo in my flow (either cargo run or cargo build). However running cargo build is enough to "taint" the binary and then the first invocation of it takes more time:

$ time ./target/debug/datafusion-cli --version
datafusion-cli 41.0.0

real	0m0.046s
user	0m0.014s
sys	0m0.017s

$ time cargo build --offline --bin datafusion-cli
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.38s

real	0m0.454s
user	0m0.131s
sys	0m0.121s

$ time ./target/debug/datafusion-cli --version
datafusion-cli 41.0.0

real	0m2.351s
user	0m0.010s
sys	0m0.044s

$ time ./target/debug/datafusion-cli --version
datafusion-cli 41.0.0

real	0m0.045s
user	0m0.013s
sys	0m0.023s

On Linux at least the only thing cargo does with the executable in target/debug when nothing has changed since the last build is opening the file as read-only and running statx on it. (presumably to get the last modified timestamp) It doesn't copy/hardlink the file again.

[...]
openat(AT_FDCWD, "/tmp/foo/target/debug/foo", O_RDONLY|O_CLOEXEC) = 11
statx(11, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0755, stx_size=3611200, ...}) = 0
close(11)                               = 0
[...]

Maybe you could check if cargo does something different on macOS? I believe dtruss should work on non-system executables like cargo even when SIP is enabled.

thanks @bjorn3 thats helpful!

you're right that I have SIP enabled. i did try to use dtrace and dtruss, but not successfully. the internet suggests i might run into "apple endpoint security framework". All in all, i couldn't get a strace-equivalent on cargo build (or anything else).

i did an blind experiment -- wrote a C program that opens the binary (r/w + append), and then execve's it. Doing open (even in write mode) didn't trigger the verification though.

What terminal are you using?

Because I had been idly wondering for a while why XprotectService on my Mac kicked in for a second or two every time I tried to run some Rust binary I had just compiled. That had started some time ago, but I wasn't sure whether it came with an OS update or at some unrelated time.

Turns out that I'm using iTerm2 as a terminal, and in the "Developer Tools" section under "Privacy & Security" in the system preferences, Apple Terminal was listed under "Allow the applications below to run software locally that does not meet the system's security policy ", but not iTerm2!

Added iTerm2 to that list, restarted iTerm2 - and hey, no more XprotectService delays when doing cargo test!

That's gold, larseggert, thank you!
It is an awesome workaround. I added my IDE to that list and now running the binary is snap just as it should be.