{ stdenv, fetchurl, xar, cpio, pkgs, python3, pbzx, lib, darwin-stubs, print-reexports }: let version = "10.12"; in # Ensure appleSdkVersion is up to date. assert stdenv.isDarwin -> stdenv.appleSdkVersion == version; let # sadly needs to be exported because security_tool needs it sdk = stdenv.mkDerivation rec { pname = "MacOS_SDK"; inherit version; # This URL comes from https://swscan.apple.com/content/catalogs/others/index-10.12.merged-1.sucatalog, which we found by: # 1. Google: site:swscan.apple.com and look for a name that seems appropriate for your version # 2. In the resulting file, search for a file called DevSDK ending in .pkg # 3. ??? # 4. Profit src = fetchurl { url = "http://swcdn.apple.com/content/downloads/33/36/041-90419-A_7JJ4H9ZHO2/xs88ob5wjz6riz7g6764twblnvksusg4ps/DevSDK_OSX1012.pkg"; sha256 = "13xq34sb7383b37hwy076gnhf96prpk1b4087p87xnwswxbrisih"; }; nativeBuildInputs = [ xar cpio python3 pbzx ]; outputs = [ "out" "dev" "man" ]; unpackPhase = '' xar -x -f $src ''; installPhase = '' start="$(pwd)" mkdir -p $out cd $out pbzx -n $start/Payload | cpio -idm mv usr/* . rmdir usr mv System/* . rmdir System pushd lib cp ${darwin-stubs}/usr/lib/libcups*.tbd . ln -s libcups.2.tbd libcups.tbd ln -s libcupscgi.1.tbd libcupscgi.tbd ln -s libcupsimage.2.tbd libcupsimage.tbd ln -s libcupsmime.1.tbd libcupsmime.tbd ln -s libcupsppdc.1.tbd libcupsppdc.tbd popd ''; meta = with lib; { description = "Apple SDK ${version}"; maintainers = with maintainers; [ copumpkin ]; platforms = platforms.darwin; }; }; mkFrameworkSubs = name: deps: let deps' = deps // { "${name}" = placeholder "out"; }; substArgs = lib.concatMap (x: [ "--subst-var-by" x deps'."${x}" ]) (lib.attrNames deps'); in lib.escapeShellArgs substArgs; framework = name: deps: stdenv.mkDerivation { name = "apple-framework-${name}"; dontUnpack = true; # because we copy files from the system preferLocalBuild = true; disallowedRequisites = [ sdk ]; nativeBuildInputs = [ print-reexports ]; extraTBDFiles = []; installPhase = '' linkFramework() { local path="$1" local nested_path="$1" if [ "$path" == "JavaNativeFoundation.framework" ]; then local nested_path="JavaVM.framework/Versions/A/Frameworks/JavaNativeFoundation.framework" fi if [ "$path" == "JavaRuntimeSupport.framework" ]; then local nested_path="JavaVM.framework/Versions/A/Frameworks/JavaRuntimeSupport.framework" fi local name="$(basename "$path" .framework)" local current="$(readlink "/System/Library/Frameworks/$nested_path/Versions/Current")" if [ -z "$current" ]; then current=A fi local dest="$out/Library/Frameworks/$path" mkdir -p "$dest/Versions/$current" pushd "$dest/Versions/$current" >/dev/null if [ -d "${sdk.out}/Library/Frameworks/$nested_path/Versions/$current/Headers" ]; then cp -R "${sdk.out}/Library/Frameworks/$nested_path/Versions/$current/Headers" . elif [ -d "${sdk.out}/Library/Frameworks/$name.framework/Versions/$current/Headers" ]; then current="$(readlink "/System/Library/Frameworks/$name.framework/Versions/Current")" cp -R "${sdk.out}/Library/Frameworks/$name.framework/Versions/$current/Headers" . fi local tbd_source=${darwin-stubs}/System/Library/Frameworks/$nested_path/Versions/$current if [ "${name}" != "Kernel" ]; then # The Kernel.framework has headers but no actual library component. cp -v $tbd_source/*.tbd . fi if [ -d "$tbd_source/Libraries" ]; then mkdir Libraries cp -v $tbd_source/Libraries/*.tbd Libraries/ fi ln -s -L "/System/Library/Frameworks/$nested_path/Versions/$current/Resources" if [ -f "/System/Library/Frameworks/$nested_path/module.map" ]; then ln -s "/System/Library/Frameworks/$nested_path/module.map" fi pushd "${sdk.out}/Library/Frameworks/$nested_path/Versions/$current" >/dev/null local children=$(echo Frameworks/*.framework) popd >/dev/null for child in $children; do childpath="$path/Versions/$current/$child" linkFramework "$childpath" done pushd ../.. >/dev/null ln -s "$current" Versions/Current ln -s Versions/Current/* . popd >/dev/null popd >/dev/null } linkFramework "${name}.framework" # linkFramework is recursive, the rest of the processing is not. local tbd_source=${darwin-stubs}/System/Library/Frameworks/${name}.framework for tbd in $extraTBDFiles; do local tbd_dest_dir=$out/Library/Frameworks/${name}.framework/$(dirname "$tbd") mkdir -p "$tbd_dest_dir" cp -v "$tbd_source/$tbd" "$tbd_dest_dir" done # Fix and check tbd re-export references find $out -name '*.tbd' | while read tbd; do echo "Fixing re-exports in $tbd" substituteInPlace "$tbd" ${mkFrameworkSubs name deps} echo "Checking re-exports in $tbd" print-reexports "$tbd" | while read target; do local expected="''${target%.dylib}.tbd" if ! [ -e "$expected" ]; then echo -e "Re-export missing:\n\t$target\n\t(expected $expected)" echo -e "While processing\n\t$tbd" exit 1 else echo "Re-exported target $target ok" fi done done ''; propagatedBuildInputs = builtins.attrValues deps; # don't use pure CF for dylibs that depend on frameworks setupHook = ./framework-setup-hook.sh; # Not going to be more specific than this for now __propagatedImpureHostDeps = lib.optionals (name != "Kernel") [ # The setup-hook ensures that everyone uses the impure CoreFoundation who uses these SDK frameworks, so let's expose it "/System/Library/Frameworks/CoreFoundation.framework" "/System/Library/Frameworks/${name}.framework" "/System/Library/Frameworks/${name}.framework/${name}" ]; meta = with lib; { description = "Apple SDK framework ${name}"; maintainers = with maintainers; [ copumpkin ]; platforms = platforms.darwin; }; }; tbdOnlyFramework = name: { private ? true }: stdenv.mkDerivation { name = "apple-framework-${name}"; dontUnpack = true; installPhase = '' mkdir -p $out/Library/Frameworks/ cp -r ${darwin-stubs}/System/Library/${lib.optionalString private "Private"}Frameworks/${name}.framework \ $out/Library/Frameworks # NOTE there's no re-export checking here, this is probably wrong ''; }; in rec { libs = { xpc = stdenv.mkDerivation { name = "apple-lib-xpc"; dontUnpack = true; installPhase = '' mkdir -p $out/include pushd $out/include >/dev/null cp -r "${lib.getDev sdk}/include/xpc" $out/include/xpc cp "${lib.getDev sdk}/include/launch.h" $out/include/launch.h popd >/dev/null ''; }; Xplugin = stdenv.mkDerivation { name = "apple-lib-Xplugin"; dontUnpack = true; # Not enough __propagatedImpureHostDeps = [ "/usr/lib/libXplugin.1.dylib" ]; propagatedBuildInputs = with frameworks; [ OpenGL ApplicationServices Carbon IOKit CoreGraphics CoreServices CoreText ]; installPhase = '' mkdir -p $out/include $out/lib ln -s "${lib.getDev sdk}/include/Xplugin.h" $out/include/Xplugin.h cp ${darwin-stubs}/usr/lib/libXplugin.1.tbd $out/lib ln -s libXplugin.1.tbd $out/lib/libXplugin.tbd ''; }; utmp = stdenv.mkDerivation { name = "apple-lib-utmp"; dontUnpack = true; installPhase = '' mkdir -p $out/include pushd $out/include >/dev/null ln -s "${lib.getDev sdk}/include/utmp.h" ln -s "${lib.getDev sdk}/include/utmpx.h" popd >/dev/null ''; }; }; overrides = super: { AppKit = lib.overrideDerivation super.AppKit (drv: { __propagatedImpureHostDeps = drv.__propagatedImpureHostDeps ++ [ "/System/Library/PrivateFrameworks/" ]; }); Carbon = lib.overrideDerivation super.Carbon (drv: { extraTBDFiles = [ "Versions/A/Frameworks/HTMLRendering.framework/Versions/A/HTMLRendering.tbd" ]; }); CoreFoundation = lib.overrideDerivation super.CoreFoundation (drv: { setupHook = ./cf-setup-hook.sh; }); CoreMedia = lib.overrideDerivation super.CoreMedia (drv: { __propagatedImpureHostDeps = drv.__propagatedImpureHostDeps ++ [ "/System/Library/Frameworks/CoreImage.framework" ]; }); CoreMIDI = lib.overrideDerivation super.CoreMIDI (drv: { __propagatedImpureHostDeps = drv.__propagatedImpureHostDeps ++ [ "/System/Library/PrivateFrameworks/" ]; setupHook = ./private-frameworks-setup-hook.sh; }); IMServicePlugIn = lib.overrideDerivation super.IMServicePlugIn (drv: { extraTBDFiles = [ "Versions/A/Frameworks/IMServicePlugInSupport.framework/Versions/A/IMServicePlugInSupport.tbd" ]; }); Security = lib.overrideDerivation super.Security (drv: { setupHook = ./security-setup-hook.sh; }); QuartzCore = lib.overrideDerivation super.QuartzCore (drv: { installPhase = drv.installPhase + '' f="$out/Library/Frameworks/QuartzCore.framework/Headers/CoreImage.h" substituteInPlace "$f" \ --replace "QuartzCore/../Frameworks/CoreImage.framework/Headers" "CoreImage" ''; }); MetalKit = lib.overrideDerivation super.MetalKit (drv: { installPhase = drv.installPhase + '' mkdir -p $out/include/simd cp ${lib.getDev sdk}/include/simd/*.h $out/include/simd/ ''; }); WebKit = lib.overrideDerivation super.WebKit (drv: { extraTBDFiles = [ "Versions/A/Frameworks/WebCore.framework/Versions/A/WebCore.tbd" "Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy.tbd" ]; }); } // lib.genAttrs [ "ContactsPersistence" "UIFoundation" "GameCenter" ] (x: tbdOnlyFramework x {}); bareFrameworks = lib.mapAttrs framework (import ./frameworks.nix { inherit frameworks libs; inherit (pkgs.darwin) libobjc; }); frameworks = bareFrameworks // overrides bareFrameworks; inherit sdk; }