nixpkgs/pkgs/development/libraries/kerberos/krb5.nix
Elliot Cameron 311277204d krb5: merge krb5 and libkrb5 with krb5.lib output
krb5 and libkrb5 are two separate derivations that can easily end up
in the same closure. They both provide the same shared libraries and
some packages end up getting both copies. Since both copies come from
the same source, packages often get lucky in this situation and just
use whichever library is found first. Sometimes packages are less
fortunate and end up trying to load both. This has gone largely
unnoticed in Nixpkgs, likely because Kerberos is not widely used
outside of enterprise deployments.

This situation seems to have arisen out of a need to break a cycle
in `fetchurl -> curl -> krb5 -> fetchurl`. The libkrb5 build was able to
avoid depending on bison and libedit, making it easier to break the
cycle.

However, we can break the cycle without resorting to two variants of
krb5. Libedit can be removed with configure flags and byacc can be used
instead of bison, allowing a much smaller build closure that can easily
be resolved when breaking the cycle.

This change also adds a "lib" output to krb5 so that packages depending
on krb5 can still benefit from a smaller runtime closure if they only
need the shared libraries.

A future change will include a tree-wide refactor to switch uses of
libkrb5 to krb5.
2024-08-16 13:58:01 -04:00

138 lines
4.3 KiB
Nix

{ lib
, stdenv
, fetchurl
, bootstrap_cmds
, byacc # can also use bison, but byacc has fewer dependencies
, darwin
, keyutils
, openssl
, perl
, pkg-config
# for passthru.tests
, bind
, curl
, nixosTests
, openssh
, postgresql
, python3
# Extra Arguments
, withLdap ? false, openldap
, withLibedit ? true, libedit
, withVerto ? false, libverto
# This is called "staticOnly" because krb5 does not support
# builting both static and shared, see below.
, staticOnly ? false
}:
stdenv.mkDerivation rec {
pname = "krb5";
version = "1.21.3";
src = fetchurl {
url = "https://kerberos.org/dist/krb5/${lib.versions.majorMinor version}/krb5-${version}.tar.gz";
hash = "sha256-t6TNXq1n+wi5gLIavRUP9yF+heoyDJ7QxtrdMEhArTU=";
};
outputs = [ "out" "lib" "dev" ];
# While "out" acts as the bin output, most packages only care about the lib output.
# We set prefix such that all the pkg-config configuration stays inside the dev and lib outputs.
# stdenv will take care of overriding bindir, sbindir, etc. such that "out" contains the binaries.
prefix = builtins.placeholder "lib";
configureFlags = [
"--localstatedir=/var/lib"
(lib.withFeature withLdap "ldap")
(lib.withFeature withLibedit "libedit")
(lib.withFeature withVerto "system-verto")
]
# krb5's ./configure does not allow passing --enable-shared and --enable-static at the same time.
# See https://bbs.archlinux.org/viewtopic.php?pid=1576737#p1576737
++ lib.optionals staticOnly [ "--enable-static" "--disable-shared" ]
++ lib.optional stdenv.isFreeBSD ''WARN_CFLAGS=''
++ lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform)
[ "krb5_cv_attr_constructor_destructor=yes,yes"
"ac_cv_func_regcomp=yes"
"ac_cv_printf_positional=yes"
];
nativeBuildInputs = [ byacc perl pkg-config ]
# Provides the mig command used by the build scripts
++ lib.optional stdenv.isDarwin bootstrap_cmds;
buildInputs = [ openssl ]
++ lib.optionals (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.libc != "bionic" && !(stdenv.hostPlatform.useLLVM or false)) [ keyutils ]
++ lib.optionals withLdap [ openldap ]
++ lib.optionals withLibedit [ libedit ]
++ lib.optionals withVerto [ libverto ];
propagatedBuildInputs = lib.optionals stdenv.isDarwin (with darwin.apple_sdk; [
libs.xpc
frameworks.Kerberos
]);
sourceRoot = "krb5-${version}/src";
postPatch = ''
substituteInPlace config/shlib.conf \
--replace "'ld " "'${stdenv.cc.targetPrefix}ld "
''
# this could be accomplished by updateAutotoolsGnuConfigScriptsHook, but that causes infinite recursion
# necessary for FreeBSD code path in configure
+ ''
substituteInPlace ./config/config.guess --replace-fail /usr/bin/uname uname
'';
libFolders = [ "util" "include" "lib" "build-tools" ];
# To avoid cyclic outputs, we can't let lib depend on out in any way. Unfortunately, the configure
# options don't give us enough granularity to specify that, so we have to override the generated
# Makefiles manually.
postConfigure = ''
find $libFolders -type f -name Makefile -print0 | while IFS= read -rd "" f; do
substituteInPlace "$f" --replace-fail "$out" "$lib"
done
'';
preInstall = ''
mkdir -p "$lib"/{bin,sbin,lib/pkgconfig,share/{et,man/man1}}
'';
# not via outputBin, due to reference from libkrb5.so
postInstall = ''
moveToOutput bin/krb5-config "$dev"
'';
# Disable _multioutDocs in stdenv by overriding it to be a no-op.
# We do this because $lib has its own docs and we don't want to squash them into $out.
preFixup = ''
_multioutDocs() {
echo Skipping multioutDocs
}
'';
enableParallelBuilding = true;
doCheck = false; # fails with "No suitable file for testing purposes"
meta = with lib; {
description = "MIT Kerberos 5";
homepage = "http://web.mit.edu/kerberos/";
license = licenses.mit;
platforms = platforms.unix ++ platforms.windows;
};
passthru = {
implementation = "krb5";
tests = {
inherit (nixosTests) kerberos;
inherit (python3.pkgs) requests-credssp;
bind = bind.override { enableGSSAPI = true; };
curl = curl.override { gssSupport = true; };
openssh = openssh.override { withKerberos = true; };
postgresql = postgresql.override { gssSupport = true; };
};
};
}