ghc binary: Fix interpreter than patch RPATH

The newer to-be-added binaries have relative RPATHs that we'll break if
we try to `patchelf` before installation. We instead us LD_LOAD_LIBRARY
during the installation, which avoids needing to change the RPATH
temporarily.
This commit is contained in:
John Ericson 2017-09-22 14:29:04 -04:00 committed by Domen Kožar
parent 26a46295eb
commit 150255e318
No known key found for this signature in database
GPG key ID: C2FFBCAFD2C24246
3 changed files with 95 additions and 54 deletions

View file

@ -24,6 +24,10 @@ stdenv.mkDerivation rec {
nativeBuildInputs = [ perl ]; nativeBuildInputs = [ perl ];
# Cannot patchelf beforehand due to relative RPATHs that anticipate
# the final install location/
LD_LIBRARY_PATH = stdenv.lib.makeLibraryPath [ libedit ncurses5 gmp ];
postUnpack = postUnpack =
# Strip is harmful, see also below. It's important that this happens # Strip is harmful, see also below. It's important that this happens
# first. The GHC Cabal build system makes use of strip by default and # first. The GHC Cabal build system makes use of strip by default and
@ -40,9 +44,9 @@ stdenv.mkDerivation rec {
# On Linux, use patchelf to modify the executables so that they can # On Linux, use patchelf to modify the executables so that they can
# find editline/gmp. # find editline/gmp.
stdenv.lib.optionalString stdenv.hostPlatform.isLinux '' stdenv.lib.optionalString stdenv.hostPlatform.isLinux ''
find . -type f -perm -0100 \ find . -type f -perm -0100 -exec patchelf \
-exec patchelf --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \ --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" {} \;
--set-rpath "${stdenv.lib.makeLibraryPath [ libedit ncurses5 gmp ]}" {} \;
for prog in ld ar gcc strip ranlib; do for prog in ld ar gcc strip ranlib; do
find . -name "setup-config" -exec sed -i "s@/usr/bin/$prog@$(type -p $prog)@g" {} \; find . -name "setup-config" -exec sed -i "s@/usr/bin/$prog@$(type -p $prog)@g" {} \;
done done
@ -67,6 +71,13 @@ stdenv.mkDerivation rec {
sed -i "s@^\(.*pkgName = PackageName \"rts\".*\libraryDirs = \\[\)\(.*\)@\\1\"${gmp.out}/lib\",\2@" $out/lib/ghc-${version}/package.conf sed -i "s@^\(.*pkgName = PackageName \"rts\".*\libraryDirs = \\[\)\(.*\)@\\1\"${gmp.out}/lib\",\2@" $out/lib/ghc-${version}/package.conf
''; '';
# On Linux, use patchelf to modify the executables so that they can
# find editline/gmp.
preFixup = stdenv.lib.optionalString stdenv.isLinux ''
find "$out" -type f -executable \
-exec patchelf --set-rpath "${LD_LIBRARY_PATH}" {} \;
'';
doInstallCheck = true; doInstallCheck = true;
installCheckPhase = '' installCheckPhase = ''
# Sanity check, can ghc create executables? # Sanity check, can ghc create executables?

View file

@ -3,6 +3,16 @@
, ncurses5, gmp, libiconv , ncurses5, gmp, libiconv
}: }:
let
libPath = stdenv.lib.makeLibraryPath ([
ncurses5 gmp
] ++ stdenv.lib.optional (stdenv.hostPlatform.isDarwin) libiconv);
libEnvVar = stdenv.lib.optionalString stdenv.hostPlatform.isDarwin "DY"
+ "LD_LIBRARY_PATH";
in
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
version = "7.0.4"; version = "7.0.4";
@ -30,6 +40,10 @@ stdenv.mkDerivation rec {
nativeBuildInputs = [ perl ]; nativeBuildInputs = [ perl ];
# Cannot patchelf beforehand due to relative RPATHs that anticipate
# the final install location/
${libEnvVar} = libPath;
postUnpack = postUnpack =
# GHC has dtrace probes, which causes ld to try to open /usr/lib/libdtrace.dylib # GHC has dtrace probes, which causes ld to try to open /usr/lib/libdtrace.dylib
# during linking # during linking
@ -57,34 +71,18 @@ stdenv.mkDerivation rec {
find . -name base.buildinfo \ find . -name base.buildinfo \
-exec sed -i "s@extra-lib-dirs: @extra-lib-dirs: ${libiconv}/lib@" {} \; -exec sed -i "s@extra-lib-dirs: @extra-lib-dirs: ${libiconv}/lib@" {} \;
'' + '' +
# On Linux, use patchelf to modify the executables so that they can # Rename needed libraries and binaries, fix interpreter
# find editline/gmp.
stdenv.lib.optionalString stdenv.isLinux '' stdenv.lib.optionalString stdenv.isLinux ''
find . -type f -perm -0100 \ find . -type f -perm -0100 -exec patchelf \
-exec patchelf --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \ --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" {} \;
--set-rpath "${stdenv.lib.makeLibraryPath [ ncurses5 gmp ]}" {} \;
paxmark m ./ghc-${version}/ghc/stage2/build/tmp/ghc-stage2
sed -i "s|/usr/bin/perl|perl\x00 |" ghc-${version}/ghc/stage2/build/tmp/ghc-stage2 sed -i "s|/usr/bin/perl|perl\x00 |" ghc-${version}/ghc/stage2/build/tmp/ghc-stage2
sed -i "s|/usr/bin/gcc|gcc\x00 |" ghc-${version}/ghc/stage2/build/tmp/ghc-stage2 sed -i "s|/usr/bin/gcc|gcc\x00 |" ghc-${version}/ghc/stage2/build/tmp/ghc-stage2
for prog in ld ar gcc strip ranlib; do for prog in ld ar gcc strip ranlib; do
find . -name "setup-config" -exec sed -i "s@/usr/bin/$prog@$(type -p $prog)@g" {} \; find . -name "setup-config" -exec sed -i "s@/usr/bin/$prog@$(type -p $prog)@g" {} \;
done done
'' + stdenv.lib.optionalString stdenv.isDarwin ''
# not enough room in the object files for the full path to libiconv :(
fix () {
install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib $1
}
ln -s ${libiconv}/lib/libiconv.dylib ghc-${version}/utils/ghc-pwd/dist/build/tmp
ln -s ${libiconv}/lib/libiconv.dylib ghc-${version}/utils/hpc/dist/build/tmp
ln -s ${libiconv}/lib/libiconv.dylib ghc-${version}/ghc/stage2/build/tmp
for file in ghc-cabal ghc-pwd ghc-stage2 ghc-pkg haddock hsc2hs hpc; do
fix $(find . -type f -name $file)
done
for file in $(find . -name setup-config); do
substituteInPlace $file --replace /usr/bin/ranlib "$(type -P ranlib)"
done
''; '';
configurePlatforms = [ ]; configurePlatforms = [ ];
@ -101,6 +99,29 @@ stdenv.mkDerivation rec {
# calls install-strip ... # calls install-strip ...
dontBuild = true; dontBuild = true;
# On Linux, use patchelf to modify the executables so that they can
# find editline/gmp.
preFixup = stdenv.lib.optionalString stdenv.isLinux ''
find "$out" -type f -executable \
-exec patchelf --set-rpath "${libPath}" {} \;
'' + stdenv.lib.optionalString stdenv.isDarwin ''
# not enough room in the object files for the full path to libiconv :(
ln -s ${libiconv}/lib/libiconv.dylib $out/bin
ln -s ${libiconv}/lib/libiconv.dylib $out/lib/ghc-${version}/libiconv.dylib
fix () {
install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib $1
}
for file in ghc-cabal ghc-pwd ghc-stage2 ghc-pkg haddock hsc2hs hpc; do
fix $(find "$out" -type f -name $file)
done
for file in $(find "$out" -name setup-config); do
substituteInPlace $file --replace /usr/bin/ranlib "$(type -P ranlib)"
done
'';
doInstallCheck = true; doInstallCheck = true;
installCheckPhase = '' installCheckPhase = ''
# Sanity check, can ghc create executables? # Sanity check, can ghc create executables?

View file

@ -1,8 +1,18 @@
{ stdenv { stdenv
, fetchurl, perl, makeWrapper , fetchurl, perl
, ncurses5, gmp, libiconv , ncurses5, gmp, libiconv
}: }:
let
libPath = stdenv.lib.makeLibraryPath ([
ncurses5 gmp
] ++ stdenv.lib.optional (stdenv.hostPlatform.isDarwin) libiconv);
libEnvVar = stdenv.lib.optionalString stdenv.hostPlatform.isDarwin "DY"
+ "LD_LIBRARY_PATH";
in
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
version = "7.4.2"; version = "7.4.2";
@ -30,6 +40,10 @@ stdenv.mkDerivation rec {
nativeBuildInputs = [ perl ]; nativeBuildInputs = [ perl ];
# Cannot patchelf beforehand due to relative RPATHs that anticipate
# the final install location/
${libEnvVar} = libPath;
postUnpack = postUnpack =
# GHC has dtrace probes, which causes ld to try to open /usr/lib/libdtrace.dylib # GHC has dtrace probes, which causes ld to try to open /usr/lib/libdtrace.dylib
# during linking # during linking
@ -57,14 +71,11 @@ stdenv.mkDerivation rec {
find . -name base.buildinfo \ find . -name base.buildinfo \
-exec sed -i "s@extra-lib-dirs: @extra-lib-dirs: ${libiconv}/lib@" {} \; -exec sed -i "s@extra-lib-dirs: @extra-lib-dirs: ${libiconv}/lib@" {} \;
'' + '' +
# On Linux, use patchelf to modify the executables so that they can # Rename needed libraries and binaries, fix interpreter
# find editline/gmp.
stdenv.lib.optionalString stdenv.isLinux '' stdenv.lib.optionalString stdenv.isLinux ''
mkdir -p "$out/lib" find . -type f -perm -0100 -exec patchelf \
ln -sv "${ncurses5.out}/lib/libncurses.so" "$out/lib/libncurses${stdenv.lib.optionalString stdenv.is64bit "w"}.so.5" --replace-needed libncurses${stdenv.lib.optionalString stdenv.is64bit "w"}.so.5 libncurses.so \
find . -type f -perm -0100 \ --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" {} \;
-exec patchelf --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
--set-rpath "${stdenv.lib.makeLibraryPath [ "$out" gmp ]}" {} \;
paxmark m ./ghc-${version}/ghc/stage2/build/tmp/ghc-stage2 paxmark m ./ghc-${version}/ghc/stage2/build/tmp/ghc-stage2
@ -73,23 +84,6 @@ stdenv.mkDerivation rec {
for prog in ld ar gcc strip ranlib; do for prog in ld ar gcc strip ranlib; do
find . -name "setup-config" -exec sed -i "s@/usr/bin/$prog@$(type -p $prog)@g" {} \; find . -name "setup-config" -exec sed -i "s@/usr/bin/$prog@$(type -p $prog)@g" {} \;
done done
'' + stdenv.lib.optionalString stdenv.isDarwin ''
# not enough room in the object files for the full path to libiconv :(
fix () {
install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib $1
}
ln -s ${libiconv}/lib/libiconv.dylib ghc-${version}/utils/ghc-pwd/dist-install/build/tmp
ln -s ${libiconv}/lib/libiconv.dylib ghc-${version}/utils/hpc/dist-install/build/tmp
ln -s ${libiconv}/lib/libiconv.dylib ghc-${version}/ghc/stage2/build/tmp
for file in ghc-cabal ghc-pwd ghc-stage2 ghc-pkg haddock hsc2hs hpc; do
fix $(find . -type f -name $file)
done
for file in $(find . -name setup-config); do
substituteInPlace $file --replace /usr/bin/ranlib "$(type -P ranlib)"
done
''; '';
configurePlatforms = [ ]; configurePlatforms = [ ];
@ -106,12 +100,27 @@ stdenv.mkDerivation rec {
# calls install-strip ... # calls install-strip ...
dontBuild = true; dontBuild = true;
preInstall = stdenv.lib.optionalString stdenv.isDarwin '' # On Linux, use patchelf to modify the executables so that they can
mkdir -p $out/lib/ghc-${version} # find editline/gmp.
mkdir -p $out/bin preFixup = stdenv.lib.optionalString stdenv.isLinux ''
find "$out" -type f -executable \
-exec patchelf --set-rpath "${libPath}" {} \;
'' + stdenv.lib.optionalString stdenv.isDarwin ''
# not enough room in the object files for the full path to libiconv :(
ln -s ${libiconv}/lib/libiconv.dylib $out/bin ln -s ${libiconv}/lib/libiconv.dylib $out/bin
ln -s ${libiconv}/lib/libiconv.dylib $out/lib/ghc-${version}/libiconv.dylib ln -s ${libiconv}/lib/libiconv.dylib $out/lib/ghc-${version}/libiconv.dylib
ln -s ${libiconv}/lib/libiconv.dylib utils/ghc-cabal/dist-install/build/tmp
fix () {
install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib $1
}
for file in ghc-cabal ghc-pwd ghc-stage2 ghc-pkg haddock hsc2hs hpc; do
fix $(find "$out" -type f -name $file)
done
for file in $(find "$out" -name setup-config); do
substituteInPlace $file --replace /usr/bin/ranlib "$(type -P ranlib)"
done
''; '';
doInstallCheck = true; doInstallCheck = true;