1{ lib, stdenv, makeWrapper, writeText, writeTextFile, runCommand, callPackage
2, CoreServices, ImageIO, CoreGraphics
3, xcodePlatform ? stdenv.targetPlatform.xcodePlatform or "MacOSX"
4, xcodeVer ? stdenv.targetPlatform.xcodeVer or "9.4.1"
5, sdkVer ? stdenv.targetPlatform.darwinSdkVersion or "10.12"
6, productBuildVer ? null
7}:
8
9let
10
11 toolchainName = "com.apple.dt.toolchain.XcodeDefault";
12 sdkName = "${xcodePlatform}${sdkVer}";
13 xcrunSdkName = lib.toLower xcodePlatform;
14
15 # TODO: expose MACOSX_DEPLOYMENT_TARGET in nix so we can use it here.
16 sdkBuildVersion = "17E189";
17 xcodeSelectVersion = "2349";
18
19 xcbuild = callPackage ./default.nix {
20 inherit CoreServices ImageIO CoreGraphics stdenv;
21 };
22
23 toolchains = callPackage ./toolchains.nix {
24 inherit toolchainName stdenv;
25 };
26
27 sdks = callPackage ./sdks.nix {
28 inherit toolchainName sdkName xcodePlatform sdkVer productBuildVer;
29 };
30
31 platforms = callPackage ./platforms.nix {
32 inherit sdks xcodePlatform stdenv;
33 };
34
35 xcconfig = writeText "nix.xcconfig" ''
36 SDKROOT=${sdkName}
37 '';
38
39 xcode-select = writeText "xcode-select" ''
40#!${stdenv.shell}
41while [ $# -gt 0 ]; do
42 case "$1" in
43 -h | --help) ;; # noop
44 -s | --switch) shift;; # noop
45 -r | --reset) ;; # noop
46 -v | --version) echo xcode-select version ${xcodeSelectVersion} ;;
47 -p | -print-path | --print-path) echo @DEVELOPER_DIR@ ;;
48 --install) ;; # noop
49 esac
50 shift
51done
52 '';
53
54 xcrun = writeTextFile {
55 name = "xcrun";
56 executable = true;
57 destination = "/bin/xcrun";
58 text = ''
59#!${stdenv.shell}
60args=( "$@" )
61
62# If an SDK was requested, check that it matches.
63for ((i = 0; i < ''${#args[@]}; i++)); do
64 case "''${args[i]}" in
65 --sdk | -sdk)
66 i=$((i + 1))
67 if [[ "''${args[i]}" != '${xcrunSdkName}' ]]; then
68 echo >&2 "xcodebuild: error: SDK \"''${args[i]}\" cannot be located."
69 exit 1
70 fi
71 ;;
72 esac
73done
74
75while [ $# -gt 0 ]; do
76 case "$1" in
77 --sdk | -sdk) shift ;;
78 --toolchain | -toolchain) shift ;;
79 --find | -find | -f)
80 shift
81 command -v $1 || exit 1 ;;
82 --log | -log) ;; # noop
83 --verbose | -verbose) ;; # noop
84 --no-cache | -no-cache) ;; # noop
85 --kill-cache | -kill-cache) ;; # noop
86 --show-sdk-path | -show-sdk-path)
87 echo ${sdks}/${sdkName}.sdk ;;
88 --show-sdk-platform-path | -show-sdk-platform-path)
89 echo ${platforms}/${xcodePlatform}.platform ;;
90 --show-sdk-version | -show-sdk-version)
91 echo ${sdkVer} ;;
92 --show-sdk-build-version | -show-sdk-build-version)
93 echo ${sdkBuildVersion} ;;
94 *) break ;;
95 esac
96 shift
97done
98
99if ! [[ -z "$@" ]]; then
100 exec "$@"
101fi
102 '';
103 checkPhase = ''
104 ${stdenv.shellDryRun} "$target"
105 '';
106 };
107
108in
109
110runCommand "xcodebuild-${xcbuild.version}" {
111 nativeBuildInputs = [ makeWrapper ];
112 inherit (xcbuild) meta;
113
114 # ensure that the toolchain goes in PATH
115 propagatedBuildInputs = [ "${toolchains}/XcodeDefault.xctoolchain" ];
116
117 passthru = {
118 inherit xcbuild xcrun;
119 toolchain = "${toolchains}/XcodeDefault.xctoolchain";
120 sdk = "${sdks}/${sdkName}";
121 platform = "${platforms}/${xcodePlatform}.platform";
122 };
123
124 preferLocalBuild = true;
125} ''
126 mkdir -p $out/bin
127
128 ln -s $out $out/usr
129
130 mkdir -p $out/Library/Xcode
131 ln -s ${xcbuild}/Library/Xcode/Specifications $out/Library/Xcode/Specifications
132
133 ln -s ${platforms} $out/Platforms
134 ln -s ${toolchains} $out/Toolchains
135
136 mkdir -p $out/Applications/Xcode.app/Contents
137 ln -s $out $out/Applications/Xcode.app/Contents/Developer
138
139 # The native xcodebuild command supports an invocation like "xcodebuild -version -sdk" without specifying the specific SDK, so we simulate this by
140 # detecting this case and simulating the output; printing the header and appending the normal output via appending the sdk version to the positional
141 # arguments we pass through to the wrapped xcodebuild.
142 makeWrapper ${xcbuild}/bin/xcodebuild $out/bin/xcodebuild \
143 --add-flags "-xcconfig ${xcconfig}" \
144 --add-flags "DERIVED_DATA_DIR=." \
145 --set DEVELOPER_DIR "$out" \
146 --set SDKROOT ${sdkName} \
147 --run '[ "$#" -eq 2 ] && [ "$1" = "-version" ] && [ "$2" = "-sdk" ] && echo ${sdkName}.sdk - macOS ${sdkVer} \(macosx${sdkVer}\) && set -- "$@" "${sdkName}"' \
148 --run '[ "$1" = "-version" ] && [ "$#" -eq 1 ] && (echo Xcode ${xcodeVer}; echo Build version ${sdkBuildVersion}) && exit 0' \
149 --run '[ "$1" = "-license" ] && exit 0'
150
151 substitute ${xcode-select} $out/bin/xcode-select \
152 --subst-var-by DEVELOPER_DIR $out/Applications/Xcode.app/Contents/Developer
153 chmod +x $out/bin/xcode-select
154
155 cp ${xcrun}/bin/xcrun $out/bin/xcrun
156
157 for bin in PlistBuddy actool builtin-copy builtin-copyPlist \
158 builtin-copyStrings builtin-copyTiff \
159 builtin-embeddedBinaryValidationUtility \
160 builtin-infoPlistUtility builtin-lsRegisterURL \
161 builtin-productPackagingUtility builtin-validationUtility \
162 lsbom plutil; do
163 ln -s ${xcbuild}/bin/$bin $out/bin/$bin
164 done
165
166 fixupPhase
167''