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 <ajstewart426@gmail.com>
Co-authored-by: Tom Scogland <tscogland@llnl.gov>
Co-authored-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
Tom Scogland 2022-05-09 21:54:38 -07:00 committed by GitHub
parent b5da0d02bf
commit 7f1659786b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 593 additions and 244 deletions

View file

@ -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]

View file

@ -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

View file

@ -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 <archive>.src.rock
$ # preprocess is a noop by default
$ luarocks make <name>.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/

View file

@ -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)

View file

@ -187,6 +187,27 @@ def cmake_args(self):
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 @@ def __init__(self, name, *args, **kwargs):
'makefile': MakefilePackageTemplate,
'intel': IntelPackageTemplate,
'meson': MesonPackageTemplate,
'lua': LuaPackageTemplate,
'sip': SIPPackageTemplate,
'generic': PackageTemplate,
}
@ -644,6 +666,9 @@ def __call__(self, stage, url):
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 @@ def __call__(self, stage, url):
(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'),

View file

@ -48,13 +48,13 @@ class OpenMpi(Package):
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)

View file

@ -25,6 +25,7 @@
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

View file

@ -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).

View file

@ -18,26 +18,27 @@
@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):

View file

@ -58,6 +58,7 @@ def find_list_urls(url):
BitBucket https://bitbucket.org/<repo>/<name>/downloads/?tab=tags
CRAN https://\*.r-project.org/src/contrib/Archive/<name>
PyPI https://pypi.org/simple/<name>/
LuaRocks https://luarocks.org/modules/<repo>/<name>
========= =======================================================
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<org>[^/]+)/'
+ r'(?P<name>.+?)-[0-9.-]*\.src\.rock',
lambda m: 'https://luarocks.org/modules/' + m.group('org') + '/' + m.group('name') + '/'),
]
list_urls = set([os.path.dirname(url)])

View file

@ -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 @@ def cmake_args(self):
'-DBUILD_STATIC_LIBS=ON',
'-DBUILD_SHARED_LIBS=ON',
'-DWITH_SHARED_LIBUV=ON',
'-DWITH_LUA_ENGINE=Lua',
]
return args

View file

@ -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')

View file

@ -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')

View file

@ -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")

View file

@ -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)

View file

@ -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))

View file

@ -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):

View file

@ -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')

View file

@ -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"
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')
depends_on("msgpack-c")
version('1.0.6-0', sha256='9068d9d3f407c72a7ea18bc270b0fa90aad60a2f3099fa23d5902dd71ea4cd5f',
expand=False)
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",
)
extends('lua')
def install(self, spec, prefix):
luarocks('--tree=' + prefix, 'install', 'mpack-1.0.6-0.src.rock')
def luarocks_args(self):
return ["CFLAGS='-Wno-error=implicit-function-declaration'"]

View file

@ -3,14 +3,215 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import glob
import os
from llnl.util.filesystem import join_path
from spack import *
import spack.build_environment
from spack.pkgkit import *
from spack.util.executable import Executable
class Lua(Package):
class LuaImplPackage(MakefilePackage):
"""Specialized class for lua *implementations*
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 @@ def install(self, spec, prefix):
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'))