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