Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

writers.writePython3: created script fails to run on MacOS #93609

Closed
adrian-gierakowski opened this issue Jul 21, 2020 · 7 comments
Closed

writers.writePython3: created script fails to run on MacOS #93609

adrian-gierakowski opened this issue Jul 21, 2020 · 7 comments
Labels
0.kind: bug 6.topic: darwin Running or building packages on Darwin 6.topic: python

Comments

@adrian-gierakowski
Copy link
Contributor

Describe the bug
Executables produced by writers.writePython3 (and probably also writePython2 etc) fail to run on MacOS

To Reproduce
Steps to reproduce the behavior:

  1. clone https://github.com/adrian-gierakowski/nix-writePython3-broken-on-darwin
  2. run $(nix-build) from top level the repo (assuming POSIX shell)
  3. see it fail

Expected behavior
The command from step 2 should print success

Additional context

This seems to be caused by the fact that ${python3.withPackages}/bin/python which is used for shebang line
in the produced script is itself a "script text executable" which does not seem to work on MacOS.

The repo mentioned above contains a tentative fix, which prepend ${pkgs.bash}/bin/bash to the shebang line in the produced script.

NOTE: the repo above uses my own fork of nixpkgs since dash is currently broken on darwin (and writePython3 depends on dash)

Notify maintainers
@Lassulus

Metadata

  • system: "x86_64-darwin"
  • host os: Darwin 18.7.0, macOS 10.14.6
  • multi-user?: no
  • sandbox: yes
  • version: nix-env (Nix) 2.3.6pre7027_6f162d8
  • channels(adriangierakowski): ""
  • nixpkgs: /nix/store/ciqd3l5bznq5ms389b4w7yjv7vk9vpm0-source

Maintainer information:

# a list of nixpkgs attributes affected by the problem
attribute:
- writers.writePython2
- writers.writePython3
- writers.writePython2Bin
- writers.writePython3Bin
@veprbl veprbl added 6.topic: darwin Running or building packages on Darwin 6.topic: python labels Jul 22, 2020
@Lassulus
Copy link
Member

that seems quite sad. Sadly I'm not able to reproduce it since I have to working MacOS installation. Did this work in the past for you? Or is it generally broken?
I guess there is also no harm in switching from a shebang to a shell wrapper script, I'm just not sure how to test it :D

@veprbl
Copy link
Member

veprbl commented Jul 22, 2020

Related to #65351 and #11133

@adrian-gierakowski
Copy link
Contributor Author

thanks @veprbl

@Lassulus as described in the issues liked above this is generally broken since writePython3 uses ${python3.withPackages}/bin/python. which is a bash script, as interpreter which does not work on darwin (and BSD in general).

I believe a good way to fix it is to use "${self.bash}/bin/bash ${py}/bin/python" as interpreter (but only if sdenv.isDarwin == true). This should not introduce any extra run time dependencies since bash is already a dependency of python3.withPackages.

I'm happy to submit a PR

@adrian-gierakowski
Copy link
Contributor Author

additionally when libraries == [] we could simply use "${python3}/bin/python" as interpreter which would avoid the dependency on bash

@adrian-gierakowski
Copy link
Contributor Author

this is the fix I'd go for:

{
  interpreter =
    if libraries == []
    then "${super.python3}/bin/python"
    else if super.stdenv.isDarwin
      then "${self.bash}/bin/bash ${py}/bin/python"
      else "${py}/bin/python"
  ;
}

adrian-gierakowski added a commit to adrian-gierakowski/nixpkgs that referenced this issue Jul 24, 2020
On Darwin a script cannot be used as an interpreter in a shebang line, which
causes scripts produced with makeScriptWriter (and its derivatives) to fail at
run time if the used interpreter was wrapped with makeWrapper (as in the case
of python3.withPackages).

This commit fixes the problem by detecting if the interpreter is a script
and prepending its shebang to the final interpreter line.

For example if used interpreter is;
```
/nix/store/ynwv137n2650qy39swcflxbcygk5jwv1-python3-3.8.3-env/bin/python
```

which is a script with following shebang:
```
#! /nix/store/knd85yc7iwli8344ghav3zli8d9gril0-bash-4.4-p23/bin/bash -e
```

then the shebang line in the produced script will be
```
#! /nix/store/knd85yc7iwli8344ghav3zli8d9gril0-bash-4.4-p23/bin/bash -e /nix/store/ynwv137n2650qy39swcflxbcygk5jwv1-python3-3.8.3-env/bin/python
```

This works on Darwin since there does not seem to be a limit to the length
of the shabang line and the shebang lines support multiple arguments to
the interpreters (as opposed to linux where the kernel imposes a strict limit
on shebang lengh and everything following the interpreter is passed to it
as a single string).

fixes; NixOS#93609
related to: NixOS#65351 NixOS#11133 (and probably a bunch of others)

NOTE: scripts produced on platforms other tha Darwin will remain unmodified
by this PR. However it might worth considering extending this fix to BSD systems
in general. I didn't do it since I have no way of testing it on systems other
than MacOS and linux.
adrian-gierakowski added a commit to adrian-gierakowski/nixpkgs that referenced this issue Jul 24, 2020
…re needed

`python.withPackages` has a runtime dependecy on bash since it's wrapped with
`makeWrapper`. This fix avoids bash as runtime dependency when it's not
needed.

as discussed here: NixOS#93609 (comment)
Lassulus pushed a commit that referenced this issue Jul 25, 2020
* writers.makeScriptWriter: fix on Darwin\MacOS

On Darwin a script cannot be used as an interpreter in a shebang line, which
causes scripts produced with makeScriptWriter (and its derivatives) to fail at
run time if the used interpreter was wrapped with makeWrapper (as in the case
of python3.withPackages).

This commit fixes the problem by detecting if the interpreter is a script
and prepending its shebang to the final interpreter line.

For example if used interpreter is;
```
/nix/store/ynwv137n2650qy39swcflxbcygk5jwv1-python3-3.8.3-env/bin/python
```

which is a script with following shebang:
```
#! /nix/store/knd85yc7iwli8344ghav3zli8d9gril0-bash-4.4-p23/bin/bash -e
```

then the shebang line in the produced script will be
```
#! /nix/store/knd85yc7iwli8344ghav3zli8d9gril0-bash-4.4-p23/bin/bash -e /nix/store/ynwv137n2650qy39swcflxbcygk5jwv1-python3-3.8.3-env/bin/python
```

This works on Darwin since there does not seem to be a limit to the length
of the shabang line and the shebang lines support multiple arguments to
the interpreters (as opposed to linux where the kernel imposes a strict limit
on shebang lengh and everything following the interpreter is passed to it
as a single string).

fixes; #93609
related to: #65351 #11133 (and probably a bunch of others)

NOTE: scripts produced on platforms other than Darwin will remain unmodified
by this PR. However it might worth considering extending this fix to BSD systems
in general. I didn't do it since I have no way of testing it on systems other
than MacOS and linux.

* writers.makeScriptWriter: fix typo in comment

* writers.makeScriptWriter: fail build if interpreter of interpreter is a script
adrian-gierakowski added a commit to rhinofi/nixpkgs that referenced this issue Jul 26, 2020
* writers.makeScriptWriter: fix on Darwin\MacOS

On Darwin a script cannot be used as an interpreter in a shebang line, which
causes scripts produced with makeScriptWriter (and its derivatives) to fail at
run time if the used interpreter was wrapped with makeWrapper (as in the case
of python3.withPackages).

This commit fixes the problem by detecting if the interpreter is a script
and prepending its shebang to the final interpreter line.

For example if used interpreter is;
```
/nix/store/ynwv137n2650qy39swcflxbcygk5jwv1-python3-3.8.3-env/bin/python
```

which is a script with following shebang:
```
#! /nix/store/knd85yc7iwli8344ghav3zli8d9gril0-bash-4.4-p23/bin/bash -e
```

then the shebang line in the produced script will be
```
#! /nix/store/knd85yc7iwli8344ghav3zli8d9gril0-bash-4.4-p23/bin/bash -e /nix/store/ynwv137n2650qy39swcflxbcygk5jwv1-python3-3.8.3-env/bin/python
```

This works on Darwin since there does not seem to be a limit to the length
of the shabang line and the shebang lines support multiple arguments to
the interpreters (as opposed to linux where the kernel imposes a strict limit
on shebang lengh and everything following the interpreter is passed to it
as a single string).

fixes; NixOS#93609
related to: NixOS#65351 NixOS#11133 (and probably a bunch of others)

NOTE: scripts produced on platforms other than Darwin will remain unmodified
by this PR. However it might worth considering extending this fix to BSD systems
in general. I didn't do it since I have no way of testing it on systems other
than MacOS and linux.

* writers.makeScriptWriter: fix typo in comment

* writers.makeScriptWriter: fail build if interpreter of interpreter is a script
@bergkvist
Copy link
Member

This is still an issue for me. How to reproduce:

  1. Create shell.nix
let
  pkgs = import <nixpkgs> {};
  python39 = pkgs.python39.withPackages(ps: [ ps.pip ]);
in pkgs.mkShell {
  buildInputs = [ python39 ];
  shellHook = ''
    export PIP_PREFIX="$(pwd)/.build/pip"
    export PYTHONPATH="$(pwd):$(pwd)/.build/pip/lib/python3.9/site-packages:$PYTHONPATH"
    export PATH="$(pwd)/.build/pip/bin:$PATH"
  '';
}
  1. Try to install and run ipython in the nix-shell (or any other executable python library)
[nix-shell:~/my-project]$ pip install ipython

# Now, after installing ipython, let's try to execute it
[nix-shell:~/my-project]$ ipython

# /Users/tobias/my-project/.build/pip/bin/ipython: line 3: import: command not found
# /Users/tobias/my-project/.build/pip/bin/ipython: line 4: import: command not found
# from: can't read /var/mail/IPython
# /Users/tobias/my-project/.build/pip/bin/ipython: line 7: syntax error near unexpected token `('
# /Users/tobias/my-project/.build/pip/bin/ipython: line 7: `    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])'

Looking inside .build/pip/bin/ipython, I see this:

#!/nix/store/i46k148mi830riq4wxh49ki8qmq0731k-python3-3.9.2-env/bin/python3.9
# -*- coding: utf-8 -*-
import re
import sys
from IPython import start_ipython
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(start_ipython())

@veprbl
Copy link
Member

veprbl commented Apr 25, 2021

@bergkvist Please file a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0.kind: bug 6.topic: darwin Running or building packages on Darwin 6.topic: python
Projects
None yet
Development

No branches or pull requests

5 participants