247 lines
8.6 KiB
Python
247 lines
8.6 KiB
Python
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
|
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
|
#
|
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
|
|
import glob
|
|
import os
|
|
|
|
from spack.package import *
|
|
|
|
|
|
class Ncurses(AutotoolsPackage, GNUMirrorPackage):
|
|
"""The ncurses (new curses) library is a free software emulation of
|
|
curses in System V Release 4.0, and more. It uses terminfo format,
|
|
supports pads and color and multiple highlights and forms
|
|
characters and function-key mapping, and has all the other
|
|
SYSV-curses enhancements over BSD curses."""
|
|
|
|
homepage = "https://invisible-island.net/ncurses/ncurses.html"
|
|
# URL must remain http:// so Spack can bootstrap curl
|
|
gnu_mirror_path = "ncurses/ncurses-6.1.tar.gz"
|
|
|
|
executables = [r"^ncursesw?(?:\d+(?:\.\d+)*)?-config$"]
|
|
|
|
license("X11")
|
|
|
|
version("6.4", sha256="6931283d9ac87c5073f30b6290c4c75f21632bb4fc3603ac8100812bed248159")
|
|
version("6.3", sha256="97fc51ac2b085d4cde31ef4d2c3122c21abc217e9090a43a30fc5ec21684e059")
|
|
version("6.2", sha256="30306e0c76e0f9f1f0de987cf1c82a5c21e1ce6568b9227f7da5b71cbea86c9d")
|
|
version("6.1", sha256="aa057eeeb4a14d470101eff4597d5833dcef5965331be3528c08d99cebaa0d17")
|
|
version("6.0", sha256="f551c24b30ce8bfb6e96d9f59b42fbea30fa3a6123384172f9e7284bcf647260")
|
|
version("5.9", sha256="9046298fb440324c9d4135ecea7879ffed8546dd1b58e59430ea07a4633f563b")
|
|
|
|
variant("symlinks", default=False, description="Enables symlinks. Needed on AFS filesystem.")
|
|
variant(
|
|
"termlib",
|
|
default=True,
|
|
description="Enables termlib features. This is an extra "
|
|
"lib and optional internal dependency.",
|
|
)
|
|
# Build ncurses with ABI compaitibility.
|
|
variant(
|
|
"abi",
|
|
default="none",
|
|
description="choose abi compatibility",
|
|
values=("none", "5", "6"),
|
|
multi=False,
|
|
)
|
|
|
|
conflicts("abi=6", when="@:5.9", msg="6 is not compatible with this release")
|
|
|
|
depends_on("pkgconfig", type="build")
|
|
|
|
# avoid disallowed const_cast from T* to void* and use reinterpret_cast
|
|
# Ref: https://lists.gnu.org/archive/html/bug-ncurses/2014-08/msg00008.html
|
|
patch("0001-Fix-errors-in-type-conversion.patch", when="@:5")
|
|
patch("sed_pgi.patch", when="@:6.0")
|
|
patch("nvhpc_fix_preprocessor_flag.patch", when="@6.0:6.2%nvhpc")
|
|
|
|
@classmethod
|
|
def determine_version(cls, exe):
|
|
return Executable(exe)("--version", output=str, error=str).rstrip()
|
|
|
|
@classmethod
|
|
def determine_variants(cls, exes, version):
|
|
results = []
|
|
for exe in exes:
|
|
variants = ""
|
|
output = Executable(exe)("--libs", output=str, error=str)
|
|
|
|
if "-ltinfo" in output:
|
|
variants += "+termlib"
|
|
|
|
output = Executable(exe)("--terminfo-dirs", output=str, error=str)
|
|
usingSymlinks = False
|
|
for termDir in output.split(":"):
|
|
for top, dirs, files in os.walk(termDir):
|
|
for filename in files:
|
|
if os.path.islink(os.path.join(top, filename)):
|
|
usingSymlinks = True
|
|
break
|
|
if usingSymlinks:
|
|
break
|
|
if usingSymlinks:
|
|
break
|
|
if usingSymlinks:
|
|
variants += "+symlinks"
|
|
|
|
abiVersion = "none"
|
|
output = Executable(exe)("--abi-version", output=str, error=str)
|
|
if "6" in output:
|
|
abiVersion = "6"
|
|
elif "5" in output:
|
|
abiVersion = "5"
|
|
variants += " abi=" + abiVersion
|
|
|
|
results.append(variants)
|
|
return results
|
|
|
|
def setup_build_environment(self, env):
|
|
env.unset("TERMINFO")
|
|
|
|
def flag_handler(self, name, flags):
|
|
if name == "cflags":
|
|
flags.append(self.compiler.cc_pic_flag)
|
|
elif name == "cxxflags":
|
|
flags.append(self.compiler.cxx_pic_flag)
|
|
|
|
# ncurses@:6.0 fails in definition of macro 'mouse_trafo' without -P
|
|
if self.spec.satisfies("@:6.0 %gcc@5.0:"):
|
|
if name == "cppflags":
|
|
flags.append("-P")
|
|
|
|
# ncurses@:6.0 uses dynamic exception specifications not allowed in c++17
|
|
if self.spec.satisfies("@:5"):
|
|
if name == "cxxflags":
|
|
flags.append(self.compiler.cxx14_flag)
|
|
|
|
return (flags, None, None)
|
|
|
|
def configure(self, spec, prefix):
|
|
opts = [
|
|
"--disable-stripping",
|
|
"--with-shared",
|
|
"--with-cxx-shared",
|
|
"--enable-overwrite",
|
|
"--without-ada",
|
|
"--enable-pc-files",
|
|
"--disable-overwrite",
|
|
]
|
|
|
|
if spec.satisfies("@:6.2"):
|
|
opts.append("--with-pkg-config-libdir={0}/pkgconfig".format(prefix.lib))
|
|
else:
|
|
pcstage = "{0}/lib/pkgconfig".format(self.stage.source_path)
|
|
mkdirp(pcstage)
|
|
opts.append("--with-pkg-config-libdir={0}".format(pcstage))
|
|
|
|
nwide_opts = ["--disable-widec", "--without-manpages", "--without-tests"]
|
|
|
|
wide_opts = ["--enable-widec", "--without-manpages", "--without-tests"]
|
|
|
|
if "+symlinks" in self.spec:
|
|
opts.append("--enable-symlinks")
|
|
|
|
if "+termlib" in self.spec:
|
|
opts.extend(
|
|
(
|
|
"--with-termlib",
|
|
"--enable-termcap",
|
|
"--enable-getcap",
|
|
"--enable-tcap-names",
|
|
"--with-versioned-syms",
|
|
)
|
|
)
|
|
|
|
abi = self.spec.variants["abi"].value
|
|
if abi != "none":
|
|
opts.append("--with-abi-version=" + abi)
|
|
|
|
prefix = "--prefix={0}".format(prefix)
|
|
|
|
configure = Executable("../configure")
|
|
|
|
with working_dir("build_ncurses", create=True):
|
|
configure(prefix, *(opts + nwide_opts))
|
|
|
|
with working_dir("build_ncursesw", create=True):
|
|
configure(prefix, *(opts + wide_opts))
|
|
|
|
def build(self, spec, prefix):
|
|
with working_dir("build_ncurses"):
|
|
make()
|
|
with working_dir("build_ncursesw"):
|
|
make()
|
|
|
|
def install(self, spec, prefix):
|
|
with working_dir("build_ncurses"):
|
|
make("install")
|
|
with working_dir("build_ncursesw"):
|
|
make("install")
|
|
|
|
# fix for packages that use "#include <ncurses.h>" (use wide by default)
|
|
headers = glob.glob(os.path.join(prefix.include, "ncursesw", "*.h"))
|
|
for header in headers:
|
|
h = os.path.basename(header)
|
|
os.symlink(os.path.join("ncursesw", h), os.path.join(prefix.include, h))
|
|
|
|
if spec.satisfies("@6.3:"):
|
|
pc_stage = "{0}/lib/pkgconfig".format(self.stage.source_path)
|
|
pc_install = "{0}/pkgconfig".format(prefix.lib)
|
|
mkdirp(pc_install)
|
|
install_tree(pc_stage, pc_install)
|
|
|
|
@run_after("install")
|
|
def symlink_curses(self):
|
|
soext = "so" if not self.spec.satisfies("platform=darwin") else "dylib"
|
|
libncurses = "{0}/libncurses.{1}".format(self.prefix.lib, soext)
|
|
libcurses = "{0}/libcurses.{1}".format(self.prefix.lib, soext)
|
|
if not os.path.exists(libcurses) and os.path.exists(libncurses):
|
|
os.symlink(libncurses, libcurses)
|
|
|
|
def query_parameter_options(self):
|
|
"""Use query parameters passed to spec (e.g., "spec[ncurses:wide]")
|
|
to select wide, non-wide, or default/both."""
|
|
query_parameters = self.spec.last_query.extra_parameters
|
|
return "nowide" in query_parameters, "wide" in query_parameters
|
|
|
|
@property
|
|
def headers(self):
|
|
nowide, wide = self.query_parameter_options()
|
|
include = self.prefix.include
|
|
hdirs = []
|
|
if not (nowide or wide):
|
|
# default (top-level, wide)
|
|
hdirs.append(include)
|
|
if nowide:
|
|
hdirs.append(include.ncurses)
|
|
if wide:
|
|
hdirs.append(include.ncursesw)
|
|
|
|
headers = HeaderList([])
|
|
for hdir in hdirs:
|
|
headers = headers + find_headers("*", root=hdir, recursive=False).headers
|
|
headers.directories = hdirs
|
|
return headers
|
|
|
|
@property
|
|
def libs(self):
|
|
nowide, wide = self.query_parameter_options()
|
|
if not (nowide or wide):
|
|
# default (both)
|
|
nowide = True
|
|
wide = True
|
|
|
|
libs = ["libncurses"]
|
|
if "+termlib" in self.spec:
|
|
libs.append("libtinfo")
|
|
wlibs = [lib + "w" for lib in libs]
|
|
|
|
libraries = []
|
|
if nowide:
|
|
libraries.extend(libs)
|
|
if wide:
|
|
libraries.extend(wlibs)
|
|
return find_libraries(libraries, root=self.prefix, recursive=True)
|