1{
2 lib,
3 stdenv,
4 fetchFromGitHub,
5 runCommand,
6 ncurses,
7 gettext,
8 pkg-config,
9 cscope,
10 ruby_3_2,
11 tcl,
12 perl540,
13 luajit,
14 darwin,
15 libiconv,
16 python3,
17}:
18
19# Try to match MacVim's documented script interface compatibility
20let
21 perl = perl540;
22 # Ruby 3.2
23 ruby = ruby_3_2;
24
25 # Building requires a few system tools to be in PATH.
26 # Some of these we could patch into the relevant source files (such as xcodebuild and
27 # qlmanage) but some are used by Xcode itself and we have no choice but to put them in PATH.
28 # Symlinking them in this way is better than just putting all of /usr/bin in there.
29 buildSymlinks = runCommand "macvim-build-symlinks" { } ''
30 mkdir -p $out/bin
31 ln -s /usr/bin/xcrun /usr/bin/xcodebuild /usr/bin/tiffutil /usr/bin/qlmanage $out/bin
32 '';
33in
34
35stdenv.mkDerivation (finalAttrs: {
36 pname = "macvim";
37
38 version = "179";
39
40 src = fetchFromGitHub {
41 owner = "macvim-dev";
42 repo = "macvim";
43 rev = "release-${finalAttrs.version}";
44 hash = "sha256-L9LVXyeA09aMtNf+b/Oo+eLpeVEKTD1/oNWCiFn5FbU=";
45 };
46
47 enableParallelBuilding = true;
48
49 nativeBuildInputs = [
50 pkg-config
51 buildSymlinks
52 ];
53 buildInputs = [
54 gettext
55 ncurses
56 cscope
57 luajit
58 ruby
59 tcl
60 perl
61 python3
62 ];
63
64 patches = [ ./macvim.patch ];
65
66 configureFlags = [
67 "--enable-cscope"
68 "--enable-fail-if-missing"
69 "--with-features=huge"
70 "--enable-gui=macvim"
71 "--enable-multibyte"
72 "--enable-nls"
73 "--enable-luainterp=dynamic"
74 "--enable-python3interp=dynamic"
75 "--enable-perlinterp=dynamic"
76 "--enable-rubyinterp=dynamic"
77 "--enable-tclinterp=yes"
78 "--without-local-dir"
79 "--with-luajit"
80 "--with-lua-prefix=${luajit}"
81 "--with-python3-command=${python3}/bin/python3"
82 "--with-ruby-command=${ruby}/bin/ruby"
83 "--with-tclsh=${tcl}/bin/tclsh"
84 "--with-tlib=ncurses"
85 "--with-compiledby=Nix"
86 "--disable-sparkle"
87 ];
88
89 # Remove references to Sparkle.framework from the project.
90 # It's unused (we disabled it with --disable-sparkle) and this avoids
91 # copying the unnecessary several-megabyte framework into the result.
92 postPatch = ''
93 echo "Patching file src/MacVim/MacVim.xcodeproj/project.pbxproj"
94 sed -e '/Sparkle\.framework/d' -i src/MacVim/MacVim.xcodeproj/project.pbxproj
95 '';
96
97 # This is unfortunate, but we need to use the same compiler as Xcode, but Xcode doesn't provide a
98 # way to configure the compiler. We also need to pull in lib/include paths for some of our build
99 # inputs since we don't have cc-wrapper to do that for us.
100 preConfigure =
101 let
102 # ideally we'd recurse, but we don't need that right now
103 inputs = [ ncurses ] ++ perl.propagatedBuildInputs;
104 ldflags = map (drv: "-L${lib.getLib drv}/lib") inputs;
105 cppflags = map (drv: "-isystem ${lib.getDev drv}/include") inputs;
106 in
107 ''
108 unset DEVELOPER_DIR # Use the system Xcode not the nixpkgs SDK.
109
110 CC=/usr/bin/clang
111
112 DEV_DIR=$(/usr/bin/xcode-select -print-path)/Platforms/MacOSX.platform/Developer
113 configureFlagsArray+=(
114 --with-developer-dir="$DEV_DIR"
115 LDFLAGS=${lib.escapeShellArg ldflags}
116 CPPFLAGS=${lib.escapeShellArg cppflags}
117 CFLAGS="-Wno-error=implicit-function-declaration"
118 )
119 ''
120 # For some reason having LD defined causes PSMTabBarControl to fail at link-time as it
121 # passes arguments to ld that it meant for clang.
122 + ''
123 unset LD
124 ''
125 # When building with nix-daemon, we need to pass -derivedDataPath or else it tries to use
126 # a folder rooted in /var/empty and fails. Unfortunately we can't just pass -derivedDataPath
127 # by itself as this flag requires the use of -scheme or -xctestrun (not sure why), but MacVim
128 # by default just runs `xcodebuild -project src/MacVim/MacVim.xcodeproj`, relying on the default
129 # behavior to build the first target in the project. Experimentally, there seems to be a scheme
130 # called MacVim, so we'll explicitly select that. We also need to specify the configuration too
131 # as the scheme seems to have the wrong default.
132 + ''
133 configureFlagsArray+=(
134 XCODEFLAGS="-scheme MacVim -derivedDataPath $NIX_BUILD_TOP/derivedData"
135 --with-xcodecfg="Release"
136 )
137 '';
138
139 # Because we're building with system clang, this means we're building against Xcode's SDK and
140 # linking against system libraries. The configure script is picking up Nix Libsystem (via ruby)
141 # so we need to patch that out or we'll get linker issues. The MacVim binary built by Xcode links
142 # against the system anyway so it doesn't really matter that the Vim binary will too. If we
143 # decide that matters, we can always patch it back to the Nix libsystem post-build.
144 # It also picks up libiconv, libunwind, and objc4 from Nix. These seem relatively harmless but
145 # let's strip them out too.
146 #
147 # Note: If we do add a post-build install_name_tool patch, we need to add the
148 # "LDFLAGS=-headerpad_max_install_names" flag to configureFlags and either patch it into the
149 # Xcode project or pass it as a flag to xcodebuild as well.
150 postConfigure = ''
151 substituteInPlace src/auto/config.mk \
152 --replace " -L${stdenv.cc.libc}/lib" "" \
153 --replace " -L${darwin.libunwind}/lib" "" \
154 --replace " -L${libiconv}/lib" ""
155
156 # All the libraries we stripped have -osx- in their name as of this time.
157 # Assert now that this pattern no longer appears in config.mk.
158 ( # scope variable
159 while IFS="" read -r line; do
160 if [[ "$line" == LDFLAGS*-osx-* ]]; then
161 echo "WARNING: src/auto/config.mk contains reference to Nix osx library" >&2
162 fi
163 done <src/auto/config.mk
164 )
165
166 substituteInPlace src/MacVim/vimrc --subst-var-by CSCOPE ${cscope}/bin/cscope
167 '';
168
169 # Note that $out/MacVim.app has a misnamed set of binaries in the Contents/bin folder (the V is
170 # capitalized) and is missing a bunch of them. This is why we're grabbing the version from the
171 # build folder.
172 postInstall = ''
173 mkdir -p $out/Applications
174 cp -r src/MacVim/build/Release/MacVim.app $out/Applications
175 rm -rf $out/MacVim.app
176
177 mkdir -p $out/bin
178 for prog in ex vi {,g,m,r}vi{m,mdiff,ew}; do
179 ln -s $out/Applications/MacVim.app/Contents/bin/mvim $out/bin/$prog
180 done
181 for prog in {,g}vimtutor xxd; do
182 ln -s $out/Applications/MacVim.app/Contents/bin/$prog $out/bin/$prog
183 done
184 ln -s $out/Applications/MacVim.app/Contents/bin/gvimtutor $out/bin/mvimtutor
185
186 mkdir -p $out/share
187 ln -s $out/Applications/MacVim.app/Contents/man $out/share/man
188
189 # Fix rpaths
190 exe="$out/Applications/MacVim.app/Contents/MacOS/Vim"
191 libperl=$(dirname $(find ${perl} -name "libperl.dylib"))
192 install_name_tool -add_rpath ${luajit}/lib $exe
193 install_name_tool -add_rpath ${tcl}/lib $exe
194 install_name_tool -add_rpath ${python3}/lib $exe
195 install_name_tool -add_rpath $libperl $exe
196 install_name_tool -add_rpath ${ruby}/lib $exe
197
198 # Remove manpages from tools we aren't providing
199 find $out/Applications/MacVim.app/Contents/man -name evim.1 -delete
200 '';
201
202 # We rely on the user's Xcode install to build. It may be located in an arbitrary place, and
203 # it's not clear what system-level components it may require, so for now we'll just allow full
204 # filesystem access. This way the package still can't access the network.
205 sandboxProfile = ''
206 (allow file-read* file-write* process-exec mach-lookup)
207 ; block homebrew dependencies
208 (deny file-read* file-write* process-exec mach-lookup (subpath "/usr/local") (with no-log))
209 '';
210
211 meta = with lib; {
212 description = "Vim - the text editor - for macOS";
213 homepage = "https://macvim.org/";
214 license = licenses.vim;
215 maintainers = [ ];
216 platforms = platforms.darwin;
217 hydraPlatforms = [ ]; # hydra can't build this as long as we rely on Xcode and sandboxProfile
218 };
219})