Co-authored-by: Robin Gloster <mail@glob.in>
stdenv: print message if structuredAttrs is enabled
stdenv: add _append
reduces the chance of a user doing it wrong
fix nix develop issue
output hooks don't work yet in nix develop though
making $outputs be the same on non-structuredAttrs and structuredAttrs
is too much trouble.
lets instead make a function that gets the output names
reading environment file '/nix/store/2x7m69a2sm2kh0r6v0q5s9z1dh41m4xf-xz-5.2.5-env-bin'
nix: src/nix/develop.cc:299: std::string Common::makeRcScript(nix::ref<nix::Store>, const BuildEnvironment&, const Path&): Assertion `outputs != buildEnvironment.vars.end()' failed.
use a function to get all output names instead of using $outputs
copy env functionality from https://github.com/NixOS/nixpkgs/pull/76732/commits
This commit fixes precise dependency ignorance by converting the
environment variable `autoPatchelfIgnoreMissingDeps` into a bash array
`ignoreMissingDepsArray`, passing `"${ignoreMissingDepsArray[@]}"`
instead of `"${autoPatchelfIgnoreMissingDeps[@]}"` to the python
script.
The original implementation does not work when
`autoPatchelfIgnoreMissingDeps` contains multiple dependency names.
Because it mistakenly passes `"${autoPatchelfIgnoreMissingDeps[@]}"`
to the python script. According to the Nix manual
(https://nixos.org/manual/nix/stable/expressions/derivations.html),
lists of strings are concatenated into whitespace-separated strings,
then passed to the builder as environment variables. So, if
`autoPatchelfIgnoreMissingDeps = [ "dep1" "dep2" "dep3" ]`,
`"${autoPatchelfIgnoreMissingDeps[@]}"` will be expanded to a single
argument `"dep1 dep2 dep3"`, which is not the intended behavior,
because the python script takes the long argument as a dependency
name.
With this commit, `"${ignoreMissingDepsArray[@]}"` will be expanded to
three arguments `"dep1" "dep2" "dep3"` arguments as expected, fixing
the issue.
* rewrite autoPatchelfHook in python
* Update pkgs/build-support/setup-hooks/auto-patchelf.py
Co-authored-by: aszlig <aszlig@redmoonstudios.org>
* Update pkgs/build-support/setup-hooks/auto-patchelf.py
Co-authored-by: aszlig <aszlig@redmoonstudios.org>
* Apply suggestions from code review
Co-authored-by: aszlig <aszlig@redmoonstudios.org>
* Fix issues discovered during tests
* Apply suggestions from code review
Co-authored-by: aszlig <aszlig@redmoonstudios.org>
* fixup line wrapping
* autoPatchelfHook: Improve compatibility with bash version
* autoPatchelfHook: Fix symlink-reated issues
* autoPatchelfHook: Revert dubious patchelf invocation test
* autoPatchelfHook: Untangle the executable detection logic
* fixup! autoPatchelfHook: Untangle the executable detection logic
* autoPatchelfHook: Fix invalid borrow issue
* autoPatchelfHook: Handle runtimeDependencies as the bare string it is
* autoPatchelfHook: add bintools dependency
For the very rare cases where it is not included by default.
* autoPatchelfHook: replace old hook with the rewrite
* autoPatchelfHook: get rid of the old hook content
* autoPatchelfHook: fix wrong ordering of debug info
* autoPatchelfHook: persist extra search path across incovations
* autoPatchelfHook: fix wrong usage of global variables
* Update auto-patchelf.py
PEP8: ignoreMissing -> ignore_missing
* Apply suggestions from code review
Co-authored-by: aszlig <aszlig@redmoonstudios.org>
* autoPatchelfHook: remove imprecise and incorrect warning
* Apply explicit types from code review
Co-authored-by: Jörg Thalheim <Mic92@users.noreply.github.com>
* Complement and polish types and snake_casing
Co-authored-by: aszlig <aszlig@redmoonstudios.org>
Co-authored-by: Jörg Thalheim <Mic92@users.noreply.github.com>
autoPatchelfHook actually doesn't depend on stdenv and only needs
bintools (with its wrapper). This change uses $NIX_BINTOOLS instead of
$NIX_CC and makes the dependency on bintools explicit.
Fully enabling crossSystem support for autoPatchelfHook came with some
perhaps unintended consequences of being a bit more aggressive about
patching ELF files from architectures/ABIs that differ from the target
(previously, those files would be ignored because ldd usually couldn't
handle them).
This change adds architecture and rough OS ABI detection to the script
so that it doesn't try to blindly replace the interpreter of files that
can't possibly use that interpreter, and also makes sure it doesn't
accidentally use libraries of other architectures/ABIs.
In #84415, autoPatchelfHook was taught to use the correct path to the
readelf binary when a crossSystem is specified. Unfortunately, the
remainder of the functionality in the script depended on ldd, which only
reads ELF files of its own architecture. It has the further unfortunate
quality of not reporting any useful error, but rather that the file is
not a dynamic executable.
This change uses patchelf to directly analyze the DT_NEEDED tags in the
target files instead, which correctly works across architectures. It
also updates the use of objdump to be prefix-aware $OBJDUMP (which would
have been required in the PR mentioned above, but we never made it that
far into the script execution).
Go beyond the obvious setup hooks now, with a bit of sed, with a skipped case:
- cc-wrapper's `dontlink`, because it already is handled.
Also, in nix files escaping was manually added.
EMP
This rare sitation was caught when building zoom-us package:
```
automatically fixing dependencies for ELF files
/nix/store/71d65fplq44y9yn2fvkpn2d3hrszracd-auto-patchelf-hook/nix-support/setup-hook: line 213: echo: write error: Broken pipe
/nix/store/71d65fplq44y9yn2fvkpn2d3hrszracd-auto-patchelf-hook/nix-support/setup-hook: line 210: echo: write error: Broken pipe
```
The worst is that derivation continued and resulted into broken package:
https://github.com/NixOS/nixpkgs/pull/55566#issuecomment-470065690
I hope, replacing `grep -q` with `grep` will remove this race condition.
If the file in question is not a shared object file but an ELF, we
really want to skip the file, because we won't have anything to patch
there.
For example if the file is created via "gcc -c -o foo.o foo.c", we don't
get a segment header and so far autoPatchelf was trying to patch such a
file.
By checking for missing segment headers, we're now no longer going to
attempt patching such a file.
Signed-off-by: aszlig <aszlig@nix.build>
Reported-by: Sander van der Burg <svanderburg@gmail.com>
While declaring it as an array doesn't do any harm in our usage, it
might be a bit confusing when reading the code.
Signed-off-by: aszlig <aszlig@nix.build>
This function is useful if autoPatchelf is invoked during some of the
phases of a build and allows to add arbitrary shared objects to the
search path.
So far the same functionality was in autoPatchelf itself, but not
available as a separate function, so when adding shared objects to the
dependency cache one would have to do so manually.
The function also has the --no-recurse flag, which prevents recursing
into subdirectories.
Signed-off-by: aszlig <aszlig@nix.build>
This is to be used with the autoPatchelf command and allows to only
patch a specific file or directory without recursing into
subdirectories.
Apart from being able to run the command in a standalone way, as
detailled in the previous commit this is also needed for the Android SDK
emulator, because according to @svanderburg there are subdirectories we
don't want to patch.
The reason why I didn't use GNU getopt is that it might not be available
on all operating systems and the getopts bash builtin doesn't support
long arguments. Apart from that, the implementation for recognizing the
flag is pretty trivial and it's also using bash builtins only, so if we
want to do something really fancy someday, we can still change it.
Signed-off-by: aszlig <aszlig@nix.build>
If you want to only run autoPatchelf on a specific path and leave
everything else alone, we now have a $dontAutoPatchelf environment
variable, which causes the postFixup hook to not run at all.
The name "dontAutoPatchelf" probably is a bit weird in conjunction with
putting "autoPatchelfHook" in nativeBuildInputs, but unless someone
comes up with a better name I keep it that way because it's consistent
with all the other dontStrip, dontPatchShebangs, dontPatchELF and
whatnot.
A specific example where this is needed is when building the Android SDK
emulator, which contains a few ARM binaries in subdirectories that
should not be patched. If we were to run autoPatchelf on all outputs
unconditionally we'd run into errors because some ARM libraries couldn't
be found.
Signed-off-by: aszlig <aszlig@nix.build>
The autoPatchelf main function which is run against all of the outputs
was pretty much tailored towards this specific setup-hook and was
relying on $prefix to be set globally.
So if you wanted to run autoPatchelf manually - let's say during
buildPhase - you would have needed to run it like this:
prefix=/some/directory autoPatchelf
This is now more intuitive and all you need to do is run the following:
autoPatchelf /some/directory
Signed-off-by: aszlig <aszlig@nix.build>
I originally thought it would just be enough to just check for an INTERP
section in isExecutable, however this would mean that we don't detect
statically linked ELF files, which would break our recent improvement to
gracefully handle those.
In theory, we are only interested in ELF files that have an INTERP
section, so checking for INTERP would be enough. Unfortunately the
isExecutable function is already used outside of autoPatchelfHook, so we
can't easily get rid of it now, so let's actually strive for more
correctness and make isExecutable actually match ELF files that are
executable.
So what we're doing instead now is to check whether either the ELF type
is EXEC *or* we have an INTERP section and if one of them is true we
should have an ELF executable, even if it's statically linked.
Along the way I also set LANG=C for the invocations of readelf, just to
be sure we don't get locale-dependent output.
Tested this with the following command (which contains almost[1] all the
packages using autoPatchelfHook), checking whether we run into any
library-related errors:
nix-build -E 'with import ./. { config.allowUnfree = true; };
runCommand "test-executables" {
drvs = [
anydesk cups-kyodialog3 elasticsearch franz gurobi
masterpdfeditor oracle-instantclient powershell reaper
sourcetrail teamviewer unixODBCDrivers.msodbcsql17 virtlyst
vk-messenger wavebox zoom-us
];
} ("for i in $drvs; do for b in $i/bin/*; do " +
"[ -x \"$b\" ] && timeout 10 \"$b\" || :; done; done")
'
Apart from testing against library-related errors I also compared the
resulting store paths against the ones prior to this commit. Only
anydesk and virtlyst had the same as they didn't have self-references,
everything else differed only because of self-references, except
elasticsearch, which had the following PIE binaries:
* modules/x-pack/x-pack-ml/platform/linux-x86_64/bin/autoconfig
* modules/x-pack/x-pack-ml/platform/linux-x86_64/bin/autodetect
* modules/x-pack/x-pack-ml/platform/linux-x86_64/bin/categorize
* modules/x-pack/x-pack-ml/platform/linux-x86_64/bin/controller
* modules/x-pack/x-pack-ml/platform/linux-x86_64/bin/normalize
These binaries were now patched, which is what this commit is all about.
[1]: I didn't include the "maxx" package (MaXX Interactive Desktop)
because the upstream URLs are no longer existing and I couldn't
find them elsewhere on the web.
Signed-off-by: aszlig <aszlig@nix.build>
Fixes: https://github.com/NixOS/nixpkgs/issues/48330
Cc: @gnidorah (for MaXX Interactive Desktop)
The "maxx" package recursively runs isExecutable on a bunch of files and
since the change to use "readelf" instead of "file" a lot of errors like
this one are printed during build:
readelf: Error: Not an ELF file - it has the wrong magic bytes at the
start
While the isExecutable was never meant to be used outside of the
autoPatchelfHook, it's still a good idea to silence the errors because
whenever readelf fails, it clearly indicates that the file in question
is not a valid ELF file.
Signed-off-by: aszlig <aszlig@nix.build>
If the ELF file is not an executable, we do not get a PT_INTERP section,
because after all, it's a *shared* library.
So instead of checking for PT_INTERP (to avoid statically linked
executables) for all ELF files, we add another check to see if it's an
executable and *only* skip it when it is and there's no PT_INTERP.
Signed-off-by: aszlig <aszlig@nix.build>
So far the runtimeDependencies variable has been rather useless unless
you also set dontPatchelf, because the patchelf setup hook ran *after*
the autoPatchelfHook and thus stripped off the additional RPATHs added
using runtimeDependencies.
I did this by moving the autoPatchelfHook to be run in postFixup instead
of fixupOutput, however I needed to replicate the for loop that runs the
hook on all outputs.
Until we have a way to influence order of execution for hooks I've
marked this with an XXX so that we can use fixupOutput again.
Tested this against all packages that use autoPatchelfHook using the
following and checking whether the output contains any errors concerning
shared libraries:
nix-build -E 'with import ./. { config.allowUnfree = true; };
runCommand "test-executables" {
drvs = [
masterpdfeditor franz zoom-us anydesk teamviewer maxx
oracle-instantclient cups-kyodialog3 virtlyst powershell
];
} "for i in $drvs; do for b in $i/bin/*; do \"$b\" || :; done; done"
'
Signed-off-by: aszlig <aszlig@nix.build>
Fixes: https://github.com/NixOS/nixpkgs/issues/43082
Cc: @Ericson2314
If there is a shared object or executable that's using
position-independent code, the file's mime type is
"application/x-pie-executable", so until this change its dependencies
wouldn't be patched.
This simply adds the mime type to the search loop.
Signed-off-by: aszlig <aszlig@nix.build>
I originally wrote this for packaging proprietary games in Vuizvui[1]
but I thought it would be generally useful as we have a fair amount of
proprietary software lurking around in nixpkgs, which are a bit tedious
to maintain, especially when the library dependencies change after an
update.
So this setup hook searches for all ELF executables and libraries in the
resulting output paths after install phase and uses patchelf to set the
RPATH and interpreter according to what dependencies are available
inside the builder.
For example consider something like this:
stdenv.mkDerivation {
...
nativeBuildInputs = [ autoPatchelfHook ];
buildInputs = [ mesa zlib ];
...
}
Whenever for example an executable requires mesa or zlib, the RPATH will
automatically be set to the lib dir of the corresponding dependency.
If the library dependency is required at runtime, an attribute called
runtimeDependencies can be used to list dependencies that are added to
all executables that are discovered unconditionally.
Beside this, it also makes initial packaging of proprietary software
easier, because one no longer has to manually figure out the
dependencies in the first place.
[1]: https://github.com/openlab-aux/vuizvui
Signed-off-by: aszlig <aszlig@nix.build>
Closes: #34506