aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2017-01-16 16:08:00 +0530
committerJussi Pakkanen <jpakkane@gmail.com>2017-01-23 20:34:45 +0200
commit23f3cec9d029b5d44fa7f6a109ab9cda948b12ba (patch)
tree4334fc2fc36c12766ddc5c005bfe20f3ed119599
parentf762e896d2891edc53058ffeb57d38ee2c1fb8db (diff)
downloadmeson-23f3cec9d029b5d44fa7f6a109ab9cda948b12ba.zip
meson-23f3cec9d029b5d44fa7f6a109ab9cda948b12ba.tar.gz
meson-23f3cec9d029b5d44fa7f6a109ab9cda948b12ba.tar.bz2
Force installation dir options to be inside prefix
With the exception of things like sysconfdir (/etc), every other installation directory option must be inside the prefix. Also move the prefix checks to coredata.py since prefix can also be set from inside project() with default_options and via mesonconf. Earlier you could set prefix to a relative path that way. This also allows us to return consistent values for get_option('xxxdir') regardless of whether relative paths are passed or absolute paths are passed while setting options on the command-line, via mesonconf, or via default_options in project(). Now the returned path will *always* be relative to the prefix. Includes a unit test for this, and a failing test. Closes #1299
-rw-r--r--mesonbuild/coredata.py55
-rw-r--r--mesonbuild/mesonmain.py9
-rwxr-xr-xrun_unittests.py26
-rw-r--r--test cases/failing/39 libdir must be inside prefix/meson.build2
-rw-r--r--test cases/failing/40 prefix absolute/meson.build2
5 files changed, 78 insertions, 16 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index a7be91f..60bb10b 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -131,10 +131,54 @@ class CoreData:
# Only to print a warning if it changes between Meson invocations.
self.pkgconf_envvar = os.environ.get('PKG_CONFIG_PATH', '')
+ def sanitize_prefix(self, prefix):
+ if not os.path.isabs(prefix):
+ raise MesonException('prefix value {!r} must be an absolute path'
+ ''.format(prefix))
+ if prefix.endswith('/') or prefix.endswith('\\'):
+ # On Windows we need to preserve the trailing slash if the
+ # string is of type 'C:\' because 'C:' is not an absolute path.
+ if len(prefix) == 3 and prefix[1] == ':':
+ pass
+ else:
+ prefix = prefix[:-1]
+ return prefix
+
+ def sanitize_dir_option_value(self, prefix, option, value):
+ '''
+ If the option is an installation directory option and the value is an
+ absolute path, check that it resides within prefix and return the value
+ as a path relative to the prefix.
+
+ This way everyone can do f.ex, get_option('libdir') and be sure to get
+ the library directory relative to prefix.
+ '''
+ if option.endswith('dir') and os.path.isabs(value) and \
+ option not in builtin_dir_noprefix_options:
+ # Value must be a subdir of the prefix
+ if os.path.commonpath([value, prefix]) != prefix:
+ m = 'The value of the {!r} option is {!r} which must be a ' \
+ 'subdir of the prefix {!r}.\nNote that if you pass a ' \
+ 'relative path, it is assumed to be a subdir of prefix.'
+ raise MesonException(m.format(option, value, prefix))
+ # Convert path to be relative to prefix
+ skip = len(prefix) + 1
+ value = value[skip:]
+ return value
+
def init_builtins(self, options):
self.builtins = {}
+ # Sanitize prefix
+ options.prefix = self.sanitize_prefix(options.prefix)
+ # Initialize other builtin options
for key in get_builtin_options():
- args = [key] + builtin_options[key][1:-1] + [getattr(options, key, get_builtin_option_default(key))]
+ if hasattr(options, key):
+ value = getattr(options, key)
+ value = self.sanitize_dir_option_value(options.prefix, key, value)
+ setattr(options, key, value)
+ else:
+ value = get_builtin_option_default(key)
+ args = [key] + builtin_options[key][1:-1] + [value]
self.builtins[key] = builtin_options[key][0](*args)
def get_builtin_option(self, optname):
@@ -143,7 +187,11 @@ class CoreData:
raise RuntimeError('Tried to get unknown builtin option %s.' % optname)
def set_builtin_option(self, optname, value):
- if optname in self.builtins:
+ if optname == 'prefix':
+ value = self.sanitize_prefix(value)
+ elif optname in self.builtins:
+ prefix = self.builtins['prefix'].value
+ value = self.sanitize_dir_option_value(prefix, optname, value)
self.builtins[optname].set_value(value)
else:
raise RuntimeError('Tried to set unknown builtin option %s.' % optname)
@@ -235,6 +283,9 @@ builtin_options = {
'errorlogs': [UserBooleanOption, "Whether to print the logs from failing tests.", True],
}
+# Installation directories that can reside in a path outside of the prefix
+builtin_dir_noprefix_options = {'sysconfdir', 'localstatedir', 'sharedstatedir'}
+
forbidden_target_names = {'clean': None,
'clean-ctlist': None,
'clean-gcno': None,
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 37b8055..031486c 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -73,15 +73,6 @@ class MesonApp:
def __init__(self, dir1, dir2, script_launcher, handshake, options, original_cmd_line_args):
(self.source_dir, self.build_dir) = self.validate_dirs(dir1, dir2, handshake)
- if not os.path.isabs(options.prefix):
- raise RuntimeError('--prefix value must be an absolute path: {!r}'.format(options.prefix))
- if options.prefix.endswith('/') or options.prefix.endswith('\\'):
- # On Windows we need to preserve the trailing slash if the
- # string is of type 'C:\' because 'C:' is not an absolute path.
- if len(options.prefix) == 3 and options.prefix[1] == ':':
- pass
- else:
- options.prefix = options.prefix[:-1]
self.meson_script_launcher = script_launcher
self.options = options
self.original_cmd_line_args = original_cmd_line_args
diff --git a/run_unittests.py b/run_unittests.py
index 123bca8..6aa5b2b 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -33,10 +33,11 @@ def get_soname(fname):
return m.group(1)
raise RuntimeError('Could not determine soname:\n\n' + raw_out)
-def get_fake_options():
+def get_fake_options(prefix):
import argparse
opts = argparse.Namespace()
opts.cross_file = None
+ opts.prefix = prefix
return opts
class FakeEnvironment(object):
@@ -85,7 +86,8 @@ class LinuxlikeTests(unittest.TestCase):
super().tearDown()
def _run(self, command):
- self.output += subprocess.check_output(command, env=os.environ.copy())
+ self.output += subprocess.check_output(command, stderr=subprocess.STDOUT,
+ env=os.environ.copy())
def init(self, srcdir, extra_args=None):
if extra_args is None:
@@ -510,7 +512,7 @@ class LinuxlikeTests(unittest.TestCase):
'''
testdir = os.path.join(self.common_test_dir, '1 trivial')
env = Environment(testdir, self.builddir, self.meson_command,
- get_fake_options(), [])
+ get_fake_options(self.prefix), [])
cc = env.detect_c_compiler(False)
self._test_stds_impl(testdir, cc, 'c')
@@ -521,11 +523,10 @@ class LinuxlikeTests(unittest.TestCase):
'''
testdir = os.path.join(self.common_test_dir, '2 cpp')
env = Environment(testdir, self.builddir, self.meson_command,
- get_fake_options(), [])
+ get_fake_options(self.prefix), [])
cpp = env.detect_cpp_compiler(False)
self._test_stds_impl(testdir, cpp, 'cpp')
-
def test_build_by_default(self):
testdir = os.path.join(self.unit_test_dir, '5 build by default')
self.init(testdir)
@@ -537,6 +538,21 @@ class LinuxlikeTests(unittest.TestCase):
self._run(self.ninja_command + ['fooprog'])
self.assertTrue(os.path.exists(exe))
+ def test_libdir_must_be_inside_prefix(self):
+ testdir = os.path.join(self.common_test_dir, '1 trivial')
+ # libdir being inside prefix is ok
+ args = ['--prefix', '/opt', '--libdir', '/opt/lib32']
+ self.init(testdir, args)
+ self.wipe()
+ # libdir not being inside prefix is not ok
+ args = ['--prefix', '/usr', '--libdir', '/opt/lib32']
+ self.assertRaises(subprocess.CalledProcessError, self.init, testdir, args)
+ self.wipe()
+ # libdir must be inside prefix even when set via mesonconf
+ self.init(testdir)
+ self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt')
+
+
class RewriterTests(unittest.TestCase):
def setUp(self):
diff --git a/test cases/failing/39 libdir must be inside prefix/meson.build b/test cases/failing/39 libdir must be inside prefix/meson.build
new file mode 100644
index 0000000..66272ea
--- /dev/null
+++ b/test cases/failing/39 libdir must be inside prefix/meson.build
@@ -0,0 +1,2 @@
+project('libdir prefix', 'c',
+ default_options : ['libdir=/opt/lib'])
diff --git a/test cases/failing/40 prefix absolute/meson.build b/test cases/failing/40 prefix absolute/meson.build
new file mode 100644
index 0000000..e2863e7
--- /dev/null
+++ b/test cases/failing/40 prefix absolute/meson.build
@@ -0,0 +1,2 @@
+project('prefix-abs', 'c',
+ default_options : ['prefix=some/path/notabs'])