diff options
-rw-r--r-- | docs/markdown/Cross-compilation.md | 26 | ||||
-rw-r--r-- | docs/markdown/snippets/system-wide-cross-files.md | 20 | ||||
-rw-r--r-- | mesonbuild/coredata.py | 46 | ||||
-rwxr-xr-x | run_unittests.py | 46 |
4 files changed, 134 insertions, 4 deletions
diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md index f68b1f5..c1ad317 100644 --- a/docs/markdown/Cross-compilation.md +++ b/docs/markdown/Cross-compilation.md @@ -257,3 +257,29 @@ then you can access that using the `meson` object like this: myvar = meson.get_cross_property('somekey') # myvar now has the value 'somevalue' ``` + +## Cross file locations + +As of version 0.44.0 meson supports loading cross files from system locations +on Linux and the BSDs. This will be $XDG_DATA_DIRS/meson/cross, or if +XDG_DATA_DIRS is undefined, then /usr/local/share/meson/cross and +/usr/share/meson/cross will be tried in that order, for system wide cross +files. User local files can be put in $XDG_DATA_HOME/meson/cross, or +~/.local/share/meson/cross if that is undefined. + +The order of locations tried is as follows: + - A file relative to the local dir + - The user local location + - The system wide locations in order + +Linux and BSD distributions are encouraged to ship cross files either with +their cross compiler toolchain packages or as a standalone package, and put +them in one of the system paths referenced above. + +These files can be loaded automatically without adding a path to the cross +file. For example, if a ~/.local/share/meson/cross contains a file called x86-linux, +then the following command would start a cross build using that cross files: + +```sh +meson builddir/ --cross-file x86-linux +``` diff --git a/docs/markdown/snippets/system-wide-cross-files.md b/docs/markdown/snippets/system-wide-cross-files.md new file mode 100644 index 0000000..66c454f --- /dev/null +++ b/docs/markdown/snippets/system-wide-cross-files.md @@ -0,0 +1,20 @@ +## System wide and user local cross files + +Meson has gained the ability to load cross files from predefined locations +without passing a full path on Linux and the BSD OSes. User local files will be +loaded from `$XDG_DATA_HOME/meson/cross`, or if XDG_DATA_HOME is undefined, +`~/.local/share/meson/cross` will be used. + +For system wide paths the values of `$XDG_DATA_DIRS` + `/meson/cross` will be used, +if XDG_DATA_DIRS is undefined then `/usr/local/share/meson/cross:/usr/share/meson/cross` +will be used instead. + +A file relative to the current working directory will be tried first, then the +user specific path will be tried before the system wide paths. + +Assuming that a file x86-linux is located in one of those places a cross build +can be started with: + +```sh +meson builddir/ --cross-file x86-linux +``` diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 401211a..68b1abf 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -14,6 +14,7 @@ # limitations under the License. import pickle, os, uuid +import sys from pathlib import PurePath from collections import OrderedDict from .mesonlib import MesonException, commonpath @@ -172,10 +173,7 @@ class CoreData: self.external_preprocess_args = {} # CPPFLAGS only self.external_args = {} # CPPFLAGS + CFLAGS self.external_link_args = {} # CFLAGS + LDFLAGS (with MSVC: only LDFLAGS) - if options.cross_file is not None: - self.cross_file = os.path.join(os.getcwd(), options.cross_file) - else: - self.cross_file = None + self.cross_file = self.__load_cross_file(options.cross_file) self.wrap_mode = options.wrap_mode self.compilers = OrderedDict() self.cross_compilers = OrderedDict() @@ -184,6 +182,46 @@ class CoreData: # Only to print a warning if it changes between Meson invocations. self.pkgconf_envvar = os.environ.get('PKG_CONFIG_PATH', '') + @staticmethod + def __load_cross_file(filename): + """Try to load the cross file. + + If the filename is None return None. If the filename is an absolute + (after resolving variables and ~), return that absolute path. Next, + check if the file is relative to the current source dir. If the path + still isn't resolved do the following: + Linux + BSD: + - $XDG_DATA_HOME/meson/cross (or ~/.local/share/meson/cross if + undefined) + - $XDG_DATA_DIRS/meson/cross (or + /usr/local/share/meson/cross:/usr/share/meson/cross if undefined) + - Error + *: + - Error + BSD follows the Linux path and will honor XDG_* if set. This simplifies + the implementation somewhat, especially since most BSD users wont set + those environment variables. + """ + if filename is None: + return None + filename = os.path.expanduser(os.path.expandvars(filename)) + if os.path.isabs(filename): + return filename + path_to_try = os.path.abspath(filename) + if os.path.exists(path_to_try): + return path_to_try + if sys.platform == 'linux' or 'bsd' in sys.platform.lower(): + paths = [ + os.environ.get('XDG_DATA_HOME', os.path.expanduser('~/.local/share')), + ] + os.environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share').split(':') + for path in paths: + path_to_try = os.path.join(path, 'meson', 'cross', filename) + if os.path.exists(path_to_try): + return path_to_try + raise MesonException('Cannot find specified cross file: ' + filename) + + raise MesonException('Cannot find specified cross file: ' + filename) + def sanitize_prefix(self, prefix): if not os.path.isabs(prefix): raise MesonException('prefix value {!r} must be an absolute path' diff --git a/run_unittests.py b/run_unittests.py index 8af872e..5b3b3e1 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -19,10 +19,12 @@ import shlex import subprocess import re, json import tempfile +import textwrap import os import shutil import sys import unittest +from unittest import mock from configparser import ConfigParser from glob import glob from pathlib import PurePath @@ -2223,6 +2225,50 @@ endian = 'little' self.init(testdir, ['-Db_lto=true'], default_args=False) self.build('reconfigure') + def test_cross_file_system_paths(self): + testdir = os.path.join(self.common_test_dir, '1 trivial') + cross_content = textwrap.dedent("""\ + [binaries] + c = '/usr/bin/cc' + ar = '/usr/bin/ar' + strip = '/usr/bin/ar' + + [properties] + + [host_machine] + system = 'linux' + cpu_family = 'x86' + cpu = 'i686' + endian = 'little' + """) + + with tempfile.TemporaryDirectory() as d: + dir_ = os.path.join(d, 'meson', 'cross') + os.makedirs(dir_) + with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f: + f.write(cross_content) + name = os.path.basename(f.name) + + with mock.patch.dict(os.environ, {'XDG_DATA_HOME': d}): + self.init(testdir, ['--cross-file=' + name], inprocess=True) + self.wipe() + + with mock.patch.dict(os.environ, {'XDG_DATA_DIRS': d}): + os.environ.pop('XDG_DATA_HOME', None) + self.init(testdir, ['--cross-file=' + name], inprocess=True) + self.wipe() + + with tempfile.TemporaryDirectory() as d: + dir_ = os.path.join(d, '.local', 'share', 'meson', 'cross') + os.makedirs(dir_) + with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f: + f.write(cross_content) + name = os.path.basename(f.name) + + with mock.patch('mesonbuild.coredata.os.path.expanduser', lambda x: x.replace('~', d)): + self.init(testdir, ['--cross-file=' + name], inprocess=True) + self.wipe() + class LinuxArmCrossCompileTests(BasePlatformTests): ''' |