aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.coveragerc50
-rw-r--r--.github/workflows/cygwin.yml7
-rw-r--r--.github/workflows/macos.yml13
-rw-r--r--.github/workflows/msys2.yml7
-rw-r--r--.github/workflows/nonative.yml5
-rw-r--r--.github/workflows/os_comp.yml9
-rw-r--r--.github/workflows/unusedargs_missingreturn.yml12
-rw-r--r--.gitignore3
-rw-r--r--azure-pipelines.yml1
-rw-r--r--ci/run.ps119
-rwxr-xr-xci/upload_cov.sh13
-rw-r--r--ci/usercustomize.py19
-rw-r--r--data/.coveragerc.in25
-rw-r--r--docs/markdown/Builtin-options.md2
-rw-r--r--docs/markdown/Reference-manual.md4
-rw-r--r--docs/markdown/snippets/newvsbackends.md15
-rw-r--r--mesonbuild/backend/backends.py6
-rw-r--r--mesonbuild/backend/vs2010backend.py40
-rw-r--r--mesonbuild/backend/vs2012backend.py38
-rw-r--r--mesonbuild/backend/vs2013backend.py38
-rw-r--r--mesonbuild/cmake/common.py4
-rw-r--r--mesonbuild/coredata.py2
-rw-r--r--mesonbuild/interpreter/interpreter.py17
-rw-r--r--mesonbuild/interpreterbase/interpreterbase.py31
-rwxr-xr-xrun_tests.py78
-rwxr-xr-xrun_unittests.py7
-rw-r--r--test cases/common/137 whole archive/meson.build11
-rw-r--r--test cases/common/242 set and get variable/meson.build63
-rw-r--r--test cases/common/242 set and get variable/test1.txt0
-rw-r--r--test cases/common/242 set and get variable/test2.txt0
-rwxr-xr-xtools/run_with_cov.py53
31 files changed, 441 insertions, 151 deletions
diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index c3d41d4..0000000
--- a/.coveragerc
+++ /dev/null
@@ -1,50 +0,0 @@
-[run]
-branch = True
-concurrency =
- multiprocessing
-data_file = .coverage/coverage
-parallel = True
-source =
- meson.py
- mesonbuild/
- mesonconf.py
- mesonintrospect.py
- mesonrewriter.py
- mesontest.py
- run_cross_test.py
- run_project_tests.py
- run_tests.py
- run_unittests.py
-
-# Aliases to /root/ are needed because Travis runs in docker at /root/.
-[paths]
-meson =
- meson.py
- /root/meson.py
-mesonbuild =
- mesonbuild/
- /root/mesonbuild/
-mesonconf =
- mesonconf.py
- /root/mesonconf.py
-mesonintrospect =
- mesonintrospect.py
- /root/mesonintrospect.py
-mesonrewriter =
- mesonrewriter.py
- /root/mesonrewriter.py
-mesontest =
- mesontest.py
- /root/mesontest.py
-run_cross_test =
- run_cross_test.py
- /root/run_cross_test.py
-run_project_tests =
- run_project_tests.py
- /root/run_project_tests.py
-run_tests =
- run_tests.py
- /root/run_tests.py
-run_unittests =
- run_unittests.py
- /root/run_unittests.py
diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml
index 32d33d8..3954094 100644
--- a/.github/workflows/cygwin.yml
+++ b/.github/workflows/cygwin.yml
@@ -68,13 +68,13 @@ jobs:
- name: Run pip
run: |
export PATH=/usr/bin:/usr/local/bin:$(cygpath ${SYSTEMROOT})/system32
- python3 -m pip --disable-pip-version-check install gcovr jsonschema pefile pytest pytest-xdist
+ python3 -m pip --disable-pip-version-check install gcovr jsonschema pefile pytest pytest-xdist coverage codecov
shell: C:\cygwin\bin\bash.exe --noprofile --norc -o igncr -eo pipefail '{0}'
- name: Run tests
run: |
export PATH=/usr/bin:/usr/local/bin:$(cygpath ${SYSTEMROOT})/system32
- python3 run_tests.py --backend=ninja
+ python3 ./tools/run_with_cov.py run_tests.py --backend=ninja
env:
# Cygwin's static boost installation is broken (some static library
# variants such as boost_thread are not present)
@@ -87,3 +87,6 @@ jobs:
path: meson-test-run.*
# test log should be saved on failure
if: ${{ !cancelled() }}
+
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "${{ matrix.NAME }}"
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index faff3ae..c7ef7d3 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -24,7 +24,7 @@ jobs:
python-version: '3.x'
- run: |
python -m pip install --upgrade pip
- python -m pip install pytest pytest-xdist jsonschema
+ python -m pip install pytest pytest-xdist jsonschema coverage codecov
- run: brew install pkg-config ninja llvm qt@5
- env:
CPPFLAGS: "-I/usr/local/include"
@@ -35,7 +35,10 @@ jobs:
export SDKROOT="$(xcodebuild -version -sdk macosx Path)"
export PATH="$HOME/tools:/usr/local/opt/qt@5/bin:$PATH:$(brew --prefix llvm)/bin"
export PKG_CONFIG_PATH="/usr/local/opt/qt@5/lib/pkgconfig:$PKG_CONFIG_PATH"
- ./run_unittests.py
+ ./tools/run_with_cov.py ./run_unittests.py
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "appleclang [unit tests]"
+
project-tests-appleclang:
runs-on: macos-latest
@@ -50,7 +53,7 @@ jobs:
- run: |
python3 -m pip install --upgrade setuptools
python3 -m pip install --upgrade pip
- python3 -m pip install cython
+ python3 -m pip install cython coverage codecov
- env:
CPPFLAGS: "-I/usr/local/include"
LDFLAGS: "-L/usr/local/lib"
@@ -61,7 +64,9 @@ jobs:
export SDKROOT="$(xcodebuild -version -sdk macosx Path)"
export PATH="$HOME/tools:/usr/local/opt/qt@5/bin:$PATH:$(brew --prefix llvm)/bin"
export PKG_CONFIG_PATH="/usr/local/opt/qt@5/lib/pkgconfig:$PKG_CONFIG_PATH"
- ./run_project_tests.py --backend=ninja
+ ./tools/run_with_cov.py ./run_project_tests.py --backend=ninja
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "appleclang [project tests; unity=${{ matrix.unity }}]"
Qt4macos:
runs-on: macos-latest
diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml
index cbab904..64a0979 100644
--- a/.github/workflows/msys2.yml
+++ b/.github/workflows/msys2.yml
@@ -71,7 +71,7 @@ jobs:
- name: Install dependencies
run: |
- python3 -m pip --disable-pip-version-check install gcovr jsonschema pefile pytest pytest-xdist
+ python3 -m pip --disable-pip-version-check install gcovr jsonschema pefile pytest pytest-xdist coverage codecov
- name: Run Tests
run: |
@@ -89,9 +89,12 @@ jobs:
pacman --noconfirm --needed -S mingw-w64-${{ matrix.MSYS2_ARCH }}-${{ matrix.MSYS2_CURSES }}
fi
- MSYSTEM= python3 run_tests.py --backend=ninja
+ MSYSTEM= python3 ./tools/run_with_cov.py run_tests.py --backend=ninja
- uses: actions/upload-artifact@v2
with:
name: ${{ matrix.NAME }}
path: meson-test-run.*
+
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "${{ matrix.NAME }}"
diff --git a/.github/workflows/nonative.yml b/.github/workflows/nonative.yml
index 1fc43b4..c4bad95 100644
--- a/.github/workflows/nonative.yml
+++ b/.github/workflows/nonative.yml
@@ -26,6 +26,9 @@ jobs:
- run: |
apt-get -y purge clang gcc gdc
apt-get -y autoremove
+ python3 -m pip install coverage codecov
- uses: actions/checkout@v2
- name: Run tests
- run: bash -c 'source /ci/env_vars.sh; cd $GITHUB_WORKSPACE; ./run_tests.py $CI_ARGS --cross ubuntu-armhf.json --cross-only'
+ run: bash -c 'source /ci/env_vars.sh; cd $GITHUB_WORKSPACE; ./tools/run_with_cov.py ./run_tests.py $CI_ARGS --cross ubuntu-armhf.json --cross-only'
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "Ubuntu nonnative"
diff --git a/.github/workflows/os_comp.yml b/.github/workflows/os_comp.yml
index 34b113b..6531e2b 100644
--- a/.github/workflows/os_comp.yml
+++ b/.github/workflows/os_comp.yml
@@ -40,7 +40,9 @@ jobs:
# All environment variables are stored inside the docker image in /ci/env_vars.sh
# They are defined in the `env` section in each image.json. CI_ARGS should be set
# via the `args` array ub the image.json
- run: bash -c 'source /ci/env_vars.sh; cd $GITHUB_WORKSPACE; ./run_tests.py $CI_ARGS'
+ run: bash -c 'source /ci/env_vars.sh; cd $GITHUB_WORKSPACE; ./tools/run_with_cov.py ./run_tests.py $CI_ARGS'
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "OS Comp [${{ matrix.cfg.name }}]"
ubuntu-rolling:
name: 'Ubuntu Rolling'
@@ -110,4 +112,7 @@ jobs:
update-alternatives --set i686-w64-mingw32-gcc /usr/bin/i686-w64-mingw32-gcc-posix
update-alternatives --set i686-w64-mingw32-g++ /usr/bin/i686-w64-mingw32-g++-posix
- ./run_tests.py $RUN_TESTS_ARGS -- $MESON_ARGS
+ ./tools/run_with_cov.py ./run_tests.py $RUN_TESTS_ARGS -- $MESON_ARGS
+
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "Ubuntu [${{ matrix.cfg.CC }} ${{ matrix.cfg.RUN_TESTS_ARGS }} ${{ matrix.cfg.MESON_ARGS }}]"
diff --git a/.github/workflows/unusedargs_missingreturn.yml b/.github/workflows/unusedargs_missingreturn.yml
index 3e82568..8e6e42d 100644
--- a/.github/workflows/unusedargs_missingreturn.yml
+++ b/.github/workflows/unusedargs_missingreturn.yml
@@ -45,7 +45,10 @@ jobs:
run: |
sudo apt update -yq
sudo apt install -yq --no-install-recommends g++ gfortran ninja-build gobjc gobjc++
- - run: python run_project_tests.py --only cmake common fortran platform-linux "objective c" "objective c++"
+ python -m pip install coverage codecov
+ - run: ./tools/run_with_cov.py run_project_tests.py --only cmake common fortran platform-linux "objective c" "objective c++"
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "UnusedMissingReturn"
windows:
runs-on: windows-latest
@@ -55,10 +58,13 @@ jobs:
with:
python-version: '3.x'
- - run: pip install ninja pefile
+ - run: pip install ninja pefile coverage codecov
- - run: python run_project_tests.py --only platform-windows
+ - run: python ./tools/run_with_cov.py run_project_tests.py --only platform-windows
env:
CC: gcc
CXX: g++
FC: gfortran
+
+ - name: Upload coverage report
+ run: ./ci/upload_cov.sh "UnusedMissingReturn Windows"
diff --git a/.gitignore b/.gitignore
index fea337e..8ff5e78 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,7 +8,8 @@
/.vscode
__pycache__
-.coverage
+/.coverage/
+/.coveragerc
/install dir
/work area
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 14ff1bd..614f344 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -9,6 +9,7 @@ trigger:
variables:
CI: 1
+ SOURCE_VERSION: $(Build.SourceVersion)
jobs:
diff --git a/ci/run.ps1 b/ci/run.ps1
index 424af72..961c423 100644
--- a/ci/run.ps1
+++ b/ci/run.ps1
@@ -68,11 +68,26 @@ python --version
# Needed for running unit tests in parallel.
echo ""
-python -m pip --disable-pip-version-check install --upgrade pefile pytest-xdist jsonschema
+python -m pip --disable-pip-version-check install --upgrade pefile pytest-xdist jsonschema coverage
echo ""
echo "=== Start running tests ==="
# Starting from VS2019 Powershell(?) will fail the test run
# if it prints anything to stderr. Python's test runner
# does that by default so we need to forward it.
-cmd /c "python 2>&1 run_tests.py --backend $env:backend $env:extraargs"
+cmd /c "python 2>&1 ./tools/run_with_cov.py run_tests.py --backend $env:backend $env:extraargs"
+
+echo ""
+echo ""
+echo "=== Gathering coverage report ==="
+echo ""
+
+python3 -m coverage combine
+python3 -m coverage xml
+python3 -m coverage report
+
+# Currently codecov.py does not handle Azure, use this fork of a fork to get it
+# working without requireing a token
+git clone https://github.com/mensinda/codecov-python
+python3 -m pip install --ignore-installed ./codecov-python
+python3 -m codecov -f .coverage/coverage.xml -n "VS$env:compiler $env:arch $env:backend" -c $env:SOURCE_VERSION
diff --git a/ci/upload_cov.sh b/ci/upload_cov.sh
new file mode 100755
index 0000000..089641b
--- /dev/null
+++ b/ci/upload_cov.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+echo "Combining coverage reports..."
+coverage combine
+
+echo "Generating XML report..."
+coverage xml
+
+echo "Printing report"
+coverage report
+
+echo "Uploading to codecov..."
+codecov -f .coverage/coverage.xml -n "$1"
diff --git a/ci/usercustomize.py b/ci/usercustomize.py
new file mode 100644
index 0000000..72421ba
--- /dev/null
+++ b/ci/usercustomize.py
@@ -0,0 +1,19 @@
+# Copyright 2021 The Meson development team
+
+# 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.
+
+# This script is used by coverage (see tools/run_with_cov.py) to enable coverage
+# reports in python subprocesses
+
+import coverage
+coverage.process_startup()
diff --git a/data/.coveragerc.in b/data/.coveragerc.in
new file mode 100644
index 0000000..328e13c
--- /dev/null
+++ b/data/.coveragerc.in
@@ -0,0 +1,25 @@
+[run]
+branch = True
+parallel = True
+concurrency = multiprocessing
+data_file = @ROOT@/.coverage/coverage
+source = @ROOT@/mesonbuild/
+
+[report]
+exclude_lines =
+ if T.TYPE_CHECKING:
+
+[paths]
+mesonbuild =
+ mesonbuild/
+ __w/meson/meson/mesonbuild/
+ @ROOT@/mesonbuild/
+
+[html]
+directory = @ROOT@/.coverage/html
+
+[xml]
+output = @ROOT@/.coverage/coverage.xml
+
+[json]
+output = @ROOT@/.coverage/coverage.json
diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md
index ce33fce..0536e77 100644
--- a/docs/markdown/Builtin-options.md
+++ b/docs/markdown/Builtin-options.md
@@ -69,7 +69,7 @@ machine](#specifying-options-per-machine) section for details.
| Option | Default value | Description | Is per machine | Is per subproject |
| ------ | ------------- | ----------- | -------------- | ----------------- |
| auto_features {enabled, disabled, auto} | auto | Override value of all 'auto' features | no | no |
-| backend {ninja, vs,<br>vs2010, vs2015, vs2017, vs2019, xcode} | ninja | Backend to use | no | no |
+| backend {ninja, vs,<br>vs2010, vs2012, vs2013, vs2015, vs2017, vs2019, xcode} | ninja | Backend to use | no | no |
| buildtype {plain, debug,<br>debugoptimized, release, minsize, custom} | debug | Build type to use | no | no |
| debug | true | Debug | no | no |
| default_library {shared, static, both} | shared | Default library type | no | yes |
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index de7f9f2..388c975 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -1984,8 +1984,8 @@ the following methods.
*used as the `script_name` parameter.
- `backend()` *(since 0.37.0)*: returns a string representing the
- current backend: `ninja`, `vs2010`, `vs2015`, `vs2017`, `vs2019`,
- or `xcode`.
+ current backend: `ninja`, `vs2010`, `vs2012`, `vs2013`, `vs2015`,
+ `vs2017`, `vs2019`, or `xcode`.
- `build_root()`: returns a string with the absolute path to the build
root directory. *(deprecated since 0.56.0)*: this function will return the
diff --git a/docs/markdown/snippets/newvsbackends.md b/docs/markdown/snippets/newvsbackends.md
new file mode 100644
index 0000000..cb7437a
--- /dev/null
+++ b/docs/markdown/snippets/newvsbackends.md
@@ -0,0 +1,15 @@
+## New `vs2012` and `vs2013` backend options
+
+Adds the ability to generate Visual Studio 2012 and 2013 projects. This is an
+extension to the existing Visual Studio 2010 projects so that it is no longer
+required to manually upgrade the generated Visual Studio 2010 projects.
+
+Generating Visual Studio 2010 projects has also been fixed since its developer
+command prompt does not provide a `%VisualStudioVersion%` envvar.
+
+## Developer environment
+
+Expand the support for the `link_whole:` project option for pre-Visual Studio 2015
+Update 2, where previously Visual Studio 2015 Update 2 or later was required for
+this, for the Ninja backend as well as the vs2010 (as well as the newly-added
+vs2012 and vs2013 backends).
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 2652ae6..2239fdd 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -199,6 +199,12 @@ def get_backend_from_name(backend: str, build: T.Optional[build.Build] = None, i
elif backend == 'vs2010':
from . import vs2010backend
return vs2010backend.Vs2010Backend(build, interpreter)
+ elif backend == 'vs2012':
+ from . import vs2012backend
+ return vs2012backend.Vs2012Backend(build, interpreter)
+ elif backend == 'vs2013':
+ from . import vs2013backend
+ return vs2013backend.Vs2013Backend(build, interpreter)
elif backend == 'vs2015':
from . import vs2015backend
return vs2015backend.Vs2015Backend(build, interpreter)
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 2d3197a..5595fd0 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -27,7 +27,7 @@ from .. import mlog
from .. import compilers
from ..interpreter import Interpreter
from ..mesonlib import (
- MesonException, python_command, replace_if_different, OptionKey,
+ File, MesonException, python_command, replace_if_different, OptionKey, version_compare,
)
from ..environment import Environment, build_filename
@@ -37,8 +37,14 @@ def autodetect_vs_version(build: T.Optional[build.Build], interpreter: T.Optiona
if not vs_install_dir:
raise MesonException('Could not detect Visual Studio: Environment variable VSINSTALLDIR is not set!\n'
'Are you running meson from the Visual Studio Developer Command Prompt?')
- # VisualStudioVersion is set since Visual Studio 12.0, but sometimes
+ # VisualStudioVersion is set since Visual Studio 11.0, but sometimes
# vcvarsall.bat doesn't set it, so also use VSINSTALLDIR
+ if vs_version == '11.0' or 'Visual Studio 11' in vs_install_dir:
+ from mesonbuild.backend.vs2012backend import Vs2012Backend
+ return Vs2012Backend(build, interpreter)
+ if vs_version == '12.0' or 'Visual Studio 12' in vs_install_dir:
+ from mesonbuild.backend.vs2013backend import Vs2013Backend
+ return Vs2013Backend(build, interpreter)
if vs_version == '14.0' or 'Visual Studio 14' in vs_install_dir:
from mesonbuild.backend.vs2015backend import Vs2015Backend
return Vs2015Backend(build, interpreter)
@@ -210,7 +216,7 @@ class Vs2010Backend(backends.Backend):
if 'VCINSTALLDIR' in os.environ:
vs_version = os.environ['VisualStudioVersion'] \
if 'VisualStudioVersion' in os.environ else None
- relative_path = 'Auxiliary\\Build\\' if vs_version >= '15.0' else ''
+ relative_path = 'Auxiliary\\Build\\' if vs_version is not None and vs_version >= '15.0' else ''
script_path = os.environ['VCINSTALLDIR'] + relative_path + 'vcvarsall.bat'
if os.path.exists(script_path):
if has_arch_values:
@@ -1149,8 +1155,32 @@ class Vs2010Backend(backends.Backend):
lobj = self.build.targets[t.get_id()]
linkname = os.path.join(down, self.get_target_filename_for_linking(lobj))
if t in target.link_whole_targets:
- # /WHOLEARCHIVE:foo must go into AdditionalOptions
- extra_link_args += compiler.get_link_whole_for(linkname)
+ if compiler.id == 'msvc' and version_compare(compiler.version, '<19.00.23918'):
+ # Expand our object lists manually if we are on pre-Visual Studio 2015 Update 2
+ l = t.extract_all_objects(False)
+
+ # Unforunately, we can't use self.object_filename_from_source()
+ gensrclist: T.List[File] = []
+ for gen in l.genlist:
+ for src in gen.get_outputs():
+ if self.environment.is_source(src) and not self.environment.is_header(src):
+ path = self.get_target_generated_dir(t, gen, src)
+ gen_src_ext = '.' + os.path.splitext(path)[1][1:]
+ extra_link_args.append(path[:-len(gen_src_ext)] + '.obj')
+
+ for src in l.srclist:
+ obj_basename = None
+ if self.environment.is_source(src) and not self.environment.is_header(src):
+ obj_basename = self.object_filename_from_source(t, src)
+ target_private_dir = self.relpath(self.get_target_private_dir(t),
+ self.get_target_dir(t))
+ rel_obj = os.path.join(target_private_dir, obj_basename)
+ extra_link_args.append(rel_obj)
+
+ extra_link_args.extend(self.flatten_object_list(t))
+ else:
+ # /WHOLEARCHIVE:foo must go into AdditionalOptions
+ extra_link_args += compiler.get_link_whole_for(linkname)
# To force Visual Studio to build this project even though it
# has no sources, we include a reference to the vcxproj file
# that builds this target. Technically we should add this only
diff --git a/mesonbuild/backend/vs2012backend.py b/mesonbuild/backend/vs2012backend.py
new file mode 100644
index 0000000..a9ba5f4
--- /dev/null
+++ b/mesonbuild/backend/vs2012backend.py
@@ -0,0 +1,38 @@
+# Copyright 2014-2016 The Meson development team
+
+# 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.
+
+from .vs2010backend import Vs2010Backend
+from ..mesonlib import MesonException
+from ..interpreter import Interpreter
+from ..build import Build
+import typing as T
+
+
+class Vs2012Backend(Vs2010Backend):
+ def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter]):
+ super().__init__(build, interpreter)
+ self.name = 'vs2012'
+ self.vs_version = '2012'
+ if self.environment is not None:
+ # TODO: we assume host == build
+ comps = self.environment.coredata.compilers.host
+ if comps and all(c.id == 'intel-cl' for c in comps.values()):
+ c = list(comps.values())[0]
+ if c.version.startswith('19'):
+ self.platform_toolset = 'Intel C++ Compiler 19.0'
+ else:
+ # We don't have support for versions older than 2019 right now.
+ raise MesonException('There is currently no support for ICL before 19, patches welcome.')
+ if self.platform_toolset is None:
+ self.platform_toolset = 'v110'
diff --git a/mesonbuild/backend/vs2013backend.py b/mesonbuild/backend/vs2013backend.py
new file mode 100644
index 0000000..0f2c8bd
--- /dev/null
+++ b/mesonbuild/backend/vs2013backend.py
@@ -0,0 +1,38 @@
+# Copyright 2014-2016 The Meson development team
+
+# 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.
+
+from .vs2010backend import Vs2010Backend
+from ..mesonlib import MesonException
+from ..interpreter import Interpreter
+from ..build import Build
+import typing as T
+
+
+class Vs2013Backend(Vs2010Backend):
+ def __init__(self, build: T.Optional[Build], interpreter: T.Optional[Interpreter]):
+ super().__init__(build, interpreter)
+ self.name = 'vs2013'
+ self.vs_version = '2013'
+ if self.environment is not None:
+ # TODO: we assume host == build
+ comps = self.environment.coredata.compilers.host
+ if comps and all(c.id == 'intel-cl' for c in comps.values()):
+ c = list(comps.values())[0]
+ if c.version.startswith('19'):
+ self.platform_toolset = 'Intel C++ Compiler 19.0'
+ else:
+ # We don't have support for versions older than 2019 right now.
+ raise MesonException('There is currently no support for ICL before 19, patches welcome.')
+ if self.platform_toolset is None:
+ self.platform_toolset = 'v120'
diff --git a/mesonbuild/cmake/common.py b/mesonbuild/cmake/common.py
index d1f86f0..5cc154c 100644
--- a/mesonbuild/cmake/common.py
+++ b/mesonbuild/cmake/common.py
@@ -39,7 +39,9 @@ backend_generator_map = {
'ninja': 'Ninja',
'xcode': 'Xcode',
'vs2010': 'Visual Studio 10 2010',
- 'vs2015': 'Visual Studio 15 2017',
+ 'vs2012': 'Visual Studio 11 2012',
+ 'vs2013': 'Visual Studio 12 2013',
+ 'vs2015': 'Visual Studio 14 2015',
'vs2017': 'Visual Studio 15 2017',
'vs2019': 'Visual Studio 16 2019',
}
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 107e4b8..a0ee7df 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -44,7 +44,7 @@ if T.TYPE_CHECKING:
CompilerCheckCacheKey = T.Tuple[T.Tuple[str, ...], str, str, T.Tuple[str, ...], str]
version = '0.58.999'
-backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode']
+backendlist = ['ninja', 'vs', 'vs2010', 'vs2012', 'vs2013', 'vs2015', 'vs2017', 'vs2019', 'xcode']
default_yielding = False
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py
index f1869e3..2faec4e 100644
--- a/mesonbuild/interpreter/interpreter.py
+++ b/mesonbuild/interpreter/interpreter.py
@@ -752,14 +752,7 @@ external dependencies (including libraries) must go to "dependencies".''')
def func_subproject(self, nodes, args, kwargs):
if len(args) != 1:
raise InterpreterException('Subproject takes exactly one argument')
- subp_name = args[0]
- subp = self.do_subproject(subp_name, 'meson', kwargs)
- # Update the holder maps from the subproject. Additional entries to the
- # holder maps can be added through imported Meson modules
- if isinstance(subp.held_object, Interpreter):
- self.holder_map.update(subp.held_object.holder_map)
- self.bound_holder_map.update(subp.held_object.bound_holder_map)
- return subp
+ return self.do_subproject(args[0], 'meson', kwargs)
def disabled_subproject(self, subp_name, disabled_feature=None, exception=None):
sub = SubprojectHolder(NullSubprojectInterpreter(), os.path.join(self.subproject_dir, subp_name),
@@ -824,7 +817,7 @@ external dependencies (including libraries) must go to "dependencies".''')
elif method == 'cmake':
return self._do_subproject_cmake(subp_name, subdir, subdir_abs, default_options, kwargs)
else:
- raise InterpreterException(f'The method {method} is invalid for the subproject {subp_name}')
+ raise mesonlib.MesonBugException(f'The method {method} is invalid for the subproject {subp_name}')
# Invalid code is always an error
except InvalidCode:
raise
@@ -879,6 +872,10 @@ external dependencies (including libraries) must go to "dependencies".''')
self.build.subprojects[subp_name] = subi.project_version
self.coredata.initialized_subprojects.add(subp_name)
self.summary.update(subi.summary)
+ # Update the holder maps from the subproject. Additional entries to the
+ # holder maps can be added through imported Meson modules
+ self.holder_map.update(subi.holder_map)
+ self.bound_holder_map.update(subi.bound_holder_map)
return self.subprojects[subp_name]
def _do_subproject_cmake(self, subp_name, subdir, subdir_abs, default_options, kwargs):
@@ -2675,7 +2672,7 @@ This will become a hard error in the future.''', location=self.current_node)
if len(args) != 2:
raise InvalidCode('Set_variable takes two arguments.')
varname, value = args
- self.set_variable(varname, value)
+ self.set_variable(varname, value, holderify=True)
@noKwargs
@noArgsFlattening
diff --git a/mesonbuild/interpreterbase/interpreterbase.py b/mesonbuild/interpreterbase/interpreterbase.py
index 0acb699..3ea10f4 100644
--- a/mesonbuild/interpreterbase/interpreterbase.py
+++ b/mesonbuild/interpreterbase/interpreterbase.py
@@ -16,7 +16,7 @@
# or an interpreter-based tool.
from .. import mparser, mesonlib, mlog
-from .. import environment, dependencies
+from .. import environment
from .baseobjects import (
InterpreterObject,
@@ -592,7 +592,7 @@ The result of this is undefined and will become a hard error in a future Meson r
obj.current_node = node
return self._holderify(obj.method_call(method_name, args, kwargs))
- def _holderify(self, res: T.Optional[TYPE_var]) -> T.Union[TYPE_elementary, InterpreterObject]:
+ def _holderify(self, res: T.Union[TYPE_var, InterpreterObject, None]) -> T.Union[TYPE_elementary, InterpreterObject]:
if res is None:
return None
if isinstance(res, (int, bool, str)):
@@ -799,7 +799,7 @@ The result of this is undefined and will become a hard error in a future Meson r
index = posargs[0]
fallback = None
if len(posargs) == 2:
- fallback = posargs[1]
+ fallback = self._holderify(posargs[1])
elif len(posargs) > 2:
m = 'Array method \'get()\' only takes two arguments: the ' \
'index and an optional fallback value if the index is ' \
@@ -845,7 +845,7 @@ The result of this is undefined and will become a hard error in a future Meson r
return obj[key]
if len(posargs) == 2:
- fallback = posargs[1]
+ fallback = self._holderify(posargs[1])
if isinstance(fallback, mparser.BaseNode):
return self.evaluate_statement(fallback)
return fallback
@@ -909,20 +909,34 @@ To specify a keyword argument, use : instead of =.''')
raise InvalidArguments('Tried to assign value to a non-variable.')
value = self.evaluate_statement(node.value)
if not self.is_assignable(value):
- raise InvalidCode('Tried to assign an invalid value to variable.')
+ raise InvalidCode(f'Tried to assign the invalid value "{value}" of type {type(value).__name__} to variable.')
# For mutable objects we need to make a copy on assignment
if isinstance(value, MutableInterpreterObject):
value = copy.deepcopy(value)
self.set_variable(var_name, value)
return None
- def set_variable(self, varname: str, variable: T.Union[TYPE_var, InterpreterObject]) -> None:
+ def set_variable(self, varname: str, variable: T.Union[TYPE_var, InterpreterObject], *, holderify: bool = False) -> None:
if variable is None:
raise InvalidCode('Can not assign None to variable.')
+ if holderify:
+ variable = self._holderify(variable)
+ else:
+ # Ensure that we are never storing a HoldableObject
+ def check(x: T.Union[TYPE_var, InterpreterObject]) -> None:
+ if isinstance(x, mesonlib.HoldableObject):
+ raise mesonlib.MesonBugException(f'set_variable in InterpreterBase called with a HoldableObject {x} of type {type(x).__name__}')
+ elif isinstance(x, list):
+ for y in x:
+ check(y)
+ elif isinstance(x, dict):
+ for v in x.values():
+ check(v)
+ check(variable)
if not isinstance(varname, str):
raise InvalidCode('First argument to set_variable must be a string.')
if not self.is_assignable(variable):
- raise InvalidCode('Assigned value not of assignable type.')
+ raise InvalidCode(f'Assigned value "{variable}" of type {type(variable).__name__} is not an assignable type.')
if re.match('[_a-zA-Z][_0-9a-zA-Z]*$', varname) is None:
raise InvalidCode('Invalid variable name: ' + varname)
if varname in self.builtin:
@@ -937,8 +951,7 @@ To specify a keyword argument, use : instead of =.''')
raise InvalidCode('Unknown variable "%s".' % varname)
def is_assignable(self, value: T.Any) -> bool:
- return isinstance(value, (InterpreterObject, dependencies.Dependency,
- str, int, list, dict, mesonlib.File))
+ return isinstance(value, (InterpreterObject, str, int, list, dict))
def validate_extraction(self, buildtarget: mesonlib.HoldableObject) -> None:
raise InterpreterException('validate_extraction is not implemented in this context (please file a bug)')
diff --git a/run_tests.py b/run_tests.py
index 10d63df..ae96bfa 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -20,7 +20,6 @@ import sys
import time
import shutil
import subprocess
-import tempfile
import platform
import argparse
import traceback
@@ -311,7 +310,6 @@ def print_system_info():
def main():
print_system_info()
parser = argparse.ArgumentParser()
- parser.add_argument('--cov', action='store_true')
parser.add_argument('--backend', default=None, dest='backend',
choices=backendlist)
parser.add_argument('--cross', default=[], dest='cross', action='append')
@@ -319,13 +317,6 @@ def main():
parser.add_argument('--failfast', action='store_true')
parser.add_argument('--no-unittests', action='store_true', default=False)
(options, _) = parser.parse_known_args()
- # Enable coverage early...
- enable_coverage = options.cov
- if enable_coverage:
- os.makedirs('.coverage', exist_ok=True)
- sys.argv.remove('--cov')
- import coverage
- coverage.process_startup()
returncode = 0
backend, _ = guess_backend(options.backend, shutil.which('msbuild'))
no_unittests = options.no_unittests
@@ -349,52 +340,41 @@ def main():
# Run tests
# Can't pass arguments to unit tests, so set the backend to use in the environment
env = os.environ.copy()
- with tempfile.TemporaryDirectory() as temp_dir:
- # Enable coverage on all subsequent processes.
- if enable_coverage:
- Path(temp_dir, 'usercustomize.py').open('w').write(
- 'import coverage\n'
- 'coverage.process_startup()\n')
- env['COVERAGE_PROCESS_START'] = '.coveragerc'
- if 'PYTHONPATH' in env:
- env['PYTHONPATH'] = os.pathsep.join([temp_dir, env.get('PYTHONPATH')])
- else:
- env['PYTHONPATH'] = temp_dir
- if not options.cross:
- cmd = mesonlib.python_command + ['run_meson_command_tests.py', '-v']
+ if not options.cross:
+ cmd = mesonlib.python_command + ['run_meson_command_tests.py', '-v']
+ if options.failfast:
+ cmd += ['--failfast']
+ returncode += subprocess.call(cmd, env=env)
+ if options.failfast and returncode != 0:
+ return returncode
+ if no_unittests:
+ print('Skipping all unit tests.')
+ print(flush=True)
+ returncode = 0
+ else:
+ print(mlog.bold('Running unittests.'))
+ print(flush=True)
+ cmd = mesonlib.python_command + ['run_unittests.py', '--backend=' + backend.name, '-v']
if options.failfast:
cmd += ['--failfast']
returncode += subprocess.call(cmd, env=env)
if options.failfast and returncode != 0:
return returncode
- if no_unittests:
- print('Skipping all unit tests.')
- print(flush=True)
- returncode = 0
- else:
- print(mlog.bold('Running unittests.'))
- print(flush=True)
- cmd = mesonlib.python_command + ['run_unittests.py', '--backend=' + backend.name, '-v']
- if options.failfast:
- cmd += ['--failfast']
- returncode += subprocess.call(cmd, env=env)
- if options.failfast and returncode != 0:
- return returncode
- cmd = mesonlib.python_command + ['run_project_tests.py'] + sys.argv[1:]
+ cmd = mesonlib.python_command + ['run_project_tests.py'] + sys.argv[1:]
+ returncode += subprocess.call(cmd, env=env)
+ else:
+ cross_test_args = mesonlib.python_command + ['run_cross_test.py']
+ for cf in options.cross:
+ print(mlog.bold(f'Running {cf} cross tests.'))
+ print(flush=True)
+ cmd = cross_test_args + ['cross/' + cf]
+ if options.failfast:
+ cmd += ['--failfast']
+ if options.cross_only:
+ cmd += ['--cross-only']
returncode += subprocess.call(cmd, env=env)
- else:
- cross_test_args = mesonlib.python_command + ['run_cross_test.py']
- for cf in options.cross:
- print(mlog.bold(f'Running {cf} cross tests.'))
- print(flush=True)
- cmd = cross_test_args + ['cross/' + cf]
- if options.failfast:
- cmd += ['--failfast']
- if options.cross_only:
- cmd += ['--cross-only']
- returncode += subprocess.call(cmd, env=env)
- if options.failfast and returncode != 0:
- return returncode
+ if options.failfast and returncode != 0:
+ return returncode
return returncode
if __name__ == '__main__':
diff --git a/run_unittests.py b/run_unittests.py
index b55ba96..13149ce 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -10302,6 +10302,13 @@ def main():
pytest_args += ['--color=yes']
pytest_args += ['./run_unittests.py']
pytest_args += convert_args(sys.argv[1:])
+ # Always disable pytest-cov because we use a custom setup
+ try:
+ import pytest_cov # noqa: F401
+ print('Disabling pytest-cov')
+ pytest_args += ['-p' 'no:cov']
+ except ImportError:
+ pass
return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode
except ImportError:
print('pytest-xdist not found, using unittest instead')
diff --git a/test cases/common/137 whole archive/meson.build b/test cases/common/137 whole archive/meson.build
index 133146b..d4cbb83 100644
--- a/test cases/common/137 whole archive/meson.build
+++ b/test cases/common/137 whole archive/meson.build
@@ -1,15 +1,14 @@
project('whole archive', 'c')
-if meson.backend() == 'xcode'
- error('MESON_SKIP_TEST: whole-archive not supported in Xcode. Patches welcome.')
+if meson.backend() == 'xcode' or \
+ meson.backend() == 'vs2010' or \
+ meson.backend() == 'vs2012' or \
+ meson.backend() == 'vs2013'
+ error('MESON_SKIP_TEST: whole-archive not supported in Xcode nor pre-VS2015 IDE. Patches welcome.')
endif
add_project_arguments('-I' + meson.source_root(), language : 'c')
-if meson.backend() == 'vs2010'
- error('MESON_SKIP_TEST whole-archive not supported in VS2010. Patches welcome.')
-endif
-
# Test 1: link_whole keeps all symbols
# Make static func1
subdir('st_func1')
diff --git a/test cases/common/242 set and get variable/meson.build b/test cases/common/242 set and get variable/meson.build
new file mode 100644
index 0000000..6023e88
--- /dev/null
+++ b/test cases/common/242 set and get variable/meson.build
@@ -0,0 +1,63 @@
+project('set and get')
+
+var1 = 'test1.txt'
+var2 = files('test1.txt')[0]
+
+# Use is_disabler for accessing variables
+assert(var1 == 'test1.txt')
+assert(not is_disabler(var2))
+
+# Ensure that set variables behave correctly
+set_variable('var3', 'test2.txt')
+set_variable('var4', files('test2.txt')[0])
+
+assert(var3 == 'test2.txt')
+assert(not is_disabler(var4))
+
+# Test get_variable directly
+assert(get_variable('var1') == 'test1.txt')
+assert(not is_disabler(get_variable('var2')))
+assert(get_variable('var3') == 'test2.txt')
+assert(not is_disabler(get_variable('var4')))
+
+# Test get_variable indirectly
+
+var5 = get_variable('var1')
+var6 = get_variable('var2')
+var7 = get_variable('var3')
+var8 = get_variable('var4')
+set_variable('var9', get_variable('var7'))
+set_variable('var0', get_variable('var8'))
+
+assert(var5 == 'test1.txt')
+assert(not is_disabler(var6))
+assert(var7 == 'test2.txt')
+assert(not is_disabler(var8))
+assert(get_variable('var9') == 'test2.txt')
+assert(not is_disabler(get_variable('var0')))
+
+# test dict get
+dict = {'a': var2}
+
+dict_t1 = dict['a']
+dict_t2 = dict.get('a')
+dict_t3 = dict.get('a', var2)
+dict_t4 = dict.get('b', var2)
+
+assert(not is_disabler(dict_t1))
+assert(not is_disabler(dict_t2))
+assert(not is_disabler(dict_t3))
+assert(not is_disabler(dict_t4))
+
+# test lists
+list = [var2]
+
+list_t1 = list[0]
+list_t2 = list.get(0)
+list_t3 = list.get(0, var2)
+list_t4 = list.get(1, var2)
+
+assert(not is_disabler(list_t1))
+assert(not is_disabler(list_t2))
+assert(not is_disabler(list_t3))
+assert(not is_disabler(list_t4))
diff --git a/test cases/common/242 set and get variable/test1.txt b/test cases/common/242 set and get variable/test1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/242 set and get variable/test1.txt
diff --git a/test cases/common/242 set and get variable/test2.txt b/test cases/common/242 set and get variable/test2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/242 set and get variable/test2.txt
diff --git a/tools/run_with_cov.py b/tools/run_with_cov.py
new file mode 100755
index 0000000..17fb300
--- /dev/null
+++ b/tools/run_with_cov.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# Copyright 2021 The Meson development team
+
+# 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.
+
+import subprocess
+import coverage
+import os
+import sys
+from pathlib import Path
+
+root_path = Path(__file__).parent.parent.absolute()
+
+# Python magic so we can import mesonlib
+sys.path.append(root_path.as_posix())
+from mesonbuild import mesonlib
+
+def generate_coveragerc() -> Path:
+ i_file = (root_path / 'data' / '.coveragerc.in')
+ o_file = (root_path / '.coveragerc')
+ raw = i_file.read_text()
+ raw = raw.replace('@ROOT@', root_path.as_posix())
+ o_file.write_text(raw)
+ return o_file
+
+def main() -> int:
+ # Remove old run data
+ out_dir = root_path / '.coverage'
+ mesonlib.windows_proof_rmtree(out_dir.as_posix())
+ out_dir.mkdir(parents=True, exist_ok=True)
+
+ # Setup coverage
+ python_path = (root_path / 'ci').as_posix()
+ os.environ['PYTHONPATH'] = os.pathsep.join([python_path, os.environ.get('PYTHONPATH', '')])
+ os.environ['COVERAGE_PROCESS_START'] = generate_coveragerc().as_posix()
+ coverage.process_startup()
+
+ # Run the actual command
+ cmd = mesonlib.python_command + sys.argv[1:]
+ return subprocess.run(cmd, env=os.environ.copy()).returncode
+
+if __name__ == '__main__':
+ raise SystemExit(main())