1{
2 lib,
3 stdenv,
4 fetchurl,
5 buildPackages,
6 updateAutotoolsGnuConfigScriptsHook,
7 ncurses,
8 pkg-config,
9 abiVersion ? "6",
10 enableStatic ? stdenv.hostPlatform.isStatic,
11 withCxx ? !stdenv.hostPlatform.useAndroidPrebuilt,
12 mouseSupport ? false,
13 gpm,
14 withTermlib ? false,
15 unicodeSupport ? true,
16 testers,
17 binlore,
18}:
19
20stdenv.mkDerivation (finalAttrs: {
21 version = "6.5";
22 pname = "ncurses" + lib.optionalString (abiVersion == "5") "-abi5-compat";
23
24 src = fetchurl {
25 url = "https://invisible-island.net/archives/ncurses/ncurses-${finalAttrs.version}.tar.gz";
26 hash = "sha256-E22RvCaamleF5fnpgLx2q1dCj2BM4+WlqQzrx2eXHMY=";
27 };
28
29 outputs = [
30 "out"
31 "dev"
32 "man"
33 ];
34 setOutputFlags = false; # some aren't supported
35
36 # see other isOpenBSD clause below
37 configurePlatforms =
38 if stdenv.hostPlatform.isOpenBSD then
39 [ "build" ]
40 else
41 [
42 "build"
43 "host"
44 ];
45
46 configureFlags = [
47 (lib.withFeature (!enableStatic) "shared")
48 "--without-debug"
49 "--enable-pc-files"
50 "--enable-symlinks"
51 "--with-manpage-format=normal"
52 "--disable-stripping"
53 "--with-versioned-syms"
54 ]
55 ++ lib.optional unicodeSupport "--enable-widec"
56 ++ lib.optional (!withCxx) "--without-cxx"
57 ++ lib.optional (abiVersion == "5") "--with-abi-version=5"
58 ++ lib.optional stdenv.hostPlatform.isNetBSD "--enable-rpath"
59 ++ lib.optional withTermlib "--with-termlib"
60 ++ lib.optionals stdenv.hostPlatform.isWindows [
61 "--enable-sp-funcs"
62 "--enable-term-driver"
63 ]
64 ++ lib.optionals (stdenv.hostPlatform.isUnix && enableStatic) [
65 # For static binaries, the point is to have a standalone binary with
66 # minimum dependencies. So here we make sure that binaries using this
67 # package won't depend on a terminfo database located in the Nix store.
68 "--with-terminfo-dirs=${
69 lib.concatStringsSep ":" [
70 "/etc/terminfo" # Debian, Fedora, Gentoo
71 "/lib/terminfo" # Debian
72 "/usr/share/terminfo" # upstream default, probably all FHS-based distros
73 "/run/current-system/sw/share/terminfo" # NixOS
74 ]
75 }"
76 ]
77 ++ lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform) [
78 "--with-build-cc=${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc"
79 ]
80 ++ (lib.optionals (stdenv.cc.bintools.isLLVM && lib.versionAtLeast stdenv.cc.bintools.version "17")
81 [
82 # lld17+ passes `--no-undefined-version` by default and makes this a hard
83 # error; ncurses' `resulting.map` version script references symbols that
84 # aren't present.
85 #
86 # See: https://lists.gnu.org/archive/html/bug-ncurses/2024-05/msg00086.html
87 #
88 # For now we allow this with `--undefined-version`:
89 "LDFLAGS=-Wl,--undefined-version"
90 ]
91 )
92 ++ lib.optionals stdenv.hostPlatform.isOpenBSD [
93 # If you don't specify the version number in the host specification, a branch gets taken in configure
94 # which assumes that your openbsd is from the 90s, leading to a truly awful compiler/linker configuration.
95 # No, autoreconfHook doesn't work.
96 "--host=${stdenv.hostPlatform.config}${stdenv.cc.libc.version}"
97 ];
98
99 # Only the C compiler, and explicitly not C++ compiler needs this flag on solaris:
100 CFLAGS = lib.optionalString stdenv.hostPlatform.isSunOS "-D_XOPEN_SOURCE_EXTENDED";
101
102 strictDeps = true;
103
104 nativeBuildInputs = [
105 updateAutotoolsGnuConfigScriptsHook
106 pkg-config
107 ]
108 ++ lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform) [
109 # for `tic`, build already depends on for build `cc` so it's weird the build doesn't just build `tic`.
110 ncurses
111 ];
112
113 buildInputs = lib.optional (mouseSupport && stdenv.hostPlatform.isLinux) gpm;
114
115 preConfigure = ''
116 export PKG_CONFIG_LIBDIR="$dev/lib/pkgconfig"
117 mkdir -p "$PKG_CONFIG_LIBDIR"
118 configureFlagsArray+=(
119 "--libdir=$out/lib"
120 "--includedir=$dev/include"
121 "--bindir=$dev/bin"
122 "--mandir=$man/share/man"
123 "--with-pkg-config-libdir=$PKG_CONFIG_LIBDIR"
124 )
125 ''
126 + lib.optionalString stdenv.hostPlatform.isSunOS ''
127 sed -i -e '/-D__EXTENSIONS__/ s/-D_XOPEN_SOURCE=\$cf_XOPEN_SOURCE//' \
128 -e '/CPPFLAGS="$CPPFLAGS/s/ -D_XOPEN_SOURCE_EXTENDED//' \
129 configure
130 CFLAGS=-D_XOPEN_SOURCE_EXTENDED
131 '';
132
133 enableParallelBuilding = true;
134
135 doCheck = false;
136
137 postFixup =
138 let
139 abiVersion-extension =
140 if stdenv.hostPlatform.isDarwin then "${abiVersion}.$dylibtype" else "$dylibtype.${abiVersion}";
141 in
142 ''
143 # Determine what suffixes our libraries have
144 suffix="$(awk -F': ' 'f{print $3; f=0} /default library suffix/{f=1}' config.log)"
145 ''
146 # When building a wide-character (Unicode) build, create backward
147 # compatibility links from the the "normal" libraries to the
148 # wide-character libraries (e.g. libncurses.so to libncursesw.so).
149 + lib.optionalString unicodeSupport ''
150 libs="$(ls $dev/lib/pkgconfig | tr ' ' '\n' | sed "s,\(.*\)$suffix\.pc,\1,g")"
151 suffixes="$(echo "$suffix" | awk '{for (i=1; i < length($0); i++) {x=substr($0, i+1, length($0)-i); print x}}')"
152
153 # Get the path to the config util
154 cfg=$(basename $dev/bin/ncurses*-config)
155
156 # symlink the full suffixed include directory
157 ln -svf . $dev/include/ncurses$suffix
158
159 for newsuffix in $suffixes ""; do
160 # Create a non-abi versioned config util links
161 ln -svf $cfg $dev/bin/ncurses$newsuffix-config
162
163 # Allow for end users who #include <ncurses?w/*.h>
164 ln -svf . $dev/include/ncurses$newsuffix
165
166 for library in $libs; do
167 for dylibtype in so dll dylib; do
168 if [ -e "$out/lib/lib''${library}$suffix.$dylibtype" ]; then
169 ln -svf lib''${library}$suffix.$dylibtype $out/lib/lib$library$newsuffix.$dylibtype
170 ln -svf lib''${library}$suffix.${abiVersion-extension} $out/lib/lib$library$newsuffix.${abiVersion-extension}
171 if [ "ncurses" = "$library" ]
172 then
173 # make libtinfo symlinks
174 ln -svf lib''${library}$suffix.$dylibtype $out/lib/libtinfo$newsuffix.$dylibtype
175 ln -svf lib''${library}$suffix.${abiVersion-extension} $out/lib/libtinfo$newsuffix.${abiVersion-extension}
176 fi
177 fi
178 done
179 for statictype in a dll.a la; do
180 if [ -e "$out/lib/lib''${library}$suffix.$statictype" ]; then
181 ln -svf lib''${library}$suffix.$statictype $out/lib/lib$library$newsuffix.$statictype
182 if [ "ncurses" = "$library" ]
183 then
184 # make libtinfo symlinks
185 ln -svf lib''${library}$suffix.$statictype $out/lib/libtinfo$newsuffix.$statictype
186 fi
187 fi
188 done
189 ln -svf ''${library}$suffix.pc $dev/lib/pkgconfig/$library$newsuffix.pc
190 done
191 done
192 ''
193 # Unconditional patches. Leading newline is to avoid mass rebuilds.
194 + ''
195
196 # add pkg-config aliases for libraries that are built-in to libncurses(w)
197 for library in tinfo tic; do
198 for suffix in "" ${lib.optionalString unicodeSupport "w"}; do
199 ln -svf ncurses$suffix.pc $dev/lib/pkgconfig/$library$suffix.pc
200 done
201 done
202
203 # move some utilities to $bin
204 # these programs are used at runtime and don't really belong in $dev
205 moveToOutput "bin/clear" "$out"
206 moveToOutput "bin/reset" "$out"
207 moveToOutput "bin/tabs" "$out"
208 moveToOutput "bin/tic" "$out"
209 moveToOutput "bin/tput" "$out"
210 moveToOutput "bin/tset" "$out"
211 moveToOutput "bin/captoinfo" "$out"
212 moveToOutput "bin/infotocap" "$out"
213 moveToOutput "bin/infocmp" "$out"
214 '';
215
216 preFixup = lib.optionalString (!stdenv.hostPlatform.isCygwin && !enableStatic) ''
217 rm "$out"/lib/*.a
218 '';
219
220 # I'm not very familiar with ncurses, but it looks like most of the
221 # exec here will run hard-coded executables. There's one that is
222 # dynamic, but it looks like it only comes from executing a terminfo
223 # file, so I think it isn't going to be under user control via CLI?
224 # Happy to have someone help nail this down in either direction!
225 # The "capability" is 'iprog', and I could only find 1 real example:
226 # https://invisible-island.net/ncurses/terminfo.ti.html#tic-linux-s
227 passthru.binlore.out = binlore.synthesize ncurses ''
228 execer cannot bin/{reset,tput,tset}
229 '';
230
231 meta = with lib; {
232 homepage = "https://www.gnu.org/software/ncurses/";
233 description = "Free software emulation of curses in SVR4 and more";
234 longDescription = ''
235 The Ncurses (new curses) library is a free software emulation of curses in
236 System V Release 4.0, and more. It uses Terminfo format, supports pads and
237 color and multiple highlights and forms characters and function-key
238 mapping, and has all the other SYSV-curses enhancements over BSD Curses.
239
240 The ncurses code was developed under GNU/Linux. It has been in use for
241 some time with OpenBSD as the system curses library, and on FreeBSD and
242 NetBSD as an external package. It should port easily to any
243 ANSI/POSIX-conforming UNIX. It has even been ported to OS/2 Warp!
244 '';
245 license = licenses.mit;
246 pkgConfigModules =
247 let
248 base = [
249 "form"
250 "menu"
251 "ncurses"
252 "panel"
253 ]
254 ++ lib.optional withCxx "ncurses++";
255 in
256 base ++ lib.optionals unicodeSupport (map (p: p + "w") base);
257 platforms = platforms.all;
258 };
259
260 passthru = {
261 ldflags = "-lncurses";
262 inherit unicodeSupport abiVersion;
263 tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
264 };
265})