aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Reference-manual.md6
-rw-r--r--docs/markdown/Syntax.md2
-rw-r--r--docs/markdown/snippets/summary_prog_dep.md4
-rw-r--r--mesonbuild/backend/backends.py11
-rw-r--r--mesonbuild/backend/ninjabackend.py22
-rw-r--r--mesonbuild/backend/vs2010backend.py8
-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/dependencies/base.py17
-rw-r--r--mesonbuild/environment.py4
-rw-r--r--mesonbuild/interpreter.py28
-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
-rw-r--r--mesonbuild/mlog.py18
-rw-r--r--mesonbuild/scripts/depscan.py4
-rwxr-xr-xrun_mypy.py15
-rwxr-xr-xrun_project_tests.py17
-rwxr-xr-xrun_tests.py6
-rwxr-xr-xrun_unittests.py6
-rw-r--r--setup.py1
-rw-r--r--test cases/fortran/21 install static/main.f904
-rw-r--r--test cases/fortran/21 install static/main_lib.f9016
-rw-r--r--test cases/fortran/21 install static/meson.build20
-rw-r--r--test cases/fortran/21 install static/subprojects/static_hello/meson.build12
-rw-r--r--test cases/fortran/21 install static/subprojects/static_hello/static_hello.f9017
-rw-r--r--test cases/fortran/21 install static/test.json5
-rw-r--r--test cases/unit/73 summary/meson.build5
33 files changed, 454 insertions, 114 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 802002b..cb8347a 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -1313,7 +1313,11 @@ The content is a series of key/value pairs grouped into sections. If the section
keyword argument is omitted, those key/value pairs are implicitly grouped into a section
with no title. key/value pairs can optionally be grouped into a dictionary,
but keep in mind that dictionaries does not guarantee ordering. `key` must be string,
-`value` can only be integer, boolean, string, or a list of those.
+`value` can be:
+
+- an integer, boolean or string
+- *since 0.57.0* an external program or a dependency
+- a list of those.
`summary()` can be called multiple times as long as the same section/key
pair doesn't appear twice. All sections will be collected and printed at
diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md
index 65cb70f..4f17ac8 100644
--- a/docs/markdown/Syntax.md
+++ b/docs/markdown/Syntax.md
@@ -657,7 +657,7 @@ equality_expression: relational_expression | (equality_expression equality_opera
equality_operator: "==" | "!="
expression: assignment_expression
expression_list: expression ("," expression)*
-expression_statememt: expression
+expression_statement: expression
function_expression: id_expression "(" [argument_list] ")"
hex_literal: "0x" HEX_NUMBER
HEX_NUMBER: /[a-fA-F0-9]+/
diff --git a/docs/markdown/snippets/summary_prog_dep.md b/docs/markdown/snippets/summary_prog_dep.md
new file mode 100644
index 0000000..6f0262f
--- /dev/null
+++ b/docs/markdown/snippets/summary_prog_dep.md
@@ -0,0 +1,4 @@
+## `summary()` accepts external programs or dependencies
+
+External program objects and dependency objects can be passed to
+`summary()` as the value to be printed.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index ced1d7d..8143941 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -14,6 +14,7 @@
from collections import OrderedDict
from functools import lru_cache
+from itertools import chain
from pathlib import Path
import enum
import json
@@ -44,6 +45,11 @@ if T.TYPE_CHECKING:
InstallType = T.List[T.Tuple[str, str, T.Optional['FileMode']]]
InstallSubdirsType = T.List[T.Tuple[str, str, T.Optional['FileMode'], T.Tuple[T.Set[str], T.Set[str]]]]
+# Languages that can mix with C or C++ but don't support unity builds yet
+# because the syntax we use for unity builds is specific to C/++/ObjC/++.
+# Assembly files cannot be unitified and neither can LLVM IR files
+LANGS_CANT_UNITY = ('d', 'fortran')
+
class TestProtocol(enum.Enum):
EXITCODE = 0
@@ -636,6 +642,9 @@ class Backend:
unity_size = self.get_option_for_target(OptionKey('unity_size'), extobj.target)
for comp, srcs in compsrcs.items():
+ if comp.language in LANGS_CANT_UNITY:
+ sources += srcs
+ continue
for i in range(len(srcs) // unity_size + 1):
osrc = self.get_unity_source_file(extobj.target,
comp.get_default_suffix(), i)
@@ -767,7 +776,7 @@ class Backend:
# pkg-config puts the thread flags itself via `Cflags:`
# Fortran requires extra include directives.
if compiler.language == 'fortran':
- for lt in target.link_targets:
+ for lt in chain(target.link_targets, target.link_whole_targets):
priv_dir = self.get_target_private_dir(lt)
commands += compiler.get_include_args(priv_dir, False)
return commands
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 6c524a0..dd70ae0 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -626,19 +626,14 @@ int dummy;
srcs[f] = s
return srcs
- # Languages that can mix with C or C++ but don't support unity builds yet
- # because the syntax we use for unity builds is specific to C/++/ObjC/++.
- # Assembly files cannot be unitified and neither can LLVM IR files
- langs_cant_unity = ('d', 'fortran')
-
def get_target_source_can_unity(self, target, source):
if isinstance(source, File):
source = source.fname
if self.environment.is_llvm_ir(source) or \
self.environment.is_assembly(source):
return False
- suffix = os.path.splitext(source)[1][1:]
- for lang in self.langs_cant_unity:
+ suffix = os.path.splitext(source)[1][1:].lower()
+ for lang in backends.LANGS_CANT_UNITY:
if lang not in target.compilers:
continue
if suffix in target.compilers[lang].file_suffixes:
@@ -762,7 +757,7 @@ int dummy;
if is_unity:
# Warn about incompatible sources if a unity build is enabled
langs = set(target.compilers.keys())
- langs_cant = langs.intersection(self.langs_cant_unity)
+ langs_cant = langs.intersection(backends.LANGS_CANT_UNITY)
if langs_cant:
langs_are = langs = ', '.join(langs_cant).upper()
langs_are += ' are' if len(langs_cant) > 1 else ' is'
@@ -918,7 +913,7 @@ int dummy;
all_suffixes = set(compilers.lang_suffixes['cpp']) | set(compilers.lang_suffixes['fortran'])
selected_sources = []
for source in compiled_sources:
- ext = os.path.splitext(source)[1][1:]
+ ext = os.path.splitext(source)[1][1:].lower()
if ext in all_suffixes:
selected_sources.append(source)
return selected_sources
@@ -2602,7 +2597,10 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
def get_fortran_orderdeps(self, target, compiler):
if compiler.language != 'fortran':
return []
- return [os.path.join(self.get_target_dir(lt), lt.get_filename()) for lt in target.link_targets]
+ return [
+ os.path.join(self.get_target_dir(lt), lt.get_filename())
+ for lt in itertools.chain(target.link_targets, target.link_whole_targets)
+ ]
def generate_msvc_pch_command(self, target, compiler, pch):
header = pch[0]
@@ -3026,14 +3024,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/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 6e070a7..e4886ba 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -176,7 +176,11 @@ class Vs2010Backend(backends.Backend):
# x86
self.platform = 'Win32'
elif target_machine == 'aarch64' or target_machine == 'arm64':
- self.platform = 'arm64'
+ target_cpu = self.interpreter.builtin['target_machine'].cpu_method(None, None)
+ if target_cpu == 'arm64ec':
+ self.platform = 'arm64ec'
+ else:
+ self.platform = 'arm64'
elif 'arm' in target_machine.lower():
self.platform = 'ARM'
else:
@@ -1218,6 +1222,8 @@ class Vs2010Backend(backends.Backend):
targetmachine.text = 'MachineARM'
elif targetplatform == 'arm64':
targetmachine.text = 'MachineARM64'
+ elif targetplatform == 'arm64ec':
+ targetmachine.text = 'MachineARM64EC'
else:
raise MesonException('Unsupported Visual Studio target machine: ' + targetplatform)
# /nologo
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/dependencies/base.py b/mesonbuild/dependencies/base.py
index e72f346..cd77b4b 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -134,6 +134,13 @@ class Dependency:
def is_built(self) -> bool:
return False
+ def summary_value(self) -> T.Union[str, mlog.AnsiDecorator, mlog.AnsiText]:
+ if not self.found():
+ return mlog.red('NO')
+ if not self.version:
+ return mlog.green('YES')
+ return mlog.AnsiText(mlog.green('YES'), ' ', mlog.cyan(self.version))
+
def get_compile_args(self) -> T.List[str]:
if self.include_type == 'system':
converted = []
@@ -263,6 +270,11 @@ class InternalDependency(Dependency):
setattr(result, k, copy.deepcopy(v, memo))
return result
+ def summary_value(self) -> mlog.AnsiDecorator:
+ # Omit the version. Most of the time it will be just the project
+ # version, which is uninteresting in the summary.
+ return mlog.green('YES')
+
def is_built(self) -> bool:
if self.sources or self.libraries or self.whole_libraries:
return True
@@ -1888,6 +1900,11 @@ class ExternalProgram:
else:
mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))
+ def summary_value(self) -> T.Union[str, mlog.AnsiDecorator]:
+ if not self.found():
+ return mlog.red('NO')
+ return self.path
+
def __repr__(self) -> str:
r = '<{} {!r} -> {!r}>'
return r.format(self.__class__.__name__, self.name, self.command)
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/interpreter.py b/mesonbuild/interpreter.py
index c7049c3..a3fa050 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1854,7 +1854,7 @@ class Summary:
self.sections = collections.defaultdict(dict)
self.max_key_len = 0
- def add_section(self, section, values, kwargs):
+ def add_section(self, section, values, kwargs, subproject):
bool_yn = kwargs.get('bool_yn', False)
if not isinstance(bool_yn, bool):
raise InterpreterException('bool_yn keyword argument must be boolean')
@@ -1866,24 +1866,20 @@ class Summary:
raise InterpreterException('Summary section {!r} already have key {!r}'.format(section, k))
formatted_values = []
for i in listify(v):
- if not isinstance(i, (str, int)):
- m = 'Summary value in section {!r}, key {!r}, must be string, integer or boolean'
- raise InterpreterException(m.format(section, k))
- if bool_yn and isinstance(i, bool):
+ i = unholder(i)
+ if isinstance(i, bool) and bool_yn:
formatted_values.append(mlog.green('YES') if i else mlog.red('NO'))
- else:
+ elif isinstance(i, (str, int, bool)):
formatted_values.append(str(i))
+ elif isinstance(i, (ExternalProgram, Dependency)):
+ FeatureNew.single_use('dependency or external program in summary', '0.57.0', subproject)
+ formatted_values.append(i.summary_value())
+ else:
+ m = 'Summary value in section {!r}, key {!r}, must be string, integer, boolean, dependency or external program'
+ raise InterpreterException(m.format(section, k))
self.sections[section][k] = (formatted_values, list_sep)
self.max_key_len = max(self.max_key_len, len(k))
- def text_len(self, v):
- if isinstance(v, str):
- return len(v)
- elif isinstance(v, mlog.AnsiDecorator):
- return len(v.text)
- else:
- raise RuntimeError('Expecting only strings or AnsiDecorator')
-
def dump(self):
mlog.log(self.project_name, mlog.normal_cyan(self.project_version))
for section, values in self.sections.items():
@@ -1909,7 +1905,7 @@ class Summary:
line_len = indent
lines_sep = list_sep.rstrip() + lines_sep
for v in arr:
- v_len = self.text_len(v) + len(list_sep)
+ v_len = len(v) + len(list_sep)
if line and line_len + v_len > max_len:
mlog.log(*line, sep=list_sep, end=lines_sep)
line_len = indent
@@ -3292,7 +3288,7 @@ external dependencies (including libraries) must go to "dependencies".''')
def summary_impl(self, section, values, kwargs):
if self.subproject not in self.summary:
self.summary[self.subproject] = Summary(self.active_projectname, self.project_version)
- self.summary[self.subproject].add_section(section, values, kwargs)
+ self.summary[self.subproject].add_section(section, values, kwargs, self.subproject)
def _print_summary(self):
# Add automatic 'Supbrojects' section in main project.
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/mesonbuild/mlog.py b/mesonbuild/mlog.py
index 0cffba7..20794df 100644
--- a/mesonbuild/mlog.py
+++ b/mesonbuild/mlog.py
@@ -130,6 +130,24 @@ class AnsiDecorator:
text = '"{}"'.format(text)
return text
+ def __len__(self) -> int:
+ return len(self.text)
+
+ def __str__(self) -> str:
+ return self.get_text(colorize_console())
+
+
+class AnsiText:
+ def __init__(self, *args: T.List[T.Union[str, AnsiDecorator]]):
+ self.args = args
+
+ def __len__(self) -> int:
+ return sum((len(x) for x in self.args))
+
+ def __str__(self) -> str:
+ return ''.join((str(x) for x in self.args))
+
+
def bold(text: str, quoted: bool = False) -> AnsiDecorator:
return AnsiDecorator(text, "\033[1m", quoted=quoted)
diff --git a/mesonbuild/scripts/depscan.py b/mesonbuild/scripts/depscan.py
index df7df48..c85f8e7 100644
--- a/mesonbuild/scripts/depscan.py
+++ b/mesonbuild/scripts/depscan.py
@@ -46,7 +46,7 @@ class DependencyScanner:
self.sources_with_exports = [] # type: T.List[str]
def scan_file(self, fname: str) -> None:
- suffix = os.path.splitext(fname)[1][1:]
+ suffix = os.path.splitext(fname)[1][1:].lower()
if suffix in lang_suffixes['fortran']:
self.scan_fortran_file(fname)
elif suffix in lang_suffixes['cpp']:
@@ -131,7 +131,7 @@ class DependencyScanner:
return objname
def module_name_for(self, src: str) -> str:
- suffix= os.path.splitext(src)[1][1:]
+ suffix = os.path.splitext(src)[1][1:].lower()
if suffix in lang_suffixes['fortran']:
exported = self.exports[src]
# Module foo:bar goes to a file name foo@bar.smod
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/run_project_tests.py b/run_project_tests.py
index 772aa2e..33641d7 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -43,6 +43,7 @@ from mesonbuild import mlog
from mesonbuild import mtest
from mesonbuild.build import ConfigurationData
from mesonbuild.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof
+from mesonbuild.mlog import bold, green, red, yellow
from mesonbuild.coredata import backendlist, version as meson_version
from run_tests import get_fake_options, run_configure, get_meson_script
@@ -345,22 +346,6 @@ def log_text_file(logfile, testdir, stdo, stde):
raise StopException()
-def bold(text):
- return mlog.bold(text).get_text(mlog.colorize_console())
-
-
-def green(text):
- return mlog.green(text).get_text(mlog.colorize_console())
-
-
-def red(text):
- return mlog.red(text).get_text(mlog.colorize_console())
-
-
-def yellow(text):
- return mlog.yellow(text).get_text(mlog.colorize_console())
-
-
def _run_ci_include(args: T.List[str]) -> str:
if not args:
return 'At least one parameter required'
diff --git a/run_tests.py b/run_tests.py
index da894c0..24d6a51 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -290,7 +290,7 @@ def run_configure(commandlist, env=None):
return run_configure_inprocess(commandlist, env=env)
def print_system_info():
- print(mlog.bold('System information.').get_text(mlog.colorize_console()))
+ print(mlog.bold('System information.'))
print('Architecture:', platform.architecture())
print('Machine:', platform.machine())
print('Platform:', platform.system())
@@ -364,7 +364,7 @@ def main():
print(flush=True)
returncode = 0
else:
- print(mlog.bold('Running unittests.').get_text(mlog.colorize_console()))
+ print(mlog.bold('Running unittests.'))
print(flush=True)
cmd = mesonlib.python_command + ['run_unittests.py', '-v']
if options.failfast:
@@ -377,7 +377,7 @@ def main():
else:
cross_test_args = mesonlib.python_command + ['run_cross_test.py']
for cf in options.cross:
- print(mlog.bold('Running {} cross tests.'.format(cf)).get_text(mlog.colorize_console()))
+ print(mlog.bold('Running {} cross tests.'.format(cf)))
print(flush=True)
cmd = cross_test_args + ['cross/' + cf]
if options.failfast:
diff --git a/run_unittests.py b/run_unittests.py
index da6d329..b244a07 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -4707,6 +4707,12 @@ class AllPlatformTests(BasePlatformTests):
no : NO
coma list : a, b, c
+ Stuff
+ missing prog : NO
+ existing prog : ''' + sys.executable + '''
+ missing dep : NO
+ internal dep : YES
+
Plugins
long coma list : alpha, alphacolor, apetag, audiofx, audioparsers, auparse,
autodetect, avi
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',
diff --git a/test cases/fortran/21 install static/main.f90 b/test cases/fortran/21 install static/main.f90
new file mode 100644
index 0000000..c83a6a0
--- /dev/null
+++ b/test cases/fortran/21 install static/main.f90
@@ -0,0 +1,4 @@
+use main_lib
+implicit none
+call main_hello()
+end program \ No newline at end of file
diff --git a/test cases/fortran/21 install static/main_lib.f90 b/test cases/fortran/21 install static/main_lib.f90
new file mode 100644
index 0000000..5f3cb45
--- /dev/null
+++ b/test cases/fortran/21 install static/main_lib.f90
@@ -0,0 +1,16 @@
+module main_lib
+
+ use static_hello
+ implicit none
+
+ private
+ public :: main_hello
+
+ contains
+
+ subroutine main_hello
+ call static_say_hello()
+ print *, "Main hello routine finished."
+ end subroutine main_hello
+
+end module main_lib
diff --git a/test cases/fortran/21 install static/meson.build b/test cases/fortran/21 install static/meson.build
new file mode 100644
index 0000000..a91613f
--- /dev/null
+++ b/test cases/fortran/21 install static/meson.build
@@ -0,0 +1,20 @@
+# Based on 'fortran/5 static', but:
+# - Uses a subproject dependency
+# - Is an install:true static library to trigger certain codepath (promotion to link_whole)
+# - Does fortran code 'generation' with configure_file
+# - Uses .F90 ext (capital F typically denotes a dependence on preprocessor treatment, which however is not used)
+project('try-static-subproject-dependency', 'fortran', default_options: ['default_library=static'])
+
+static_dep = dependency('static_hello', fallback: ['static_hello', 'static_hello_dep'])
+
+mainsrc = 'main_lib.f90'
+mainsrc = configure_file(
+ command: [find_program('cp'), '@INPUT@', '@OUTPUT@'],
+ input: mainsrc,
+ output: 'main_lib_output.F90'
+)
+main_lib = library('mainstatic', mainsrc, dependencies: static_dep, install: true)
+main_dep = declare_dependency(link_with: main_lib)
+
+main_exe = executable('main_exe', 'main.f90', dependencies: main_dep)
+test('static_subproject_test', main_exe)
diff --git a/test cases/fortran/21 install static/subprojects/static_hello/meson.build b/test cases/fortran/21 install static/subprojects/static_hello/meson.build
new file mode 100644
index 0000000..7edca39
--- /dev/null
+++ b/test cases/fortran/21 install static/subprojects/static_hello/meson.build
@@ -0,0 +1,12 @@
+project('static-hello', 'fortran')
+
+# staticlibsource = 'static_hello.f90'
+staticlibsource = configure_file(
+ command: [find_program('cp'), '@INPUT@', '@OUTPUT@'],
+ input: 'static_hello.f90',
+ output: 'static_hello_output.F90'
+)
+
+static_hello_lib = static_library('static_hello', staticlibsource, install: false)
+
+static_hello_dep = declare_dependency(link_with: static_hello_lib)
diff --git a/test cases/fortran/21 install static/subprojects/static_hello/static_hello.f90 b/test cases/fortran/21 install static/subprojects/static_hello/static_hello.f90
new file mode 100644
index 0000000..5407560
--- /dev/null
+++ b/test cases/fortran/21 install static/subprojects/static_hello/static_hello.f90
@@ -0,0 +1,17 @@
+module static_hello
+implicit none
+
+private
+public :: static_say_hello
+
+interface static_say_hello
+ module procedure say_hello
+end interface static_say_hello
+
+contains
+
+subroutine say_hello
+ print *, "Static library called."
+end subroutine say_hello
+
+end module static_hello
diff --git a/test cases/fortran/21 install static/test.json b/test cases/fortran/21 install static/test.json
new file mode 100644
index 0000000..b31e91d
--- /dev/null
+++ b/test cases/fortran/21 install static/test.json
@@ -0,0 +1,5 @@
+{
+ "installed": [
+ {"file": "usr/lib/libmainstatic.a", "type": "file"}
+ ]
+} \ No newline at end of file
diff --git a/test cases/unit/73 summary/meson.build b/test cases/unit/73 summary/meson.build
index 1bc05ca..50383b4 100644
--- a/test cases/unit/73 summary/meson.build
+++ b/test cases/unit/73 summary/meson.build
@@ -9,6 +9,11 @@ summary({'Some boolean': false,
'A list': ['string', 1, true],
'empty list': [],
}, section: 'Configuration')
+summary({'missing prog': find_program('xyzzy', required: false),
+ 'existing prog': import('python').find_installation(),
+ 'missing dep': dependency('', required: false),
+ 'internal dep': declare_dependency(),
+ }, section: 'Stuff')
summary('A number', 1, section: 'Configuration')
summary('yes', true, bool_yn : true, section: 'Configuration')
summary('no', false, bool_yn : true, section: 'Configuration')