spack/var/spack/repos/builtin/packages/visit/package.py
kwryankrattiger cef59ad0bf
Patch VTK to enable python 3.8 in VTK 8.2 (#38735)
* VTK: Add patch for python 3.8 support

* CI: Re-enable VisIt in CI

* Configure spec matrix for stack with VisIt

* Add pugixml dep for 8.2.0

* Make VTK and ParaView consistent on proj dep

* OpenMPI 3: provides MP support by default

* Add details on proj dep in ParaView

* Add python 3.8 to test mock repo

* Patches to get VisIt VTK interface

* CI: Disable VisIt with GUI in DAV
2023-08-28 16:56:31 -05:00

360 lines
14 KiB
Python

# Copyright 2013-2023 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 os
from spack.package import *
class Visit(CMakePackage):
"""VisIt is an Open Source, interactive, scalable, visualization,
animation and analysis tool.
"""
############################
# Suggestions for building:
############################
# cyrush note:
#
# Out of the box, VisIt's python 2 requirement will cause
# spack spec constraint errors due Qt + Mesa build
# dependencies.
#
# You can avoid this using:
#
# linux:
# spack install visit ^python+shared ^glib@2.56.3 ^py-setuptools@44.1.0
#
# linux w/o opengl: (add mesa as opengl if system lacks system opengl )
#
# spack install visit ^python+shared ^glib@2.56.3 ^py-setuptools@44.1.0 \
# ^mesa+opengl
#
# macOS:
# spack install visit ^python+shared ^glib@2.56.3 ^py-setuptools@44.1.0 \
# ^qt~framework
#
# Rpath issues undermine qwt (not qt) when a build as a framework
# VisIt's osxfixup resolves this for us in other cases,
# but we can't use osxfixup with spack b/c it will undermine other libs.
#
# Even with these changes, VisIt's Python CLI does not work on macOS,
# there is a linking issue related to OpenSSL.
# (dyld: Symbol not found: _GENERAL_NAME_free - which comes from OpenSSL)
#
############################
homepage = "https://wci.llnl.gov/simulation/computer-codes/visit/"
git = "https://github.com/visit-dav/visit.git"
url = "https://github.com/visit-dav/visit/releases/download/v3.2.1/visit3.2.1.tar.gz"
tags = ["radiuss"]
maintainers("cyrush")
extendable = True
executables = ["^visit$"]
version("develop", branch="develop")
version("3.3.3", sha256="cc67abb7585e23b51ad576e797df4108641ae6c8c5e80e5359a279c729769187")
version("3.3.2", sha256="0ae7c38287598e8d7d238cf284ea8be1096dcf13f58a7e9e444a28a32c085b56")
version("3.3.1", sha256="2e969d3146b559fb833e4cdfaefa72f303d8ad368ef325f68506003f7bc317b9")
version(
"3.3.0",
sha256="1a7485146133ac5f1e330d9029697750046ef8d9e9de23a6c2a3685c1c5f4aac",
deprecated=True,
)
version("3.2.2", sha256="d19ac24c622a3bc0a71bc9cd6e5c9860e43f39e3279672129278b6ebce8d0ead")
version("3.2.1", sha256="779d59564c63f31fcbfeff24b14ddd6ac941b3bb7d671d31765a770d193f02e8")
version("3.1.1", sha256="0b60ac52fd00aff3cf212a310e36e32e13ae3ca0ddd1ea3f54f75e4d9b6c6cf0")
version("3.0.1", sha256="a506d4d83b8973829e68787d8d721199523ce7ec73e7594e93333c214c2c12bd")
root_cmakelists_dir = "src"
generator("ninja")
variant("gui", default=True, description="Enable VisIt's GUI")
variant("osmesa", default=False, description="Use OSMesa for off-screen CPU rendering")
variant("adios2", default=True, description="Enable ADIOS2 file format")
variant("hdf5", default=True, description="Enable HDF5 file format")
variant("silo", default=True, description="Enable Silo file format")
variant("python", default=True, description="Enable Python support")
variant("mpi", default=True, description="Enable parallel engine")
variant("vtkm", default=False, description="Enable VTK-m support")
variant("conduit", default=True, description="Enable Conduit support")
variant("mfem", default=True, description="Enable MFEM support")
variant("plugins", default=True, description="Enable plugin development (xml2cmake)")
patch("spack-changes-3.1.patch", when="@3.1.0:3.2.2")
patch("spack-changes-3.0.1.patch", when="@3.0.1")
patch("nonframework-qwt.patch", when="^qt~framework platform=darwin")
patch("parallel-hdf5.patch", when="@3.0.1:3.2.2+hdf5+mpi")
patch("parallel-hdf5-3.3.patch", when="@3.3.0:+hdf5+mpi")
patch("cmake-findvtkh-3.3.patch", when="@3.3.0:3.3.2+vtkm")
patch("cmake-findjpeg.patch", when="@3.1.0:3.2.2")
patch("cmake-findjpeg-3.3.patch", when="@3.3.0")
# Fix pthread and librt link errors
patch("visit32-missing-link-libs.patch", when="@3.2")
# Fix const-correctness in VTK interface
patch("vtk-8.2-constcorrect.patch", when="@3.3.3 ^vtk@8.2.1a")
# Exactly one of 'gui' or 'osmesa' has to be enabled
conflicts("+gui", when="+osmesa")
depends_on("cmake@3.14.7:", type="build")
depends_on("mpi", when="+mpi")
# VTK flavors
depends_on("vtk@8.1:8 +opengl2")
depends_on("vtk +osmesa", when="+osmesa")
depends_on("vtk +qt", when="+gui")
depends_on("vtk +python", when="+python")
depends_on("vtk +mpi", when="+mpi")
depends_on("vtk ~mpi", when="~mpi")
# Necessary VTK patches
depends_on("vtk", patches=[patch("vtk_compiler_visibility.patch")], when="^vtk@8")
depends_on(
"vtk",
patches=[patch("vtk_rendering_opengl2_x11.patch")],
when="~osmesa platform=linux ^vtk@8",
)
depends_on("vtk", patches=[patch("vtk_wrapping_python_x11.patch")], when="+python ^vtk@8")
depends_on("glu")
# VisIt doesn't work with later versions of qt.
depends_on("qt+gui+opengl@5:5.14", when="+gui")
depends_on("qwt+opengl", when="+gui")
# python@3.8 doesn't work with VisIt.
depends_on("python@3.2:3.7,3.9:", when="@:3.2 +python")
depends_on("python@3.2:", when="@3.3: +python")
extends("python", when="+python")
# VisIt uses the hdf5 1.8 api
# set the API version later on down in setup_build_environment
depends_on("hdf5@1.8:", when="+hdf5")
depends_on("hdf5+mpi", when="+hdf5+mpi")
depends_on("hdf5~mpi", when="+hdf5~mpi")
# VisIt uses Silo's 'ghost zone' data structures, which are only available
# in v4.10+ releases: https://wci.llnl.gov/simulation/computer-codes/silo/releases/release-notes-4.10
depends_on("silo@4.10: +shared", when="+silo")
depends_on("silo+hdf5", when="+silo+hdf5")
depends_on("silo~hdf5", when="+silo~hdf5")
depends_on("silo+mpi", when="+silo+mpi")
depends_on("silo~mpi", when="+silo~mpi")
depends_on("conduit@0.8.3:", when="+conduit")
depends_on("conduit+python", when="+conduit")
depends_on("conduit+hdf5", when="+conduit+hdf5")
depends_on("conduit~hdf5", when="+conduit~hdf5")
depends_on("conduit+mpi", when="+conduit+mpi")
depends_on("conduit~mpi", when="+conduit~mpi")
depends_on("mfem@4.4:", when="+mfem")
depends_on("mfem+shared+exceptions+fms+conduit", when="+mfem")
depends_on("libfms@0.2:", when="+mfem")
depends_on("adios2@2.6:", when="+adios2")
depends_on("adios2+hdf5", when="+adios2+hdf5")
depends_on("adios2~hdf5", when="+adios2~hdf5")
depends_on("adios2+mpi", when="+adios2+mpi")
depends_on("adios2~mpi", when="+adios2~mpi")
depends_on("adios2+python", when="+adios2+python")
depends_on("adios2~python", when="+adios2~python")
# For version 3.3.0 through 3.3.2, we used vtk-h to utilize vtk-m.
# For version starting with 3.3.3 we use vtk-m directly.
depends_on("vtk-m@1.7.0+testlib~cuda", when="@3.3.0:3.3.2+vtkm")
depends_on("vtk-h@0.8.1+shared~mpi~openmp~cuda", when="@3.3.0:3.3.2+vtkm")
depends_on("vtk-m@1.9.0+testlib~cuda", when="@3.3.3:+vtkm")
# This patch prevents vtk-m from throwing an exception whenever any
# vtk-m operations are performed.
depends_on("vtk-m", patches=[patch("vtk-m_transport_tag_topology_field_in.patch")])
depends_on("zlib-api")
@when("@3:,develop")
def patch(self):
# Some of VTK's targets don't create explicit libraries, so there is no
# 'vtktiff'. Instead, replace with the library variable defined from
# VTK's module flies (e.g. lib/cmake/vtk-8.1/Modules/vtktiff.cmake)
for filename in find("src", "CMakeLists.txt"):
filter_file(r"\bvtk(tiff|jpeg|png)", r"${vtk\1_LIBRARIES}", filename)
def flag_handler(self, name, flags):
if name in ("cflags", "cxxflags"):
# NOTE: This is necessary in order to allow VisIt to compile a couple
# of lines of code with 'const char*' to/from 'char*' conversions.
if "@3:%gcc" in self.spec:
flags.append("-fpermissive")
# VisIt still uses the hdf5 1.8 api
if "+hdf5" in self.spec and "@1.10:" in self.spec["hdf5"]:
flags.append("-DH5_USE_18_API")
elif name == "ldlibs":
# Python support is missing a pthread dependency
if "@3 +python" in self.spec:
flags.append("-lpthread")
return (flags, None, None)
def cmake_args(self):
spec = self.spec
args = [
self.define("CMAKE_SKIP_COMPATIBILITY_TESTS", True),
self.define("CMAKE_POSITION_INDEPENDENT_CODE", True),
self.define("VTK_MAJOR_VERSION", spec["vtk"].version[0]),
self.define("VTK_MINOR_VERSION", spec["vtk"].version[1]),
self.define("VISIT_VTK_DIR", spec["vtk"].prefix),
self.define("VISIT_ZLIB_DIR", spec["zlib-api"].prefix),
self.define("VISIT_JPEG_DIR", spec["jpeg"].prefix),
self.define("VISIT_USE_GLEW", False),
self.define("VISIT_CONFIG_SITE", "NONE"),
]
# Provide the plugin compilation environment so as to extend VisIt
args.append(self.define_from_variant("VISIT_INSTALL_THIRD_PARTY", "plugins"))
if "@3.1: platform=darwin" in spec:
args.append(self.define("FIXUP_OSX", False))
if "+python" in spec:
args.extend(
[
self.define("VISIT_PYTHON_FILTERS", True),
self.define("VISIT_PYTHON_SCRIPTING", True),
self.define("PYTHON_DIR", spec["python"].home),
]
)
else:
args.extend(
[
self.define("VISIT_PYTHON_FILTERS", False),
self.define("VISIT_PYTHON_SCRIPTING", False),
]
)
if "+gui" in spec:
qt_bin = spec["qt"].prefix.bin
qmake_exe = os.path.join(qt_bin, "qmake")
args.extend(
[
self.define("VISIT_SERVER_COMPONENTS_ONLY", False),
self.define("VISIT_ENGINE_ONLY", False),
self.define("VISIT_LOC_QMAKE_EXE", qmake_exe),
self.define("VISIT_QT_DIR", spec["qt"].prefix),
self.define("VISIT_QWT_DIR", spec["qwt"].prefix),
]
)
else:
args.extend(
[
self.define("VISIT_SERVER_COMPONENTS_ONLY", True),
self.define("VISIT_ENGINE_ONLY", True),
]
)
# OpenGL args
args.extend(
[
self.define("VISIT_USE_X", "glx" in spec),
self.define("VISIT_MESAGL_DIR", "IGNORE"),
self.define("VISIT_OPENGL_DIR", "IGNORE"),
self.define("VISIT_OSMESA_DIR", "IGNORE"),
self.define("OpenGL_GL_PREFERENCE", "LEGACY"),
self.define("OPENGL_INCLUDE_DIR", spec["gl"].headers.directories[0]),
self.define("OPENGL_glu_LIBRARY", spec["glu"].libs[0]),
]
)
if "+osmesa" in spec:
args.extend(
[
self.define("HAVE_OSMESA", True),
self.define("OSMESA_LIBRARIES", spec["osmesa"].libs[0]),
self.define("OPENGL_gl_LIBRARY", spec["osmesa"].libs[0]),
]
)
else:
args.append(self.define("OPENGL_gl_LIBRARY", spec["gl"].libs[0]))
if "+hdf5" in spec:
args.append(self.define("HDF5_DIR", spec["hdf5"].prefix))
if "+mpi" in spec and "+mpi" in spec["hdf5"]:
args.append(self.define("VISIT_HDF5_MPI_DIR", spec["hdf5"].prefix))
if "+silo" in spec:
args.append(self.define("VISIT_SILO_DIR", spec["silo"].prefix))
if "+conduit" in spec:
args.extend(
[
self.define("VISIT_CONDUIT_DIR", spec["conduit"].prefix),
self.define("CONDUIT_VERSION", spec["conduit"].version),
]
)
if "+mfem" in spec:
args.extend(
[
self.define("VISIT_MFEM_DIR", spec["mfem"].prefix),
self.define("VISIT_FMS_DIR", spec["libfms"].prefix),
self.define("VISIT_MFEM_INCDEP", "CONDUIT_INCLUDE_DIR;FMS_INCLUDE_DIR"),
]
)
if "+mpi" in spec:
args.extend(
[
self.define("VISIT_PARALLEL", True),
self.define("VISIT_MPI_COMPILER", spec["mpi"].mpicxx),
]
)
else:
args.append(self.define("VISIT_PARALLEL", False))
if "@3.3.0:3.3.2 +vtkm" in spec:
args.append(self.define("VISIT_VTKM_DIR", spec["vtk-m"].prefix))
args.append(self.define("VISIT_VTKH_DIR", spec["vtk-h"].prefix))
if "@3.3.3: +vtkm" in spec:
args.append(self.define("VISIT_VTKM_DIR", spec["vtk-m"].prefix))
args.append(
self.define(
"CMAKE_EXE_LINKER_FLAGS",
"-L%s/lib -L%s/lib" % (spec["hip"].prefix, spec["libx11"].prefix),
)
)
args.append(
self.define(
"CMAKE_MODULE_LINKER_FLAGS",
"-L%s/lib -L%s/lib" % (spec["hip"].prefix, spec["libx11"].prefix),
)
)
args.append(
self.define(
"CMAKE_SHARED_LINKER_FLAGS",
"-L%s/lib -L%s/lib" % (spec["hip"].prefix, spec["libx11"].prefix),
)
)
return args
# https://spack.readthedocs.io/en/latest/packaging_guide.html?highlight=executables#making-a-package-discoverable-with-spack-external-find
# Here we are only able to determine the latest version
# despite VisIt may have multiple versions
@classmethod
def determine_version(cls, exe):
output = Executable(exe)("-version", output=str, error=str)
match = re.search(r"\s*(\d[\d\.]+)\.", output)
return match.group(1) if match else None