denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
96.1k stars 5.31k forks source link

Runtime API to check whether in self-contained exe #15996

Open DerZade opened 2 years ago

DerZade commented 2 years ago

I couldn't find a runtime API to check whether the current code is running inside a self-contained exe.

This would make it easy to distinguish between the "production" (compiled) version and testing via deno run.

I was thinking about something like Deno.standalone or maybe something more descriptive like Deno.selfContainedExe.

dsherret commented 2 years ago

Would you be able to provide some use cases for this suggestion? There might be alternatives.

DerZade commented 2 years ago

Would you be able to provide some use cases for this suggestion? There might be alternatives.

I want to have a data directory at a relative path to the executable (or the main module when not compiled).

I can't use Deno.mainModule as a base, because that doesn't work in self contained executables (it includes the path of the main module at build time) and I can't use Deno.execPath, because that returns the deno exe, when not compiled.

Also the relative path differs a bit between compiled and not compiled. For compiled it is ./data (relative to the executable) otherwise it's ../data (relative to the main module)


This is my specific use case, but I bet there are more use cases, which would benefit from such an API.

jsejcksn commented 2 years ago

@DerZade Not a solution, but here's a potential workaround if you're in control of compiling the binary:

You can switch on the presence of a specific CLI argument to make the determination, and embed that argument into the compiled binary:

example.ts:

import * as path from "https://deno.land/std@0.158.0/path/mod.ts";

const isCompiled = Deno.args.includes("--is_compiled_binary");

const programPath = isCompiled
  ? Deno.execPath()
  : path.fromFileUrl(Deno.mainModule);

const programDir = path.dirname(programPath);

console.log({
  isCompiled,
  programDir,
  programPath,
});
gh-issue-15996 % deno --version                              
deno 1.26.0 (release, x86_64-apple-darwin)
v8 10.7.193.3
typescript 4.8.3

gh-issue-15996 % deno run --allow-read --no-prompt example.ts
{
  isCompiled: false,
  programDir: "/Users/deno/gh-issue-15996",
  programPath: "/Users/deno/gh-issue-15996/example.ts"
}

gh-issue-15996 % mkdir binary_dir

gh-issue-15996 % deno compile --output=binary_dir/example --allow-read --no-prompt example.ts --is_compiled_binary
Compile file:///Users/deno/gh-issue-15996/example.ts
Emit binary_dir/example

gh-issue-15996 % ./binary_dir/example 
{
  isCompiled: true,
  programDir: "/Users/deno/gh-issue-15996/binary_dir",
  programPath: "/Users/deno/gh-issue-15996/binary_dir/example"
}

Of course, you'll have to account for this potential extra argument if your program already accepts other arguments — and if you're concerned about the target argument being inadvertently used with the not-compiled script (a false positive), just use something unguessable like a UUID in place of the one I used in the example above.

DerZade commented 2 years ago

@jsejcksn I also thought about that workaround and we will probably use something similar in our product, but I still think a actual Deno-API would be nice.

mxcl commented 1 year ago

What I don’t like about the suggestion is the user could supply this argument themselves to deno run. However that's less of an issue since I plan to distribute the binary and only expect users to run the sources when hacking on them.

Also I would feel better if the code I'm trying to change is actively not included in the final binaries, which I would expect to happen due to dead code removal if there was a static API for the “you're being compiled” condition.

K0IN commented 3 months ago

Hei, is there any update on this (the PR seems to be stale, last update a year ago) I would really like this feature as a workaround (if the behaviour is intended) for my issue: https://github.com/denoland/deno/issues/24318

KaKi87 commented 3 months ago

Hello, Any news on this ? Thanks

DerZade commented 3 months ago

The PR is not stale, although it might seem like it.

Im still more than willing to implement this. My time is just to precious to to put effort into something, without knowing if there is actually any chance of it getting merged.

Considering that my first attempt just got "ignored", I'm waiting for an "official" signal on if this is actually something the core team would consider merging.

lino-levan commented 2 months ago

This is pretty easy to implement yourself in userland (though I will admit it is a bit hacky).

Lucsoft from discord's suggestion:

const isDenoRT = Deno.mainModule.includes("deno-compile-temp")
localhosted commented 1 month ago

Is this moving forward? I need to be able to load a DLL from current dir when running compiled, or from import.meta.url if using deno task or running directly

lino-levan commented 1 month ago

Does the suggestion I posted not solve your issue while we wait for an official API?

localhosted commented 1 month ago

I tried your suggestion and another snippet I found:

const isDenoRT = Deno.mainModule.includes("deno-compile-temp");
const isCompiled = Deno.args.includes("--is_compiled_binary");

console.log(isDenoRT, isCompiled, Deno.mainModule, Deno.args)

But it didn't work when running the executable generated from deno compile -A run.ts

false false file:///C:/Users/User/AppData/Local/Temp/deno-compile-run.exe/deno-demo-master/run.ts []

I'm using Windows

lino-levan commented 1 month ago

Ah, well it seems to me like you could modify it to be

const isDenoRT = Deno.mainModule.includes("deno-compile");

and that would be a hack that would work for now.

KaKi87 commented 1 month ago

Oh, I would have adopted this, but if it breaks every few months, then I guess the only realistic workaround is to use the additional arbitrary CLI argument. :/

lucacasonato commented 3 weeks ago

I think the best path forward is to expose this information in Deno.build as Deno.build.standalone: boolean. It would be true for deno compile binaries, and false everywhere else.