From 7f1659786b32dd492b062347c6ca1538a8c71495 Mon Sep 17 00:00:00 2001 From: Tom Scogland Date: Mon, 9 May 2022 21:54:38 -0700 Subject: Add a Lua build-system (#28854) Reworking lua to allow easier substitution of the base lua implementation. Also adding in a maintained version of luajit and re-factoring the entire stack to use a custom build-system to centralize functionality like environment variable management and luarocks installation. The `lua-lang` virtual is now versioned so that a package that requires Lua 5.1 semantics can get any lua, but one that requires 5.2 will only get upstream lua. The luaposix package requires lua-bit32, but only when built with a lua conforming to version 5.1. This adds the package, and the dependencies, but exposed a problem with luarocks dependency detection. Since we're installing each package in its own "tree" and there's no environment variable to list extra trees, spack now generates a luarocks config file that lists all the trees of all the dependencies, and references it by setting `LUAROCKS_CONFIG` in the build environment of every LuaPackage. This allows luarocks to find the spack installed dependencies correctly rather than trying (and failing) to download them. Co-authored-by: Adam J. Stewart Co-authored-by: Tom Scogland Co-authored-by: Massimiliano Culpo --- etc/spack/defaults/packages.yaml | 3 +- lib/spack/docs/build_systems.rst | 1 + lib/spack/docs/build_systems/luapackage.rst | 105 +++++++ lib/spack/spack/build_systems/lua.py | 102 +++++++ lib/spack/spack/cmd/create.py | 26 ++ lib/spack/spack/directives.py | 10 +- lib/spack/spack/pkgkit.py | 1 + lib/spack/spack/solver/concretize.lp | 2 + lib/spack/spack/test/build_system_guess.py | 41 +-- lib/spack/spack/url.py | 8 + var/spack/repos/builtin/packages/libluv/package.py | 5 +- .../repos/builtin/packages/lua-bit32/package.py | 17 ++ .../repos/builtin/packages/lua-bitlib/package.py | 17 +- .../repos/builtin/packages/lua-lpeg/package.py | 8 +- .../builtin/packages/lua-luafilesystem/package.py | 30 +- .../packages/lua-luajit-openresty/package.py | 51 ++++ .../repos/builtin/packages/lua-luajit/package.py | 35 +-- .../repos/builtin/packages/lua-luaposix/package.py | 10 +- .../repos/builtin/packages/lua-mpack/package.py | 38 ++- var/spack/repos/builtin/packages/lua/package.py | 331 +++++++++++++-------- 20 files changed, 595 insertions(+), 246 deletions(-) create mode 100644 lib/spack/docs/build_systems/luapackage.rst create mode 100644 lib/spack/spack/build_systems/lua.py create mode 100644 var/spack/repos/builtin/packages/lua-bit32/package.py create mode 100644 var/spack/repos/builtin/packages/lua-luajit-openresty/package.py diff --git a/etc/spack/defaults/packages.yaml b/etc/spack/defaults/packages.yaml index 00da33b10d..71bac6f247 100644 --- a/etc/spack/defaults/packages.yaml +++ b/etc/spack/defaults/packages.yaml @@ -35,7 +35,8 @@ packages: jpeg: [libjpeg-turbo, libjpeg] lapack: [openblas, amdlibflame] libllvm: [llvm, llvm-amdgpu] - lua-lang: [lua, lua-luajit] + lua-lang: [lua, lua-luajit-openresty, lua-luajit] + luajit: [lua-luajit-openresty, lua-luajit] mariadb-client: [mariadb-c-client, mariadb] mkl: [intel-mkl] mpe: [mpe2] diff --git a/lib/spack/docs/build_systems.rst b/lib/spack/docs/build_systems.rst index 77fb5c7838..11f0df4f49 100644 --- a/lib/spack/docs/build_systems.rst +++ b/lib/spack/docs/build_systems.rst @@ -47,6 +47,7 @@ on these ideas for each distinct build system that Spack supports: :maxdepth: 1 :caption: Language-specific + build_systems/luapackage build_systems/octavepackage build_systems/perlpackage build_systems/pythonpackage diff --git a/lib/spack/docs/build_systems/luapackage.rst b/lib/spack/docs/build_systems/luapackage.rst new file mode 100644 index 0000000000..6332edfc20 --- /dev/null +++ b/lib/spack/docs/build_systems/luapackage.rst @@ -0,0 +1,105 @@ +.. Copyright 2013-2022 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) + +.. _luapackage: + +------------ +LuaPackage +------------ + +LuaPackage is a helper for the common case of Lua packages that provide +a rockspec file. This is not meant to take a rock archive, but to build +a source archive or repository that provides a rockspec, which should cover +most lua packages. In the case a Lua package builds by Make rather than +luarocks, prefer MakefilePackage. + +^^^^^^ +Phases +^^^^^^ + +The ``LuaPackage`` base class comes with the following phases: + +#. ``unpack`` - if using a rock, unpacks the rock and moves into the source directory +#. ``preprocess`` - adjust sources or rockspec to fix build +#. ``install`` - install the project + +By default, these phases run: + +.. code-block:: console + + # If the archive is a source rock + $ luarocks unpack .src.rock + $ # preprocess is a noop by default + $ luarocks make .rockspec + + +Any of these phases can be overridden in your package as necessary. + +^^^^^^^^^^^^^^^ +Important files +^^^^^^^^^^^^^^^ + +Packages that use the Lua/LuaRocks build system can be identified by the +presence of a ``*.rockspec`` file in their sourcetree, or can be fetched as +a source rock archive (``.src.rock``). This file declares things like build +instructions and dependencies, the ``.src.rock`` also contains all code. + +It is common for the rockspec file to list the lua version required in +a dependency. The LuaPackage class adds appropriate dependencies on a Lua +implementation, but it is a good idea to specify the version required with +a ``depends_on`` statement. The block normally will be a table definition like +this: + +.. code-block:: lua + + dependencies = { + "lua >= 5.1", + } + +The LuaPackage class supports source repositories and archives containing +a rockspec and directly downloading source rock files. It *does not* support +downloading dependencies listed inside a rockspec, and thus does not support +directly downloading a rockspec as an archive. + +^^^^^^^^^^^^^^^^^^^^^^^^^ +Build system dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^ + +All base dependencies are added by the build system, but LuaRocks is run to +avoid downloading extra Lua dependencies during build. If the package needs +Lua libraries outside the standard set, they should be added as dependencies. + +To specify a Lua version constraint but allow all lua implementations, prefer +to use ``depends_on("lua-lang@5.1:5.1.99")`` to express any 5.1 compatible +version. If the package requires LuaJit rather than Lua, +a ``depends_on("luajit")`` should be used to ensure a LuaJit distribution is +used instead of the Lua interpreter. Alternately, if only interpreted Lua will +work ``depends_on("lua")`` will express that. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Passing arguments to luarocks make +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you need to pass any arguments to the ``luarocks make`` call, you can +override the ``luarocks_args`` method like so: + +.. code-block:: python + + def luarocks_args(self): + return ['flag1', 'flag2'] + +One common use of this is to override warnings or flags for newer compilers, as in: + +.. code-block:: python + + def luarocks_args(self): + return ["CFLAGS='-Wno-error=implicit-function-declaration'"] + +^^^^^^^^^^^^^^^^^^^^^^ +External documentation +^^^^^^^^^^^^^^^^^^^^^^ + +For more information on the LuaRocks build system, see: +https://luarocks.org/ diff --git a/lib/spack/spack/build_systems/lua.py b/lib/spack/spack/build_systems/lua.py new file mode 100644 index 0000000000..3a836de012 --- /dev/null +++ b/lib/spack/spack/build_systems/lua.py @@ -0,0 +1,102 @@ +# Copyright 2013-2022 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 llnl.util.filesystem import find + +from spack.directives import depends_on, extends +from spack.multimethod import when +from spack.package import PackageBase +from spack.util.executable import Executable + + +class LuaPackage(PackageBase): + """Specialized class for lua packages""" + + phases = ['unpack', 'generate_luarocks_config', 'preprocess', 'install'] + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = 'LuaPackage' + + list_depth = 1 # LuaRocks requires at least one level of spidering to find versions + depends_on('lua-lang') + extends('lua', when='^lua') + with when('^lua-luajit'): + extends('lua-luajit') + depends_on('luajit') + depends_on('lua-luajit+lualinks') + with when('^lua-luajit-openresty'): + extends('lua-luajit-openresty') + depends_on('luajit') + depends_on('lua-luajit-openresty+lualinks') + + def unpack(self, spec, prefix): + if os.path.splitext(self.stage.archive_file)[1] == '.rock': + directory = self.luarocks('unpack', self.stage.archive_file, output=str) + dirlines = directory.split('\n') + # TODO: figure out how to scope this better + os.chdir(dirlines[2]) + + def _generate_tree_line(self, name, prefix): + return """{{ name = "{name}", root = "{prefix}" }};""".format( + name=name, + prefix=prefix, + ) + + def _luarocks_config_path(self): + return os.path.join(self.stage.source_path, 'spack_luarocks.lua') + + def generate_luarocks_config(self, spec, prefix): + spec = self.spec + table_entries = [] + for d in spec.traverse( + deptypes=("build", "run"), deptype_query="run" + ): + if d.package.extends(self.extendee_spec): + table_entries.append(self._generate_tree_line(d.name, d.prefix)) + + path = self._luarocks_config_path() + with open(path, 'w') as config: + config.write( + """ + deps_mode="all" + rocks_trees={{ + {} + }} + """.format( + "\n".join(table_entries) + ) + ) + return path + + def setup_build_environment(self, env): + env.set('LUAROCKS_CONFIG', self._luarocks_config_path()) + + def preprocess(self, spec, prefix): + """Override this to preprocess source before building with luarocks""" + pass + + @property + def lua(self): + return Executable(self.spec['lua-lang'].prefix.bin.lua) + + @property + def luarocks(self): + lr = Executable(self.spec['lua-lang'].prefix.bin.luarocks) + return lr + + def luarocks_args(self): + return [] + + def install(self, spec, prefix): + rock = '.' + specs = find('.', '*.rockspec', recursive=False) + if specs: + rock = specs[0] + rocks_args = self.luarocks_args() + rocks_args.append(rock) + self.luarocks('--tree=' + prefix, 'make', *rocks_args) diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py index 1e3e89760b..94ddc7d292 100644 --- a/lib/spack/spack/cmd/create.py +++ b/lib/spack/spack/cmd/create.py @@ -187,6 +187,27 @@ class CMakePackageTemplate(PackageTemplate): return args""" +class LuaPackageTemplate(PackageTemplate): + """Provides appropriate overrides for LuaRocks-based packages""" + + base_class_name = 'LuaPackage' + + body_def = """\ + def luarocks_args(self): + # FIXME: Add arguments to `luarocks make` other than rockspec path + # FIXME: If not needed delete this function + args = [] + return args""" + + def __init__(self, name, url, *args, **kwargs): + # If the user provided `--name lua-lpeg`, don't rename it lua-lua-lpeg + if not name.startswith('lua-'): + # Make it more obvious that we are renaming the package + tty.msg("Changing package name from {0} to lua-{0}".format(name)) + name = 'lua-{0}'.format(name) + super(LuaPackageTemplate, self).__init__(name, url, *args, **kwargs) + + class MesonPackageTemplate(PackageTemplate): """Provides appropriate overrides for meson-based packages""" @@ -580,6 +601,7 @@ templates = { 'makefile': MakefilePackageTemplate, 'intel': IntelPackageTemplate, 'meson': MesonPackageTemplate, + 'lua': LuaPackageTemplate, 'sip': SIPPackageTemplate, 'generic': PackageTemplate, } @@ -644,6 +666,9 @@ class BuildSystemGuesser: if url.endswith('.whl') or '.whl#' in url: self.build_system = 'python' return + if url.endswith('.rock'): + self.build_system = 'lua' + return # A list of clues that give us an idea of the build system a package # uses. If the regular expression matches a file contained in the @@ -668,6 +693,7 @@ class BuildSystemGuesser: (r'/Rakefile$', 'ruby'), (r'/setup\.rb$', 'ruby'), (r'/.*\.pro$', 'qmake'), + (r'/.*\.rockspec$', 'lua'), (r'/(GNU)?[Mm]akefile$', 'makefile'), (r'/DESCRIPTION$', 'octave'), (r'/meson\.build$', 'meson'), diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py index 7d92a203e5..2de6552a82 100644 --- a/lib/spack/spack/directives.py +++ b/lib/spack/spack/directives.py @@ -48,13 +48,13 @@ from spack.fetch_strategy import from_kwargs from spack.resource import Resource from spack.version import Version, VersionChecksumError -__all__ = ['DirectiveError', 'DirectiveMeta'] +__all__ = ['DirectiveError', 'DirectiveMeta', 'version', 'conflicts', 'depends_on', + 'extends', 'provides', 'patch', 'variant', 'resource'] #: These are variant names used by Spack internally; packages can't use them reserved_names = ['patches', 'dev_path'] -#: Names of possible directives. This list is populated elsewhere in the file and then -#: added to `__all__` at the bottom. +#: Names of possible directives. This list is populated elsewhere in the file. directive_names = [] _patch_order_index = 0 @@ -731,7 +731,3 @@ class DependencyPatchError(DirectiveError): class UnsupportedPackageDirective(DirectiveError): """Raised when an invalid or unsupported package directive is specified.""" - - -#: add all directive names to __all__ -__all__.extend(directive_names) diff --git a/lib/spack/spack/pkgkit.py b/lib/spack/spack/pkgkit.py index 3fde349b9a..c7fbfe1af8 100644 --- a/lib/spack/spack/pkgkit.py +++ b/lib/spack/spack/pkgkit.py @@ -25,6 +25,7 @@ from spack.build_systems.cmake import CMakePackage from spack.build_systems.cuda import CudaPackage from spack.build_systems.gnu import GNUMirrorPackage from spack.build_systems.intel import IntelPackage +from spack.build_systems.lua import LuaPackage from spack.build_systems.makefile import MakefilePackage from spack.build_systems.maven import MavenPackage from spack.build_systems.meson import MesonPackage diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index 19bec37908..65dbd0b19d 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -288,6 +288,7 @@ possible_provider_weight(Dependency, Virtual, 100, "fallback") :- provider(Depen % These allow us to easily define conditional dependency and conflict rules % without enumerating all spec attributes every time. node(Package) :- attr("node", Package). +virtual_node(Virtual) :- attr("virtual_node", Virtual). hash(Package, Hash) :- attr("hash", Package, Hash). version(Package, Version) :- attr("version", Package, Version). version_satisfies(Package, Constraint) :- attr("version_satisfies", Package, Constraint). @@ -306,6 +307,7 @@ node_compiler_version_satisfies(Package, Compiler, Version) :- attr("node_compiler_version_satisfies", Package, Compiler, Version). attr("node", Package) :- node(Package). +attr("virtual_node", Virtual) :- virtual_node(Virtual). attr("hash", Package, Hash) :- hash(Package, Hash). attr("version", Package, Version) :- version(Package, Version). attr("version_satisfies", Package, Constraint) :- version_satisfies(Package, Constraint). diff --git a/lib/spack/spack/test/build_system_guess.py b/lib/spack/spack/test/build_system_guess.py index 9e97dfbfb2..7850d70fff 100644 --- a/lib/spack/spack/test/build_system_guess.py +++ b/lib/spack/spack/test/build_system_guess.py @@ -18,26 +18,27 @@ pytestmark = pytest.mark.skipif(sys.platform == "win32", @pytest.fixture( scope='function', params=[ - ('configure', 'autotools'), - ('CMakeLists.txt', 'cmake'), - ('project.pro', 'qmake'), - ('pom.xml', 'maven'), - ('SConstruct', 'scons'), - ('waf', 'waf'), - ('setup.py', 'python'), - ('NAMESPACE', 'r'), - ('WORKSPACE', 'bazel'), - ('Makefile.PL', 'perlmake'), - ('Build.PL', 'perlbuild'), - ('foo.gemspec', 'ruby'), - ('Rakefile', 'ruby'), - ('setup.rb', 'ruby'), - ('GNUmakefile', 'makefile'), - ('makefile', 'makefile'), - ('Makefile', 'makefile'), - ('meson.build', 'meson'), - ('configure.py', 'sip'), - ('foobar', 'generic') + ('configure', 'autotools'), + ('CMakeLists.txt', 'cmake'), + ('project.pro', 'qmake'), + ('pom.xml', 'maven'), + ('SConstruct', 'scons'), + ('waf', 'waf'), + ('argbah.rockspec', 'lua'), + ('setup.py', 'python'), + ('NAMESPACE', 'r'), + ('WORKSPACE', 'bazel'), + ('Makefile.PL', 'perlmake'), + ('Build.PL', 'perlbuild'), + ('foo.gemspec', 'ruby'), + ('Rakefile', 'ruby'), + ('setup.rb', 'ruby'), + ('GNUmakefile', 'makefile'), + ('makefile', 'makefile'), + ('Makefile', 'makefile'), + ('meson.build', 'meson'), + ('configure.py', 'sip'), + ('foobar', 'generic') ] ) def url_and_build_system(request, tmpdir): diff --git a/lib/spack/spack/url.py b/lib/spack/spack/url.py index 2eb2ab7ed7..8ad7b196af 100644 --- a/lib/spack/spack/url.py +++ b/lib/spack/spack/url.py @@ -58,6 +58,7 @@ def find_list_urls(url): BitBucket https://bitbucket.org///downloads/?tab=tags CRAN https://\*.r-project.org/src/contrib/Archive/ PyPI https://pypi.org/simple// + LuaRocks https://luarocks.org/modules// ========= ======================================================= Note: this function is called by `spack versions`, `spack checksum`, @@ -106,6 +107,13 @@ def find_list_urls(url): # e.g. https://pypi.io/packages/py2.py3/o/opencensus-context/opencensus_context-0.1.1-py2.py3-none-any.whl (r'(?:pypi|pythonhosted)[^/]+/packages/[^/]+/./([^/]+)', lambda m: 'https://pypi.org/simple/' + m.group(1) + '/'), + + # LuaRocks + # e.g. https://luarocks.org/manifests/gvvaughan/lpeg-1.0.2-1.src.rock + # e.g. https://luarocks.org/manifests/openresty/lua-cjson-2.1.0-1.src.rock + (r'luarocks[^/]+/(?:modules|manifests)/(?P[^/]+)/' + + r'(?P.+?)-[0-9.-]*\.src\.rock', + lambda m: 'https://luarocks.org/modules/' + m.group('org') + '/' + m.group('name') + '/'), ] list_urls = set([os.path.dirname(url)]) diff --git a/var/spack/repos/builtin/packages/libluv/package.py b/var/spack/repos/builtin/packages/libluv/package.py index 62f58a9a6a..5a8b1e17d3 100644 --- a/var/spack/repos/builtin/packages/libluv/package.py +++ b/var/spack/repos/builtin/packages/libluv/package.py @@ -15,9 +15,11 @@ class Libluv(CMakePackage): url = "https://github.com/luvit/luv/releases/download/1.36.0-0/luv-1.36.0-0.tar.gz" version('1.43.0-0', sha256='567a6f3dcdcf8a9b54ddc57ffef89d1e950d72832b85ee81c8c83a9d4e0e9de2') + version('1.42.0-1', sha256='4b6fbaa89d2420edf6070ad9e522993e132bd7eb2540ff754c2b9f1497744db2') + version('1.42.0-0', sha256='b5228a9d0eaacd9f862b6270c732d5c90773a28ce53b6d9e32a14050e7947f36') version('1.36.0-0', sha256='f2e7eb372574f25c6978c1dc74280d22efdcd7df2dda4a286c7fe7dceda26445') - depends_on('lua', type='link') + depends_on('lua-lang', type='link') depends_on('libuv', type='link') def cmake_args(self): @@ -26,6 +28,5 @@ class Libluv(CMakePackage): '-DBUILD_STATIC_LIBS=ON', '-DBUILD_SHARED_LIBS=ON', '-DWITH_SHARED_LIBUV=ON', - '-DWITH_LUA_ENGINE=Lua', ] return args diff --git a/var/spack/repos/builtin/packages/lua-bit32/package.py b/var/spack/repos/builtin/packages/lua-bit32/package.py new file mode 100644 index 0000000000..4dca82dd64 --- /dev/null +++ b/var/spack/repos/builtin/packages/lua-bit32/package.py @@ -0,0 +1,17 @@ +# Copyright 2013-2022 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) + +from spack.pkgkit import * + + +class LuaBit32(LuaPackage): + """Lua 5.2 bit operations for Lua 5.1""" + + homepage = "https://luarocks.org/modules/siffiejoe/bit32/" + url = "https://luarocks.org/manifests/siffiejoe/bit32-5.3.5.1-1.src.rock" + + version('5.3.5.1-1', sha256='0e273427f2b877270f9cec5642ebe2670242926ba9638d4e6df7e4e1263ca12c', expand=False) + + depends_on('lua-lang@5.1') diff --git a/var/spack/repos/builtin/packages/lua-bitlib/package.py b/var/spack/repos/builtin/packages/lua-bitlib/package.py index 4da0849840..e07effd7ae 100644 --- a/var/spack/repos/builtin/packages/lua-bitlib/package.py +++ b/var/spack/repos/builtin/packages/lua-bitlib/package.py @@ -4,25 +4,18 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import os - from spack import * -class LuaBitlib(Package): +class LuaBitlib(LuaPackage): """Lua-jit-like bitwise operations for lua""" homepage = "http://luaforge.net/projects/bitlib" - url = "https://luarocks.org/bitlib-23-2.src.rock" + url = "https://luarocks.org/manifests/luarocks/bitlib-23-2.src.rock" version('23-2', sha256='fe226edc2808162e67418e6b2c98befc0ed25a489ecffc6974fa153f951c0c34', expand=False) - extends('lua') - - def install(self, spec, prefix): - luarocks('unpack', "bitlib-23-2.src.rock") - os.chdir(os.path.join('bitlib-23-2', 'bitlib-23')) - sed = which('sed') - sed('-ie', 's/luaL_reg/luaL_Reg/', 'lbitlib.c') - luarocks('--tree=' + prefix, 'make') + def preprocess(self, spec, prefix): + m = FileFilter('lbitlib.c') + m.filter('luaL_reg', 'luaL_Reg') diff --git a/var/spack/repos/builtin/packages/lua-lpeg/package.py b/var/spack/repos/builtin/packages/lua-lpeg/package.py index 88f648b0eb..6c0d8f495c 100644 --- a/var/spack/repos/builtin/packages/lua-lpeg/package.py +++ b/var/spack/repos/builtin/packages/lua-lpeg/package.py @@ -7,7 +7,7 @@ from spack import * -class LuaLpeg(Package): +class LuaLpeg(LuaPackage): """pattern-matching for lua""" homepage = "http://www.inf.puc-rio.br/~roberto/lpeg/" @@ -16,8 +16,4 @@ class LuaLpeg(Package): version('1.0.2-1', sha256='e0d0d687897f06588558168eeb1902ac41a11edd1b58f1aa61b99d0ea0abbfbc', expand=False) version('0.12-1', sha256='3962e8d695d0f9095c9453f2a42f9f1a89fb94db9b0c3bf22934c1e8a3b0ef5a', expand=False) - extends("lua") - depends_on("lua@:5.1.9", when="@:0.12.1") - - def install(self, spec, prefix): - luarocks('--tree=' + prefix, 'install', self.stage.archive_file) + depends_on("lua@:5.1.9", when="@:0.12.1^lua") diff --git a/var/spack/repos/builtin/packages/lua-luafilesystem/package.py b/var/spack/repos/builtin/packages/lua-luafilesystem/package.py index e33a7ca1bf..0e3e3f5fd2 100644 --- a/var/spack/repos/builtin/packages/lua-luafilesystem/package.py +++ b/var/spack/repos/builtin/packages/lua-luafilesystem/package.py @@ -3,10 +3,10 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import os.path +from spack.pkgkit import * -class LuaLuafilesystem(Package): +class LuaLuafilesystem(LuaPackage): """LuaFileSystem is a Lua library developed to complement the set of functions related to file systems offered by the standard Lua distribution. @@ -19,30 +19,6 @@ class LuaLuafilesystem(Package): homepage = 'http://keplerproject.github.io/luafilesystem' url = 'https://github.com/keplerproject/luafilesystem/archive/v1_6_3.tar.gz' + version('1_8_0', sha256='16d17c788b8093f2047325343f5e9b74cccb1ea96001e45914a58bbae8932495') version('1_7_0_2', sha256='23b4883aeb4fb90b2d0f338659f33a631f9df7a7e67c54115775a77d4ac3cc59') version('1_6_3', sha256='11c7b1fc2e560c0a521246b84e6257138d97dddde5a19e405714dbabcb9436ca') - - # The version constraint here comes from this post: - # - # https://www.perforce.com/blog/git-beyond-basics-using-shallow-clones - # - # where it is claimed that full shallow clone support was added @1.9 - depends_on('git@1.9.0:', type='build') - extends('lua') - - @property - def rockspec(self): - version = self.spec.version - semver = version[0:3] - tweak_level = version[3] if len(version) > 3 else 1 - fmt = os.path.join( - self.stage.source_path, - 'rockspecs', - 'luafilesystem-{semver.dotted}-{tweak_level}.rockspec' - ) - return fmt.format( - version=version, semver=semver, tweak_level=tweak_level - ) - - def install(self, spec, prefix): - luarocks('--tree=' + prefix, 'make', self.rockspec) diff --git a/var/spack/repos/builtin/packages/lua-luajit-openresty/package.py b/var/spack/repos/builtin/packages/lua-luajit-openresty/package.py new file mode 100644 index 0000000000..c081e34989 --- /dev/null +++ b/var/spack/repos/builtin/packages/lua-luajit-openresty/package.py @@ -0,0 +1,51 @@ +# Copyright 2013-2022 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.pkg.builtin.lua import LuaImplPackage +from spack.pkgkit import * + + +class LuaLuajitOpenresty(LuaImplPackage): + """Flast flexible JITed lua - OpenResty maintained fork""" + homepage = "https://openresty.org/en/luajit.html" + url = "https://github.com/openresty/luajit2/archive/refs/tags/v2.1-20220111.tar.gz" + + version('2.1-20220111', sha256='1ad2e34b111c802f9d0cdf019e986909123237a28c746b21295b63c9e785d9c3') + + variant('lualinks', default=True, description="add symlinks to make lua-luajit a drop-in lua replacement") + + provides("lua-lang@5.1", when="+lualinks") + conflicts("lua", when="+lualinks") + provides("luajit") + lua_version_override = "5.1" + + @run_after("install") + def install_links(self): + self.symlink_luajit() + + @property + def headers(self): + hdrs = find_headers('luajit', self.prefix.include, recursive=True) + hdrs.directories = os.path.dirname(hdrs[0]) + return hdrs or None + + def edit(self, spec, prefix): + makefile = FileFilter('Makefile') + makefile.filter('PREFIX= .*', 'PREFIX = {0}'.format(prefix)) + src_makefile = FileFilter(join_path('src', 'Makefile')) + src_makefile.filter( + '^DEFAULT_CC = .*', + 'DEFAULT_CC = {0}'.format(spack_cc)) + src_makefile.filter( + '^DYNAMIC_CC = .*', + 'DYNAMIC_CC = $(CC) {0}'.format(self.compiler.cc_pic_flag)) + # Linking with the C++ compiler is a dirty hack to deal with the fact + # that unwinding symbols are not included by libc, this is necessary + # on some platforms for the final link stage to work + src_makefile.filter( + '^TARGET_LD = .*', + 'TARGET_LD = {0}'.format(spack_cxx)) diff --git a/var/spack/repos/builtin/packages/lua-luajit/package.py b/var/spack/repos/builtin/packages/lua-luajit/package.py index 3f95e81a27..5c87e25c03 100644 --- a/var/spack/repos/builtin/packages/lua-luajit/package.py +++ b/var/spack/repos/builtin/packages/lua-luajit/package.py @@ -3,13 +3,13 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import glob import os -from spack import * +from spack.pkg.builtin.lua import LuaImplPackage +from spack.pkgkit import * -class LuaLuajit(MakefilePackage): +class LuaLuajit(LuaImplPackage): """Flast flexible JITed lua""" homepage = "https://www.luajit.org" url = "https://luajit.org/download/LuaJIT-2.0.5.tar.gz" @@ -20,33 +20,16 @@ class LuaLuajit(MakefilePackage): conflicts('@:2.0.5', when='target=aarch64:') - variant('lualinks', default=False, description="add symlinks to make lua-luajit a drop-in lua replacement") + variant('lualinks', default=True, description="add symlinks to make lua-luajit a drop-in lua replacement") - provides("lua-lang", when="+lualinks") + provides("lua-lang@5.1", when="+lualinks") + conflicts("lua", when="+lualinks") + provides("luajit") + lua_version_override = "5.1" @run_after("install") def install_links(self): - if not self.spec.satisfies("+lualinks"): - return - - with working_dir(self.prefix.bin): - luajit = os.readlink(self.prefix.bin.luajit) - symlink(luajit, "lua") - - with working_dir(self.prefix.include): - luajit_include_subdirs = glob.glob( - os.path.join(self.prefix.include, "luajit*")) - assert len(luajit_include_subdirs) == 1 - symlink(luajit_include_subdirs[0], "lua") - - with working_dir(self.prefix.lib): - luajit_libnames = glob.glob( - os.path.join(self.prefix.lib, "libluajit*.so*")) - real_lib = next( - lib for lib in luajit_libnames - if os.path.isfile(lib) and not os.path.islink(lib) - ) - symlink(real_lib, "liblua.so") + self.symlink_luajit() @property def headers(self): diff --git a/var/spack/repos/builtin/packages/lua-luaposix/package.py b/var/spack/repos/builtin/packages/lua-luaposix/package.py index 1249bbff8d..e22be239c4 100644 --- a/var/spack/repos/builtin/packages/lua-luaposix/package.py +++ b/var/spack/repos/builtin/packages/lua-luaposix/package.py @@ -3,12 +3,10 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import glob - from spack import * -class LuaLuaposix(Package): +class LuaLuaposix(LuaPackage): """Lua posix bindings, including ncurses""" homepage = "https://github.com/luaposix/luaposix/" url = "https://github.com/luaposix/luaposix/archive/release-v33.4.0.tar.gz" @@ -18,8 +16,4 @@ class LuaLuaposix(Package): version('33.4.0', sha256='e66262f5b7fe1c32c65f17a5ef5ffb31c4d1877019b4870a5d373e2ab6526a21') version('33.2.1', sha256='4fb34dfea67f4cf3194cdecc6614c9aea67edc3c4093d34137669ea869c358e1') - extends("lua") - - def install(self, spec, prefix): - rockspec = glob.glob('luaposix-*.rockspec') - luarocks('--tree=' + prefix, 'make', rockspec[0]) + depends_on('lua-bit32', when='^lua-lang@5.1:5.1.99') diff --git a/var/spack/repos/builtin/packages/lua-mpack/package.py b/var/spack/repos/builtin/packages/lua-mpack/package.py index 7fc72d8ed4..8030a0b5a7 100644 --- a/var/spack/repos/builtin/packages/lua-mpack/package.py +++ b/var/spack/repos/builtin/packages/lua-mpack/package.py @@ -7,18 +7,30 @@ from spack import * -class LuaMpack(Package): +class LuaMpack(LuaPackage): """lua bindings to libmpack""" - homepage = "https://luarocks.org/modules/tarruda/mpack" - url = "https://luarocks.org/manifests/tarruda/mpack-1.0.6-0.src.rock" - - depends_on('msgpack-c') - - version('1.0.6-0', sha256='9068d9d3f407c72a7ea18bc270b0fa90aad60a2f3099fa23d5902dd71ea4cd5f', - expand=False) - - extends('lua') - - def install(self, spec, prefix): - luarocks('--tree=' + prefix, 'install', 'mpack-1.0.6-0.src.rock') + homepage = "https://github.com/libmpack/libmpack-lua/" + url = "https://github.com/libmpack/libmpack-lua/releases/download/1.0.8/libmpack-lua-1.0.8.tar.gz" + + depends_on("msgpack-c") + + version( + "1.0.9", + sha256="0fd07e709c3f6f201c2ffc9f77cef1b303b02c12413f0c15670a32bf6c959e9e", + ) + version( + "1.0.8", + sha256="ed6b1b4bbdb56f26241397c1e168a6b1672f284989303b150f7ea8d39d1bc9e9", + ) + version( + "1.0.7", + sha256="68565484a3441d316bd51bed1cacd542b7f84b1ecfd37a8bd18dd0f1a20887e8", + ) + version( + "1.0.6-0", + sha256="9068d9d3f407c72a7ea18bc270b0fa90aad60a2f3099fa23d5902dd71ea4cd5f", + ) + + def luarocks_args(self): + return ["CFLAGS='-Wno-error=implicit-function-declaration'"] diff --git a/var/spack/repos/builtin/packages/lua/package.py b/var/spack/repos/builtin/packages/lua/package.py index 2695834759..32322c7d36 100644 --- a/var/spack/repos/builtin/packages/lua/package.py +++ b/var/spack/repos/builtin/packages/lua/package.py @@ -3,14 +3,215 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import glob import os -from llnl.util.filesystem import join_path +import spack.build_environment +from spack.pkgkit import * +from spack.util.executable import Executable -from spack import * +class LuaImplPackage(MakefilePackage): + """Specialized class for lua *implementations* -class Lua(Package): + This exists to ensure that lua, luajit and luajit-openresty all initialize extension + packages the same way and provide luarocks the same way.""" + + extendable = True + + variant( + "fetcher", + default="curl", + values=("curl", "wget"), + description="Fetcher to use in the LuaRocks package manager", + ) + + phases = MakefilePackage.phases + ["add_luarocks"] + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = "LuaImplPackage" + + lua_version_override = None + + def __init__(self, *args, **kwargs): + super(LuaImplPackage, self).__init__(*args, **kwargs) + self.lua_dir_name = "lua" + pass + + def __verdir(self): + return ( + str(self.version.up_to(2)) + if self.lua_version_override is None + else self.lua_version_override + ) + + @property + def lua_lib_dir(self): + return os.path.join("lib", self.lua_dir_name, self.__verdir()) + + @property + def lua_lib64_dir(self): + return os.path.join("lib64", self.lua_dir_name, self.__verdir()) + + @property + def lua_share_dir(self): + return os.path.join("share", self.lua_dir_name, self.__verdir()) + + # luarocks needs unzip for some packages (e.g. lua-luaposix) + depends_on("unzip", type="run") + + # luarocks needs a fetcher (curl/wget), unfortunately I have not found + # how to force a choice for curl or wget, but curl seems the default. + depends_on("curl", when="fetcher=curl", type="run") + depends_on("wget", when="fetcher=wget", type="run") + + resource( + name="luarocks", + url="https://luarocks.github.io/luarocks/releases/" "luarocks-3.8.0.tar.gz", + sha256="56ab9b90f5acbc42eb7a94cf482e6c058a63e8a1effdf572b8b2a6323a06d923", + destination="luarocks", + placement="luarocks", + ) + + def symlink_luajit(self): + """helper for luajit-like packages that need symlinks""" + if not self.spec.satisfies("+lualinks"): + return + + with working_dir(self.prefix.bin): + if not os.path.exists(self.prefix.bin.lua): + luajits = find(self.prefix.bin, "luajit*") + assert len(luajits) >= 1 + luajit = luajits[0] + if os.path.islink(luajit): + luajit = os.readlink(luajit) + symlink(luajit, "lua") + + with working_dir(self.prefix.include): + if not os.path.exists(self.prefix.include.lua): + luajit_include_subdirs = glob.glob( + os.path.join(self.prefix.include, "luajit*") + ) + assert len(luajit_include_subdirs) == 1 + symlink(luajit_include_subdirs[0], "lua") + + with working_dir(self.prefix.lib): + for ext in ("." + spack.build_environment.dso_suffix, ".a"): + luajit_libnames = glob.glob( + os.path.join(self.prefix.lib, "libluajit") + "*" + ext + "*" + ) + real_lib = next( + lib + for lib in luajit_libnames + if os.path.isfile(lib) and not os.path.islink(lib) + ) + symlink(real_lib, "liblua" + ext) + + def add_luarocks(self, spec, prefix): + with working_dir(os.path.join("luarocks", "luarocks")): + configure("--prefix=" + prefix, "--with-lua=" + prefix) + make("build") + make("install") + + def append_paths(self, paths, cpaths, path): + paths.append(os.path.join(path, "?.lua")) + paths.append(os.path.join(path, "?", "init.lua")) + cpaths.append(os.path.join(path, "?.so")) + + def _setup_dependent_env_helper(self, env, dependent_spec): + lua_paths = [] + for d in dependent_spec.traverse( + deptypes=("build", "run"), deptype_query="run" + ): + if d.package.extends(self.spec): + lua_paths.append(os.path.join(d.prefix, self.lua_lib_dir)) + lua_paths.append(os.path.join(d.prefix, self.lua_lib64_dir)) + lua_paths.append(os.path.join(d.prefix, self.lua_share_dir)) + + lua_patterns = [] + lua_cpatterns = [] + for p in lua_paths: + if os.path.isdir(p): + self.append_paths(lua_patterns, lua_cpatterns, p) + + # Always add this package's paths + for p in ( + os.path.join(self.spec.prefix, self.lua_lib_dir), + os.path.join(self.spec.prefix, self.lua_lib64_dir), + os.path.join(self.spec.prefix, self.lua_share_dir), + ): + self.append_paths(lua_patterns, lua_cpatterns, p) + + return lua_patterns, lua_cpatterns + + def setup_dependent_build_environment(self, env, dependent_spec): + lua_patterns, lua_cpatterns = self._setup_dependent_env_helper( + env, dependent_spec + ) + + env.prepend_path("LUA_PATH", ";".join(lua_patterns), separator=";") + env.prepend_path("LUA_CPATH", ";".join(lua_cpatterns), separator=";") + + def setup_dependent_run_environment(self, env, dependent_spec): + # For run time environment set only the path for dependent_spec and + # prepend it to LUAPATH + lua_patterns, lua_cpatterns = self._setup_dependent_env_helper( + env, dependent_spec + ) + + if dependent_spec.package.extends(self.spec): + env.prepend_path("LUA_PATH", ";".join(lua_patterns), separator=";") + env.prepend_path("LUA_CPATH", ";".join(lua_cpatterns), separator=";") + + def setup_run_environment(self, env): + env.prepend_path( + "LUA_PATH", + os.path.join(self.spec.prefix, self.lua_share_dir, "?.lua"), + separator=";", + ) + env.prepend_path( + "LUA_PATH", + os.path.join(self.spec.prefix, self.lua_share_dir, "?", "init.lua"), + separator=";", + ) + env.prepend_path( + "LUA_PATH", + os.path.join(self.spec.prefix, self.lua_lib_dir, "?.lua"), + separator=";", + ) + env.prepend_path( + "LUA_PATH", + os.path.join(self.spec.prefix, self.lua_lib_dir, "?", "init.lua"), + separator=";", + ) + env.prepend_path( + "LUA_CPATH", + os.path.join(self.spec.prefix, self.lua_lib_dir, "?.so"), + separator=";", + ) + + @property + def lua(self): + return Executable(self.spec.prefix.bin.lua) + + @property + def luarocks(self): + return Executable(self.spec.prefix.bin.luarocks) + + def setup_dependent_package(self, module, dependent_spec): + """ + Called before lua modules's install() methods. + + In most cases, extensions will only need to have two lines:: + + luarocks('--tree=' + prefix, 'install', rock_spec_path) + """ + # Lua extension builds can have lua and luarocks executable functions + module.lua = Executable(self.spec.prefix.bin.lua) + module.luarocks = Executable(self.spec.prefix.bin.luarocks) + + +class Lua(LuaImplPackage): """The Lua programming language interpreter and library.""" homepage = "https://www.lua.org" @@ -33,21 +234,13 @@ class Lua(Package): variant("pcfile", default=False, description="Add patch for lua.pc generation") variant('shared', default=True, description='Builds a shared version of the library') - variant('fetcher', default='curl', values=('curl', 'wget'), description='Fetcher to use in the LuaRocks package manager') - extendable = True - - provides('lua-lang') + provides('lua-lang@5.1', when='@5.1:5.1.99') + provides('lua-lang@5.2', when='@5.2:5.2.99') + provides('lua-lang@5.3', when='@5.3:5.3.99') depends_on('ncurses+termlib') depends_on('readline') - # luarocks needs unzip for some packages (e.g. lua-luaposix) - depends_on('unzip', type='run') - - # luarocks needs a fetcher (curl/wget), unfortunately I have not found - # how to force a choice for curl or wget, but curl seems the default. - depends_on('curl', when='fetcher=curl', type='run') - depends_on('wget', when='fetcher=wget', type='run') patch( "http://lua.2524044.n2.nabble.com/attachment/7666421/0/pkg-config.patch", @@ -55,14 +248,6 @@ class Lua(Package): when="+pcfile" ) - resource( - name="luarocks", - url="https://keplerproject.github.io/luarocks/releases/" - "luarocks-2.3.0.tar.gz", - sha256="68e38feeb66052e29ad1935a71b875194ed8b9c67c2223af5f4d4e3e2464ed97", - destination="luarocks", - placement='luarocks') - def install(self, spec, prefix): if spec.satisfies("platform=darwin"): target = 'macosx' @@ -107,110 +292,8 @@ class Lua(Package): dso_suffix) os.symlink(src_path, dest_path) - with working_dir(os.path.join('luarocks', 'luarocks')): - configure('--prefix=' + prefix, '--with-lua=' + prefix) - make('build') - make('install') - - def append_paths(self, paths, cpaths, path): - paths.append(os.path.join(path, '?.lua')) - paths.append(os.path.join(path, '?', 'init.lua')) - if '+shared' in self.spec: - cpaths.append(os.path.join(path, '?.so')) - - def _setup_dependent_env_helper(self, env, dependent_spec): - lua_paths = [] - for d in dependent_spec.traverse( - deptypes=('build', 'run'), deptype_query='run'): - if d.package.extends(self.spec): - lua_paths.append(os.path.join(d.prefix, self.lua_lib_dir)) - lua_paths.append(os.path.join(d.prefix, self.lua_lib64_dir)) - lua_paths.append(os.path.join(d.prefix, self.lua_share_dir)) - - lua_patterns = [] - lua_cpatterns = [] - for p in lua_paths: - if os.path.isdir(p): - self.append_paths(lua_patterns, lua_cpatterns, p) - - # Always add this package's paths - for p in (os.path.join(self.spec.prefix, self.lua_lib_dir), - os.path.join(self.spec.prefix, self.lua_lib64_dir), - os.path.join(self.spec.prefix, self.lua_share_dir)): - self.append_paths(lua_patterns, lua_cpatterns, p) - - return lua_patterns, lua_cpatterns - - def setup_dependent_build_environment(self, env, dependent_spec): - lua_patterns, lua_cpatterns = self._setup_dependent_env_helper( - env, dependent_spec) - - env.set('LUA_PATH', ';'.join(lua_patterns), separator=';') - if '+shared' in self.spec: - env.set('LUA_CPATH', ';'.join(lua_cpatterns), separator=';') - - def setup_dependent_run_environment(self, env, dependent_spec): - # For run time environment set only the path for dependent_spec and - # prepend it to LUAPATH - lua_patterns, lua_cpatterns = self._setup_dependent_env_helper( - env, dependent_spec) - - if dependent_spec.package.extends(self.spec): - env.prepend_path('LUA_PATH', ';'.join(lua_patterns), separator=';') - if '+shared' in self.spec: - env.prepend_path('LUA_CPATH', ';'.join(lua_cpatterns), - separator=';') - - def setup_run_environment(self, env): - env.prepend_path( - 'LUA_PATH', - os.path.join(self.spec.prefix, self.lua_share_dir, '?.lua'), - separator=';') - env.prepend_path( - 'LUA_PATH', os.path.join(self.spec.prefix, self.lua_share_dir, '?', - 'init.lua'), - separator=';') - env.prepend_path( - 'LUA_PATH', - os.path.join(self.spec.prefix, self.lua_lib_dir, '?.lua'), - separator=';') - env.prepend_path( - 'LUA_PATH', - os.path.join(self.spec.prefix, self.lua_lib_dir, '?', 'init.lua'), - separator=';') - if '+shared' in self.spec: - env.prepend_path( - 'LUA_CPATH', - os.path.join(self.spec.prefix, self.lua_lib_dir, '?.so'), - separator=';') - @run_after('install') def link_pkg_config(self): if "+pcfile" in self.spec: symlink(join_path(self.prefix.lib, 'pkgconfig', 'lua5.3.pc'), join_path(self.prefix.lib, 'pkgconfig', 'lua.pc')) - - @property - def lua_lib_dir(self): - return os.path.join('lib', 'lua', str(self.version.up_to(2))) - - @property - def lua_lib64_dir(self): - return os.path.join('lib64', 'lua', str(self.version.up_to(2))) - - @property - def lua_share_dir(self): - return os.path.join('share', 'lua', str(self.version.up_to(2))) - - def setup_dependent_package(self, module, dependent_spec): - """ - Called before lua modules's install() methods. - - In most cases, extensions will only need to have two lines:: - - luarocks('--tree=' + prefix, 'install', rock_spec_path) - """ - # Lua extension builds can have lua and luarocks executable functions - module.lua = Executable(join_path(self.spec.prefix.bin, 'lua')) - module.luarocks = Executable( - join_path(self.spec.prefix.bin, 'luarocks')) -- cgit v1.2.3-60-g2f50