summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/docs/developer_guide.rst15
-rw-r--r--lib/spack/docs/features.rst2
-rw-r--r--lib/spack/docs/packaging_guide.rst26
-rwxr-xr-xlib/spack/env/cc42
-rw-r--r--lib/spack/llnl/util/filesystem.py11
-rw-r--r--lib/spack/spack/hooks/sbang.py77
-rw-r--r--lib/spack/spack/multimethod.py36
-rw-r--r--lib/spack/spack/package.py4
-rw-r--r--lib/spack/spack/test/cc.py10
-rw-r--r--lib/spack/spack/url.py2
10 files changed, 169 insertions, 56 deletions
diff --git a/lib/spack/docs/developer_guide.rst b/lib/spack/docs/developer_guide.rst
index db47de80f5..0b618aa683 100644
--- a/lib/spack/docs/developer_guide.rst
+++ b/lib/spack/docs/developer_guide.rst
@@ -73,19 +73,32 @@ with a high level view of Spack's directory structure::
spack/ <- installation root
bin/
spack <- main spack executable
+
+ etc/
+ spack/ <- Spack config files.
+ Can be overridden by files in ~/.spack.
+
var/
spack/ <- build & stage directories
+ repos/ <- contains package repositories
+ builtin/ <- pkg repository that comes with Spack
+ repo.yaml <- descriptor for the builtin repository
+ packages/ <- directories under here contain packages
+
opt/
spack/ <- packages are installed here
+
lib/
spack/
docs/ <- source for this documentation
env/ <- compiler wrappers for build environment
+ external/ <- external libs included in Spack distro
+ llnl/ <- some general-use libraries
+
spack/ <- spack module; contains Python code
cmd/ <- each file in here is a spack subcommand
compilers/ <- compiler description files
- packages/ <- each file in here is a spack package
test/ <- unit test modules
util/ <- common code
diff --git a/lib/spack/docs/features.rst b/lib/spack/docs/features.rst
index fcb810086d..0998ba8da4 100644
--- a/lib/spack/docs/features.rst
+++ b/lib/spack/docs/features.rst
@@ -103,7 +103,7 @@ creates a simple python file:
It doesn't take much python coding to get from there to a working
package:
-.. literalinclude:: ../../../var/spack/packages/libelf/package.py
+.. literalinclude:: ../../../var/spack/repos/builtin/packages/libelf/package.py
:lines: 25-
Spack also provides wrapper functions around common commands like
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst
index 983adb28b0..b7e0b6a4f3 100644
--- a/lib/spack/docs/packaging_guide.rst
+++ b/lib/spack/docs/packaging_guide.rst
@@ -84,7 +84,7 @@ always choose to download just one tarball initially, and run
If it fails entirely, you can get minimal boilerplate by using
:ref:`spack-edit-f`, or you can manually create a directory and
- ``package.py`` file for the package in ``var/spack/packages``.
+ ``package.py`` file for the package in ``var/spack/repos/builtin/packages``.
.. note::
@@ -203,7 +203,7 @@ edit`` command:
So, if you used ``spack create`` to create a package, then saved and
closed the resulting file, you can get back to it with ``spack edit``.
The ``cmake`` package actually lives in
-``$SPACK_ROOT/var/spack/packages/cmake/package.py``, but this provides
+``$SPACK_ROOT/var/spack/repos/builtin/packages/cmake/package.py``, but this provides
a much simpler shortcut and saves you the trouble of typing the full
path.
@@ -269,18 +269,18 @@ live in Spack's directory structure. In general, `spack-create`_ and
`spack-edit`_ handle creating package files for you, so you can skip
most of the details here.
-``var/spack/packages``
+``var/spack/repos/builtin/packages``
~~~~~~~~~~~~~~~~~~~~~~~
A Spack installation directory is structured like a standard UNIX
install prefix (``bin``, ``lib``, ``include``, ``var``, ``opt``,
etc.). Most of the code for Spack lives in ``$SPACK_ROOT/lib/spack``.
-Packages themselves live in ``$SPACK_ROOT/var/spack/packages``.
+Packages themselves live in ``$SPACK_ROOT/var/spack/repos/builtin/packages``.
If you ``cd`` to that directory, you will see directories for each
package:
-.. command-output:: cd $SPACK_ROOT/var/spack/packages; ls -CF
+.. command-output:: cd $SPACK_ROOT/var/spack/repos/builtin/packages; ls -CF
:shell:
:ellipsis: 10
@@ -288,7 +288,7 @@ Each directory contains a file called ``package.py``, which is where
all the python code for the package goes. For example, the ``libelf``
package lives in::
- $SPACK_ROOT/var/spack/packages/libelf/package.py
+ $SPACK_ROOT/var/spack/repos/builtin/packages/libelf/package.py
Alongside the ``package.py`` file, a package may contain extra
directories or files (like patches) that it needs to build.
@@ -301,7 +301,7 @@ Packages are named after the directory containing ``package.py``. So,
``libelf``'s ``package.py`` lives in a directory called ``libelf``.
The ``package.py`` file defines a class called ``Libelf``, which
extends Spack's ``Package`` class. for example, here is
-``$SPACK_ROOT/var/spack/packages/libelf/package.py``:
+``$SPACK_ROOT/var/spack/repos/builtin/packages/libelf/package.py``:
.. code-block:: python
:linenos:
@@ -328,7 +328,7 @@ these:
$ spack install libelf@0.8.13
Spack sees the package name in the spec and looks for
-``libelf/package.py`` in ``var/spack/packages``. Likewise, if you say
+``libelf/package.py`` in ``var/spack/repos/builtin/packages``. Likewise, if you say
``spack install py-numpy``, then Spack looks for
``py-numpy/package.py``.
@@ -732,7 +732,7 @@ supply is a filename, then the patch needs to live within the spack
source tree. For example, the patch above lives in a directory
structure like this::
- $SPACK_ROOT/var/spack/packages/
+ $SPACK_ROOT/var/spack/repos/builtin/packages/
mvapich2/
package.py
ad_lustre_rwcontig_open_source.patch
@@ -1562,7 +1562,7 @@ The last element of a package is its ``install()`` method. This is
where the real work of installation happens, and it's the main part of
the package you'll need to customize for each piece of software.
-.. literalinclude:: ../../../var/spack/packages/libelf/package.py
+.. literalinclude:: ../../../var/spack/repos/builtin/packages/libelf/package.py
:start-after: 0.8.12
:linenos:
@@ -1740,15 +1740,15 @@ Compile-time library search paths
* ``-L$dep_prefix/lib``
* ``-L$dep_prefix/lib64``
Runtime library search paths (RPATHs)
- * ``-Wl,-rpath=$dep_prefix/lib``
- * ``-Wl,-rpath=$dep_prefix/lib64``
+ * ``-Wl,-rpath,$dep_prefix/lib``
+ * ``-Wl,-rpath,$dep_prefix/lib64``
Include search paths
* ``-I$dep_prefix/include``
An example of this would be the ``libdwarf`` build, which has one
dependency: ``libelf``. Every call to ``cc`` in the ``libdwarf``
build will have ``-I$LIBELF_PREFIX/include``,
-``-L$LIBELF_PREFIX/lib``, and ``-Wl,-rpath=$LIBELF_PREFIX/lib``
+``-L$LIBELF_PREFIX/lib``, and ``-Wl,-rpath,$LIBELF_PREFIX/lib``
inserted on the command line. This is done transparently to the
project's build system, which will just think it's using a system
where ``libelf`` is readily available. Because of this, you **do
diff --git a/lib/spack/env/cc b/lib/spack/env/cc
index b8b6c86e01..a19346ce97 100755
--- a/lib/spack/env/cc
+++ b/lib/spack/env/cc
@@ -175,32 +175,44 @@ while [ -n "$1" ]; do
;;
-Wl,*)
arg="${1#-Wl,}"
- if [ -z "$arg" ]; then shift; arg="$1"; fi
- if [[ "$arg" = -rpath=* ]]; then
- rpaths+=("${arg#-rpath=}")
- elif [[ "$arg" = -rpath ]]; then
+ # TODO: Handle multiple -Wl, continuations of -Wl,-rpath
+ if [[ $arg == -rpath=* ]]; then
+ arg="${arg#-rpath=}"
+ for rpath in ${arg//,/ }; do
+ rpaths+=("$rpath")
+ done
+ elif [[ $arg == -rpath,* ]]; then
+ arg="${arg#-rpath,}"
+ for rpath in ${arg//,/ }; do
+ rpaths+=("$rpath")
+ done
+ elif [[ $arg == -rpath ]]; then
shift; arg="$1"
- if [[ "$arg" != -Wl,* ]]; then
+ if [[ $arg != '-Wl,'* ]]; then
die "-Wl,-rpath was not followed by -Wl,*"
fi
- rpaths+=("${arg#-Wl,}")
+ arg="${arg#-Wl,}"
+ for rpath in ${arg//,/ }; do
+ rpaths+=("$rpath")
+ done
else
other_args+=("-Wl,$arg")
fi
;;
- -Xlinker,*)
- arg="${1#-Xlinker,}"
- if [ -z "$arg" ]; then shift; arg="$1"; fi
- if [[ "$arg" = -rpath=* ]]; then
+ -Xlinker)
+ shift; arg="$1";
+ if [[ $arg = -rpath=* ]]; then
rpaths+=("${arg#-rpath=}")
- elif [[ "$arg" = -rpath ]]; then
+ elif [[ $arg = -rpath ]]; then
shift; arg="$1"
- if [[ "$arg" != -Xlinker,* ]]; then
- die "-Xlinker,-rpath was not followed by -Xlinker,*"
+ if [[ $arg != -Xlinker ]]; then
+ die "-Xlinker -rpath was not followed by -Xlinker <arg>"
fi
- rpaths+=("${arg#-Xlinker,}")
+ shift; arg="$1"
+ rpaths+=("$arg")
else
- other_args+=("-Xlinker,$arg")
+ other_args+=("-Xlinker")
+ other_args+=("$arg")
fi
;;
*)
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index f218b7c424..c4665c284c 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -26,7 +26,8 @@ __all__ = ['set_install_permissions', 'install', 'install_tree', 'traverse_tree'
'expand_user', 'working_dir', 'touch', 'touchp', 'mkdirp',
'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file',
'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink',
- 'set_executable', 'remove_dead_links', 'remove_linked_tree']
+ 'set_executable', 'copy_mode', 'unset_executable_mode',
+ 'remove_dead_links', 'remove_linked_tree']
import os
import sys
@@ -159,6 +160,14 @@ def copy_mode(src, dest):
os.chmod(dest, dest_mode)
+def unset_executable_mode(path):
+ mode = os.stat(path).st_mode
+ mode &= ~stat.S_IXUSR
+ mode &= ~stat.S_IXGRP
+ mode &= ~stat.S_IXOTH
+ os.chmod(path, mode)
+
+
def install(src, dest):
"""Manually install a file to a particular location."""
tty.debug("Installing %s to %s" % (src, dest))
diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py
new file mode 100644
index 0000000000..3390ecea29
--- /dev/null
+++ b/lib/spack/spack/hooks/sbang.py
@@ -0,0 +1,77 @@
+##############################################################################
+# Copyright (c) 2013-2015, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://github.com/llnl/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+import os
+
+from llnl.util.filesystem import *
+import llnl.util.tty as tty
+
+import spack
+import spack.modules
+
+# Character limit for shebang line. Using Linux's 127 characters
+# here, as it is the shortest I could find on a modern OS.
+shebang_limit = 127
+
+def shebang_too_long(path):
+ """Detects whether an file has a shebang line that is too long."""
+ with open(path, 'r') as script:
+ bytes = script.read(2)
+ if bytes != '#!':
+ return False
+
+ line = bytes + script.readline()
+ return len(line) > shebang_limit
+
+
+def filter_shebang(path):
+ """Adds a second shebang line, using sbang, at the beginning of a file."""
+ backup = path + ".shebang.bak"
+ os.rename(path, backup)
+
+ with open(backup, 'r') as bak_file:
+ original = bak_file.read()
+
+ with open(path, 'w') as new_file:
+ new_file.write('#!/bin/bash %s/bin/sbang\n' % spack.spack_root)
+ new_file.write(original)
+
+ copy_mode(backup, path)
+ unset_executable_mode(backup)
+
+ tty.warn("Patched overly long shebang in %s" % path)
+
+
+def post_install(pkg):
+ """This hook edits scripts so that they call /bin/bash
+ $spack_prefix/bin/sbang instead of something longer than the
+ shebang limit."""
+ if not os.path.isdir(pkg.prefix.bin):
+ return
+
+ for file in os.listdir(pkg.prefix.bin):
+ path = os.path.join(pkg.prefix.bin, file)
+ if shebang_too_long(path):
+ filter_shebang(path)
+
diff --git a/lib/spack/spack/multimethod.py b/lib/spack/spack/multimethod.py
index 51c6a8e89d..3cd17e796a 100644
--- a/lib/spack/spack/multimethod.py
+++ b/lib/spack/spack/multimethod.py
@@ -138,7 +138,7 @@ class when(object):
methods like install() that depend on the package's spec.
For example:
- .. code-block::
+ .. code-block:: python
class SomePackage(Package):
...
@@ -163,26 +163,28 @@ class when(object):
if you only have part of the install that is platform specific, you
could do this:
- class SomePackage(Package):
- ...
- # virtual dependence on MPI.
- # could resolve to mpich, mpich2, OpenMPI
- depends_on('mpi')
+ .. code-block:: python
- def setup(self):
- # do nothing in the default case
- pass
+ class SomePackage(Package):
+ ...
+ # virtual dependence on MPI.
+ # could resolve to mpich, mpich2, OpenMPI
+ depends_on('mpi')
- @when('^openmpi')
- def setup(self):
- # do something special when this is built with OpenMPI for
- # its MPI implementations.
+ def setup(self):
+ # do nothing in the default case
+ pass
+ @when('^openmpi')
+ def setup(self):
+ # do something special when this is built with OpenMPI for
+ # its MPI implementations.
- def install(self, prefix):
- # Do common install stuff
- self.setup()
- # Do more common install stuff
+
+ def install(self, prefix):
+ # Do common install stuff
+ self.setup()
+ # Do more common install stuff
There must be one (and only one) @when clause that matches the
package's spec. If there is more than one, or if none match,
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index ce8cce27e2..d4acbf5024 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -1216,8 +1216,8 @@ class Package(object):
@property
def rpath_args(self):
- """Get the rpath args as a string, with -Wl,-rpath= for each element."""
- return " ".join("-Wl,-rpath=%s" % p for p in self.rpath)
+ """Get the rpath args as a string, with -Wl,-rpath, for each element."""
+ return " ".join("-Wl,-rpath,%s" % p for p in self.rpath)
def validate_package_url(url_string):
diff --git a/lib/spack/spack/test/cc.py b/lib/spack/spack/test/cc.py
index 905af28a06..f3f6d4a22e 100644
--- a/lib/spack/spack/test/cc.py
+++ b/lib/spack/spack/test/cc.py
@@ -39,11 +39,11 @@ test_command = [
'arg1',
'-Wl,--start-group',
'arg2',
- '-Wl,-rpath=/first/rpath', 'arg3', '-Wl,-rpath', '-Wl,/second/rpath',
+ '-Wl,-rpath,/first/rpath', 'arg3', '-Wl,-rpath', '-Wl,/second/rpath',
'-llib1', '-llib2',
'arg4',
'-Wl,--end-group',
- '-Xlinker,-rpath', '-Xlinker,/third/rpath', '-Xlinker,-rpath=/fourth/rpath',
+ '-Xlinker', '-rpath', '-Xlinker', '/third/rpath', '-Xlinker', '-rpath', '-Xlinker', '/fourth/rpath',
'-llib3', '-llib4',
'arg5', 'arg6']
@@ -95,13 +95,13 @@ class CompilerTest(unittest.TestCase):
def test_ccld_mode(self):
self.check_cc('dump-mode', [], "ccld")
self.check_cc('dump-mode', ['foo.c', '-o', 'foo'], "ccld")
- self.check_cc('dump-mode', ['foo.c', '-o', 'foo', '-Wl,-rpath=foo'], "ccld")
- self.check_cc('dump-mode', ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath=foo'], "ccld")
+ self.check_cc('dump-mode', ['foo.c', '-o', 'foo', '-Wl,-rpath,foo'], "ccld")
+ self.check_cc('dump-mode', ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], "ccld")
def test_ld_mode(self):
self.check_ld('dump-mode', [], "ld")
- self.check_ld('dump-mode', ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath=foo'], "ld")
+ self.check_ld('dump-mode', ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], "ld")
def test_includes(self):
diff --git a/lib/spack/spack/url.py b/lib/spack/spack/url.py
index 02c0b83e26..ad551a6ded 100644
--- a/lib/spack/spack/url.py
+++ b/lib/spack/spack/url.py
@@ -225,7 +225,7 @@ def parse_version_offset(path):
(r'_((\d+\.)+\d+[a-z]?)[.]orig$', stem),
# e.g. http://www.openssl.org/source/openssl-0.9.8s.tar.gz
- (r'-([^-]+(-alpha|-beta)?)', stem),
+ (r'-v?([^-]+(-alpha|-beta)?)', stem),
# e.g. astyle_1.23_macosx.tar.gz
(r'_([^_]+(_alpha|_beta)?)', stem),