{
clangStdenv,
lib,
runCommandWith,
writeShellScript,
fetchFromGitHub,
fetchpatch,
nixosTests,
freetype,
libjpeg,
libpng,
libtiff,
giflib,
libX11,
libXext,
libXrandr,
libXcursor,
libxkbfile,
cairo,
libglvnd,
fontconfig,
dbus,
libGLU,
fuse,
ffmpeg,
pulseaudio,
makeWrapper,
python2,
python3,
cmake,
ninja,
pkg-config,
bison,
flex,
libbsd,
openssl,
xdg-user-dirs,
addDriverRunpath,
# Whether to pre-compile Python 2 bytecode for performance.
compilePy2Bytecode ? false,
}:
let
stdenv = clangStdenv;
# The build system invokes clang to compile Darwin executables.
# In this case, our cc-wrapper must not be used.
ccWrapperBypass =
runCommandWith
inherit stdenv;
name = "cc-wrapper-bypass";
runLocal = false;
derivationArgs = {
template = writeShellScript "template" ''
for (( i=1; i<=$#; i++)); do
j=$((i+1))
if [[ "''${!i}" == "-target" && "''${!j}" == *"darwin"* ]]; then
# their flags must take precedence
exec @unwrapped@ "$@" $NIX_CFLAGS_COMPILE
fi
done
exec @wrapped@ "$@"
'';
};
}
''
unwrapped_bin=${stdenv.cc.cc}/bin
wrapped_bin=${stdenv.cc}/bin
mkdir -p $out/bin
unwrapped=$unwrapped_bin/$CC wrapped=$wrapped_bin/$CC \
substituteAll $template $out/bin/$CC
unwrapped=$unwrapped_bin/$CXX wrapped=$wrapped_bin/$CXX \
substituteAll $template $out/bin/$CXX
chmod +x $out/bin/$CC $out/bin/$CXX
wrappedLibs = [
# To find all of them: rg -w wrap_elf
# src/native/CMakeLists.txt
freetype
libjpeg
libpng
libtiff
giflib
libX11
libXext
libXrandr
libXcursor
libxkbfile
cairo
libglvnd
fontconfig
dbus
libGLU
# src/external/darling-dmg/CMakeLists.txt
fuse
# src/CoreAudio/CMakeLists.txt
ffmpeg
pulseaudio
];
in
stdenv.mkDerivation {
pname = "darling";
version = "unstable-2024-02-03";
src = fetchFromGitHub {
owner = "darlinghq";
repo = "darling";
rev = "25afbc76428c39c3909e9efcf5caef1140425211";
fetchSubmodules = true;
hash = "sha256-z9IMgc5hH2Upn8wHl1OgP42q9HTSkeHnxB3N812A+Kc=";
# Remove 500MB of dependency test files to get under Hydra output limit
postFetch = ''
rm -r $out/src/external/openjdk/test
rm -r $out/src/external/libmalloc/tests
rm -r $out/src/external/libarchive/libarchive/tar/test
outputs = [
"out"
"sdk"
patches = [
# Fix 'clang: error: no such file or directory: .../signal/mach_excUser.c'
# https://github.com/darlinghq/darling/issues/1511
# https://github.com/darlinghq/darling/commit/f46eb721c11d32addd807f092f4b3a6ea515bb6d
(fetchpatch {
url = "https://github.com/darlinghq/darling/commit/f46eb721c11d32addd807f092f4b3a6ea515bb6d.patch?full_index=1";
hash = "sha256-FnLcHnK4cNto+E3OQSxE3iK+FHSU8y459FcpMvrzd6o=";
})
# Fix compatibility with ffmpeg_7
# https://github.com/darlinghq/darling/pull/1537
# https://github.com/darlinghq/darling/commit/9655d5598c87dcb22c54a83cc7741b77cb47a1b0
url = "https://github.com/darlinghq/darling/commit/9655d5598c87dcb22c54a83cc7741b77cb47a1b0.patch?full_index=1";
hash = "sha256-ogMo4SRRwiOhaVJ+OS8BVolGDa7vGKyR9bdGiOiCuRc=";
postPatch = ''
# We have to be careful - Patching everything indiscriminately
# would affect Darwin scripts as well
chmod +x src/external/bootstrap_cmds/migcom.tproj/mig.sh
patchShebangs \
src/external/bootstrap_cmds/migcom.tproj/mig.sh \
src/external/darlingserver/scripts \
src/external/openssl_certificates/scripts
substituteInPlace src/startup/CMakeLists.txt --replace SETUID ""
substituteInPlace src/external/basic_cmds/CMakeLists.txt --replace SETGID ""
nativeBuildInputs = [
bison
ccWrapperBypass
cmake
flex
makeWrapper
ninja
pkg-config
python3
] ++ lib.optional compilePy2Bytecode python2;
buildInputs = wrappedLibs ++ [
libbsd
openssl
stdenv.cc.libc.linuxHeaders
# Breaks valid paths like
# Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include
dontFixCmake = true;
# src/external/objc4 forces OBJC_IS_DEBUG_BUILD=1, which conflicts with NDEBUG
# TODO: Fix in a better way
cmakeBuildType = " ";
cmakeFlags = [
"-DTARGET_i386=OFF"
"-DCOMPILE_PY2_BYTECODE=${if compilePy2Bytecode then "ON" else "OFF"}"
"-DDARLINGSERVER_XDG_USER_DIR_CMD=${xdg-user-dirs}/bin/xdg-user-dir"
env.NIX_CFLAGS_COMPILE = "-Wno-macro-redefined -Wno-unused-command-line-argument";
# Linux .so's are dlopen'd by wrapgen during the build
env.LD_LIBRARY_PATH = lib.makeLibraryPath wrappedLibs;
# Breaks shebangs of Darwin scripts
dontPatchShebangs = true;
postInstall = ''
# Install the SDK as a separate output
mkdir -p $sdk
sdkDir=$(readlink -f ../Developer)
while read -r path; do
dst="$sdk/Developer/''${path#$sdkDir}"
if [[ -L "$path" ]]; then
target=$(readlink -m "$path")
if [[ -e "$target" && "$target" == "$NIX_BUILD_TOP"* && "$target" != "$sdkDir"* ]]; then
# dereference
cp -r -L "$path" "$dst"
elif [[ -e "$target" ]]; then
# preserve symlink
cp -d "$path" "$dst"
else
# ignore symlink
>&2 echo "Ignoring symlink $path -> $target"
elif [[ -f $path ]]; then
cp "$path" "$dst"
elif [[ -d $path ]]; then
mkdir -p "$dst"
done < <(find $sdkDir)
mkdir -p $sdk/bin
cp src/external/cctools-port/cctools/ld64/src/*-ld $sdk/bin
cp src/external/cctools-port/cctools/ar/*-{ar,ranlib} $sdk/bin
postFixup = ''
echo "Checking for references to $NIX_STORE in Darling root..."
set +e
grep -r --exclude=mldr "$NIX_STORE" $out/libexec/darling
ret=$?
set -e
if [[ $ret == 0 ]]; then
echo "Found references to $NIX_STORE in Darling root (see above)"
exit 1
patchelf --add-rpath "${lib.makeLibraryPath wrappedLibs}:${addDriverRunpath.driverLink}/lib" \
$out/libexec/darling/usr/libexec/darling/mldr
passthru.tests.nixos = nixosTests.darling;
meta = with lib; {
description = "Open-source Darwin/macOS emulation layer for Linux";
homepage = "https://www.darlinghq.org";
changelog = "https://github.com/darlinghq/darling/releases";
license = licenses.gpl3Plus;
maintainers = with maintainers; [ zhaofengli ];
platforms = [ "x86_64-linux" ];
mainProgram = "darling";