diff options
98 files changed, 807 insertions, 488 deletions
diff --git a/.github/workflows/unusedargs_missingreturn.yml b/.github/workflows/unusedargs_missingreturn.yml index a75a6d5..c190af0 100644 --- a/.github/workflows/unusedargs_missingreturn.yml +++ b/.github/workflows/unusedargs_missingreturn.yml @@ -12,14 +12,21 @@ on: - "test cases/cmake/**" - "test cases/common/**" - "test cases/fortran/**" - - "test cases/platform-linux/**" + - "test cases/linuxlike/**" + - "test cases/objc/**" + - "test cases/objcpp/**" + - "test caes/windows/**" + pull_request: paths: - ".github/workflows/unusedargs_missingreturn.yml" - "test cases/cmake/**" - "test cases/common/**" - "test cases/fortran/**" - - "test cases/platform-linux/**" + - "test cases/linuxlike/**" + - "test cases/objc/**" + - "test cases/objcpp/**" + - "test caes/windows/**" jobs: @@ -33,9 +40,26 @@ jobs: - name: Install Compilers run: | sudo apt update -yq - sudo apt install -yq --no-install-recommends g++ gfortran ninja-build - - run: python run_project_tests.py --only cmake common fortran platform-linux + 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++" + env: + CFLAGS: "-Werror=unused-parameter -Werror=return-type -Werror=strict-prototypes" + CPPFLAGS: "-Werror=unused-parameter -Werror=return-type" + FFLAGS: "-fimplicit-none" + + windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - run: pip install ninja + - run: python run_project_tests.py --only platform-windows env: CFLAGS: "-Werror=unused-parameter -Werror=return-type -Werror=strict-prototypes" CPPFLAGS: "-Werror=unused-parameter -Werror=return-type" FFLAGS: "-fimplicit-none" + CC: gcc + CXX: g++ + FC: gfortran diff --git a/docs/genrelnotes.py b/docs/genrelnotes.py index e5ff432..70d8915 100755 --- a/docs/genrelnotes.py +++ b/docs/genrelnotes.py @@ -13,13 +13,17 @@ # 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 sys, os, subprocess +''' + Generates release notes for new releases of Meson build system +''' +import subprocess +import sys +import os from glob import glob -relnote_template = '''--- -title: Release %s -short-description: Release notes for %s +RELNOTE_TEMPLATE = '''--- +title: Release {} +short-description: Release notes for {} ... # New features @@ -28,21 +32,27 @@ short-description: Release notes for %s def add_to_sitemap(from_version, to_version): + ''' + Adds release note entry to sitemap.txt. + ''' sitemapfile = '../sitemap.txt' - sf = open(sitemapfile) - lines = sf.readlines() - sf.close() - with open(sitemapfile, 'w') as sf: + s_f = open(sitemapfile) + lines = s_f.readlines() + s_f.close() + with open(sitemapfile, 'w') as s_f: for line in lines: if 'Release-notes' in line and from_version in line: new_line = line.replace(from_version, to_version) - sf.write(new_line) - sf.write(line) + s_f.write(new_line) + s_f.write(line) def generate(from_version, to_version): - ofilename = 'Release-notes-for-%s.md' % to_version + ''' + Generate notes for Meson build next release. + ''' + ofilename = 'Release-notes-for-{}.md'.format(to_version) with open(ofilename, 'w') as ofile: - ofile.write(relnote_template % (to_version, to_version)) + ofile.write(RELNOTE_TEMPLATE.format(to_version, to_version)) for snippetfile in glob('snippets/*.md'): snippet = open(snippetfile).read() ofile.write(snippet) @@ -57,7 +67,7 @@ if __name__ == '__main__': if len(sys.argv) != 3: print(sys.argv[0], 'from_version to_version') sys.exit(1) - from_version = sys.argv[1] - to_version = sys.argv[2] + FROM_VERSION = sys.argv[1] + TO_VERSION = sys.argv[2] os.chdir('markdown') - generate(from_version, to_version) + generate(FROM_VERSION, TO_VERSION) diff --git a/docs/markdown/Continuous-Integration.md b/docs/markdown/Continuous-Integration.md index 13a9a00..0846f2d 100644 --- a/docs/markdown/Continuous-Integration.md +++ b/docs/markdown/Continuous-Integration.md @@ -6,20 +6,16 @@ Travis and AppVeyor. Please [file an issue](https://github.com/mesonbuild/meson/issues/new) if these instructions don't work for you. -## Travis for OS X and Linux (with Docker) +## Travis-CI with Docker -Travis for Linux provides ancient versions of Ubuntu which will likely -cause problems building your projects regardless of which build system -you're using. We recommend using Docker to get a more-recent version -of Ubuntu and installing Ninja, Python3, and Meson inside it. +Travis with Docker gives access to newer non-LTS Ubuntu versions with +pre-installed libraries of your choice. -This `yml` file is derived from the [configuration used by Meson for -running its own -tests](https://github.com/mesonbuild/meson/blob/master/.travis.yml). +This `yml` file is derived from the +[configuration used by Meson](https://github.com/mesonbuild/meson/blob/master/.travis.yml) +for running its own tests. ```yaml -sudo: false - os: - linux - osx @@ -34,10 +30,10 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python3 ninja; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pip3 install meson; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull YOUR/REPO:yakkety; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull YOUR/REPO:eoan; fi script: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM YOUR/REPO:yakkety > Dockerfile; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM YOUR/REPO:eoan > Dockerfile; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo ADD . /root >> Dockerfile; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -t withgit .; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true CC=$CC CXX=$CXX meson builddir && ninja -C builddir test"; fi @@ -46,7 +42,7 @@ script: ## CircleCi for Linux (with Docker) -[CircleCi](https://circleci.com/) can work for spinning all of the Linux images you wish. +[CircleCi](https://circleci.com/) can work for spinning all of the Linux images you wish. Here's a sample `yml` file for use with that. ```yaml @@ -59,7 +55,7 @@ executors: docker: - image: your_dockerhub_username/ubuntu-sys - meson_debain_builder: + meson_debian_builder: docker: - image: your_dockerhub_username/debian-sys @@ -76,8 +72,8 @@ jobs: - run: ninja -C builddir - run: meson test -C builddir - meson_debain_build: - executor: meson_debain_builder + meson_debian_build: + executor: meson_debian_builder steps: - checkout - run: meson setup builddir --backend ninja @@ -97,17 +93,20 @@ workflows: linux_workflow: jobs: - meson_ubuntu_build - - meson_debain_build + - meson_debian_build - meson_fedora_build ``` ## AppVeyor for Windows -For CI on Windows, [AppVeyor](https://www.appveyor.com/) is probably -your best bet. Here's a sample `yml` file for use with that. +For CI on Windows, [AppVeyor](https://www.appveyor.com/) has a wide selection of +[default configurations](https://www.appveyor.com/docs/windows-images-software/). +AppVeyor also has [MacOS](https://www.appveyor.com/docs/macos-images-software/) and +[Linux](https://www.appveyor.com/docs/linux-images-software/) CI images. +This is a sample `appveyor.yml` file for Windows with Visual Studio 2015 and 2017. ```yaml -os: Visual Studio 2017 +image: Visual Studio 2017 environment: matrix: @@ -148,9 +147,11 @@ test_script: ### Qt For Qt 5, add the following line near the `PYTHON_ROOT` assignment: + ```yaml - cmd: if %arch%==x86 (set QT_ROOT=C:\Qt\5.11\%compiler%) else (set QT_ROOT=C:\Qt\5.11\%compiler%_64) ``` + And afterwards add `%QT_ROOT%\bin` to the `PATH` variable. You might have to adjust your build matrix as there are, for example, no msvc2017 32-bit builds. Visit the [Build Environment](https://www.appveyor.com/docs/build-environment/) page in the AppVeyor docs for more details. @@ -158,35 +159,31 @@ You might have to adjust your build matrix as there are, for example, no msvc201 ### Boost The following statement is sufficient for meson to find Boost: + ```yaml - cmd: set BOOST_ROOT=C:\Libraries\boost_1_67_0 ``` ## Travis without Docker -You can cheat your way around docker by using **python** as language and setting your compiler in the build **matrix**. This example just uses **linux** and **c** but can be easily adapted to **c++** and **osx**. +Non-Docker Travis-CI builds can use Linux, MacOS or Windows. +Set the desired compiler(s) in the build **matrix**. +This example is for **Linux** (Ubuntu 18.04) and **C**. ```yaml -sudo: false +dist: bionic +group: travis_latest os: linux -dist: trusty - language: python -python: 3.6 - matrix: include: - env: CC=gcc - env: CC=clang install: - - export NINJA_LATEST=$(curl -s https://api.github.com/repos/ninja-build/ninja/releases/latest | grep browser_download_url | cut -d '"' -f 4 | grep ninja-linux.zip) - - wget "$NINJA_LATEST" - - unzip -q ninja-linux.zip -d build - - export PATH="$PWD/build:$PATH" - - pip install meson + - pip install meson ninja script: - meson builddir @@ -194,27 +191,80 @@ script: - ninja -C builddir test ``` -This setup uses the **beta** group. It is not recommended but included here for completeness: +## GitHub Actions -```yaml -sudo: false -language: cpp -group: beta +GitHub Actions are distinct from Azure Pipelines in their workflow syntax. +It can be easier to setup specific CI tasks in Actions than Pipelines, depending on the particular task. +This is an example file: .github/workflows/ci_meson.yml supposing the project is C-based, using GCC on Linux, Mac and Windows. +The optional `on:` parameters only run this CI when the C code is changed--corresponding ci_python.yml might run only on "**.py" file changes. -matrix: - include: - - os: linux - dist: trusty - - os: osx +```yml +name: ci_meson -install: - - export PATH="$(pwd)/build:${PATH}" - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install python3 ninja; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-linux.zip && unzip -q ninja-linux.zip -d build; fi - - pip3 install meson +on: + push: + paths: + - "**.c" + - "**.h" + pull_request: + paths: + - "**.h" + - "**.h" -script: - - meson builddir - - ninja -C builddir - - ninja -C builddir test +jobs: + + linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - run: pip install meson ninja + - run: meson setup build + env: + CC: gcc + - run: meson test -C build -v + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: Linux_Meson_Testlog + path: build/meson-logs/testlog.txt + + macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - run: brew install gcc + - run: pip install meson ninja + - run: meson setup build + env: + CC: gcc + - run: meson test -C build -v + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: MacOS_Meson_Testlog + path: build/meson-logs/testlog.txt + + windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - run: pip install meson ninja + - run: meson setup build + env: + CC: gcc + - run: meson test -C build -v + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: Windows_Meson_Testlog + path: build/meson-logs/testlog.txt ``` diff --git a/docs/markdown/D.md b/docs/markdown/D.md index ed8986b..39aebc8 100644 --- a/docs/markdown/D.md +++ b/docs/markdown/D.md @@ -74,6 +74,8 @@ my_lib = library('mylib', soversion: project_soversion, d_module_versions: ['FeatureA', 'featureB'] ) + +pkgc = import('pkgconfig') pkgc.generate(name: 'mylib', libraries: my_lib, subdirs: 'd/mylib', diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index dd0b3f4..5c5d164 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -151,9 +151,10 @@ Abort with an error message if `condition` evaluates to `false`. ``` Creates a benchmark item that will be run when the benchmark target is -run. The behavior of this function is identical to `test` with the -exception that there is no `is_parallel` keyword, because benchmarks -are never run in parallel. +run. The behavior of this function is identical to [`test()`](#test) except for: + +* benchmark() has no `is_parallel` keyword because benchmarks are not run in parallel +* benchmark() does not automatically add the `MALLOC_PERTURB_` environment variable *Note:* Prior to 0.52.0 benchmark would warn that `depends` and `priority` were unsupported, this is incorrect @@ -701,6 +702,9 @@ Keyword arguments are the following: If the output is more complicated than that, the version checking will have to be done manually using [`run_command()`](#run_command). +- `dirs` *(since 0.53.0)* Extra list of absolute paths where to look for program + names. + Meson will also autodetect scripts with a shebang line and run them with the executable/interpreter specified in it both on Windows (because the command invocator will reject the command otherwise) and @@ -1509,7 +1513,25 @@ object](#build-target-object) returned by object](#external-program-object) returned by [`find_program()`](#find_program). -Keyword arguments are the following: +By default, environment variable +[`MALLOC_PERTURB_`](http://man7.org/linux/man-pages/man3/mallopt.3.html) +is automatically set by `meson test` to a random value between 1..255. +This can help find memory leaks on configurations using glibc, +including with non-GCC compilers. However, this can have a performance impact, +and may fail a test due to external libraries whose internals are out of the +user's control. To check if this feature is causing an expected runtime crash, +disable the feature by temporarily setting environment variable +`MALLOC_PERTURB_=0`. While it's preferable to only temporarily disable this +check, if a project requires permanent disabling of this check +in meson.build do like: + +```meson +nomalloc = environment({'MALLOC_PERTURB_': '0'}) + +test(..., env: nomalloc, ...) +``` + +#### test() Keyword arguments - `args` arguments to pass to the executable diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md index b96e6e1..cf0516c 100644 --- a/docs/markdown/Syntax.md +++ b/docs/markdown/Syntax.md @@ -324,8 +324,8 @@ Dictionaries -- Dictionaries are delimited by curly braces. A dictionary can contain an -arbitrary number of key value pairs. Keys are required to be literal -strings, values can be objects of any type. +arbitrary number of key value pairs. Keys are required to be strings, values can +be objects of any type. Prior to *0.53.0* keys were required to be literal strings. ```meson my_dict = {'foo': 42, 'bar': 'baz'} @@ -359,6 +359,14 @@ if 'foo' not in my_dict endif ``` +*Since 0.53.0* Keys can be any expression evaluating to a string value, not limited +to string literals any more. +```meson +d = {'a' + 'b' : 42} +k = 'cd' +d += {k : 43} +``` + Function calls -- diff --git a/docs/markdown/Unit-tests.md b/docs/markdown/Unit-tests.md index 4b21699..066b57e 100644 --- a/docs/markdown/Unit-tests.md +++ b/docs/markdown/Unit-tests.md @@ -15,8 +15,7 @@ You can add as many tests as you want. They are run with the command `ninja test Meson captures the output of all tests and writes it in the log file `meson-logs/testlog.txt`. -Test parameters --- +## Test parameters Some tests require the use of command line arguments or environment variables. These are simple to define. @@ -27,15 +26,21 @@ test('envvar test', exe2, env : ['key1=value1', 'key2=value2']) Note how you need to specify multiple values as an array. -Coverage --- +### MALLOC_PERTURB_ + +By default, environment variable +[`MALLOC_PERTURB_`](http://man7.org/linux/man-pages/man3/mallopt.3.html) +is set to a random value between 1..255. This can help find memory +leaks on configurations using glibc, including with non-GCC compilers. +This feature can be disabled as discussed in [test()](./Reference-manual#test). + +## Coverage If you enable coverage measurements by giving Meson the command line flag `-Db_coverage=true`, you can generate coverage reports. Meson will autodetect what coverage generator tools you have installed and will generate the corresponding targets. These targets are `coverage-xml` and `coverage-text` which are both provided by [Gcovr](http://gcovr.com) (version 3.3 or higher) and `coverage-html`, which requires [Lcov](https://ltp.sourceforge.io/coverage/lcov.php) and [GenHTML](https://linux.die.net/man/1/genhtml) or [Gcovr](http://gcovr.com). As a convenience, a high-level `coverage` target is also generated which will produce all 3 coverage report types, if possible. The output of these commands is written to the log directory `meson-logs` in your build directory. -Parallelism --- +## Parallelism To reduce test times, Meson will by default run multiple unit tests in parallel. It is common to have some tests which can not be run in parallel because they require unique hold on some resource such as a file or a D-Bus name. You have to specify these tests with a keyword argument. @@ -51,8 +56,7 @@ By default Meson uses as many concurrent processes as there are cores on the tes $ MESON_TESTTHREADS=5 ninja test ``` -Priorities --- +## Priorities *(added in version 0.52.0)* diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md index 5cbef8a..7290a5b 100644 --- a/docs/markdown/Users.md +++ b/docs/markdown/Users.md @@ -65,6 +65,7 @@ listed in the [`meson` GitHub topic](https://github.com/topics/meson). - [Libepoxy](https://github.com/anholt/libepoxy/), a library for handling OpenGL function pointer management - [libfuse](https://github.com/libfuse/libfuse), the reference implementation of the Linux FUSE (Filesystem in Userspace) interface - [Libgit2-glib](https://git.gnome.org/browse/libgit2-glib), a GLib wrapper for libgit2 + - [libglvnd](https://gitlab.freedesktop.org/glvnd/libglvnd), Vendor neutral OpenGL dispatch library for Unix-like OSes - [Libhttpseverywhere](https://git.gnome.org/browse/libhttpseverywhere), a library to enable httpseverywhere on any desktop app - [libmodulemd](https://github.com/fedora-modularity/libmodulemd), a GObject Introspected library for managing [Fedora Project](https://getfedora.org/) module metadata. - [Libosmscout](https://github.com/Framstag/libosmscout), a C++ library for offline map rendering, routing and location @@ -77,6 +78,7 @@ format files - [Marker](https://github.com/fabiocolacio/Marker), a GTK-3 markdown editor - [Mesa](https://gitlab.freedesktop.org/mesa/mesa/), an open source graphics driver project - [MiracleCast](https://github.com/albfan/miraclecast), connect external monitors to your system via Wifi-Display specification aka Miracast + - [mrsh](https://github.com/emersion/mrsh), a minimal POSIX shell - [Nautilus](https://gitlab.gnome.org/GNOME/nautilus), the GNOME file manager - [Nemo](https://github.com/linuxmint/nemo), the file manager for the Cinnamon desktop environment - [oomd](https://github.com/facebookincubator/oomd), a userspace Out-Of-Memory (OOM) killer for Linux systems @@ -85,9 +87,11 @@ format files - [Orc](http://cgit.freedesktop.org/gstreamer/orc/), the Optimized Inner Loop Runtime Compiler (not the default yet) - [OTS](https://github.com/khaledhosny/ots), the OpenType Sanitizer, parses and serializes OpenType files (OTF, TTF) and WOFF and WOFF2 font files, validating and sanitizing them as it goes. Used by Chromium and Firefox - [Outlier](https://github.com/kerolasa/outlier), a small Hello World style meson example project + - [Pacman](https://git.archlinux.org/pacman.git/tree/), a package manager for Arch Linux - [Pango](https://git.gnome.org/browse/pango/), an Internationalized text layout and rendering library (not the default yet) - [Parzip](https://github.com/jpakkane/parzip), a multithreaded reimplementation of Zip - [Peek](https://github.com/phw/peek), simple animated GIF screen recorder with an easy to use interface + - [PicoLibc](https://github.com/keith-packard/picolibc), a standard C library for small embedded systems with limited RAM - [PipeWire](https://github.com/PipeWire/pipewire), a framework for video and audio for containerized applications - [Pithos](https://github.com/pithos/pithos), a Pandora Radio client - [Pitivi](https://github.com/pitivi/pitivi/), a nonlinear video editor diff --git a/docs/markdown/snippets/add_dictionary_variable_key.md b/docs/markdown/snippets/add_dictionary_variable_key.md index 373ce04..72294ae 100644 --- a/docs/markdown/snippets/add_dictionary_variable_key.md +++ b/docs/markdown/snippets/add_dictionary_variable_key.md @@ -1,17 +1,9 @@ -## Adding dictionary entry using string variable as key - -New dictionary entry can now be added using string variable as key, -in addition to using string literal as key. +## Dictionary entry using string variable as key +Keys can now be any expression evaluating to a string value, not limited +to string literals any more. ```meson -dict = {} - -# A variable to be used as a key -key = 'myKey' - -# Add new entry using the variable -dict += {key : 'myValue'} - -# Test that the stored value is correct -assert(dict[key] == 'myValue', 'Incorrect value retrieved from dictionary') +d = {'a' + 'b' : 42} +k = 'cd' +d += {k : 43} ``` diff --git a/docs/markdown/snippets/find_program.md b/docs/markdown/snippets/find_program.md new file mode 100644 index 0000000..2bef824 --- /dev/null +++ b/docs/markdown/snippets/find_program.md @@ -0,0 +1,9 @@ +## Search directories for `find_program()` + +It is now possible to give a list of absolute paths where `find_program()` should +also search, using the `dirs` keyword argument. + +For example on Linux `/sbin` and `/usr/sbin` are not always in the `$PATH`: +```meson +prog = find_program('mytool', dirs : ['/usr/sbin', '/sbin']) +``` @@ -40,7 +40,7 @@ def list_projects(): return 0 def unpack(sproj, branch, outdir): - subprocess.check_call(['git', 'clone', '-b', branch, 'https://github.com/mesonbuild/%s.git' % sproj, outdir]) + subprocess.check_call(['git', 'clone', '-b', branch, 'https://github.com/mesonbuild/{}.git'.format(sproj), outdir]) usfile = os.path.join(outdir, 'upstream.wrap') assert(os.path.isfile(usfile)) config = configparser.ConfigParser() @@ -82,7 +82,7 @@ def install(sproj): if os.path.isdir(sproj_dir): print('Subproject is already there. To update, nuke the dir and reinstall.') return 1 - blist = gh_get('https://api.github.com/repos/mesonbuild/%s/branches' % sproj) + blist = gh_get('https://api.github.com/repos/mesonbuild/{}/branches'.format(sproj)) blist = [b['name'] for b in blist] blist = [b for b in blist if b != 'master'] blist.sort() diff --git a/manual tests/1 wrap/main.c b/manual tests/1 wrap/main.c index 39d3a9a..df6abe4 100644 --- a/manual tests/1 wrap/main.c +++ b/manual tests/1 wrap/main.c @@ -1,7 +1,7 @@ #include<sqlite3.h> #include<stdio.h> -int main(int argc, char **argv) { +int main(void) { sqlite3 *db; if(sqlite3_open(":memory:", &db) != SQLITE_OK) { printf("Sqlite failed.\n"); diff --git a/manual tests/10 svn wrap/prog.c b/manual tests/10 svn wrap/prog.c index df38000..6e2c4d8 100644 --- a/manual tests/10 svn wrap/prog.c +++ b/manual tests/10 svn wrap/prog.c @@ -1,6 +1,6 @@ #include"subproj.h" -int main(int argc, char **argv) { +int main(void) { subproj_function(); return 0; } diff --git a/manual tests/11 wrap imposter/meson.build b/manual tests/11 wrap imposter/meson.build new file mode 100644 index 0000000..d0575ac --- /dev/null +++ b/manual tests/11 wrap imposter/meson.build @@ -0,0 +1,8 @@ +project('evil URL') +# showing that new Meson wrap.py code tries to stop imposter WrapDB URLs +# a WrapException is raised. +# +# ERROR: https://wrapdb.mesonbuild.com.invalid/v1/projects/zlib/1.2.11/4/get_zip may be a WrapDB-impersonating URL +# + +subproject('zlib')
\ No newline at end of file diff --git a/manual tests/11 wrap imposter/subprojects/zlib.wrap b/manual tests/11 wrap imposter/subprojects/zlib.wrap new file mode 100644 index 0000000..b88f8f2 --- /dev/null +++ b/manual tests/11 wrap imposter/subprojects/zlib.wrap @@ -0,0 +1,10 @@ +[wrap-file] +directory = zlib-1.2.8 + +source_url = https://zlib.net/zlib-1.2.11.tar.gz +source_filename = zlib-1.2.11.tar.gz +source_hash = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 + +patch_url = https://wrapdb.mesonbuild.com.invalid/v1/projects/zlib/1.2.11/4/get_zip +patch_filename = zlib-1.2.11-4-wrap.zip +patch_hash = 886b67480dbe73b406ad83a1dd6d9596f93089d90c220ccfc91944c95f1c68c4
\ No newline at end of file diff --git a/manual tests/12 wrap mirror/meson.build b/manual tests/12 wrap mirror/meson.build new file mode 100644 index 0000000..6645bdf --- /dev/null +++ b/manual tests/12 wrap mirror/meson.build @@ -0,0 +1,4 @@ +project('downloader') +# this test will timeout, showing that a subdomain isn't caught as masquarading url + +subproject('zlib') diff --git a/manual tests/12 wrap mirror/subprojects/zlib.wrap b/manual tests/12 wrap mirror/subprojects/zlib.wrap new file mode 100644 index 0000000..de0b9ad --- /dev/null +++ b/manual tests/12 wrap mirror/subprojects/zlib.wrap @@ -0,0 +1,10 @@ +[wrap-file] +directory = zlib-1.2.8 + +source_url = https://zlib.net/zlib-1.2.11.tar.gz +source_filename = zlib-1.2.11.tar.gz +source_hash = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 + +patch_url = https://mirror1.wrapdb.mesonbuild.com/v1/projects/zlib/1.2.11/4/get_zip +patch_filename = zlib-1.2.11-4-wrap.zip +patch_hash = 886b67480dbe73b406ad83a1dd6d9596f93089d90c220ccfc91944c95f1c68c4
\ No newline at end of file diff --git a/manual tests/3 git wrap/prog.c b/manual tests/3 git wrap/prog.c index df38000..6e2c4d8 100644 --- a/manual tests/3 git wrap/prog.c +++ b/manual tests/3 git wrap/prog.c @@ -1,6 +1,6 @@ #include"subproj.h" -int main(int argc, char **argv) { +int main(void) { subproj_function(); return 0; } diff --git a/manual tests/4 standalone binaries/myapp.cpp b/manual tests/4 standalone binaries/myapp.cpp index 5acde46..8ddff27 100644 --- a/manual tests/4 standalone binaries/myapp.cpp +++ b/manual tests/4 standalone binaries/myapp.cpp @@ -3,7 +3,7 @@ #include<iostream> #include<string> -int main(int argc, char *argv[]) { +int main(void) { SDL_Surface *screenSurface; SDL_Event e; int keepGoing = 1; diff --git a/manual tests/5 rpm/main.c b/manual tests/5 rpm/main.c index 5c46721..8b1d193 100644 --- a/manual tests/5 rpm/main.c +++ b/manual tests/5 rpm/main.c @@ -1,6 +1,6 @@ #include<lib.h> #include<stdio.h> -int main(int argc, char **argv) +int main(void) { char *t = meson_print(); printf("%s", t); diff --git a/manual tests/6 hg wrap/prog.c b/manual tests/6 hg wrap/prog.c index df38000..6e2c4d8 100644 --- a/manual tests/6 hg wrap/prog.c +++ b/manual tests/6 hg wrap/prog.c @@ -1,6 +1,6 @@ #include"subproj.h" -int main(int argc, char **argv) { +int main(void) { subproj_function(); return 0; } diff --git a/manual tests/8 timeout/sleepprog.c b/manual tests/8 timeout/sleepprog.c index e371482..8875e12 100644 --- a/manual tests/8 timeout/sleepprog.c +++ b/manual tests/8 timeout/sleepprog.c @@ -1,6 +1,6 @@ #include<unistd.h> -int main(int argc, char **argv) { +int main(void) { sleep(1000); return 0; } diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 3c5cdf0..8af692c 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -769,7 +769,6 @@ int dummy; elem = NinjaBuildElement(self.all_outputs, target_name, 'phony', []) elem.add_dep(deps) - cmd = self.replace_paths(target, cmd) self.add_build(elem) self.processed_targets[target.get_id()] = True @@ -1018,7 +1017,6 @@ int dummy; generated_sources = self.get_target_generated_sources(target) generated_rel_srcs = [] for rel_src in generated_sources.keys(): - dirpart, fnamepart = os.path.split(rel_src) if rel_src.lower().endswith('.cs'): generated_rel_srcs.append(os.path.normpath(rel_src)) deps.append(os.path.normpath(rel_src)) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 35bc450..645db24 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -355,6 +355,26 @@ a hard error in the future.''' % name) if not hasattr(self, 'typename'): raise RuntimeError('Target type is not set for target class "{}". This is a bug'.format(type(self).__name__)) + def __lt__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']: + if not hasattr(other, 'get_id') and not callable(other.get_id): + return NotImplemented + return self.get_id() < other.get_id() + + def __le__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']: + if not hasattr(other, 'get_id') and not callable(other.get_id): + return NotImplemented + return self.get_id() <= other.get_id() + + def __gt__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']: + if not hasattr(other, 'get_id') and not callable(other.get_id): + return NotImplemented + return self.get_id() > other.get_id() + + def __ge__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']: + if not hasattr(other, 'get_id') and not callable(other.get_id): + return NotImplemented + return self.get_id() >= other.get_id() + def get_install_dir(self, environment): # Find the installation directory. default_install_dir = self.get_default_install_dir(environment) @@ -411,7 +431,7 @@ a hard error in the future.''' % name) return self.construct_id_from_path( self.subdir, self.name, self.type_suffix()) - def process_kwargs(self, kwargs): + def process_kwargs_base(self, kwargs): if 'build_by_default' in kwargs: self.build_by_default = kwargs['build_by_default'] if not isinstance(self.build_by_default, bool): @@ -488,9 +508,6 @@ class BuildTarget(Target): self.validate_install(environment) self.check_module_linking() - def __lt__(self, other): - return self.get_id() < other.get_id() - def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.filename) @@ -789,7 +806,7 @@ class BuildTarget(Target): return self.install_mode def process_kwargs(self, kwargs, environment): - super().process_kwargs(kwargs) + self.process_kwargs_base(kwargs) self.copy_kwargs(kwargs) kwargs.get('modules', []) self.need_install = kwargs.get('install', self.need_install) @@ -1106,7 +1123,7 @@ You probably should put it in link_with instead.''') msg += "Use the 'pic' option to static_library to build with PIC." raise InvalidArguments(msg) if self.for_machine is not t.for_machine: - msg = 'Tried to mix libraries for machines {1} and {2} in target {!r}'.format(self.name, self.for_machine, t.for_machine) + msg = 'Tried to mix libraries for machines {1} and {2} in target {0!r}'.format(self.name, self.for_machine, t.for_machine) if self.environment.is_cross_build(): raise InvalidArguments(msg + ' This is not possible in a cross build.') else: @@ -2005,9 +2022,6 @@ class CustomTarget(Target): def get_default_install_dir(self, environment): return None - def __lt__(self, other): - return self.get_id() < other.get_id() - def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.command) @@ -2068,7 +2082,7 @@ class CustomTarget(Target): return final_cmd def process_kwargs(self, kwargs, backend): - super().process_kwargs(kwargs) + self.process_kwargs_base(kwargs) self.sources = extract_as_list(kwargs, 'input', unholder=True) if 'output' not in kwargs: raise InvalidArguments('Missing keyword argument "output".') @@ -2245,13 +2259,13 @@ class RunTarget(Target): self.args = args self.dependencies = dependencies - def __lt__(self, other): - return self.get_id() < other.get_id() - def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.command) + def process_kwargs(self, kwargs): + return self.process_kwargs_base(kwargs) + def get_dependencies(self): return self.dependencies diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index cb0416d..d9f1e18 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -199,8 +199,6 @@ class OutputTargetMap: return '__art_{}__'.format(os.path.basename(fname)) class ConverterTarget: - lang_cmake_to_meson = {val.lower(): key for key, val in language_map.items()} - def __init__(self, target: CMakeTarget, env: Environment): self.env = env self.artifacts = target.artifacts @@ -240,7 +238,8 @@ class ConverterTarget: for i in target.files: # Determine the meson language - lang = ConverterTarget.lang_cmake_to_meson.get(i.language.lower(), 'c') + lang_cmake_to_meson = {val.lower(): key for key, val in language_map.items()} + lang = lang_cmake_to_meson.get(i.language.lower(), 'c') if lang not in self.languages: self.languages += [lang] if lang not in self.compile_opts: diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 52a2788..09c53ea 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -13,8 +13,8 @@ # limitations under the License. import contextlib, os.path, re, tempfile +import collections.abc import typing -from typing import Optional, Tuple, List from ..linkers import StaticLinker, GnuLikeDynamicLinkerMixin, SolarisDynamicLinker from .. import coredata @@ -386,11 +386,12 @@ class RunResult: self.stdout = stdout self.stderr = stderr -class CompilerArgs(list): +class CompilerArgs(typing.MutableSequence[str]): ''' - Class derived from list() that manages a list of compiler arguments. Should - be used while constructing compiler arguments from various sources. Can be - operated with ordinary lists, so this does not need to be used everywhere. + List-like class that manages a list of compiler arguments. Should be used + while constructing compiler arguments from various sources. Can be + operated with ordinary lists, so this does not need to be used + everywhere. All arguments must be inserted and stored in GCC-style (-lfoo, -Idir, etc) and can converted to the native type of each compiler by using the @@ -439,37 +440,45 @@ class CompilerArgs(list): # In generate_link() we add external libs without de-dup, but we must # *always* de-dup these because they're special arguments to the linker always_dedup_args = tuple('-l' + lib for lib in unixy_compiler_internal_libs) - compiler = None - - def _check_args(self, args): - cargs = [] - if len(args) > 2: - raise TypeError("CompilerArgs() only accepts at most 2 arguments: " - "The compiler, and optionally an initial list") - elif not args: - return cargs - elif len(args) == 1: - if isinstance(args[0], (Compiler, StaticLinker)): - self.compiler = args[0] - else: - raise TypeError("you must pass a Compiler instance as one of " - "the arguments") - elif len(args) == 2: - if isinstance(args[0], (Compiler, StaticLinker)): - self.compiler = args[0] - cargs = args[1] - elif isinstance(args[1], (Compiler, StaticLinker)): - cargs = args[0] - self.compiler = args[1] - else: - raise TypeError("you must pass a Compiler instance as one of " - "the two arguments") - else: - raise AssertionError('Not reached') - return cargs - def __init__(self, *args): - super().__init__(self._check_args(args)) + def __init__(self, compiler: typing.Union['Compiler', StaticLinker], + iterable: typing.Optional[typing.Iterable[str]] = None): + self.compiler = compiler + self.__container = list(iterable) if iterable is not None else [] # type: typing.List[str] + + @typing.overload + def __getitem__(self, index: int) -> str: + pass + + @typing.overload + def __getitem__(self, index: slice) -> typing.List[str]: + pass + + def __getitem__(self, index): + return self.__container[index] + + @typing.overload + def __setitem__(self, index: int, value: str) -> None: + pass + + @typing.overload + def __setitem__(self, index: slice, value: typing.List[str]) -> None: + pass + + def __setitem__(self, index, value) -> None: + self.__container[index] = value + + def __delitem__(self, index: typing.Union[int, slice]) -> None: + del self.__container[index] + + def __len__(self) -> int: + return len(self.__container) + + def insert(self, index: int, value: str) -> None: + self.__container.insert(index, value) + + def copy(self) -> 'CompilerArgs': + return CompilerArgs(self.compiler, self.__container.copy()) @classmethod def _can_dedup(cls, arg): @@ -534,7 +543,7 @@ class CompilerArgs(list): # This covers all ld.bfd, ld.gold, ld.gold, and xild on Linux, which # all act like (or are) gnu ld # TODO: this could probably be added to the DynamicLinker instead - if (hasattr(self.compiler, 'linker') and + if (isinstance(self.compiler, Compiler) and self.compiler.linker is not None and isinstance(self.compiler.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker))): group_start = -1 @@ -554,7 +563,7 @@ class CompilerArgs(list): # Remove system/default include paths added with -isystem if hasattr(self.compiler, 'get_default_include_dirs'): default_dirs = self.compiler.get_default_include_dirs() - bad_idx_list = [] + bad_idx_list = [] # type: typing.List[int] for i, each in enumerate(new): # Remove the -isystem and the path if the path is a default path if (each == '-isystem' and @@ -567,9 +576,9 @@ class CompilerArgs(list): bad_idx_list += [i] for i in reversed(bad_idx_list): new.pop(i) - return self.compiler.unix_args_to_native(new) + return self.compiler.unix_args_to_native(new.__container) - def append_direct(self, arg): + def append_direct(self, arg: str) -> None: ''' Append the specified argument without any reordering or de-dup except for absolute paths to libraries, etc, which can always be de-duped @@ -578,9 +587,9 @@ class CompilerArgs(list): if os.path.isabs(arg): self.append(arg) else: - super().append(arg) + self.__container.append(arg) - def extend_direct(self, iterable): + def extend_direct(self, iterable: typing.Iterable[str]) -> None: ''' Extend using the elements in the specified iterable without any reordering or de-dup except for absolute paths where the order of @@ -589,7 +598,7 @@ class CompilerArgs(list): for elem in iterable: self.append_direct(elem) - def extend_preserving_lflags(self, iterable): + def extend_preserving_lflags(self, iterable: typing.Iterable[str]) -> None: normal_flags = [] lflags = [] for i in iterable: @@ -600,20 +609,20 @@ class CompilerArgs(list): self.extend(normal_flags) self.extend_direct(lflags) - def __add__(self, args): - new = CompilerArgs(self, self.compiler) + def __add__(self, args: typing.Iterable[str]) -> 'CompilerArgs': + new = self.copy() new += args return new - def __iadd__(self, args): + def __iadd__(self, args: typing.Iterable[str]) -> 'CompilerArgs': ''' Add two CompilerArgs while taking into account overriding of arguments and while preserving the order of arguments as much as possible ''' - pre = [] - post = [] - if not isinstance(args, list): - raise TypeError('can only concatenate list (not "{}") to list'.format(args)) + pre = [] # type: typing.List[str] + post = [] # type: typing.List[str] + if not isinstance(args, collections.abc.Iterable): + raise TypeError('can only concatenate Iterable[str] (not "{}") to CompilerArgs'.format(args)) for arg in args: # If the argument can be de-duped, do it either by removing the # previous occurrence of it and adding a new one, or not adding the @@ -638,29 +647,31 @@ class CompilerArgs(list): # Insert at the beginning self[:0] = pre # Append to the end - super().__iadd__(post) + self.__container += post return self - def __radd__(self, args): - new = CompilerArgs(args, self.compiler) + def __radd__(self, args: typing.Iterable[str]): + new = CompilerArgs(self.compiler, args) new += self return new - def __mul__(self, args): - raise TypeError("can't multiply compiler arguments") - - def __imul__(self, args): - raise TypeError("can't multiply compiler arguments") + def __eq__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']: + # Only allow equality checks against other CompilerArgs and lists instances + if isinstance(other, CompilerArgs): + return self.compiler == other.compiler and self.__container == other.__container + elif isinstance(other, list): + return self.__container == other + return NotImplemented - def __rmul__(self, args): - raise TypeError("can't multiply compiler arguments") - - def append(self, arg): + def append(self, arg: str) -> None: self.__iadd__([arg]) - def extend(self, args): + def extend(self, args: typing.Iterable[str]) -> None: self.__iadd__(args) + def __repr__(self) -> str: + return 'CompilerArgs({!r}, {!r})'.format(self.compiler, self.__container) + class Compiler: # Libraries to ignore in find_library() since they are provided by the # compiler or the C library. Currently only used for MSVC. @@ -726,7 +737,7 @@ class Compiler: def get_default_suffix(self) -> str: return self.default_suffix - def get_define(self, dname, prefix, env, extra_args, dependencies) -> Tuple[str, bool]: + def get_define(self, dname, prefix, env, extra_args, dependencies) -> typing.Tuple[str, bool]: raise EnvironmentException('%s does not support get_define ' % self.get_id()) def compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies) -> int: @@ -735,10 +746,12 @@ class Compiler: def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): raise EnvironmentException('%s does not support compute_parameters_with_absolute_paths ' % self.get_id()) - def has_members(self, typename, membernames, prefix, env, *, extra_args=None, dependencies=None) -> Tuple[bool, bool]: + def has_members(self, typename, membernames, prefix, env, *, + extra_args=None, dependencies=None) -> typing.Tuple[bool, bool]: raise EnvironmentException('%s does not support has_member(s) ' % self.get_id()) - def has_type(self, typename, prefix, env, extra_args, *, dependencies=None) -> Tuple[bool, bool]: + def has_type(self, typename, prefix, env, extra_args, *, + dependencies=None) -> typing.Tuple[bool, bool]: raise EnvironmentException('%s does not support has_type ' % self.get_id()) def symbols_have_underscore_prefix(self, env) -> bool: @@ -801,7 +814,7 @@ class Compiler: Returns a tuple of (compile_flags, link_flags) for the specified language from the inherited environment """ - def log_var(var, val: Optional[str]): + def log_var(var, val: typing.Optional[str]): if val: mlog.log('Appending {} from environment: {!r}'.format(var, val)) else: @@ -888,19 +901,19 @@ class Compiler: def get_option_link_args(self, options: 'OptionDictType') -> typing.List[str]: return self.linker.get_option_args(options) - def check_header(self, *args, **kwargs) -> Tuple[bool, bool]: + def check_header(self, *args, **kwargs) -> typing.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language()) - def has_header(self, *args, **kwargs) -> Tuple[bool, bool]: + def has_header(self, *args, **kwargs) -> typing.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language()) - def has_header_symbol(self, *args, **kwargs) -> Tuple[bool, bool]: + def has_header_symbol(self, *args, **kwargs) -> typing.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header symbol checks.' % self.get_display_language()) - def compiles(self, *args, **kwargs) -> Tuple[bool, bool]: + def compiles(self, *args, **kwargs) -> typing.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support compile checks.' % self.get_display_language()) - def links(self, *args, **kwargs) -> Tuple[bool, bool]: + def links(self, *args, **kwargs) -> typing.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support link checks.' % self.get_display_language()) def run(self, *args, **kwargs) -> RunResult: @@ -912,7 +925,7 @@ class Compiler: def alignment(self, *args, **kwargs) -> int: raise EnvironmentException('Language %s does not support alignment checks.' % self.get_display_language()) - def has_function(self, *args, **kwargs) -> Tuple[bool, bool]: + def has_function(self, *args, **kwargs) -> typing.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support function checks.' % self.get_display_language()) @classmethod @@ -934,12 +947,12 @@ class Compiler: def get_program_dirs(self, *args, **kwargs): return [] - def has_multi_arguments(self, args, env) -> Tuple[bool, bool]: + def has_multi_arguments(self, args, env) -> typing.Tuple[bool, bool]: raise EnvironmentException( 'Language {} does not support has_multi_arguments.'.format( self.get_display_language())) - def has_multi_link_arguments(self, args: typing.List[str], env: 'Environment') -> Tuple[bool, bool]: + def has_multi_link_arguments(self, args: typing.List[str], env: 'Environment') -> typing.Tuple[bool, bool]: return self.linker.has_multi_arguments(args, env) def _get_compile_output(self, dirname, mode): @@ -1138,16 +1151,16 @@ class Compiler: def remove_linkerlike_args(self, args): return [x for x in args if not x.startswith('-Wl')] - def get_lto_compile_args(self) -> List[str]: + def get_lto_compile_args(self) -> typing.List[str]: return [] - def get_lto_link_args(self) -> List[str]: + def get_lto_link_args(self) -> typing.List[str]: return self.linker.get_lto_args() - def sanitizer_compile_args(self, value: str) -> List[str]: + def sanitizer_compile_args(self, value: str) -> typing.List[str]: return [] - def sanitizer_link_args(self, value: str) -> List[str]: + def sanitizer_link_args(self, value: str) -> typing.List[str]: return self.linker.sanitizer_args(value) def get_asneeded_args(self) -> typing.List[str]: @@ -1163,7 +1176,8 @@ class Compiler: return self.linker.get_buildtype_args(buildtype) def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, - suffix: str, soversion: str, darwin_versions: typing.Tuple[str, str], + suffix: str, soversion: str, + darwin_versions: typing.Tuple[str, str], is_shared_module: bool) -> typing.List[str]: return self.linker.get_soname_args( env, prefix, shlib_name, suffix, soversion, diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 907aeec..e84a18f 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -613,6 +613,7 @@ class GnuDCompiler(DCompiler, GnuCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', is_cross, exe_wrapper, arch, **kwargs): DCompiler.__init__(self, exelist, version, for_machine, info, is_cross, exe_wrapper, arch, **kwargs) + GnuCompiler.__init__(self, {}) self.id = 'gcc' default_warn_args = ['-Wall', '-Wdeprecated'] self.warn_args = {'0': [], diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 3003fcd..f66ff38 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -13,9 +13,8 @@ # limitations under the License. from pathlib import Path -from typing import List +from typing import TYPE_CHECKING, List import subprocess, os -import typing from .. import coredata from .compilers import ( @@ -36,7 +35,7 @@ from mesonbuild.mesonlib import ( version_compare, EnvironmentException, MesonException, MachineChoice, LibType ) -if typing.TYPE_CHECKING: +if TYPE_CHECKING: from ..envconfig import MachineInfo @@ -192,7 +191,7 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): 'none')}) return opts - def get_option_compile_args(self, options) -> typing.List[str]: + def get_option_compile_args(self, options) -> List[str]: args = [] std = options['fortran_std'] if std.value != 'none': @@ -273,6 +272,7 @@ class SunFortranCompiler(FortranCompiler): class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): @@ -297,7 +297,7 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): 'none')}) return opts - def get_option_compile_args(self, options) -> typing.List[str]: + def get_option_compile_args(self, options) -> List[str]: args = [] std = options['fortran_std'] stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} @@ -317,7 +317,7 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): def language_stdlib_only_link_flags(self): return ['-lifcore', '-limf'] - def get_dependency_gen_args(self, outtarget: str, outfile: str) -> typing.List[str]: + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> List[str]: return ['-gen-dep=' + outtarget, '-gen-depformat=make'] @@ -326,15 +326,6 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): file_suffixes = ['f90', 'f', 'for', 'ftn', 'fpp'] always_args = ['/nologo'] - BUILD_ARGS = { - 'plain': [], - 'debug': ["/Zi", "/Od"], - 'debugoptimized': ["/Zi", "/O1"], - 'release': ["/O2"], - 'minsize': ["/Os"], - 'custom': [], - } - def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, target: str, info: 'MachineInfo', exe_wrapper=None, **kwargs): @@ -356,7 +347,7 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): 'none')}) return opts - def get_option_compile_args(self, options) -> typing.List[str]: + def get_option_compile_args(self, options) -> List[str]: args = [] std = options['fortran_std'] stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} @@ -367,9 +358,6 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): def get_module_outdir_args(self, path) -> List[str]: return ['/module:' + path] - def get_buildtype_args(self, buildtype: str) -> List[str]: - return self.BUILD_ARGS[buildtype] - class PathScaleFortranCompiler(FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, diff --git a/mesonbuild/compilers/mixins/arm.py b/mesonbuild/compilers/mixins/arm.py index 3a7e597..28708d5 100644 --- a/mesonbuild/compilers/mixins/arm.py +++ b/mesonbuild/compilers/mixins/arm.py @@ -143,7 +143,7 @@ class ArmclangCompiler: if ver_str: ver_str = ver_str.group(0) else: - mesonlib.EnvironmentException('armlink version string not found') + raise mesonlib.EnvironmentException('armlink version string not found') assert ver_str # makes mypy happy # Using the regular expression from environment.search_version, # which is used for searching compiler version diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index b5992ef..b5516b0 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -167,7 +167,6 @@ class CLikeCompiler: retval.append(d) # at this point, it's an ELF file which doesn't match the # appropriate elf_class, so skip this one - pass return tuple(retval) @functools.lru_cache() diff --git a/mesonbuild/compilers/mixins/elbrus.py b/mesonbuild/compilers/mixins/elbrus.py index 387c5b8..e157d87 100644 --- a/mesonbuild/compilers/mixins/elbrus.py +++ b/mesonbuild/compilers/mixins/elbrus.py @@ -19,18 +19,18 @@ import typing import subprocess import re -from .gnu import GnuCompiler +from .gnu import GnuLikeCompiler from ...mesonlib import Popen_safe if typing.TYPE_CHECKING: from ...environment import Environment -class ElbrusCompiler(GnuCompiler): +class ElbrusCompiler(GnuLikeCompiler): # Elbrus compiler is nearly like GCC, but does not support # PCH, LTO, sanitizers and color output as of version 1.21.x. def __init__(self, defines: typing.Dict[str, str]): - GnuCompiler.__init__(self, defines) + super().__init__() self.id = 'lcc' self.base_options = ['b_pgo', 'b_coverage', 'b_ndebug', 'b_staticpic', diff --git a/mesonbuild/compilers/mixins/intel.py b/mesonbuild/compilers/mixins/intel.py index 72c6fdf..cf26a14 100644 --- a/mesonbuild/compilers/mixins/intel.py +++ b/mesonbuild/compilers/mixins/intel.py @@ -14,8 +14,10 @@ """Abstractions for the Intel Compiler families. -Intel provides both a posix/gcc-like compiler (ICC) and an msvc-like compiler -(ICL). +Intel provides both a posix/gcc-like compiler (ICC) for MacOS and Linux, +with Meson mixin IntelGnuLikeCompiler. +For Windows, the Intel msvc-like compiler (ICL) Meson mixin +is IntelVisualStudioLikeCompiler. """ import os @@ -30,9 +32,18 @@ if typing.TYPE_CHECKING: # XXX: avoid circular dependencies # TODO: this belongs in a posix compiler class +# NOTE: the default Intel optimization is -O2, unlike GNU which defaults to -O0. +# this can be surprising, particularly for debug builds, so we specify the +# default as -O0. +# https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-o +# https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-g +# https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-o +# https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-g +# https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-traceback +# https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html clike_optimization_args = { - '0': [], - 'g': [], + '0': ['-O0'], + 'g': ['-O0'], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], @@ -43,6 +54,15 @@ clike_optimization_args = { # Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1, 19.0.0 class IntelGnuLikeCompiler(GnuLikeCompiler): + BUILD_ARGS = { + 'plain': [], + 'debug': ["-g", "-O0", "-traceback"], + 'debugoptimized': ["-g", "-O1", "-traceback"], + 'release': ["-O2"], + 'minsize': ["-Os"], + 'custom': [], + } + def __init__(self): super().__init__() # As of 19.0.0 ICC doesn't have sanitizer, color, or lto support. @@ -96,11 +116,23 @@ class IntelGnuLikeCompiler(GnuLikeCompiler): def get_profile_use_args(self) -> typing.List[str]: return ['-prof-use'] + def get_buildtype_args(self, buildtype: str) -> typing.List[str]: + return self.BUILD_ARGS[buildtype] + class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler): """Abstractions for ICL, the Intel compiler on Windows.""" + BUILD_ARGS = { + 'plain': [], + 'debug': ["/Zi", "/Od", "/traceback"], + 'debugoptimized': ["/Zi", "/O1", "/traceback"], + 'release': ["/O2"], + 'minsize': ["/Os"], + 'custom': [], + } + def __init__(self, target: str): super().__init__(target) self.id = 'intel-cl' @@ -133,3 +165,6 @@ class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler): def openmp_flags(self) -> typing.List[str]: return ['/Qopenmp'] + + def get_buildtype_args(self, buildtype: str) -> typing.List[str]: + return self.BUILD_ARGS[buildtype] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index a5898f1..bb1d277 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -27,16 +27,16 @@ import ast import argparse import configparser from typing import ( - Any, Dict, Generic, Iterable, List, Optional, Type, TypeVar, Union + Any, Dict, Generic, Iterable, Iterator, List, MutableMapping, Optional, Tuple, Type, TypeVar, Union, + TYPE_CHECKING, ) -import typing import enum import shlex -if typing.TYPE_CHECKING: +if TYPE_CHECKING: from . import dependencies - OptionDictType = typing.Dict[str, 'UserOption[Any]'] + OptionDictType = Dict[str, 'UserOption[Any]'] version = '0.52.999' backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode'] @@ -170,7 +170,7 @@ class UserArrayOption(UserOption[List[str]]): self.allow_dups = allow_dups self.value = self.validate_value(value, user_input=user_input) - def validate_value(self, value, user_input=True) -> List[str]: + def validate_value(self, value, user_input: bool = True) -> List[str]: # User input is for options defined on the command line (via -D # options). Users can put their input in as a comma separated # string, but for defining options in meson_options.txt the format @@ -180,7 +180,10 @@ class UserArrayOption(UserOption[List[str]]): if isinstance(value, str): if value.startswith('['): - newvalue = ast.literal_eval(value) + try: + newvalue = ast.literal_eval(value) + except ValueError: + raise MesonException('malformed option {}'.format(value)) elif value == '': newvalue = [] else: @@ -191,7 +194,7 @@ class UserArrayOption(UserOption[List[str]]): elif isinstance(value, list): newvalue = value else: - raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue))) + raise MesonException('"{}" should be a string array, but it is not'.format(newvalue)) if not self.allow_dups and len(set(newvalue)) != len(newvalue): msg = 'Duplicated values in array option is deprecated. ' \ @@ -231,9 +234,9 @@ def load_configs(filenames: List[str]) -> configparser.ConfigParser: return config -if typing.TYPE_CHECKING: - CacheKeyType = typing.Tuple[typing.Tuple[typing.Any, ...], ...] - SubCacheKeyType = typing.Tuple[typing.Any, ...] +if TYPE_CHECKING: + CacheKeyType = Tuple[Tuple[Any, ...], ...] + SubCacheKeyType = Tuple[Any, ...] class DependencyCacheType(enum.Enum): @@ -257,7 +260,7 @@ class DependencySubCache: def __init__(self, type_: DependencyCacheType): self.types = [type_] - self.__cache = {} # type: typing.Dict[SubCacheKeyType, dependencies.Dependency] + self.__cache = {} # type: Dict[SubCacheKeyType, dependencies.Dependency] def __getitem__(self, key: 'SubCacheKeyType') -> 'dependencies.Dependency': return self.__cache[key] @@ -268,7 +271,7 @@ class DependencySubCache: def __contains__(self, key: 'SubCacheKeyType') -> bool: return key in self.__cache - def values(self) -> typing.Iterable['dependencies.Dependency']: + def values(self) -> Iterable['dependencies.Dependency']: return self.__cache.values() @@ -280,12 +283,12 @@ class DependencyCache: successfully lookup by providing a simple get/put interface. """ - def __init__(self, builtins_per_machine: PerMachine[typing.Dict[str, UserOption[typing.Any]]], for_machine: MachineChoice): - self.__cache = OrderedDict() # type: typing.MutableMapping[CacheKeyType, DependencySubCache] + def __init__(self, builtins_per_machine: PerMachine[Dict[str, UserOption[Any]]], for_machine: MachineChoice): + self.__cache = OrderedDict() # type: MutableMapping[CacheKeyType, DependencySubCache] self.__builtins_per_machine = builtins_per_machine self.__for_machine = for_machine - def __calculate_subkey(self, type_: DependencyCacheType) -> typing.Tuple[typing.Any, ...]: + def __calculate_subkey(self, type_: DependencyCacheType) -> Tuple[Any, ...]: if type_ is DependencyCacheType.PKG_CONFIG: return tuple(self.__builtins_per_machine[self.__for_machine]['pkg_config_path'].value) elif type_ is DependencyCacheType.CMAKE: @@ -293,7 +296,7 @@ class DependencyCache: assert type_ is DependencyCacheType.OTHER, 'Someone forgot to update subkey calculations for a new type' return tuple() - def __iter__(self) -> typing.Iterator['CacheKeyType']: + def __iter__(self) -> Iterator['CacheKeyType']: return self.keys() def put(self, key: 'CacheKeyType', dep: 'dependencies.Dependency') -> None: @@ -303,7 +306,7 @@ class DependencyCache: subkey = self.__calculate_subkey(t) self.__cache[key][subkey] = dep - def get(self, key: 'CacheKeyType') -> typing.Optional['dependencies.Dependency']: + def get(self, key: 'CacheKeyType') -> Optional['dependencies.Dependency']: """Get a value from the cache. If there is no cache entry then None will be returned. @@ -321,14 +324,14 @@ class DependencyCache: pass return None - def values(self) -> typing.Iterator['dependencies.Dependency']: + def values(self) -> Iterator['dependencies.Dependency']: for c in self.__cache.values(): yield from c.values() - def keys(self) -> typing.Iterator['CacheKeyType']: + def keys(self) -> Iterator['CacheKeyType']: return iter(self.__cache.keys()) - def items(self) -> typing.Iterator[typing.Tuple['CacheKeyType', typing.List['dependencies.Dependency']]]: + def items(self) -> Iterator[Tuple['CacheKeyType', List['dependencies.Dependency']]]: for k, v in self.__cache.items(): vs = [] for t in v.types: @@ -390,9 +393,9 @@ class CoreData: if not filenames: return [] - found_invalid = [] # type: typing.List[str] - missing = [] # type: typing.List[str] - real = [] # type: typing.List[str] + found_invalid = [] # type: List[str] + missing = [] # type: List[str] + real = [] # type: List[str] for i, f in enumerate(filenames): f = os.path.expanduser(os.path.expandvars(f)) if os.path.exists(f): @@ -618,8 +621,7 @@ class CoreData: except MesonException as e: raise type(e)(('Validation failed for option %s: ' % option_name) + str(e)) \ .with_traceback(sys.exc_info()[2]) - else: - raise MesonException('Tried to validate unknown option %s.' % option_name) + raise MesonException('Tried to validate unknown option %s.' % option_name) def get_external_args(self, for_machine: MachineChoice, lang): return self.compiler_options[for_machine][lang + '_args'].value @@ -659,7 +661,6 @@ class CoreData: if not self.is_cross_build(): options = self.strip_build_option_names(options) # Set prefix first because it's needed to sanitize other options - prefix = self.builtins['prefix'].value if 'prefix' in options: prefix = self.sanitize_prefix(options['prefix']) self.builtins['prefix'].set_value(prefix) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 13f2470..e0f68be 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -23,8 +23,7 @@ import shlex import shutil import textwrap import platform -import typing -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Optional, Tuple, Type, Union from enum import Enum from pathlib import Path, PurePath @@ -208,8 +207,8 @@ class Dependency: """ raise RuntimeError('Unreachable code in partial_dependency called') - def _add_sub_dependency(self, dep_type: typing.Type['Dependency'], env: Environment, - kwargs: typing.Dict[str, typing.Any], *, + def _add_sub_dependency(self, dep_type: Type['Dependency'], env: Environment, + kwargs: Dict[str, Any], *, method: DependencyMethods = DependencyMethods.AUTO) -> None: """Add an internal dependency of of the given type. @@ -222,14 +221,14 @@ class Dependency: kwargs['method'] = method self.ext_deps.append(dep_type(env, kwargs)) - def get_variable(self, *, cmake: typing.Optional[str] = None, pkgconfig: typing.Optional[str] = None, - configtool: typing.Optional[str] = None, default_value: typing.Optional[str] = None, - pkgconfig_define: typing.Optional[typing.List[str]] = None) -> typing.Union[str, typing.List[str]]: + def get_variable(self, *, cmake: Optional[str] = None, pkgconfig: Optional[str] = None, + configtool: Optional[str] = None, default_value: Optional[str] = None, + pkgconfig_define: Optional[List[str]] = None) -> Union[str, List[str]]: if default_value is not None: return default_value raise DependencyException('No default provided for dependency {!r}, which is not pkg-config, cmake, or config-tool based.'.format(self)) - def generate_system_dependency(self, include_type: str) -> typing.Type['Dependency']: + def generate_system_dependency(self, include_type: str) -> Type['Dependency']: new_dep = copy.deepcopy(self) new_dep.include_type = self._process_include_type_kw({'include_type': include_type}) return new_dep @@ -274,7 +273,10 @@ class InternalDependency(Dependency): class HasNativeKwarg: def __init__(self, kwargs): - self.for_machine = MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST + self.for_machine = self.get_for_machine_from_kwargs(kwargs) + + def get_for_machine_from_kwargs(self, kwargs): + return MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST class ExternalDependency(Dependency, HasNativeKwarg): def __init__(self, type_name, environment, language, kwargs): @@ -550,9 +552,9 @@ class ConfigToolDependency(ExternalDependency): def log_tried(self): return self.type_name - def get_variable(self, *, cmake: typing.Optional[str] = None, pkgconfig: typing.Optional[str] = None, - configtool: typing.Optional[str] = None, default_value: typing.Optional[str] = None, - pkgconfig_define: typing.Optional[typing.List[str]] = None) -> typing.Union[str, typing.List[str]]: + def get_variable(self, *, cmake: Optional[str] = None, pkgconfig: Optional[str] = None, + configtool: Optional[str] = None, default_value: Optional[str] = None, + pkgconfig_define: Optional[List[str]] = None) -> Union[str, List[str]]: if configtool: # In the not required case '' (empty string) will be returned if the # variable is not found. Since '' is a valid value to return we @@ -987,9 +989,9 @@ class PkgConfigDependency(ExternalDependency): def log_tried(self): return self.type_name - def get_variable(self, *, cmake: typing.Optional[str] = None, pkgconfig: typing.Optional[str] = None, - configtool: typing.Optional[str] = None, default_value: typing.Optional[str] = None, - pkgconfig_define: typing.Optional[typing.List[str]] = None) -> typing.Union[str, typing.List[str]]: + def get_variable(self, *, cmake: Optional[str] = None, pkgconfig: Optional[str] = None, + configtool: Optional[str] = None, default_value: Optional[str] = None, + pkgconfig_define: Optional[List[str]] = None) -> Union[str, List[str]]: if pkgconfig: kwargs = {} if default_value is not None: @@ -1482,9 +1484,9 @@ class CMakeDependency(ExternalDependency): return 'modules: ' + ', '.join(modules) return '' - def get_variable(self, *, cmake: typing.Optional[str] = None, pkgconfig: typing.Optional[str] = None, - configtool: typing.Optional[str] = None, default_value: typing.Optional[str] = None, - pkgconfig_define: typing.Optional[typing.List[str]] = None) -> typing.Union[str, typing.List[str]]: + def get_variable(self, *, cmake: Optional[str] = None, pkgconfig: Optional[str] = None, + configtool: Optional[str] = None, default_value: Optional[str] = None, + pkgconfig_define: Optional[List[str]] = None) -> Union[str, List[str]]: if cmake: try: v = self.traceparser.vars[cmake] @@ -1699,13 +1701,20 @@ class ExternalProgram: # An 'ExternalProgram' always runs on the build machine for_machine = MachineChoice.BUILD - def __init__(self, name: str, command: typing.Optional[typing.List[str]] = None, - silent: bool = False, search_dir: typing.Optional[str] = None): + def __init__(self, name: str, command: Optional[List[str]] = None, + silent: bool = False, search_dir: Optional[str] = None, + extra_search_dirs: Optional[List[str]] = None): self.name = name if command is not None: self.command = listify(command) else: - self.command = self._search(name, search_dir) + all_search_dirs = [search_dir] + if extra_search_dirs: + all_search_dirs += extra_search_dirs + for d in all_search_dirs: + self.command = self._search(name, d) + if self.found(): + break # Set path to be the last item that is actually a file (in order to # skip options in something like ['python', '-u', 'file.py']. If we @@ -1718,7 +1727,9 @@ class ExternalProgram: break if not silent: - if self.found(): + # ignore the warning because derived classes never call this __init__ + # method, and thus only the found() method of this class is ever executed + if self.found(): # lgtm [py/init-calls-subclass] mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'), '(%s)' % ' '.join(self.command)) else: @@ -1796,7 +1807,6 @@ class ExternalProgram: return commands + [script] except Exception as e: mlog.debug(e) - pass mlog.debug('Unusable script {!r}'.format(script)) return False @@ -1900,7 +1910,7 @@ class ExternalProgram: return self.name -class NonExistingExternalProgram(ExternalProgram): +class NonExistingExternalProgram(ExternalProgram): # lgtm [py/missing-call-to-init] "A program that will never exist" def __init__(self, name='nonexistingprogram'): @@ -1916,7 +1926,7 @@ class NonExistingExternalProgram(ExternalProgram): return False -class EmptyExternalProgram(ExternalProgram): +class EmptyExternalProgram(ExternalProgram): # lgtm [py/missing-call-to-init] ''' A program object that returns an empty list of commands. Used for cases such as a cross file exe_wrapper to represent that it's not required. diff --git a/mesonbuild/dependencies/cuda.py b/mesonbuild/dependencies/cuda.py index 67b361f..7048e81 100644 --- a/mesonbuild/dependencies/cuda.py +++ b/mesonbuild/dependencies/cuda.py @@ -20,7 +20,7 @@ from .. import mlog from .. import mesonlib from ..environment import detect_cpu_family -from .base import (DependencyException, ExternalDependency, HasNativeKwarg) +from .base import (DependencyException, ExternalDependency) class CudaDependency(ExternalDependency): @@ -28,8 +28,7 @@ class CudaDependency(ExternalDependency): supported_languages = ['cuda', 'cpp', 'c'] # see also _default_language def __init__(self, environment, kwargs): - HasNativeKwarg.__init__(self, kwargs) # initialize self.for_machine - compilers = environment.coredata.compilers[self.for_machine] + compilers = environment.coredata.compilers[self.get_for_machine_from_kwargs(kwargs)] language = self._detect_language(compilers) if language not in self.supported_languages: raise DependencyException('Language \'{}\' is not supported by the CUDA Toolkit. Supported languages are {}.'.format(language, self.supported_languages)) @@ -94,7 +93,7 @@ class CudaDependency(ExternalDependency): defaults = [(path, version) for (path, version, default) in paths if default] if defaults: - return (*defaults[0], True) + return (defaults[0][0], defaults[0][1], True) platform_msg = 'set the CUDA_PATH environment variable' if self._is_windows() \ else 'set the CUDA_PATH environment variable/create the \'/usr/local/cuda\' symbolic link' diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 894bfdc..15907d4 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -25,7 +25,7 @@ from ..mesonlib import version_compare, stringlistify, extract_as_list, MachineC from ..environment import get_llvm_tool_names from .base import ( DependencyException, DependencyMethods, ExternalDependency, PkgConfigDependency, - strip_system_libdirs, ConfigToolDependency, CMakeDependency, HasNativeKwarg + strip_system_libdirs, ConfigToolDependency, CMakeDependency ) from .misc import ThreadDependency @@ -205,17 +205,13 @@ class LLVMDependencyConfigTool(ConfigToolDependency): __cpp_blacklist = {'-DNDEBUG'} def __init__(self, environment, kwargs): - # Already called by `super().__init__`, but need `self.for_machine` - # before `super().__init__` is called. - HasNativeKwarg.__init__(self, kwargs) - self.tools = get_llvm_tool_names('llvm-config') # Fedora starting with Fedora 30 adds a suffix of the number # of bits in the isa that llvm targets, for example, on x86_64 # and aarch64 the name will be llvm-config-64, on x86 and arm # it will be llvm-config-32. - if environment.machines[self.for_machine].is_64_bit: + if environment.machines[self.get_for_machine_from_kwargs(kwargs)].is_64_bit: self.tools.append('llvm-config-64') else: self.tools.append('llvm-config-32') diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 638bc68..bdcc4a7 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -605,16 +605,14 @@ class VulkanDependency(ExternalDependency): # TODO: this config might not work on some platforms, fix bugs as reported # we should at least detect other 64-bit platforms (e.g. armv8) lib_name = 'vulkan' + lib_dir = 'lib' + inc_dir = 'include' if mesonlib.is_windows(): lib_name = 'vulkan-1' lib_dir = 'Lib32' inc_dir = 'Include' if detect_cpu_family(self.env.coredata.compilers.host) == 'x86_64': lib_dir = 'Lib' - else: - lib_name = 'vulkan' - lib_dir = 'lib' - inc_dir = 'include' # make sure header and lib are valid inc_path = os.path.join(self.vulkan_sdk, inc_dir) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index d81f34f..905a218 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -1385,10 +1385,18 @@ class Environment: linker = ClangClDynamicLinker(for_machine, version=search_version(o)) else: with tempfile.NamedTemporaryFile(suffix='.d') as f: + # LDC writes an object file to the current working directory. + # Clean it up. + objectfile = os.path.basename(f.name)[:-1] + 'o' linker = self._guess_nix_linker( exelist, for_machine, compilers.LLVMDCompiler.LINKER_PREFIX, extra_args=[f.name]) + try: + os.unlink(objectfile) + except Exception: + # Thank you Windows file system semantics and virus scanners. + pass return compilers.LLVMDCompiler( exelist, version, for_machine, info, arch, full_version=full_version, linker=linker) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 7388e91..d3a40f7 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -119,6 +119,18 @@ def extract_required_kwarg(kwargs, subproject, feature_check=None, default=True) return disabled, required, feature +def extract_search_dirs(kwargs): + search_dirs = mesonlib.stringlistify(kwargs.get('dirs', [])) + search_dirs = [Path(d).expanduser() for d in search_dirs] + for d in search_dirs: + if mesonlib.is_windows() and d.root.startswith('\\'): + # a Unix-path starting with `/` that is not absolute on Windows. + # discard without failing for end-user ease of cross-platform directory arrays + continue + if not d.is_absolute(): + raise InvalidCode('Search directory {} is not an absolute path.'.format(d)) + return list(map(str, search_dirs)) + class TryRunResultHolder(InterpreterObject): def __init__(self, res): super().__init__() @@ -882,10 +894,10 @@ class CustomTargetHolder(TargetHolder): def __getitem__(self, index): return CustomTargetIndexHolder(self.held_object[index]) - def __setitem__(self, index, value): + def __setitem__(self, index, value): # lgtm[py/unexpected-raise-in-special-method] raise InterpreterException('Cannot set a member of a CustomTarget') - def __delitem__(self, index): + def __delitem__(self, index): # lgtm[py/unexpected-raise-in-special-method] raise InterpreterException('Cannot delete a member of a CustomTarget') def outdir_include(self): @@ -1554,16 +1566,7 @@ class CompilerHolder(InterpreterObject): if not self.has_header_method([h], has_header_kwargs): return self.notfound_library(libname) - search_dirs = mesonlib.stringlistify(kwargs.get('dirs', [])) - search_dirs = [Path(d).expanduser() for d in search_dirs] - for d in search_dirs: - if mesonlib.is_windows() and d.root.startswith('\\'): - # a Unix-path starting with `/` that is not absolute on Windows. - # discard without failing for end-user ease of cross-platform directory arrays - continue - if not d.is_absolute(): - raise InvalidCode('Search directory {} is not an absolute path.'.format(d)) - search_dirs = list(map(str, search_dirs)) + search_dirs = extract_search_dirs(kwargs) libtype = mesonlib.LibType.PREFER_SHARED if 'static' in kwargs: @@ -2036,7 +2039,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'}, 'version', }, 'executable': build.known_exe_kwargs, - 'find_program': {'required', 'native', 'version'}, + 'find_program': {'required', 'native', 'version', 'dirs'}, 'generator': {'arguments', 'output', 'depends', @@ -2896,7 +2899,7 @@ external dependencies (including libraries) must go to "dependencies".''') return ExternalProgramHolder(prog) return None - def program_from_system(self, args, silent=False): + def program_from_system(self, args, search_dirs, silent=False): # Search for scripts relative to current subdir. # Do not cache found programs because find_program('foobar') # might give different results when run from different source dirs. @@ -2910,12 +2913,15 @@ external dependencies (including libraries) must go to "dependencies".''') search_dir = os.path.join(self.environment.get_source_dir(), exename.subdir) exename = exename.fname + extra_search_dirs = [] elif isinstance(exename, str): search_dir = source_dir + extra_search_dirs = search_dirs else: raise InvalidArguments('find_program only accepts strings and ' 'files, not {!r}'.format(exename)) extprog = dependencies.ExternalProgram(exename, search_dir=search_dir, + extra_search_dirs=extra_search_dirs, silent=silent) progobj = ExternalProgramHolder(extprog) if progobj.found(): @@ -2949,7 +2955,8 @@ external dependencies (including libraries) must go to "dependencies".''') # TODO update modules to always pass `for_machine`. It is bad-form to assume # the host machine. - def find_program_impl(self, args, for_machine: MachineChoice = MachineChoice.HOST, required=True, silent=True, wanted=''): + def find_program_impl(self, args, for_machine: MachineChoice = MachineChoice.HOST, + required=True, silent=True, wanted='', search_dirs=None): if not isinstance(args, list): args = [args] @@ -2957,7 +2964,7 @@ external dependencies (including libraries) must go to "dependencies".''') if progobj is None: progobj = self.program_from_file_for(for_machine, args, silent=silent) if progobj is None: - progobj = self.program_from_system(args, silent=silent) + progobj = self.program_from_system(args, search_dirs, silent=silent) if progobj is None and args[0].endswith('python3'): prog = dependencies.ExternalProgram('python3', mesonlib.python_command, silent=True) progobj = ExternalProgramHolder(prog) @@ -2980,6 +2987,7 @@ external dependencies (including libraries) must go to "dependencies".''') return ExternalProgramHolder(dependencies.NonExistingExternalProgram()) return progobj + @FeatureNewKwargs('find_program', '0.53.0', ['dirs']) @FeatureNewKwargs('find_program', '0.52.0', ['version']) @FeatureNewKwargs('find_program', '0.49.0', ['disabler']) @disablerIfNotFound @@ -2993,11 +3001,12 @@ external dependencies (including libraries) must go to "dependencies".''') mlog.log('Program', mlog.bold(' '.join(args)), 'skipped: feature', mlog.bold(feature), 'disabled') return ExternalProgramHolder(dependencies.NonExistingExternalProgram()) - if not isinstance(required, bool): - raise InvalidArguments('"required" argument must be a boolean.') + search_dirs = extract_search_dirs(kwargs) wanted = mesonlib.stringlistify(kwargs.get('version', [])) for_machine = self.machine_from_native_kwarg(kwargs) - return self.find_program_impl(args, for_machine, required=required, silent=False, wanted=wanted) + return self.find_program_impl(args, for_machine, required=required, + silent=False, wanted=wanted, + search_dirs=search_dirs) def func_find_library(self, node, args, kwargs): raise InvalidCode('find_library() is removed, use meson.get_compiler(\'name\').find_library() instead.\n' diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 46f578e..2a976d3 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -496,7 +496,19 @@ class InterpreterBase: def evaluate_dictstatement(self, cur): (arguments, kwargs) = self.reduce_arguments(cur.args) assert (not arguments) - return kwargs + result = {} + self.argument_depth += 1 + for key, value in kwargs.items(): + if not isinstance(key, mparser.StringNode): + FeatureNew('Dictionary entry using non literal key', '0.53.0').use(self.subproject) + key = self.evaluate_statement(key) + if not isinstance(key, str): + raise InvalidArguments('Key must be a string') + if key in result: + raise InvalidArguments('Duplicate dictionary key: {}'.format(key)) + result[key] = value + self.argument_depth -= 1 + return result def evaluate_notstatement(self, cur): v = self.evaluate_statement(cur.value) @@ -731,16 +743,7 @@ The result of this is undefined and will become a hard error in a future Meson r elif isinstance(old_variable, dict): if not isinstance(addition, dict): raise InvalidArguments('The += operator requires a dict on the right hand side if the variable on the left is a dict') - new_addition = {} - for (key, value) in addition.items(): - if isinstance(key, str): - new_addition[key] = value - elif isinstance(key, mparser.IdNode) and isinstance(self.get_variable(key.value), str): - FeatureNew('Adding dictionary entry using string variable as key', '0.53.0').use(self.subproject) - new_addition[self.get_variable(key.value)] = value - else: - raise InvalidArguments('Dictionary key must be a string or string variable') - new_value = {**old_variable, **new_addition} + new_value = {**old_variable, **addition} # Add other data types here. else: raise InvalidArguments('The += operator currently only works with arrays, dicts, strings or ints ') diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index 3251845..41dd929 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -153,7 +153,7 @@ class ArLinker(StaticLinker): return [target] -class ArmarLinker(ArLinker): +class ArmarLinker(ArLinker): # lgtm [py/missing-call-to-init] def __init__(self, exelist: typing.List[str]): StaticLinker.__init__(self, exelist) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index a19b2cf..0d8ec3c 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -1416,8 +1416,14 @@ class LibType(Enum): PREFER_STATIC = 3 -class ProgressBarFallback: - '''Fallback progress bar implementation when tqdm is not found''' +class ProgressBarFallback: # lgtm [py/iter-returns-non-self] + ''' + Fallback progress bar implementation when tqdm is not found + + Since this class is not an actual iterator, but only provides a minimal + fallback, it is safe to ignore the 'Iterator does not return self from + __iter__ method' warning. + ''' def __init__(self, iterable=None, total=None, bar_type=None, desc=None): if iterable is not None: self.iterable = iter(iterable) diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 3550abc..b1a55e5 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -503,7 +503,6 @@ def run(opts): log_dir = os.path.join(private_dir, '../meson-logs') if not os.path.exists(os.path.join(opts.wd, datafilename)): sys.exit('Install data not found. Run this command in build directory root.') - log_dir = os.path.join(private_dir, '../meson-logs') if not opts.no_rebuild: if not rebuild_all(opts.wd): sys.exit(-1) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index fb34b5a..8b66321 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -405,7 +405,6 @@ def run(options): 'meson version. Please regenerate it in this case.') return 1 - intro_vers = '0.0.0' with open(infofile, 'r') as fp: raw = json.load(fp) intro_vers = raw.get('introspection', {}).get('version', {}).get('full', '0.0.0') diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index ace47f4..c779a58 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -18,8 +18,7 @@ import sys import time import platform from contextlib import contextmanager -import typing -from typing import Any, Generator, List, Optional, Sequence, TextIO, Union +from typing import Any, Generator, List, Optional, Sequence, TextIO, Union, cast from pathlib import Path """This is (mostly) a standalone module used to write logging @@ -232,7 +231,7 @@ def _log_error(severity: str, *rargs: Union[str, AnsiDecorator], **kwargs: Any) location_str = get_error_location_string(location_file, location.lineno) # Unions are frankly awful, and we have to cast here to get mypy # to understand that the list concatenation is safe - location_list = typing.cast(List[Union[str, AnsiDecorator]], [location_str]) + location_list = cast(List[Union[str, AnsiDecorator]], [location_str]) args = location_list + args log(*args, **kwargs) diff --git a/mesonbuild/modules/fs.py b/mesonbuild/modules/fs.py index 6e1f5f7..3307cab 100644 --- a/mesonbuild/modules/fs.py +++ b/mesonbuild/modules/fs.py @@ -40,7 +40,7 @@ class FSModule(ExtensionModule): def _check(self, check: str, state: 'ModuleState', args: typing.Sequence[str]) -> ModuleReturnValue: if len(args) != 1: - MesonException('fs.{} takes exactly one argument.'.format(check)) + raise MesonException('fs.{} takes exactly one argument.'.format(check)) test_file = self._resolve_dir(state, args[0]) return ModuleReturnValue(getattr(test_file, check)(), []) @@ -68,7 +68,7 @@ class FSModule(ExtensionModule): @noKwargs def hash(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: if len(args) != 2: - MesonException('method takes exactly two arguments.') + raise MesonException('method takes exactly two arguments.') file = self._resolve_dir(state, args[0]) if not file.is_file(): raise MesonException('{} is not a file and therefore cannot be hashed'.format(file)) @@ -84,7 +84,7 @@ class FSModule(ExtensionModule): @noKwargs def size(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: if len(args) != 1: - MesonException('method takes exactly one argument.') + raise MesonException('method takes exactly one argument.') file = self._resolve_dir(state, args[0]) if not file.is_file(): raise MesonException('{} is not a file and therefore cannot be sized'.format(file)) @@ -97,7 +97,7 @@ class FSModule(ExtensionModule): @noKwargs def samefile(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: if len(args) != 2: - MesonException('method takes exactly two arguments.') + raise MesonException('method takes exactly two arguments.') file1 = self._resolve_dir(state, args[0]) file2 = self._resolve_dir(state, args[1]) if not file1.exists(): @@ -113,7 +113,7 @@ class FSModule(ExtensionModule): @noKwargs def replace_suffix(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: if len(args) != 2: - MesonException('method takes exactly two arguments.') + raise MesonException('method takes exactly two arguments.') original = PurePath(args[0]) new = original.with_suffix(args[1]) return ModuleReturnValue(str(new), []) @@ -122,7 +122,7 @@ class FSModule(ExtensionModule): @noKwargs def parent(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: if len(args) != 1: - MesonException('method takes exactly one argument.') + raise MesonException('method takes exactly one argument.') original = PurePath(args[0]) new = original.parent return ModuleReturnValue(str(new), []) @@ -131,7 +131,7 @@ class FSModule(ExtensionModule): @noKwargs def name(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: if len(args) != 1: - MesonException('method takes exactly one argument.') + raise MesonException('method takes exactly one argument.') original = PurePath(args[0]) new = original.name return ModuleReturnValue(str(new), []) diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py index b99ae8d..073e338 100644 --- a/mesonbuild/modules/rpm.py +++ b/mesonbuild/modules/rpm.py @@ -151,7 +151,7 @@ class RPMModule(ExtensionModule): def __get_required_compilers(self): required_compilers = set() - for compiler in self.coredata.compilers.values(): + for compiler in self.coredata.environment.coredata.compilers.host.values(): # Elbrus has one 'lcc' package for every compiler if isinstance(compiler, compilers.GnuCCompiler): required_compilers.add('gcc') diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 1baf051..2b503f1 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -674,21 +674,8 @@ class Parser: a = ArgumentNode(s) while not isinstance(s, EmptyNode): - potential = self.current if self.accept('colon'): - key_value = self.statement() - if isinstance(s, StringNode): - if s.value in a.kwargs: - # + 1 to colno to point to the actual string, not the opening quote - raise ParseException('Duplicate dictionary key: {}'.format(s.value), self.getline(), s.lineno, s.colno + 1) - a.set_kwarg(s.value, key_value) - elif isinstance(s, IdNode) and isinstance(key_value, StringNode): - for key in a.kwargs: - if s.value == key.value: - raise ParseException('Duplicate dictionary variable key: {}'.format(s.value), self.getline(), s.lineno, s.colno) - a.set_kwarg(s, key_value) - else: - raise ParseException('Key must be a string or string variable', self.getline(), s.lineno, s.colno) + a.set_kwarg(s, self.statement()) potential = self.current if not self.accept('comma'): return a diff --git a/mesonbuild/msubprojects.py b/mesonbuild/msubprojects.py index eeeb9c6..39fb4ef 100755 --- a/mesonbuild/msubprojects.py +++ b/mesonbuild/msubprojects.py @@ -178,11 +178,17 @@ def foreach(wrap, repo_dir, options): mlog.log(' -> Not downloaded yet') return try: - subprocess.check_call([options.command] + options.args, cwd=repo_dir) - mlog.log('') + out = subprocess.check_output([options.command] + options.args, + stderr=subprocess.STDOUT, + cwd=repo_dir).decode() + mlog.log(out, end='') except subprocess.CalledProcessError as e: - out = e.output.decode().strip() - mlog.log(' -> ', mlog.red(out)) + err_message = "Command '%s' returned non-zero exit status %d." % (" ".join(e.cmd), e.returncode) + out = e.output.decode() + mlog.log(' -> ', mlog.red(err_message)) + mlog.log(out, end='') + except Exception as e: + mlog.log(' -> ', mlog.red(str(e))) def add_common_arguments(p): p.add_argument('--sourcedir', default='.', diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index 9bb98cf..5078d3c 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -103,11 +103,11 @@ class RequiredKeys: class MTypeBase: def __init__(self, node: Optional[BaseNode] = None): if node is None: - self.node = self._new_node() + self.node = self._new_node() # lgtm [py/init-calls-subclass] (node creation does not depend on base class state) else: self.node = node self.node_type = None - for i in self.supported_nodes(): + for i in self.supported_nodes(): # lgtm [py/init-calls-subclass] (listing nodes does not depend on base class state) if isinstance(self.node, i): self.node_type = i @@ -854,7 +854,7 @@ class Rewriter: while raw[end] in [' ', '\n', '\t']: end += 1 - raw = files[i['file']]['raw'] = raw[:start] + i['str'] + raw[end:] + files[i['file']]['raw'] = raw[:start] + i['str'] + raw[end:] for i in str_list: if i['action'] in ['modify', 'rm']: diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py index aa764b8..21dab16 100644 --- a/mesonbuild/wrap/wrap.py +++ b/mesonbuild/wrap/wrap.py @@ -16,6 +16,7 @@ from .. import mlog import contextlib import urllib.request import urllib.error +import urllib.parse import os import hashlib import shutil @@ -33,7 +34,9 @@ if typing.TYPE_CHECKING: import http.client try: - import ssl + # Importing is just done to check if SSL exists, so all warnings + # regarding 'imported but unused' can be safely ignored + import ssl # noqa has_ssl = True API_ROOT = 'https://wrapdb.mesonbuild.com/v1/' except ImportError: @@ -42,45 +45,49 @@ except ImportError: req_timeout = 600.0 ssl_warning_printed = False +whitelist_subdomain = 'wrapdb.mesonbuild.com' -def build_ssl_context() -> 'ssl.SSLContext': - ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - ctx.options |= ssl.OP_NO_SSLv2 - ctx.options |= ssl.OP_NO_SSLv3 - ctx.verify_mode = ssl.CERT_REQUIRED - ctx.load_default_certs() - return ctx def quiet_git(cmd: typing.List[str], workingdir: str) -> typing.Tuple[bool, str]: - try: - pc = subprocess.run(['git', '-C', workingdir] + cmd, universal_newlines=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except FileNotFoundError as e: - return False, str(e) + git = shutil.which('git') + if not git: + return False, 'Git program not found.' + pc = subprocess.run([git, '-C', workingdir] + cmd, universal_newlines=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) if pc.returncode != 0: return False, pc.stderr return True, pc.stdout +def whitelist_wrapdb(urlstr: str) -> urllib.parse.ParseResult: + """ raises WrapException if not whitelisted subdomain """ + url = urllib.parse.urlparse(urlstr) + if not url.hostname: + raise WrapException('{} is not a valid URL'.format(urlstr)) + if not url.hostname.endswith(whitelist_subdomain): + raise WrapException('{} is not a whitelisted WrapDB URL'.format(urlstr)) + if has_ssl and not url.scheme == 'https': + raise WrapException('WrapDB did not have expected SSL https url, instead got {}'.format(urlstr)) + return url + def open_wrapdburl(urlstring: str) -> 'http.client.HTTPResponse': global ssl_warning_printed + + url = whitelist_wrapdb(urlstring) if has_ssl: try: - return urllib.request.urlopen(urlstring, timeout=req_timeout)# , context=build_ssl_context()) - except urllib.error.URLError: - if not ssl_warning_printed: - print('SSL connection failed. Falling back to unencrypted connections.', file=sys.stderr) - ssl_warning_printed = True + return urllib.request.urlopen(urllib.parse.urlunparse(url), timeout=req_timeout) + except urllib.error.URLError as excp: + raise WrapException('WrapDB connection failed to {} with error {}'.format(urlstring, excp)) + + # following code is only for those without Python SSL + nossl_url = url._replace(scheme='http') if not ssl_warning_printed: - print('Warning: SSL not available, traffic not authenticated.', file=sys.stderr) + mlog.warning('SSL module not available in {}: WrapDB traffic not authenticated.'.format(sys.executable)) ssl_warning_printed = True - # Trying to open SSL connection to wrapdb fails because the - # certificate is not known. - if urlstring.startswith('https'): - urlstring = 'http' + urlstring[5:] try: - return urllib.request.urlopen(urlstring, timeout=req_timeout) - except urllib.error.URLError: - raise WrapException('failed to get {} is the internet available?'.format(urlstring)) + return urllib.request.urlopen(urllib.parse.urlunparse(nossl_url), timeout=req_timeout) + except urllib.error.URLError as excp: + raise WrapException('WrapDB connection failed to {} with error {}'.format(urlstring, excp)) class WrapException(MesonException): @@ -194,6 +201,9 @@ class Resolver: raise WrapException(m) def resolve_git_submodule(self) -> bool: + git = shutil.which('git') + if not git: + raise WrapException('Git program not found.') # Are we in a git repository? ret, out = quiet_git(['rev-parse'], self.subdir_root) if not ret: @@ -210,12 +220,13 @@ class Resolver: raise WrapException('git submodule has merge conflicts') # Submodule exists, but is deinitialized or wasn't initialized elif out.startswith('-'): - if subprocess.call(['git', '-C', self.subdir_root, 'submodule', 'update', '--init', self.dirname]) == 0: + if subprocess.run([git, '-C', self.subdir_root, + 'submodule', 'update', '--init', self.dirname]).returncode == 0: return True raise WrapException('git submodule failed to init') # Submodule looks fine, but maybe it wasn't populated properly. Do a checkout. elif out.startswith(' '): - subprocess.call(['git', 'checkout', '.'], cwd=self.dirname) + subprocess.run([git, 'checkout', '.'], cwd=self.dirname) # Even if checkout failed, try building it anyway and let the user # handle any problems manually. return True @@ -238,6 +249,9 @@ class Resolver: self.apply_patch() def get_git(self) -> None: + git = shutil.which('git') + if not git: + raise WrapException('Git program not found.') revno = self.wrap.get('revision') is_shallow = False depth_option = [] # type: typing.List[str] @@ -248,42 +262,42 @@ class Resolver: if is_shallow and self.is_git_full_commit_id(revno): # git doesn't support directly cloning shallowly for commits, # so we follow https://stackoverflow.com/a/43136160 - subprocess.check_call(['git', 'init', self.directory], cwd=self.subdir_root) - subprocess.check_call(['git', 'remote', 'add', 'origin', self.wrap.get('url')], + subprocess.check_call([git, 'init', self.directory], cwd=self.subdir_root) + subprocess.check_call([git, 'remote', 'add', 'origin', self.wrap.get('url')], cwd=self.dirname) revno = self.wrap.get('revision') - subprocess.check_call(['git', 'fetch', *depth_option, 'origin', revno], + subprocess.check_call([git, 'fetch', *depth_option, 'origin', revno], cwd=self.dirname) - subprocess.check_call(['git', 'checkout', revno], cwd=self.dirname) + subprocess.check_call([git, 'checkout', revno], cwd=self.dirname) if self.wrap.values.get('clone-recursive', '').lower() == 'true': - subprocess.check_call(['git', 'submodule', 'update', + subprocess.check_call([git, 'submodule', 'update', '--init', '--checkout', '--recursive', *depth_option], cwd=self.dirname) push_url = self.wrap.values.get('push-url') if push_url: - subprocess.check_call(['git', 'remote', 'set-url', + subprocess.check_call([git, 'remote', 'set-url', '--push', 'origin', push_url], cwd=self.dirname) else: if not is_shallow: - subprocess.check_call(['git', 'clone', self.wrap.get('url'), + subprocess.check_call([git, 'clone', self.wrap.get('url'), self.directory], cwd=self.subdir_root) if revno.lower() != 'head': - if subprocess.call(['git', 'checkout', revno], cwd=self.dirname) != 0: - subprocess.check_call(['git', 'fetch', self.wrap.get('url'), revno], cwd=self.dirname) - subprocess.check_call(['git', 'checkout', revno], cwd=self.dirname) + if subprocess.run([git, 'checkout', revno], cwd=self.dirname).returncode != 0: + subprocess.check_call([git, 'fetch', self.wrap.get('url'), revno], cwd=self.dirname) + subprocess.check_call([git, 'checkout', revno], cwd=self.dirname) else: - subprocess.check_call(['git', 'clone', *depth_option, + subprocess.check_call([git, 'clone', *depth_option, '--branch', revno, self.wrap.get('url'), self.directory], cwd=self.subdir_root) if self.wrap.values.get('clone-recursive', '').lower() == 'true': - subprocess.check_call(['git', 'submodule', 'update', + subprocess.check_call([git, 'submodule', 'update', '--init', '--checkout', '--recursive', *depth_option], cwd=self.dirname) push_url = self.wrap.values.get('push-url') if push_url: - subprocess.check_call(['git', 'remote', 'set-url', + subprocess.check_call([git, 'remote', 'set-url', '--push', 'origin', push_url], cwd=self.dirname) @@ -295,28 +309,39 @@ class Resolver: def get_hg(self) -> None: revno = self.wrap.get('revision') - subprocess.check_call(['hg', 'clone', self.wrap.get('url'), + hg = shutil.which('hg') + if not hg: + raise WrapException('Mercurial program not found.') + subprocess.check_call([hg, 'clone', self.wrap.get('url'), self.directory], cwd=self.subdir_root) if revno.lower() != 'tip': - subprocess.check_call(['hg', 'checkout', revno], + subprocess.check_call([hg, 'checkout', revno], cwd=self.dirname) def get_svn(self) -> None: revno = self.wrap.get('revision') - subprocess.check_call(['svn', 'checkout', '-r', revno, self.wrap.get('url'), + svn = shutil.which('svn') + if not svn: + raise WrapException('SVN program not found.') + subprocess.check_call([svn, 'checkout', '-r', revno, self.wrap.get('url'), self.directory], cwd=self.subdir_root) - def get_data(self, url: str) -> typing.Tuple[str, str]: + def get_data(self, urlstring: str) -> typing.Tuple[str, str]: blocksize = 10 * 1024 h = hashlib.sha256() tmpfile = tempfile.NamedTemporaryFile(mode='wb', dir=self.cachedir, delete=False) - if url.startswith('https://wrapdb.mesonbuild.com'): - resp = open_wrapdburl(url) + url = urllib.parse.urlparse(urlstring) + if not url.hostname: + raise WrapException('{} is not a valid URL'.format(urlstring)) + if url.hostname.endswith(whitelist_subdomain): + resp = open_wrapdburl(urlstring) + elif whitelist_subdomain in urlstring: + raise WrapException('{} may be a WrapDB-impersonating URL'.format(urlstring)) else: try: - resp = urllib.request.urlopen(url, timeout=req_timeout) + resp = urllib.request.urlopen(urlstring, timeout=req_timeout) except urllib.error.URLError: - raise WrapException('could not get {} is the internet available?'.format(url)) + raise WrapException('could not get {} is the internet available?'.format(urlstring)) with contextlib.closing(resp) as resp: try: dlsize = int(resp.info()['Content-Length']) @@ -353,7 +378,7 @@ class Resolver: h.update(f.read()) dhash = h.hexdigest() if dhash != expected: - raise WrapException('Incorrect hash for %s:\n %s expected\n %s actual.' % (what, expected, dhash)) + raise WrapException('Incorrect hash for {}:\n {} expected\n {} actual.'.format(what, expected, dhash)) def download(self, what: str, ofname: str) -> None: self.check_can_download() @@ -363,7 +388,7 @@ class Resolver: expected = self.wrap.get(what + '_hash') if dhash != expected: os.remove(tmpfile) - raise WrapException('Incorrect hash for %s:\n %s expected\n %s actual.' % (what, expected, dhash)) + raise WrapException('Incorrect hash for {}:\n {} expected\n {} actual.'.format(what, expected, dhash)) os.rename(tmpfile, ofname) def get_file_internal(self, what: str) -> str: diff --git a/mesonbuild/wrap/wraptool.py b/mesonbuild/wrap/wraptool.py index cd15cef..351669b 100644 --- a/mesonbuild/wrap/wraptool.py +++ b/mesonbuild/wrap/wraptool.py @@ -94,7 +94,7 @@ def install(options): if os.path.exists(wrapfile): raise SystemExit('Wrap file already exists.') (branch, revision) = get_latest_version(name) - u = open_wrapdburl(API_ROOT + 'projects/%s/%s/%s/get_wrap' % (name, branch, revision)) + u = open_wrapdburl(API_ROOT + 'projects/{}/{}/{}/get_wrap'.format(name, branch, revision)) data = u.read() with open(wrapfile, 'wb') as f: f.write(data) @@ -113,7 +113,7 @@ def get_current_version(wrapfile): return branch, revision, cp['directory'], cp['source_filename'], cp['patch_filename'] def update_wrap_file(wrapfile, name, new_branch, new_revision): - u = open_wrapdburl(API_ROOT + 'projects/%s/%s/%d/get_wrap' % (name, new_branch, new_revision)) + u = open_wrapdburl(API_ROOT + 'projects/{}/{}/{}/get_wrap'.format(name, new_branch, new_revision)) data = u.read() with open(wrapfile, 'wb') as f: f.write(data) @@ -148,7 +148,7 @@ def info(options): versions = jd['versions'] if not versions: raise SystemExit('No available versions of' + name) - print('Available versions of %s:' % name) + print('Available versions of {}:'.format(name)) for v in versions: print(' ', v['branch'], v['revision']) @@ -160,7 +160,7 @@ def do_promotion(from_path, spdir_name): sproj_name = os.path.basename(from_path) outputdir = os.path.join(spdir_name, sproj_name) if os.path.exists(outputdir): - raise SystemExit('Output dir %s already exists. Will not overwrite.' % outputdir) + raise SystemExit('Output dir {} already exists. Will not overwrite.'.format(outputdir)) shutil.copytree(from_path, outputdir, ignore=shutil.ignore_patterns('subprojects')) def promote(options): @@ -177,10 +177,10 @@ def promote(options): # otherwise the argument is just a subproject basename which must be unambiguous if argument not in sprojs: - raise SystemExit('Subproject %s not found in directory tree.' % argument) + raise SystemExit('Subproject {} not found in directory tree.'.format(argument)) matches = sprojs[argument] if len(matches) > 1: - print('There is more than one version of %s in tree. Please specify which one to promote:\n' % argument, file=sys.stderr) + print('There is more than one version of {} in tree. Please specify which one to promote:\n'.format(argument), file=sys.stderr) for s in matches: print(s, file=sys.stderr) raise SystemExit(1) @@ -201,9 +201,9 @@ def status(options): print('Wrap file not from wrapdb.', file=sys.stderr) continue if current_branch == latest_branch and current_revision == latest_revision: - print('', name, 'up to date. Branch %s, revision %d.' % (current_branch, current_revision)) + print('', name, 'up to date. Branch {}, revision {}.'.format(current_branch, current_revision)) else: - print('', name, 'not up to date. Have %s %d, but %s %d is available.' % (current_branch, current_revision, latest_branch, latest_revision)) + print('', name, 'not up to date. Have {} {}, but {} {} is available.'.format(current_branch, current_revision, latest_branch, latest_revision)) def run(options): options.wrap_func(options) diff --git a/run_project_tests.py b/run_project_tests.py index 0ae987d..61ce5aa 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -282,7 +282,6 @@ def _run_ci_include(args: typing.List[str]) -> str: return 'Included file {}:\n{}\n'.format(args[0], data) except Exception: return 'Failed to open {} ({})'.format(args[0]) - return 'Appended {} to the log'.format(args[0]) ci_commands = { 'ci_include': _run_ci_include diff --git a/run_tests.py b/run_tests.py index 504e6ac..33dc1be 100755 --- a/run_tests.py +++ b/run_tests.py @@ -26,7 +26,8 @@ from io import StringIO from enum import Enum from glob import glob from pathlib import Path -import mesonbuild +from mesonbuild import compilers +from mesonbuild import dependencies from mesonbuild import mesonlib from mesonbuild import mesonmain from mesonbuild import mtest @@ -95,7 +96,6 @@ class FakeCompilerOptions: self.value = [] def get_fake_options(prefix=''): - import argparse opts = argparse.Namespace() opts.native_file = [] opts.cross_file = None @@ -135,7 +135,7 @@ def get_meson_script(): running in-process (which is the default). ''' # Is there a meson.py next to the mesonbuild currently in use? - mesonbuild_dir = Path(mesonbuild.__file__).resolve().parent.parent + mesonbuild_dir = Path(mesonmain.__file__).resolve().parent.parent meson_script = mesonbuild_dir / 'meson.py' if meson_script.is_file(): return str(meson_script) @@ -263,12 +263,12 @@ def run_mtest_inprocess(commandlist): return returncode, mystdout.getvalue(), mystderr.getvalue() def clear_meson_configure_class_caches(): - mesonbuild.compilers.CCompiler.library_dirs_cache = {} - mesonbuild.compilers.CCompiler.program_dirs_cache = {} - mesonbuild.compilers.CCompiler.find_library_cache = {} - mesonbuild.compilers.CCompiler.find_framework_cache = {} - mesonbuild.dependencies.PkgConfigDependency.pkgbin_cache = {} - mesonbuild.dependencies.PkgConfigDependency.class_pkgbin = mesonlib.PerMachine(None, None) + compilers.CCompiler.library_dirs_cache = {} + compilers.CCompiler.program_dirs_cache = {} + compilers.CCompiler.find_library_cache = {} + compilers.CCompiler.find_framework_cache = {} + dependencies.PkgConfigDependency.pkgbin_cache = {} + dependencies.PkgConfigDependency.class_pkgbin = mesonlib.PerMachine(None, None) def run_configure_inprocess(commandlist, env=None): old_stdout = sys.stdout diff --git a/run_unittests.py b/run_unittests.py index 4e56c1d..4260256 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -360,18 +360,14 @@ class InternalTests(unittest.TestCase): def test_compiler_args_class(self): cargsfunc = mesonbuild.compilers.CompilerArgs cc = mesonbuild.compilers.CCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock()) - # Test that bad initialization fails - self.assertRaises(TypeError, cargsfunc, []) - self.assertRaises(TypeError, cargsfunc, [], []) - self.assertRaises(TypeError, cargsfunc, cc, [], []) # Test that empty initialization works a = cargsfunc(cc) self.assertEqual(a, []) # Test that list initialization works - a = cargsfunc(['-I.', '-I..'], cc) + a = cargsfunc(cc, ['-I.', '-I..']) self.assertEqual(a, ['-I.', '-I..']) # Test that there is no de-dup on initialization - self.assertEqual(cargsfunc(['-I.', '-I.'], cc), ['-I.', '-I.']) + self.assertEqual(cargsfunc(cc, ['-I.', '-I.']), ['-I.', '-I.']) ## Test that appending works a.append('-I..') @@ -33,4 +33,7 @@ python_requires = >= 3.5.2 [options.extras_require] progress = - tqdm
\ No newline at end of file + tqdm + +[tool:pytest] +python_classes = diff --git a/test cases/common/193 dict/meson.build b/test cases/common/193 dict/meson.build index 41eea31..dacf01d 100644 --- a/test cases/common/193 dict/meson.build +++ b/test cases/common/193 dict/meson.build @@ -33,3 +33,39 @@ d3 = d2 d3 += {'e' : 'f'} assert(d3 == {'a' : 'b2', 'c' : 'd', 'e' : 'f'}, 'dict plusassign is not working') assert(d2 == {'a' : 'b2', 'c' : 'd'}, 'dict should be immutable') + +dict1 = {} + +# A variable to be used as a key +testkey1 = 'myKey1' +testkey2 = 'myKey2' + +# Add new entry using the variable +dict1 += {testkey1 : 'myValue'} +dict1 += {testkey2 : 42} + +# Test that the stored values are correct +assert(dict1[testkey1] == 'myValue', + 'Incorrect string value retrieved from dictionary - variable key') +assert(dict1['myKey1'] == 'myValue', + 'Incorrect string value retrieved from dictionary - literal key') +assert(dict1[testkey2] == 42, + 'Incorrect int value retrieved from dictionary - variable key') +assert(dict1['myKey2'] == 42, + 'Incorrect int value retrieved from dictionary - literal key') + +d = {testkey1 : 1} +assert(d[testkey1] == 1, + 'Incorrect int value retrieved from dictionary - variable key') +assert(d['myKey1'] == 1, + 'Incorrect int value retrieved from dictionary - literal key') + +d = {'1' / '2' : 1, join_paths('a', 'b') : 2} +k1 = '1' / '2' +k2 = join_paths('a', 'b') +assert(d[k1] == 1, 'Incorrect expression evaluation in dictionary key') +assert(d[k2] == 2, 'Incorrect expression evaluation in dictionary key') + +d = {'a' + 'b' : 1} +assert(d['a' + 'b'] == 1, 'Incorrect expression evaluation in dictionary key') +assert(d['ab'] == 1, 'Incorrect expression evaluation in dictionary key') diff --git a/test cases/common/228 add dict variable key/meson.build b/test cases/common/228 add dict variable key/meson.build deleted file mode 100644 index b39c17e..0000000 --- a/test cases/common/228 add dict variable key/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -project('add dictionary entry using string variable as key', meson_version: '>=0.52') - -dict = {} - -# A variable to be used as a key -key = 'myKey' - -# Add new entry using the variable -dict += {key : 'myValue'} - -# Test that the stored value is correct -assert(dict[key] == 'myValue', 'Incorrect value retrieved from dictionary') diff --git a/test cases/common/28 find program/meson.build b/test cases/common/28 find program/meson.build index 983b7b4..3b59caa 100644 --- a/test cases/common/28 find program/meson.build +++ b/test cases/common/28 find program/meson.build @@ -27,3 +27,9 @@ assert(prog.found(), 'Program version should match') prog = find_program('print-version-with-prefix.py', version : '>=1.0') assert(prog.found(), 'Program version should match') + +prog = find_program('test_subdir.py', required : false) +assert(not prog.found(), 'Program should not be found') + +prog = find_program('test_subdir.py', dirs : ['/donotexist', meson.current_source_dir() / 'scripts']) +assert(prog.found(), 'Program should be found') diff --git a/test cases/common/28 find program/scripts/test_subdir.py b/test cases/common/28 find program/scripts/test_subdir.py new file mode 100644 index 0000000..947ffe4 --- /dev/null +++ b/test cases/common/28 find program/scripts/test_subdir.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 + +exit(0) diff --git a/test cases/objc/1 simple/prog.m b/test cases/objc/1 simple/prog.m index f2e2315..87457bf 100644 --- a/test cases/objc/1 simple/prog.m +++ b/test cases/objc/1 simple/prog.m @@ -1,5 +1,5 @@ #import<stdio.h> -int main(int argc, char **argv) { +int main(void) { return 0; }
\ No newline at end of file diff --git a/test cases/objc/2 nsstring/stringprog.m b/test cases/objc/2 nsstring/stringprog.m index f1a2532..faef4dd 100644 --- a/test cases/objc/2 nsstring/stringprog.m +++ b/test cases/objc/2 nsstring/stringprog.m @@ -1,6 +1,6 @@ #import<Foundation/NSString.h> -int main(int argc, char **argv) { +int main(void) { int result; NSString *str = [NSString new]; result = [str length]; diff --git a/test cases/objc/3 objc args/prog.m b/test cases/objc/3 objc args/prog.m index bfd686a..003df98 100644 --- a/test cases/objc/3 objc args/prog.m +++ b/test cases/objc/3 objc args/prog.m @@ -1,6 +1,6 @@ #import<stdio.h> -int main(int argc, char **argv) +int main(void) { #ifdef MESON_TEST int x = 3; diff --git a/test cases/objcpp/1 simple/prog.mm b/test cases/objcpp/1 simple/prog.mm index 927e810..d3bbf6c 100644 --- a/test cases/objcpp/1 simple/prog.mm +++ b/test cases/objcpp/1 simple/prog.mm @@ -3,7 +3,7 @@ class MyClass { }; -int main(int argc, char **argv) { +int main(void) { return 0; } diff --git a/test cases/objcpp/2 objc++ args/prog.mm b/test cases/objcpp/2 objc++ args/prog.mm index 3decaf2..2b437ce 100644 --- a/test cases/objcpp/2 objc++ args/prog.mm +++ b/test cases/objcpp/2 objc++ args/prog.mm @@ -4,7 +4,7 @@ class TestClass { }; -int main(int argc, char **argv) +int main(void) { #ifdef MESON_OBJCPP_TEST int x = 1; diff --git a/test cases/osx/1 basic/main.c b/test cases/osx/1 basic/main.c index 2417ad8..0a07218 100644 --- a/test cases/osx/1 basic/main.c +++ b/test cases/osx/1 basic/main.c @@ -1,5 +1,5 @@ #include <CoreFoundation/CoreFoundation.h> -int main(int argc, char **argv) { +int main(void) { return 0; } diff --git a/test cases/osx/2 library versions/exe.orig.c b/test cases/osx/2 library versions/exe.orig.c index 86c4adc..ad38e6d 100644 --- a/test cases/osx/2 library versions/exe.orig.c +++ b/test cases/osx/2 library versions/exe.orig.c @@ -1,8 +1,6 @@ int myFunc (void); -int -main (int argc, char *argv[]) -{ +int main (void) { if (myFunc() == 55) return 0; return 1; diff --git a/test cases/osx/2 library versions/lib.c b/test cases/osx/2 library versions/lib.c index 67b6f4d..bd251d7 100644 --- a/test cases/osx/2 library versions/lib.c +++ b/test cases/osx/2 library versions/lib.c @@ -1,3 +1,3 @@ -int myFunc() { +int myFunc(void) { return 55; } diff --git a/test cases/osx/4 framework/prog.c b/test cases/osx/4 framework/prog.c index 11b7fad..9b6bdc2 100644 --- a/test cases/osx/4 framework/prog.c +++ b/test cases/osx/4 framework/prog.c @@ -1,3 +1,3 @@ -int main(int argc, char **argv) { +int main(void) { return 0; } diff --git a/test cases/osx/4 framework/stat.c b/test cases/osx/4 framework/stat.c index fa76a65..4825cef 100644 --- a/test cases/osx/4 framework/stat.c +++ b/test cases/osx/4 framework/stat.c @@ -1 +1 @@ -int func() { return 933; } +int func(void) { return 933; } diff --git a/test cases/osx/5 extra frameworks/prog.c b/test cases/osx/5 extra frameworks/prog.c index 11b7fad..9b6bdc2 100644 --- a/test cases/osx/5 extra frameworks/prog.c +++ b/test cases/osx/5 extra frameworks/prog.c @@ -1,3 +1,3 @@ -int main(int argc, char **argv) { +int main(void) { return 0; } diff --git a/test cases/osx/5 extra frameworks/stat.c b/test cases/osx/5 extra frameworks/stat.c index fa76a65..4825cef 100644 --- a/test cases/osx/5 extra frameworks/stat.c +++ b/test cases/osx/5 extra frameworks/stat.c @@ -1 +1 @@ -int func() { return 933; } +int func(void) { return 933; } diff --git a/test cases/osx/7 bitcode/libbar.mm b/test cases/osx/7 bitcode/libbar.mm index 22c4dd4..d9201c1 100644 --- a/test cases/osx/7 bitcode/libbar.mm +++ b/test cases/osx/7 bitcode/libbar.mm @@ -1,7 +1,7 @@ #import <stdio.h> #import "vis.h" -int EXPORT_PUBLIC libbar(int arg) { +int EXPORT_PUBLIC libbar(void) { return 0; } diff --git a/test cases/osx/7 bitcode/libfile.c b/test cases/osx/7 bitcode/libfile.c index cc87aa0..8edc66b 100644 --- a/test cases/osx/7 bitcode/libfile.c +++ b/test cases/osx/7 bitcode/libfile.c @@ -1,5 +1,5 @@ #include "vis.h" -int EXPORT_PUBLIC libfunc() { +int EXPORT_PUBLIC libfunc(void) { return 3; } diff --git a/test cases/osx/7 bitcode/libfoo.m b/test cases/osx/7 bitcode/libfoo.m index 7981ab4..f1c35a9 100644 --- a/test cases/osx/7 bitcode/libfoo.m +++ b/test cases/osx/7 bitcode/libfoo.m @@ -1,7 +1,7 @@ #import <stdio.h> #import "vis.h" -int EXPORT_PUBLIC libfoo(int arg) { +int EXPORT_PUBLIC libfoo(void) { return 0; } diff --git a/test cases/osx/8 pie/main.c b/test cases/osx/8 pie/main.c index 2417ad8..0a07218 100644 --- a/test cases/osx/8 pie/main.c +++ b/test cases/osx/8 pie/main.c @@ -1,5 +1,5 @@ #include <CoreFoundation/CoreFoundation.h> -int main(int argc, char **argv) { +int main(void) { return 0; } diff --git a/test cases/windows/10 vs module defs generated custom target/prog.c b/test cases/windows/10 vs module defs generated custom target/prog.c index 51f7805..066ac22 100644 --- a/test cases/windows/10 vs module defs generated custom target/prog.c +++ b/test cases/windows/10 vs module defs generated custom target/prog.c @@ -1,4 +1,4 @@ -int somedllfunc(); +int somedllfunc(void); int main(void) { return somedllfunc() == 42 ? 0 : 1; diff --git a/test cases/windows/10 vs module defs generated custom target/subdir/somedll.c b/test cases/windows/10 vs module defs generated custom target/subdir/somedll.c index b23d8fe..f095b18 100644 --- a/test cases/windows/10 vs module defs generated custom target/subdir/somedll.c +++ b/test cases/windows/10 vs module defs generated custom target/subdir/somedll.c @@ -1,3 +1,3 @@ -int somedllfunc() { +int somedllfunc(void) { return 42; } diff --git a/test cases/windows/11 exe implib/prog.c b/test cases/windows/11 exe implib/prog.c index 2192019..aa3bc5c 100644 --- a/test cases/windows/11 exe implib/prog.c +++ b/test cases/windows/11 exe implib/prog.c @@ -1,6 +1,6 @@ #include <windows.h> int __declspec(dllexport) -main() { +main(void) { return 0; } diff --git a/test cases/windows/12 resources with custom targets/prog.c b/test cases/windows/12 resources with custom targets/prog.c index 2bef6a2..cb6892d 100644 --- a/test cases/windows/12 resources with custom targets/prog.c +++ b/test cases/windows/12 resources with custom targets/prog.c @@ -10,5 +10,10 @@ WinMain( int nCmdShow) { HICON hIcon; hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(MY_ICON)); + // avoid unused argument error while matching template + ((void)hInstance); + ((void)hPrevInstance); + ((void)lpszCmdLine); + ((void)nCmdShow); return hIcon ? 0 : 1; } diff --git a/test cases/windows/13 test argument extra paths/exe/main.c b/test cases/windows/13 test argument extra paths/exe/main.c index 0ac9e38..1032ae2 100644 --- a/test cases/windows/13 test argument extra paths/exe/main.c +++ b/test cases/windows/13 test argument extra paths/exe/main.c @@ -1,5 +1,5 @@ #include <foo.h> -int main(int ac, char **av) { +int main(void) { return foo_process(); } diff --git a/test cases/windows/14 resources with custom target depend_files/prog.c b/test cases/windows/14 resources with custom target depend_files/prog.c index 2bef6a2..cb6892d 100644 --- a/test cases/windows/14 resources with custom target depend_files/prog.c +++ b/test cases/windows/14 resources with custom target depend_files/prog.c @@ -10,5 +10,10 @@ WinMain( int nCmdShow) { HICON hIcon; hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(MY_ICON)); + // avoid unused argument error while matching template + ((void)hInstance); + ((void)hPrevInstance); + ((void)lpszCmdLine); + ((void)nCmdShow); return hIcon ? 0 : 1; } diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c index 673b5e4..2bd8cd2 100644 --- a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c +++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c @@ -2,5 +2,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { + // avoid unused argument error while matching template + ((void)hinstDLL); + ((void)fdwReason); + ((void)lpvReserved); return TRUE; } diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c index 11b7fad..9b6bdc2 100644 --- a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c +++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c @@ -1,3 +1,3 @@ -int main(int argc, char **argv) { +int main(void) { return 0; } diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c index 673b5e4..2bd8cd2 100644 --- a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c +++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c @@ -2,5 +2,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { + // avoid unused argument error while matching template + ((void)hinstDLL); + ((void)fdwReason); + ((void)lpvReserved); return TRUE; } diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c index 11b7fad..9b6bdc2 100644 --- a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c +++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c @@ -1,3 +1,3 @@ -int main(int argc, char **argv) { +int main(void) { return 0; } diff --git a/test cases/windows/15 resource scripts with duplicate filenames/verify.c b/test cases/windows/15 resource scripts with duplicate filenames/verify.c index 4d2ccf0..8f5b88e 100644 --- a/test cases/windows/15 resource scripts with duplicate filenames/verify.c +++ b/test cases/windows/15 resource scripts with duplicate filenames/verify.c @@ -1,7 +1,7 @@ #include <assert.h> #include <windows.h> -int main(int arc, char *argv[]) +int main(int argc, char *argv[]) { // verify that the expected resource exists and has the expected contents HRSRC hRsrc; @@ -9,6 +9,8 @@ int main(int arc, char *argv[]) HGLOBAL hGlobal; void* data; + ((void)argc); + hRsrc = FindResource(NULL, argv[1], RT_RCDATA); assert(hRsrc); diff --git a/test cases/windows/16 gui app/gui_prog.c b/test cases/windows/16 gui app/gui_prog.c index 4bc688a..9cdf170 100644 --- a/test cases/windows/16 gui app/gui_prog.c +++ b/test cases/windows/16 gui app/gui_prog.c @@ -2,5 +2,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + // avoid unused argument error while matching template + ((void)hInstance); + ((void)hPrevInstance); + ((void)lpCmdLine); + ((void)nCmdShow); return 0; } diff --git a/test cases/windows/2 winmain/prog.c b/test cases/windows/2 winmain/prog.c index 77d6982..3bd4c95 100644 --- a/test cases/windows/2 winmain/prog.c +++ b/test cases/windows/2 winmain/prog.c @@ -6,5 +6,10 @@ WinMain( HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { +// avoid unused argument error while matching template + ((void)hInstance); + ((void)hPrevInstance); + ((void)lpszCmdLine); + ((void)nCmdShow); return 0; } diff --git a/test cases/windows/3 cpp/prog.cpp b/test cases/windows/3 cpp/prog.cpp index cf67335..69092f7 100644 --- a/test cases/windows/3 cpp/prog.cpp +++ b/test cases/windows/3 cpp/prog.cpp @@ -2,6 +2,6 @@ class Foo; -int main(int argc, char **argv) { +int main(void) { return 0; } diff --git a/test cases/windows/4 winmaincpp/prog.cpp b/test cases/windows/4 winmaincpp/prog.cpp index aeecb7b..6182257 100644 --- a/test cases/windows/4 winmaincpp/prog.cpp +++ b/test cases/windows/4 winmaincpp/prog.cpp @@ -8,5 +8,10 @@ WinMain( HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { +// avoid unused argument error while matching template + ((void)hInstance); + ((void)hPrevInstance); + ((void)lpszCmdLine); + ((void)nCmdShow); return 0; } diff --git a/test cases/windows/5 resources/prog.c b/test cases/windows/5 resources/prog.c index afbb6ae..3409c39 100644 --- a/test cases/windows/5 resources/prog.c +++ b/test cases/windows/5 resources/prog.c @@ -12,5 +12,10 @@ WinMain( int nCmdShow) { HICON hIcon; hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(MY_ICON)); +// avoid unused argument error while matching template + ((void)hInstance); + ((void)hPrevInstance); + ((void)lpszCmdLine); + ((void)nCmdShow); return hIcon ? 0 : 1; } diff --git a/test cases/windows/6 vs module defs/prog.c b/test cases/windows/6 vs module defs/prog.c index 51f7805..066ac22 100644 --- a/test cases/windows/6 vs module defs/prog.c +++ b/test cases/windows/6 vs module defs/prog.c @@ -1,4 +1,4 @@ -int somedllfunc(); +int somedllfunc(void); int main(void) { return somedllfunc() == 42 ? 0 : 1; diff --git a/test cases/windows/6 vs module defs/subdir/somedll.c b/test cases/windows/6 vs module defs/subdir/somedll.c index b23d8fe..f095b18 100644 --- a/test cases/windows/6 vs module defs/subdir/somedll.c +++ b/test cases/windows/6 vs module defs/subdir/somedll.c @@ -1,3 +1,3 @@ -int somedllfunc() { +int somedllfunc(void) { return 42; } diff --git a/test cases/windows/7 dll versioning/lib.c b/test cases/windows/7 dll versioning/lib.c index cf7dfdd..37e0d1d 100644 --- a/test cases/windows/7 dll versioning/lib.c +++ b/test cases/windows/7 dll versioning/lib.c @@ -1,6 +1,6 @@ #ifdef _WIN32 __declspec(dllexport) #endif -int myFunc() { +int myFunc(void) { return 55; } diff --git a/test cases/windows/9 vs module defs generated/prog.c b/test cases/windows/9 vs module defs generated/prog.c index 51f7805..066ac22 100644 --- a/test cases/windows/9 vs module defs generated/prog.c +++ b/test cases/windows/9 vs module defs generated/prog.c @@ -1,4 +1,4 @@ -int somedllfunc(); +int somedllfunc(void); int main(void) { return somedllfunc() == 42 ? 0 : 1; diff --git a/test cases/windows/9 vs module defs generated/subdir/somedll.c b/test cases/windows/9 vs module defs generated/subdir/somedll.c index b23d8fe..f095b18 100644 --- a/test cases/windows/9 vs module defs generated/subdir/somedll.c +++ b/test cases/windows/9 vs module defs generated/subdir/somedll.c @@ -1,3 +1,3 @@ -int somedllfunc() { +int somedllfunc(void) { return 42; } diff --git a/tools/ac_converter.py b/tools/ac_converter.py index a1969a9..075eae6 100755 --- a/tools/ac_converter.py +++ b/tools/ac_converter.py @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -help_message = """Usage: %s <config.h.meson> +help_message = """Usage: {} <config.h.meson> This script reads config.h.meson, looks for header checks and writes the corresponding meson declaration. @@ -368,7 +368,7 @@ functions = [] sizes = [] if len(sys.argv) != 2: - print(help_message % sys.argv[0]) + print(help_message.format(sys.argv[0])) sys.exit(0) with open(sys.argv[1]) as f: @@ -414,7 +414,7 @@ cdata = configuration_data()''') print('check_headers = [') for token, hname in headers: - print(" ['%s', '%s']," % (token, hname)) + print(" ['{}', '{}'],".format(token, hname)) print(']\n') print('''foreach h : check_headers @@ -430,7 +430,7 @@ print('check_functions = [') for tok in functions: if len(tok) == 3: tokstr, fdata0, fdata1 = tok - print(" ['%s', '%s', '#include<%s>']," % (tokstr, fdata0, fdata1)) + print(" ['{}', '{}', '#include<{}>'],".format(tokstr, fdata0, fdata1)) else: print('# check token', tok) print(']\n') @@ -445,7 +445,7 @@ endforeach # Convert sizeof checks. for elem, typename in sizes: - print("cdata.set('%s', cc.sizeof('%s'))" % (elem, typename)) + print("cdata.set('{}', cc.sizeof('{}'))".format(elem, typename)) print(''' configure_file(input : 'config.h.meson', |