PMunch/nimcr

need complete path on shebang line to nimcr

Closed this issue ยท 27 comments

jots commented

shebang line like:
#!/home/user/.nimble/bin/nimcr "c --deadCodeElim:on --"
works.
but
#!nimcr "c --deadCodeElim:on --"
gives:
-bash: ./hello.nim: nimcr: bad interpreter: No such file or directory
nimcr is on my path. even tried copying it to /usr/bin/ same problem.

is my bash messed up?

dxxb commented

I had the same problem on OSX. I worked around it using #!/usr/bin/env nimcr c --deadCodeElim:on --

0xACE commented

iirc it has to do with how the #! interpreter works. It will require assistance from /usr/bin/env unless you give a full path or change the way your shebang interpreter works. /usr/bin/env will ensure it searches your $PATH afaik. (I'm just reciting this from the top of my head, don't remember if this accurately describes how shebang works, but its something along those lines)

IIRC #! is parsed outside of current user's environment, which is why the user environment (with $PATH and such) has no effect and a full path has to be used.

On Fedora 29, #!/usr/bin/env tried to take the string nimcr c --deadCodeElim:on -- and parse it as a single string containing the program name (which obviously failed). env is a part of the coreutils package; since coreutils-8.30 it allows a switch -S, so I can use #!/usr/bin/env -S nimcr c --deadCodeElim:on --.

On RHEL 7, I had no luck with the latest available coreutils (8.22) - with anything I've tried in the shebang, I could either pass parameters to nimcr, or the resulting binary, but not both. The only solution was to build my own newer coreutils that provide the more capable env.

So for me, the solution is to use new enough coreutils package with new enough env that supports -S - I have no experience with macOS, but based on this the approach should work there, too.

dxxb commented

I solved by forbidding my fork of nimcr to accept command line arguments for Nim on the command line. This should work with different versions of coreutils and different platforms. I tested it on Ubuntu and MacOs. See dxxb@b378019

Updated usage is:

$ nimcr
Usage on the command line: nimcr filename [arguments to program]
Usage in a script:
	1- add `#!/usr/bin/env nimcr` to your script as first line
	2- (optional) add `#nimcr-args [arguments for nim compiler]` to your script as second line

so a script file starts with:

#!/usr/bin/env nimcr
#nimcr-args c --opt:size

That's actually not a bad solution. Could you update the version in the nimble file and make a PR?

dxxb commented

Sure, any preference for the version? Perhaps we should indicate a breaking change i.e. major version bump.

While I have your attention: do you think we should have some mechanism to allow overriding default parameters passed to nim on startup? I am talking about -d:release and --colors:on the issue being that #nimcr-args [args] cannot override -d:release so debug builds are not possible.

0xACE commented

That's actually not a bad solution. Could you update the version in the nimble file and make a PR?

I solved by forbidding my fork of nimcr to accept command line arguments for Nim on the command line.

Does that mean that you can no longer give arguments regarding compilation to nimcr?

Does this mean that my existing scripts that look like this:

#!/usr/bin/env -S nimcr "c -d:ssl --"

Need to be changed into this:

#!/usr/bin/env -S nimcr
#nimcr-args c -d:ssl

@dxxb, well the original idea was that this would really only be used when you wanted to run your scripts, not while writing them. That's why -d:release is always enabled. But if people have a use-case for overriding it then I'd be all for making it possible to switch. As for --colors:on that's simply because the compiler output would lose it's colours when it was passed through nimcr as it determined it was not piping to a human-read output. I guess nimcr should do the same check and enable/disable colors accordingly.

@0xACE you would be able to pass arguments to the compiler by the nimcr-args syntax like you show in your example. It's not perfect, but I want to get a proper PR for this so the pros and cons can be discussed.

dxxb commented

@PMunch, I rebased on your master branch and created a PR.

well the original idea was that this would really only be used when you wanted to run your scripts, not while writing them.

I thought so too, but it is so handy, I found myself using it while developing too. A simple solution would be to use defaults when #nimcr-args is absent or empty and use only args listed in #nimcr-args when present.

dxxb commented

Hi! Gentle ping about #6

Sorry I've been on vacation. And I'm still a bit afraid of breaking backwards compatibility.. @0xACE, did you have any input on this?

0xACE commented

Well I have been hammering the refresh key on this repo ever since this discussion was brought up, waiting for the inevitable doom of my kingdom... (nimcr carries a lot of importance in my nim-workflow)

Honestly I don't mind either way, I trust in you. Although I have seized creating any other new projects in nim until you make your decision. (My backlog is growing fast)

I like the idea of having the arguments on the second line because

#!/usr/bin/env -S nimcr "c -d:ssl --"

feels like a hack compared to

#!/usr/bin/env -S nimcr
#nimcr-args c -d:ssl

I have to be honest, I'm actually a fan of the single line method (the one used today).

But from my experience of listening to your users: they are using a pleb version of env. Their version doesn't have env -S which makes nimcr severely handicapped on machines their machines... Therefor, for the greater good, maybe the second line arguments is more fitting for a perfect world. (I don't remember exactly but I'm guessing users who do not have env -S has issues with arguments)

If second line argument is chosen:

  1. is #nimcr-args <args> the best term we can come up with? Would #nimcr <args> fit better?
    I feel like #nimcr-args <args> is explicit and makes it clear for other readers whats going on. where as #nimcr <args> is ambigious. The problem is I would never remember #nimcr-args <args>. Essentially this point is asking: Can we find a better term than #nimcr-args ? (I don't mind either way because I have a nim program that generates nim files based on a nimcr template)
  2. Will there be potential collisions with other scripts trying to reserve the second line in a nim-file? And how would it be handled? (As in maybe increase the search scope for the compiler flags) (I have previously considered adding my own #compiler-flags near the top 5 lines nim-files, sort of how vim can take flags if it's set near top/bottom of a file)

I wish we could keep both, but it feels like it would introduce problems because it's going to be confusing.

TL;DR: Unfortunately I think you have to break compatibility. Having the compiler flags on a separate line may be more portable because of env -S and would therefor be a better choice going forward.

I hope I covered my thoughts, I wish I wrote down everything I thought of the past couple of weeks... But you have my support.

dxxb commented

Sorry I've been on vacation.

No worries!

is #nimcr-args the best term we can come up with?

I wanted something unambiguous and I picked #nimcr-args because #nimcr is too close to #!nimcr. I am fine with changing to something else but I think, whatever it is, it should be unambiguous/self-explanatory.

As in maybe increase the search scope for the compiler flags

We could extend searching for #nimcr-args in the first uninterrupted comment block after the #!.

they are using a pleb version of env. Their version doesn't have env -S which makes nimcr severely handicapped on machines their machines...

FYI before settling for the solution I implemented in this PR I tried to make it work in general but different handling of #! and versions of env shipped on different platforms meant that either passing arguments to nimcr or arguments to the actual script was going to break in general.

My goal was to compile/run scripts using nimcr without changes different platforms (supporting #!). I do not like to break backwards compatibility either but I haven't found another way. On the up-side having an optional dedicated line for arguments is fairly simple and explicit.

Something that nags me a bit about my current PR is that there is no way to control some arguements nimcr passes to nim (e.g. --color and --nimcache ) but it's probably not an issue.

0xACE commented

is #nimcr-args the best term we can come up with?

I wanted something unambiguous and I picked #nimcr-args because #nimcr is too close to #!nimcr. I am fine with changing to something else but I think, whatever it is, it should be unambiguous/self-explanatory.

Yes, I see your point, but what if it was simply:

#!/usr/bin/env nimcr
# Compile with: c -d:ssl

This would help non-nimcr users realise:

"Oh, this should be compiled with: c -d:ssl"

Meaning it will sort of serve a dual purpose:

  1. nimcr will parse it automatically
  2. Human readers will understand it perfectly fine.

I'm not saying it has to be # Compile with: but it would assist in helping human readers understand it better.

Either way I'll be happy with the patch, it's not a big deal for me to implement your proposed changes.

dxxb commented

Meaning it will sort of serve a dual purpose:

I like this. If I had to look for a downside I would say that because it is so human friendly it seems to suggest it is informative instead of normative but I'd be happy with it (or something similar).

Hmm, I'm not sold on "Compile with" seems like information given to the user, rather than something which will happen automatically. Of the proposed names I prefer nimcr-args, although I'm not a huge fan of it. Maybe compiler-args or ctime-opts? Can we find some other programs that handle arguments in this way and see what they call their switch?

dxxb commented

In order of preference (high to low) for me: #nim-args[1], #nimcr-args, #compiler-args, # Compile with:.

Can we find some other programs that handle arguments in this way and see what they call their switch?

My search turn up only #! ๐Ÿคทโ€โ™‚๏ธ

[1] Those arguments are for nim not nimcr.

Order from low to high, or high to low?

dxxb commented

Order from low to high, or high to low?

Edited my comment.

dxxb commented

Hi @PMunch, just making sure this doesn't get forgotten.

dxxb commented

I updated my PR with documentation changes. I think there are at least a couple of things mentioned in this discussion we never explicitly settled one way or another.

  1. How to prefix the nim compile options line: #nim-args, #nimcr-args, #compiler-args or # Compile with:?
  2. Search for the nim compile options line only on the second line of the script or throughout the first (uninterrupted) comment block after the !# line?
dxxb commented

Hi @PMunch! Are you still ok with merging #6 ?

Yes! Just merged it ๐ŸŽ‰ What did you settle on for the second part of your last comment by the way? I think it should probably search the entire uninterrupted comment block, just in case something else requires being in line 2, but I don't think that will be an issue for anyone.

dxxb commented

Yes! Just merged it ๐ŸŽ‰

Thank you!

What did you settle on for the second part of your last comment by the way?

I was waiting for your feedback so I didn't do any work on it until now.

I think it should probably search the entire uninterrupted comment block, just in case something else requires being in line 2, but I don't think that will be an issue for anyone.

Ack, I will implement that and open a new PR.

dxxb commented

Ack, I will implement that and open a new PR.

See #7

dxxb commented

@PMunch ๐Ÿ‘‹ ๐Ÿ˜„

dxxb commented

With #7 merged I think this issue can be closed. Thanks everyone!