aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2021-01-22 12:48:22 -0800
committerDaniel Mensinger <daniel@mensinger-ka.de>2021-01-23 12:48:29 +0100
commit23d3b98fc1ed3b774cc3838da89b2e8f0f91800b (patch)
tree692320a9563026dede9650a56e78fc935cb93c5f
parentadb1b2f3f6ad54b346348ec6e5b8d96f2f7ba0a6 (diff)
downloadmeson-23d3b98fc1ed3b774cc3838da89b2e8f0f91800b.zip
meson-23d3b98fc1ed3b774cc3838da89b2e8f0f91800b.tar.gz
meson-23d3b98fc1ed3b774cc3838da89b2e8f0f91800b.tar.bz2
split mesonlib into a package
Currently mesonlib does some import tricks to figure out whether it needs to use windows or posix specific functions. This is a little hacky, but works fine. However, the way the typing stubs are implemented for the msvcrt and fnctl modules will cause mypy to fail on the other platform, since the functions are not implemented. To aleviate this (and for slightly cleaner design), I've split mesonlib into a pacakge with three modules. A universal module contains all of the platform agnositc code, a win32 module contains window specific code, a posix module contains the posix specific code, and a platform module contains no-op implementations. Then the package's __init__ file imports all of the universal functions and all of the functions from the approriate platform module, or the no-op versions as fallbacks. This makes mypy happy, and avoids `if`ing all over the code to switch between the platform specific code.
-rw-r--r--mesonbuild/backend/ninjabackend.py4
-rw-r--r--mesonbuild/backend/xcodebackend.py2
-rw-r--r--mesonbuild/cmake/interpreter.py2
-rw-r--r--mesonbuild/compilers/c.py3
-rw-r--r--mesonbuild/environment.py4
-rw-r--r--mesonbuild/mdist.py4
-rw-r--r--mesonbuild/mesonlib/__init__.py30
-rw-r--r--mesonbuild/mesonlib/platform.py37
-rw-r--r--mesonbuild/mesonlib/posix.py39
-rw-r--r--mesonbuild/mesonlib/universal.py (renamed from mesonbuild/mesonlib.py)162
-rw-r--r--mesonbuild/mesonlib/win32.py39
-rw-r--r--mesonbuild/minit.py2
-rwxr-xr-xrun_mypy.py15
-rw-r--r--setup.py1
14 files changed, 281 insertions, 63 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 400433f..964a2bd 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -3026,14 +3026,14 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
def generate_gcov_clean(self):
gcno_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcno', 'CUSTOM_COMMAND', 'PHONY')
- gcno_elem.add_item('COMMAND', mesonlib.meson_command + ['--internal', 'delwithsuffix', '.', 'gcno'])
+ gcno_elem.add_item('COMMAND', mesonlib.get_meson_command() + ['--internal', 'delwithsuffix', '.', 'gcno'])
gcno_elem.add_item('description', 'Deleting gcno files')
self.add_build(gcno_elem)
# Alias that runs the target defined above
self.create_target_alias('meson-clean-gcno')
gcda_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcda', 'CUSTOM_COMMAND', 'PHONY')
- gcda_elem.add_item('COMMAND', mesonlib.meson_command + ['--internal', 'delwithsuffix', '.', 'gcda'])
+ gcda_elem.add_item('COMMAND', mesonlib.get_meson_command() + ['--internal', 'delwithsuffix', '.', 'gcda'])
gcda_elem.add_item('description', 'Deleting gcda files')
self.add_build(gcda_elem)
# Alias that runs the target defined above
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index 0e39c65..6f14cbb 100644
--- a/mesonbuild/backend/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -578,7 +578,7 @@ class XCodeBackend(backends.Backend):
self.write_line(');')
self.write_line('runOnlyForDeploymentPostprocessing = 0;')
self.write_line('shellPath = /bin/sh;')
- cmd = mesonlib.meson_command + ['test', test_data, '-C', self.environment.get_build_dir()]
+ cmd = mesonlib.get_meson_command() + ['test', test_data, '-C', self.environment.get_build_dir()]
cmdstr = ' '.join(["'%s'" % i for i in cmd])
self.write_line('shellScript = "%s";' % cmdstr)
self.write_line('showEnvVarsInLog = 0;')
diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py
index 782b7c2..abb4983 100644
--- a/mesonbuild/cmake/interpreter.py
+++ b/mesonbuild/cmake/interpreter.py
@@ -1322,7 +1322,7 @@ class CMakeInterpreter:
# Generate the command list
command = [] # type: T.List[T.Union[str, IdNode, IndexNode]]
- command += mesonlib.meson_command
+ command += mesonlib.get_meson_command()
command += ['--internal', 'cmake_run_ctgt']
command += ['-o', '@OUTPUT@']
if tgt.original_outputs:
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index c11319b..0a2d478 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -16,7 +16,8 @@ import os.path
import typing as T
from .. import coredata
-from ..mesonlib import MachineChoice, MesonException, mlog, version_compare, OptionKey
+from .. import mlog
+from ..mesonlib import MachineChoice, MesonException, version_compare, OptionKey
from .c_function_attributes import C_FUNC_ATTRIBUTES
from .mixins.clike import CLikeCompiler
from .mixins.ccrx import CcrxCompiler
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 1a7f3f1..219b0f2 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -867,7 +867,7 @@ class Environment:
# re-initialized with project options by the interpreter during
# build file parsing.
# meson_command is used by the regenchecker script, which runs meson
- self.coredata = coredata.CoreData(options, self.scratch_dir, mesonlib.meson_command)
+ self.coredata = coredata.CoreData(options, self.scratch_dir, mesonlib.get_meson_command())
self.first_invocation = True
def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool:
@@ -887,7 +887,7 @@ class Environment:
return self.coredata
def get_build_command(self, unbuffered=False):
- cmd = mesonlib.meson_command[:]
+ cmd = mesonlib.get_meson_command().copy()
if unbuffered and 'python' in os.path.basename(cmd[0]):
cmd.insert(1, '-u')
return cmd
diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py
index 3ca13e5..5471505 100644
--- a/mesonbuild/mdist.py
+++ b/mesonbuild/mdist.py
@@ -245,7 +245,7 @@ def run(options):
b = build.load(options.wd)
# This import must be load delayed, otherwise it will get the default
# value of None.
- from mesonbuild.mesonlib import meson_command
+ from mesonbuild.mesonlib import get_meson_command
src_root = b.environment.source_dir
bld_root = b.environment.build_dir
priv_dir = os.path.join(bld_root, 'meson-private')
@@ -279,7 +279,7 @@ def run(options):
rc = 0
if not options.no_tests:
# Check only one.
- rc = check_dist(names[0], meson_command, extra_meson_args, bld_root, priv_dir)
+ rc = check_dist(names[0], get_meson_command(), extra_meson_args, bld_root, priv_dir)
if rc == 0:
for name in names:
create_hash(name)
diff --git a/mesonbuild/mesonlib/__init__.py b/mesonbuild/mesonlib/__init__.py
new file mode 100644
index 0000000..5b646b5
--- /dev/null
+++ b/mesonbuild/mesonlib/__init__.py
@@ -0,0 +1,30 @@
+# SPDX-license-identifier: Apache-2.0
+# Copyright 2012-2021 The Meson development team
+# Copyright © 2021 Intel Corporation
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Helper functions and classes."""
+
+import os
+
+from .universal import *
+
+# Here we import either the posix implementations, the windows implementations,
+# or a generic no-op implementation
+if os.name == 'posix':
+ from .posix import *
+elif os.name == 'nt':
+ from .win32 import *
+else:
+ from .platform import *
diff --git a/mesonbuild/mesonlib/platform.py b/mesonbuild/mesonlib/platform.py
new file mode 100644
index 0000000..cdd42b1
--- /dev/null
+++ b/mesonbuild/mesonlib/platform.py
@@ -0,0 +1,37 @@
+# SPDX-license-identifier: Apache-2.0
+# Copyright 2012-2021 The Meson development team
+# Copyright © 2021 Intel Corporation
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""base classes providing no-op functionality.."""
+
+import os
+import typing as T
+
+from .. import mlog
+
+__all__ = ['BuildDirLock']
+
+# This needs to be inheritted by the specific implementations to make type
+# checking happy
+class BuildDirLock:
+
+ def __init__(self, builddir: str) -> None:
+ self.lockfilename = os.path.join(builddir, 'meson-private/meson.lock')
+
+ def __enter__(self) -> None:
+ mlog.debug('Calling ther no-op version of BuildDirLock')
+
+ def __exit__(self, *args: T.Any) -> None:
+ pass
diff --git a/mesonbuild/mesonlib/posix.py b/mesonbuild/mesonlib/posix.py
new file mode 100644
index 0000000..1d8ba8c
--- /dev/null
+++ b/mesonbuild/mesonlib/posix.py
@@ -0,0 +1,39 @@
+# SPDX-license-identifier: Apache-2.0
+# Copyright 2012-2021 The Meson development team
+# Copyright © 2021 Intel Corporation
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Posix specific implementations of mesonlib functionality."""
+
+import fcntl
+import typing as T
+
+from .universal import MesonException
+from .platform import BuildDirLock as BuildDirLockBase
+
+__all__ = ['BuildDirLock']
+
+class BuildDirLock(BuildDirLockBase):
+
+ def __enter__(self) -> None:
+ self.lockfile = open(self.lockfilename, 'w')
+ try:
+ fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ except (BlockingIOError, PermissionError):
+ self.lockfile.close()
+ raise MesonException('Some other Meson process is already using this build directory. Exiting.')
+
+ def __exit__(self, *args: T.Any) -> None:
+ fcntl.flock(self.lockfile, fcntl.LOCK_UN)
+ self.lockfile.close()
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib/universal.py
index ef48ec2..c16f165 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib/universal.py
@@ -30,34 +30,117 @@ import textwrap
from mesonbuild import mlog
if T.TYPE_CHECKING:
- from .build import ConfigurationData
- from .coredata import KeyedOptionDictType, UserOption
- from .compilers.compilers import CompilerType
- from .interpreterbase import ObjectHolder
+ from ..build import ConfigurationData
+ from ..coredata import KeyedOptionDictType, UserOption
+ from ..compilers.compilers import CompilerType
+ from ..interpreterbase import ObjectHolder
- FileOrString = T.Union['File', str]
+FileOrString = T.Union['File', str]
_T = T.TypeVar('_T')
_U = T.TypeVar('_U')
-have_fcntl = False
-have_msvcrt = False
+__all__ = [
+ 'GIT',
+ 'an_unpicklable_object',
+ 'python_command',
+ 'project_meson_versions',
+ 'File',
+ 'FileMode',
+ 'GitException',
+ 'LibType',
+ 'MachineChoice',
+ 'MesonException',
+ 'EnvironmentException',
+ 'FileOrString',
+ 'GitException',
+ 'OptionKey',
+ 'dump_conf_header',
+ 'OptionOverrideProxy',
+ 'OptionProxy',
+ 'OptionType',
+ 'OrderedSet',
+ 'PerMachine',
+ 'PerMachineDefaultable',
+ 'PerThreeMachine',
+ 'PerThreeMachineDefaultable',
+ 'ProgressBar',
+ 'TemporaryDirectoryWinProof',
+ 'Version',
+ 'check_direntry_issues',
+ 'classify_unity_sources',
+ 'current_vs_supports_modules',
+ 'darwin_get_object_archs',
+ 'default_libdir',
+ 'default_libexecdir',
+ 'default_prefix',
+ 'detect_subprojects',
+ 'detect_vcs',
+ 'do_conf_file',
+ 'do_conf_str',
+ 'do_define',
+ 'do_replacement',
+ 'exe_exists',
+ 'expand_arguments',
+ 'extract_as_list',
+ 'get_compiler_for_source',
+ 'get_filenames_templates_dict',
+ 'get_library_dirs',
+ 'get_variable_regex',
+ 'get_wine_shortpath',
+ 'git',
+ 'has_path_sep',
+ 'is_aix',
+ 'is_android',
+ 'is_ascii_string',
+ 'is_cygwin',
+ 'is_debianlike',
+ 'is_dragonflybsd',
+ 'is_freebsd',
+ 'is_haiku',
+ 'is_hurd',
+ 'is_irix',
+ 'is_linux',
+ 'is_netbsd',
+ 'is_openbsd',
+ 'is_osx',
+ 'is_qnx',
+ 'is_sunos',
+ 'is_windows',
+ 'iter_regexin_iter',
+ 'join_args',
+ 'listify',
+ 'partition',
+ 'path_is_in_root',
+ 'Popen_safe',
+ 'quiet_git',
+ 'quote_arg',
+ 'relative_to_if_possible',
+ 'relpath',
+ 'replace_if_different',
+ 'run_once',
+ 'get_meson_command',
+ 'set_meson_command',
+ 'split_args',
+ 'stringlistify',
+ 'substitute_values',
+ 'substring_is_in_list',
+ 'typeslistify',
+ 'unholder',
+ 'verbose_git',
+ 'version_compare',
+ 'version_compare_condition_with_min',
+ 'version_compare_many',
+ 'windows_proof_rm',
+ 'windows_proof_rmtree',
+]
+
+
# TODO: this is such a hack, this really should be either in coredata or in the
# interpreter
# {subproject: project_meson_version}
project_meson_versions = collections.defaultdict(str) # type: T.DefaultDict[str, str]
-try:
- import fcntl
- have_fcntl = True
-except Exception:
- pass
-
-try:
- import msvcrt
- have_msvcrt = True
-except Exception:
- pass
from glob import glob
@@ -66,7 +149,7 @@ if os.path.basename(sys.executable) == 'meson.exe':
python_command = [sys.executable, 'runpython']
else:
python_command = [sys.executable]
-meson_command = None
+_meson_command = None
class MesonException(Exception):
'''Exceptions thrown by Meson'''
@@ -117,20 +200,24 @@ def verbose_git(cmd: T.List[str], workingdir: str, check: bool = False) -> bool:
def set_meson_command(mainfile: str) -> None:
global python_command
- global meson_command
+ global _meson_command
# On UNIX-like systems `meson` is a Python script
# On Windows `meson` and `meson.exe` are wrapper exes
if not mainfile.endswith('.py'):
- meson_command = [mainfile]
+ _meson_command = [mainfile]
elif os.path.isabs(mainfile) and mainfile.endswith('mesonmain.py'):
# Can't actually run meson with an absolute path to mesonmain.py, it must be run as -m mesonbuild.mesonmain
- meson_command = python_command + ['-m', 'mesonbuild.mesonmain']
+ _meson_command = python_command + ['-m', 'mesonbuild.mesonmain']
else:
# Either run uninstalled, or full path to meson-script.py
- meson_command = python_command + [mainfile]
+ _meson_command = python_command + [mainfile]
# We print this value for unit tests.
if 'MESON_COMMAND_TESTS' in os.environ:
- mlog.log('meson_command is {!r}'.format(meson_command))
+ mlog.log('meson_command is {!r}'.format(_meson_command))
+
+
+def get_meson_command() -> T.Optional[T.List[str]]:
+ return _meson_command
def is_ascii_string(astring: T.Union[str, bytes]) -> bool:
@@ -1564,29 +1651,6 @@ class OrderedSet(T.MutableSet[_T]):
def difference(self, set_: T.Union[T.Set[_T], 'OrderedSet[_T]']) -> 'OrderedSet[_T]':
return type(self)(e for e in self if e not in set_)
-class BuildDirLock:
-
- def __init__(self, builddir: str) -> None:
- self.lockfilename = os.path.join(builddir, 'meson-private/meson.lock')
-
- def __enter__(self) -> None:
- self.lockfile = open(self.lockfilename, 'w')
- try:
- if have_fcntl:
- fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
- elif have_msvcrt:
- msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1)
- except (BlockingIOError, PermissionError):
- self.lockfile.close()
- raise MesonException('Some other Meson process is already using this build directory. Exiting.')
-
- def __exit__(self, *args: T.Any) -> None:
- if have_fcntl:
- fcntl.flock(self.lockfile, fcntl.LOCK_UN)
- elif have_msvcrt:
- msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)
- self.lockfile.close()
-
def relpath(path: str, start: str) -> str:
# On Windows a relative path can't be evaluated for paths on two different
# drives (i.e. c:\foo and f:\bar). The only thing left to do is to use the
@@ -1965,7 +2029,7 @@ class OptionKey:
raw3 = raw2
for_machine = MachineChoice.HOST
- from .compilers import all_languages
+ from ..compilers import all_languages
if any(raw3.startswith(f'{l}_') for l in all_languages):
lang, opt = raw3.split('_', 1)
else:
@@ -2024,4 +2088,4 @@ class OptionKey:
def is_base(self) -> bool:
"""Convenience method to check if this is a base option."""
- return self.type is OptionType.BASE \ No newline at end of file
+ return self.type is OptionType.BASE
diff --git a/mesonbuild/mesonlib/win32.py b/mesonbuild/mesonlib/win32.py
new file mode 100644
index 0000000..0919ef7
--- /dev/null
+++ b/mesonbuild/mesonlib/win32.py
@@ -0,0 +1,39 @@
+# SPDX-license-identifier: Apache-2.0
+# Copyright 2012-2021 The Meson development team
+# Copyright © 2021 Intel Corporation
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Windows specific implementations of mesonlib functionality."""
+
+import msvcrt
+import typing as T
+
+from .universal import MesonException
+from .platform import BuildDirLock as BuildDirLockBase
+
+__all__ = ['BuildDirLock']
+
+class BuildDirLock(BuildDirLockBase):
+
+ def __enter__(self) -> None:
+ self.lockfile = open(self.lockfilename, 'w')
+ try:
+ msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1)
+ except (BlockingIOError, PermissionError):
+ self.lockfile.close()
+ raise MesonException('Some other Meson process is already using this build directory. Exiting.')
+
+ def __exit__(self, *args: T.Any) -> None:
+ msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)
+ self.lockfile.close()
diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py
index 4a38313..55e716c 100644
--- a/mesonbuild/minit.py
+++ b/mesonbuild/minit.py
@@ -174,7 +174,7 @@ def run(options: 'argparse.Namespace') -> int:
print('Build directory already exists, deleting it.')
shutil.rmtree(options.builddir)
print('Building...')
- cmd = mesonlib.meson_command + [options.builddir]
+ cmd = mesonlib.get_meson_command() + [options.builddir]
ret = subprocess.run(cmd)
if ret.returncode:
raise SystemExit
diff --git a/run_mypy.py b/run_mypy.py
index daf7431..e6900c7 100755
--- a/run_mypy.py
+++ b/run_mypy.py
@@ -1,9 +1,10 @@
#!/usr/bin/env python3
-import sys
-import subprocess
-import argparse
from pathlib import Path
+import argparse
+import os
+import subprocess
+import sys
import typing as T
modules = [
@@ -24,7 +25,8 @@ modules = [
'mesonbuild/interpreterbase.py',
'mesonbuild/linkers.py',
'mesonbuild/mcompile.py',
- 'mesonbuild/mesonlib.py',
+ 'mesonbuild/mesonlib/platform.py',
+ 'mesonbuild/mesonlib/universal.py',
'mesonbuild/minit.py',
'mesonbuild/minstall.py',
'mesonbuild/mintro.py',
@@ -40,6 +42,11 @@ modules = [
'tools'
]
+if os.name == 'posix':
+ modules.append('mesonbuild/mesonlib/posix.py')
+elif os.name == 'nt':
+ modules.append('mesonbuild/mesonlib/win32.py')
+
def check_mypy() -> None:
try:
import mypy
diff --git a/setup.py b/setup.py
index 70a76e5..17a00b3 100644
--- a/setup.py
+++ b/setup.py
@@ -33,6 +33,7 @@ packages = ['mesonbuild',
'mesonbuild.compilers',
'mesonbuild.compilers.mixins',
'mesonbuild.dependencies',
+ 'mesonbuild.mesonlib',
'mesonbuild.modules',
'mesonbuild.scripts',
'mesonbuild.templates',