How to determine crystal run vs built executable

How in my code can I determine whether it’s being run with crystal run vs when it’s a built executable?

i.e. in pseudo-code:

if CRYSTAL_RUN
    do_something
else
    do_something_else
end

crystal run also builds an executable, just like crystal build. It just builds into a temporary file.

So you could potentially use that as an indicator, if PROGRAM_NAME points to a temp file.

What do you want to achieve with this, though?

Not proud of this one, but

if (PROGRAM_NAME.starts_with? {{ `crystal env CRYSTAL_CACHE_DIR`.chomp.stringify }}) &&
   (File.basename(PROGRAM_NAME).includes?("run")) &&
   (PROGRAM_NAME.ends_with? ".tmp")
  p "run"
else
  p "build"
end

If run is setting some kind of compile-time flag, it should be possible to detect it with a macro.
But I couldn’t find anything in the docs — Maybe there’s some undocumented flag that I just don’t know about.

The cache dir should be available directly as Crystal::CACHE_DIR. You don’t need to shell out for that.

No. There’s nothing special about run. It is semantically equivalent to build into temp file + exec. The compiler doesn’t make any distinction about which command builds a program.

1 Like

Another option is to look at the parent process. When using crystal run, the parent is called crystal.
For example, on a Linux system

# crystal_run.cr
ppid = File.read("/proc/#{Process.pid}/status").scan(/(?<=PPid:\t)\d+/)[0]
crystal_run = File.read("/proc/#{ppid}/comm") == "crystal\n"
p! crystal_run
$ crystal run crystal_run.cr
crystal_run # => true
$ crystal build crystal_run.cr && ./crystal_run
crystal_run # => false
2 Likes

I was having a problem using relative paths, they would work fine on my desktop but not in my VPS ( both Debian 12 ) so I used Path[PROGRAM_NAME].expand.dirname to get the absolute path but of course that resulted in issues with crystal run

I had fudged a workaround like this:

program_path = Path[PROGRAM_NAME].expand.dirname
if program_path.includes?(".cache")

but I thought perhaps there was a proper way :slightly_smiling_face:

Would Process.executable_path be better for this?