meson-0.53.2/0000755000175000017500000000000013625242402014314 5ustar jpakkanejpakkane00000000000000meson-0.53.2/COPYING0000644000175000017500000002613612650745767015402 0ustar jpakkanejpakkane00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. meson-0.53.2/MANIFEST.in0000644000175000017500000000063713537776255016104 0ustar jpakkanejpakkane00000000000000graft test?cases graft manual?tests graft cross graft data graft graphics graft man graft syntax-highlighting graft tools include authors.txt include contributing.txt include COPYING include README.md include run_cross_test.py include run_tests.py include run_unittests.py include run_meson_command_tests.py include run_project_tests.py include mesonrewriter.py include ghwt.py include __main__.py include meson.py meson-0.53.2/PKG-INFO0000644000175000017500000000251513625242402015414 0ustar jpakkanejpakkane00000000000000Metadata-Version: 2.1 Name: meson Version: 0.53.2 Summary: A high performance build system Home-page: https://mesonbuild.com Author: Jussi Pakkanen Author-email: jpakkane@gmail.com License: Apache License, Version 2.0 Description: Meson is a cross-platform build system designed to be both as fast and as user friendly as possible. It supports many languages and compilers, including GCC, Clang, PGI, Intel, and Visual Studio. Its build definitions are written in a simple non-Turing complete DSL. Keywords: meson,mesonbuild,build system,cmake Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: Natural Language :: English Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX :: BSD Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Topic :: Software Development :: Build Tools Requires-Python: >=3.5.2 Provides-Extra: progress meson-0.53.2/README.md0000644000175000017500000000656613571777336015633 0ustar jpakkanejpakkane00000000000000

MesonĀ® is a project to create the best possible next-generation build system. #### Status [![PyPI](https://img.shields.io/pypi/v/meson.svg)](https://pypi.python.org/pypi/meson) [![Travis](https://travis-ci.org/mesonbuild/meson.svg?branch=master)](https://travis-ci.org/mesonbuild/meson) [![Build Status](https://dev.azure.com/jussi0947/jussi/_apis/build/status/mesonbuild.meson)](https://dev.azure.com/jussi0947/jussi/_build/latest?definitionId=1) [![Codecov](https://codecov.io/gh/mesonbuild/meson/coverage.svg?branch=master)](https://codecov.io/gh/mesonbuild/meson/branch/master) [![Code Quality: Python](https://img.shields.io/lgtm/grade/python/g/mesonbuild/meson.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/mesonbuild/meson/context:python) [![Total Alerts](https://img.shields.io/lgtm/alerts/g/mesonbuild/meson.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/mesonbuild/meson/alerts) #### Dependencies - [Python](https://python.org) (version 3.5 or newer) - [Ninja](https://ninja-build.org) (version 1.5 or newer) #### Installing from source You can run Meson directly from a revision control checkout or an extracted tarball. If you wish you can install it locally with the standard Python command ```sh python3 -m pip install meson ``` Meson is also available from [PyPi](https://pypi.python.org/pypi/meson), so it can be installed with `pip3 install meson` (this does not require a source checkout, pip will download the package automatically). The exact command to type to install with Pip can vary between systems, be sure to use the Python 3 version of Pip. For builds using Ninja, Ninja can be [downloaded directly](https://github.com/ninja-build/ninja/releases) or via ```sh python3 -m pip install ninja ``` #### Running Meson requires that you have a source directory and a build directory and that these two are different. In your source root must exist a file called `meson.build`. To generate the build system run this command: `meson ` Depending on how you obtained Meson the command might also be called `meson.py` instead of plain `meson`. In the rest of this document we are going to use the latter form. You can omit either of the two directories, and Meson will substitute the current directory and autodetect what you mean. This allows you to do things like this: `cd source_root; mkdir builddir; cd builddir; meson ..` or `cd source_root; mkdir builddir; meson builddir` To compile, cd into your build directory and type `ninja`. To run unit tests, type `ninja test`. Install is the same but it can take an extra argument: `DESTDIR=/destdir/path ninja install` `DESTDIR` can be omitted. If you are installing to system directories, you may need to run this command with sudo. #### Contributing We love code contributions. See the [contribution page](https://mesonbuild.com/Contributing.html) on the web site for details. #### IRC The irc channel for Meson is `#mesonbuild` over at Freenode. You can use [FreeNode's official webchat][meson_irc] to connect to this channel. [meson_irc]: https://webchat.freenode.net/?channels=%23mesonbuild #### Further info More information about the Meson build system can be found at the [project's home page](https://mesonbuild.com). Meson is a registered trademark of Jussi Pakkanen. meson-0.53.2/__main__.py0000644000175000017500000000125413366273150016416 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from mesonbuild import mesonmain import sys sys.exit(mesonmain.main()) meson-0.53.2/cross/0000755000175000017500000000000013625242353015452 5ustar jpakkanejpakkane00000000000000meson-0.53.2/cross/armcc.txt0000644000175000017500000000112413340206727017275 0ustar jpakkanejpakkane00000000000000# This file assumes that path to the arm compiler toolchain is added # to the environment(PATH) variable, so that Meson can find # the armcc, armlink and armar while building. [binaries] c = 'armcc' cpp = 'armcc' ar = 'armar' strip = 'armar' [properties] # The '--cpu' option with the appropriate target type should be mentioned # to cross compile c/c++ code with armcc,. c_args = ['--cpu=Cortex-M0plus'] cpp_args = ['--cpu=Cortex-M0plus'] [host_machine] system = 'bare metal' # Update with your system name - bare metal/OS. cpu_family = 'arm' cpu = 'Cortex-M0+' endian = 'little' meson-0.53.2/cross/armclang-linux.txt0000644000175000017500000000240113605156067021135 0ustar jpakkanejpakkane00000000000000# Using ARM compilers from Linux command line is tricky and # not really well documented because they want you to use # their IDE instead. # # First you need to do the full install with the IDE and set # up license files et al. This may be possible from the command # line. # # Then you need to do the following: # # Select toolchain by running /opt/arm/developmentstudio-2019.0/bin/select_default_toolchain # Armcc is only available in toolchain version 5. # Armclang is only available in toolchain version 6. # Start shell with /opt/arm/developmentstudio-2019.0/bin/suite_exec zsh # Now the compilers will work. [binaries] # we could set exe_wrapper = qemu-arm-static but to test the case # when cross compiled binaries can't be run we don't do that c = '/opt/arm/developmentstudio-2019.0/sw/ARMCompiler6.12/bin/armclang' #c = '/opt/arm/developmentstudio-2019.0/sw/ARMCompiler5.06u6/bin/armcc' #cpp = '/usr/bin/arm-linux-gnueabihf-g++' ar = '/opt/arm/developmentstudio-2019.0/sw/ARMCompiler6.12/bin/armar' #strip = '/usr/arm-linux-gnueabihf/bin/strip' #pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config' [properties] c_args = ['--target=aarch64-arm-none-eabi'] [host_machine] system = 'baremetal' cpu_family = 'arm' cpu = 'armv7' # Not sure if correct. endian = 'little' meson-0.53.2/cross/armclang.txt0000644000175000017500000000124313340206727017776 0ustar jpakkanejpakkane00000000000000# This file assumes that path to the arm compiler toolchain is added # to the environment(PATH) variable, so that Meson can find # the armclang, armlink and armar while building. [binaries] c = 'armclang' cpp = 'armclang' ar = 'armar' strip = 'armar' [properties] # The '--target', '-mcpu' options with the appropriate values should be mentioned # to cross compile c/c++ code with armclang. c_args = ['--target=arm-arm-none-eabi', '-mcpu=cortex-m0plus'] cpp_args = ['--target=arm-arm-none-eabi', '-mcpu=cortex-m0plus'] [host_machine] system = 'bare metal' # Update with your system name - bare metal/OS. cpu_family = 'arm' cpu = 'Cortex-M0+' endian = 'little' meson-0.53.2/cross/ccrx.txt0000644000175000017500000000103313625260316017146 0ustar jpakkanejpakkane00000000000000# This file assumes that path to the Renesas CC-RX toolchain is added # to the environment(PATH) variable, so that Meson can find # ccrx and rlink while building. [binaries] c = 'ccrx' cpp = 'ccrx' ar = 'rlink' strip = 'rlink' [properties] # The '--cpu' option with the appropriate target type should be mentioned # to cross compile c/c++ code with ccrx,. c_args = ['-cpu=rx600'] cpp_args = ['-cpu=rx600'] c_link_args = [] cpp_link_args = [] [host_machine] system = 'bare metal' cpu_family = 'rx' cpu = 'rx600' endian = 'little' meson-0.53.2/cross/iphone.txt0000644000175000017500000000230013111335362017461 0ustar jpakkanejpakkane00000000000000# This is a cross compilation file from OSX Yosemite to iPhone # Apple keeps changing the location and names of files so # these might not work for you. Use the googels and xcrun. [binaries] c = 'clang' cpp = 'clang++' ar = 'ar' strip = 'strip' [properties] root = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer' c_args = ['-arch', 'armv7', '-miphoneos-version-min=8.0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.4.sdk'] cpp_args = ['-arch', 'armv7', '-miphoneos-version-min=8.0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.4.sdk'] c_link_args = ['-arch', 'armv7', '-miphoneos-version-min=8.0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.4.sdk'] cpp_link_args = ['-arch', 'armv7', '-miphoneos-version-min=8.0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.4.sdk'] has_function_printf = true has_function_hfkerhisadf = false [host_machine] system = 'darwin' cpu_family = 'arm' cpu = 'armv7' endian = 'little' meson-0.53.2/cross/linux-mingw-w64-32bit.txt0000644000175000017500000000116013612417564022032 0ustar jpakkanejpakkane00000000000000[binaries] c = '/usr/bin/i686-w64-mingw32-gcc' cpp = '/usr/bin/i686-w64-mingw32-g++' ar = '/usr/bin/i686-w64-mingw32-ar' strip = '/usr/bin/i686-w64-mingw32-strip' pkgconfig = '/usr/bin/i686-w64-mingw32-pkg-config' windres = '/usr/bin/i686-w64-mingw32-windres' exe_wrapper = 'wine' ld = '/usr/bin/i686-w64-mingw32-ld' [properties] # Directory that contains 'bin', 'lib', etc root = '/usr/i686-w64-mingw32' # Directory that contains 'bin', 'lib', etc for the toolchain and system libraries sys_root = '/usr/i686-w64-mingw32/sys-root/mingw' [host_machine] system = 'windows' cpu_family = 'x86' cpu = 'i686' endian = 'little' meson-0.53.2/cross/linux-mingw-w64-64bit.txt0000644000175000017500000000114313340206727022033 0ustar jpakkanejpakkane00000000000000[binaries] c = '/usr/bin/x86_64-w64-mingw32-gcc' cpp = '/usr/bin/x86_64-w64-mingw32-g++' ar = '/usr/bin/x86_64-w64-mingw32-ar' strip = '/usr/bin/x86_64-w64-mingw32-strip' pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config' windres = '/usr/bin/x86_64-w64-mingw32-windres' exe_wrapper = 'wine64' [properties] # Directory that contains 'bin', 'lib', etc root = '/usr/x86_64-w64-mingw32' # Directory that contains 'bin', 'lib', etc for the toolchain and system libraries sys_root = '/usr/x86_64-w64-mingw32/sys-root/mingw' [host_machine] system = 'windows' cpu_family = 'x86_64' cpu = 'x86_64' endian = 'little' meson-0.53.2/cross/ownstdlib.txt0000644000175000017500000000046012722326652020222 0ustar jpakkanejpakkane00000000000000# This is a setup for compiling a program that runs natively # but uses a custom std lib. This test will only work on # x86_64. [target_machine] system = 'linux' cpu_family = 'x86_64' cpu = 'x86_64' endian = 'little' [properties] c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, dependency name meson-0.53.2/cross/tvos.txt0000644000175000017500000000226513501510132017175 0ustar jpakkanejpakkane00000000000000# This is a cross compilation file from OSX Yosemite to Apple tvOS # Apple keeps changing the location and names of files so # these might not work for you. Use the googels and xcrun. [binaries] c = 'clang' cpp = 'clang++' ar = 'ar' strip = 'strip' [properties] root = '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer' c_args = ['-arch', 'arm64', '-mtvos-version-min=12.0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk'] cpp_args = ['-arch', 'arm64', '-mtvos-version-min=12.0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk'] c_link_args = ['-arch', 'arm64', '-mtvos-version-min=12.0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk'] cpp_link_args = ['-arch', 'arm64', '-mtvos-version-min=12.0', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk'] has_function_printf = true has_function_hfkerhisadf = false [host_machine] system = 'darwin' cpu_family = 'arm' cpu = 'arm64' endian = 'little' meson-0.53.2/cross/ubuntu-armhf.txt0000644000175000017500000000150513612417564020635 0ustar jpakkanejpakkane00000000000000[binaries] # we could set exe_wrapper = qemu-arm-static but to test the case # when cross compiled binaries can't be run we don't do that c = '/usr/bin/arm-linux-gnueabihf-gcc' cpp = '/usr/bin/arm-linux-gnueabihf-g++' rust = ['rustc', '--target', 'arm-unknown-linux-gnueabihf', '-C', 'linker=/usr/bin/arm-linux-gnueabihf-gcc-7'] ar = '/usr/arm-linux-gnueabihf/bin/ar' strip = '/usr/arm-linux-gnueabihf/bin/strip' pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config' ld = '/usr/bin/arm-linux/gnueabihf-ld' [properties] root = '/usr/arm-linux-gnueabihf' # Used in unit test '140 get define' c_args = ['-DMESON_TEST_ISSUE_1665=1'] cpp_args = '-DMESON_TEST_ISSUE_1665=1' has_function_printf = true has_function_hfkerhisadf = false [host_machine] system = 'linux' cpu_family = 'arm' cpu = 'armv7' # Not sure if correct. endian = 'little' meson-0.53.2/cross/ubuntu-faketarget.txt0000644000175000017500000000061712650745767021672 0ustar jpakkanejpakkane00000000000000# This is a setup for compiling a program that runs natively # but produces output that runs on a different platform. # That is either a cross compiler or something like binutils. # We don't need to specify any properties or compilers, # for we use the native ones and can run the resulting # binaries directly. [target_machine] system = 'linux' cpu_family = 'mips' cpu = 'mips' endian = 'little' meson-0.53.2/cross/wasm.txt0000644000175000017500000000070513531533272017163 0ustar jpakkanejpakkane00000000000000[binaries] c = '/home/jpakkane/emsdk/fastcomp/emscripten/emcc' cpp = '/home/jpakkane/emsdk/fastcomp/emscripten/em++' ar = '/home/jpakkane/emsdk/fastcomp/emscripten/emar' [properties] c_args = ['-s', 'WASM=1', '-s', 'EXPORT_ALL=1'] c_link_args = ['-s','EXPORT_ALL=1'] cpp_args = ['-s', 'WASM=1', '-s', 'EXPORT_ALL=1'] cpp_link_args = ['-s', 'EXPORT_ALL=1'] [host_machine] system = 'emscripten' cpu_family = 'wasm32' cpu = 'wasm32' endian = 'little' meson-0.53.2/data/0000755000175000017500000000000013625242353015232 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/com.mesonbuild.install.policy0000644000175000017500000000160013426772647023050 0ustar jpakkanejpakkane00000000000000 The Meson Build System https://github.com/mesonbuild/meson Install the given project via Meson Authentication is required to install this project preferences-system no no auth_admin_keep /usr/bin/python3 /usr/bin/meson meson-0.53.2/data/macros.meson0000644000175000017500000000265213462637046017574 0ustar jpakkanejpakkane00000000000000%__meson %{_bindir}/meson %__meson_wrap_mode nodownload %__meson_auto_features enabled %_smp_mesonflags %([ -z "$MESON_BUILD_NCPUS" ] \\\ && MESON_BUILD_NCPUS="`/usr/bin/getconf _NPROCESSORS_ONLN`"; \\\ ncpus_max=%{?_smp_ncpus_max}; \\\ if [ -n "$ncpus_max" ] && [ "$ncpus_max" -gt 0 ] && [ "$MESON_BUILD_NCPUS" -gt "$ncpus_max" ]; then MESON_BUILD_NCPUS="$ncpus_max"; fi; \\\ if [ "$MESON_BUILD_NCPUS" -gt 1 ]; then echo "--num-processes $MESON_BUILD_NCPUS"; fi) %meson \ %set_build_flags \ %{shrink:%{__meson} \ --buildtype=plain \ --prefix=%{_prefix} \ --libdir=%{_libdir} \ --libexecdir=%{_libexecdir} \ --bindir=%{_bindir} \ --sbindir=%{_sbindir} \ --includedir=%{_includedir} \ --datadir=%{_datadir} \ --mandir=%{_mandir} \ --infodir=%{_infodir} \ --localedir=%{_datadir}/locale \ --sysconfdir=%{_sysconfdir} \ --localstatedir=%{_localstatedir} \ --sharedstatedir=%{_sharedstatedir} \ --wrap-mode=%{__meson_wrap_mode} \ --auto-features=%{__meson_auto_features} \ %{_vpath_srcdir} %{_vpath_builddir} \ %{nil}} %meson_build \ %ninja_build -C %{_vpath_builddir} %meson_install \ %ninja_install -C %{_vpath_builddir} %meson_test \ %{shrink: %{__meson} test \ -C %{_vpath_builddir} \ %{?_smp_mesonflags} \ --print-errorlogs \ %{nil}} meson-0.53.2/data/shell-completions/0000755000175000017500000000000013625242350020670 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/shell-completions/bash/0000755000175000017500000000000013625242353021610 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/shell-completions/bash/meson0000644000175000017500000002073413441242441022654 0ustar jpakkanejpakkane00000000000000_meson() { command="${COMP_WORDS[1]}" case "$command" in setup |\ configure |\ install |\ introspect |\ init |\ test |\ wrap |\ subprojects |\ help) _meson-$command "${COMP_WORDS[@]:1}" ;; *) _meson-setup "${COMP_WORDS[@]}" ;; esac } && complete -F _meson meson _meson_complete_option() { option_string=$1 if [[ $# -eq 2 ]] && ! [[ "$option_string" == *=* ]]; then option_string="$option_string=$2" fi if [[ "$option_string" == *=* ]]; then _meson_complete_option_value "$option_string" else _meson_complete_option_name "$option_string" fi } _meson_complete_option_name() { option=$1 options=($(python3 -c 'import sys, json for option in json.load(sys.stdin): print(option["name"]) ' <<< "$(_meson_get_options)")) compopt -o nospace COMPREPLY=($(compgen -W '${options[@]}' -S= -- "$option")) } _meson_complete_option_value() { cur=$1 option_name=${cur%%=*} option_value=${cur#*=} if _meson_complete_filedir "$option_name" "$option_value"; then return fi # TODO: support all the option types options=($(python3 -c 'import sys, json for option in json.load(sys.stdin): if option["name"] != "'$option_name'": continue choices = [] if option["type"] == "boolean": choices.append("true") choices.append("false") elif option["type"] == "combo": for choice in option["choices"]: choices.append(choice) for choice in choices: if choice.startswith("'$cur'"): print(choice) ' <<< "$(_meson_get_options)")) COMPREPLY=("${options[@]}") } _meson_get_options() { local options for builddir in "${COMP_WORDS[@]}"; do if [ -d "$builddir" ]; then break fi builddir=. done options=$(meson introspect "$builddir" --buildoptions 2>/dev/null) && echo "$options" || echo '[]' } _meson_complete_filedir() { _filedir_in() { pushd "$1" &>/dev/null local COMPREPLY=() _filedir echo "${COMPREPLY[@]}" popd &>/dev/null } option=$1 cur=$2 case $option in prefix |\ libdir |\ libexecdir |\ bindir |\ sbindir |\ includedir |\ datadir |\ mandir |\ infodir |\ localedir |\ sysconfdir |\ localstatedir |\ sharedstatedir) _filedir -d ;; cross-file) _filedir COMPREPLY+=($(_filedir_in "$XDG_DATA_DIRS"/meson/cross)) COMPREPLY+=($(_filedir_in /usr/local/share/meson/cross)) COMPREPLY+=($(_filedir_in /usr/share/meson/cross)) COMPREPLY+=($(_filedir_in "$XDG_DATA_HOME"/meson/cross)) COMPREPLY+=($(_filedir_in ~/.local/share/meson/cross)) ;; *) return 1;; esac return 0 } _meson-setup() { shortopts=( h D v ) longopts=( help prefix libdir libexecdir bindir sbindir includedir datadir mandir infodir localedir sysconfdir localstatedir sharedstatedir backend buildtype strip unity werror layout default-library warnlevel stdsplit errorlogs cross-file version wrap-mode ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null && [ "${prev:0:2}" = '--' ] && _meson_complete_option "${prev:2}" "$cur"; then return elif _get_comp_words_by_ref cur prev &>/dev/null && [ "${prev:0:1}" = '-' ] && [ "${prev:1:2}" != '-' ] && _meson_complete_option "${prev:1}"; then return elif _get_comp_words_by_ref -n '=' cur prev &>/dev/null; then if [ $prev == -D ]; then _meson_complete_option "$cur" return fi else cur="${COMP_WORDS[COMP_CWORD]}" fi if [[ "$cur" == "--"* ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) elif [[ "$cur" == "-"* ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) else _filedir -d if [ -z "$cur" ]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi if [ $COMP_CWORD -eq 1 ]; then COMPREPLY+=($(compgen -W 'setup configure test introspect' -- "$cur")) fi fi } _meson-configure() { shortopts=( h D ) longopts=( help clearcache ) local cur prev if _get_comp_words_by_ref -n '=' cur prev &>/dev/null; then if [ $prev == -D ]; then _meson_complete_option "$cur" return fi else cur="${COMP_WORDS[COMP_CWORD]}" fi if [[ "$cur" == "--"* ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) elif [[ "$cur" == "-"* ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) else for dir in "${COMP_WORDS[@]}"; do if [ -d "$dir" ]; then break fi dir=. done if [ ! -d "$dir/meson-private" ]; then _filedir -d fi if [ -z "$cur" ]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-test() { shortopts=( q v t C ) longopts=( quiet verbose timeout-multiplier repeat no-rebuild gdb list wrapper --wrap no-suite suite no-stdsplit print-errorlogs benchmark logbase num-processes setup test-args ) local cur prev if _get_comp_words_by_ref -n ':' cur prev &>/dev/null; then case $prev in --repeat) # number, can't be completed return ;; --wrapper) _command_offset $COMP_CWORD return ;; -C) _filedir -d return ;; --suite | --no-suite) for i in "${!COMP_WORDS[@]}"; do opt="${COMP_WORDS[i]}" dir="${COMP_WORDS[i+1]}" case "$opt" in -C) break ;; esac dir=. done suites=($(python3 -c 'import sys, json; for test in json.load(sys.stdin): for suite in test["suite"]: print(suite) ' <<< "$(meson introspect "$dir" --tests)")) # TODO COMPREPLY+=($(compgen -W "${suites[*]}" -- "$cur")) return ;; --logbase) # free string, can't be completed return ;; --num-processes) # number, can't be completed return ;; -t | --timeout-multiplier) # number, can't be completed return ;; --setup) # TODO return ;; --test-args) return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if [[ "$cur" == "--"* ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) elif [[ "$cur" == "-"* && ${#cur} -gt 1 ]]; then COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) else for dir in "${COMP_WORDS[@]}"; do if [ -d "$dir" ]; then break fi dir=. done if [ ! -d "$dir/meson-private" ]; then _filedir -d fi for i in "${!COMP_WORDS[@]}"; do opt="${COMP_WORDS[i]}" dir="${COMP_WORDS[i+1]}" case "$opt" in -C) break ;; esac dir=. done tests=($(python3 -c 'import sys, json; for test in json.load(sys.stdin): print(test["name"]) ' <<< "$(meson introspect "$dir" --tests)")) COMPREPLY+=($(compgen -W "${tests[*]}" -- "$cur")) if [ -z "$cur" ]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) fi fi } _meson-introspect() { shortopts=( h ) longopts=( targets installed buildsystem-files buildoptions tests benchmarks dependencies projectinfo ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if [[ "$cur" == "--"* ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) elif [[ "$cur" == "-"* ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) else for dir in "${COMP_WORDS[@]}"; do if [ -d "$dir" ]; then break fi dir=. done if [ ! -d "$dir/meson-private" ]; then _filedir -d fi if [ -z "$cur" ]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-wrap() { : TODO } meson-0.53.2/data/shell-completions/zsh/0000755000175000017500000000000013625242353021477 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/shell-completions/zsh/_meson0000644000175000017500000001777713441242441022717 0ustar jpakkanejpakkane00000000000000#compdef meson mesonconf=meson-configure mesontest=meson-test mesonintrospect=meson-introspect # vim:ts=2 sw=2 # Copyright (c) 2017 Arseny Maslennikov # All rights reserved. Individual authors, whether or not # specifically named, retain copyright in all changes; in what follows, they # are referred to as `the Meson development team'. This is for convenience # only and this body has no legal status. This file is distributed under # the following licence. # # Permission is hereby granted, without written agreement and without # licence or royalty fees, to use, copy, modify, and distribute this # software and to distribute modified versions of this software for any # purpose, provided that the above copyright notice and the following # two paragraphs appear in all copies of this software. # # In no event shall the Meson development team be liable to any party for # direct, indirect, special, incidental, or consequential damages arising out # of the use of this software and its documentation, even if the Meson # development team have been advised of the possibility of such damage. # # The Meson development team specifically disclaim any warranties, including, # but not limited to, the implied warranties of merchantability and fitness # for a particular purpose. The software provided hereunder is on an "as is" # basis, and the Meson development team have no obligation to provide # maintenance, support, updates, enhancements, or modifications. local curcontext="$curcontext" state line local -i ret local __meson_backends="(ninja xcode ${(j. .)${:-vs{,2010,2015,2017}}})" local __meson_build_types="(plain debug debugoptimized minsize release)" local __meson_wrap_modes="(WrapMode.{default,nofallback,nodownload,forcefallback})" local -a meson_commands=( 'setup:set up a build directory' 'configure:configure a project' 'test:run tests' 'introspect:query project properties' 'wrap:manage source dependencies' ) (( $+functions[__meson_is_build_dir] )) || __meson_is_build_dir() { local mpd="${1:-$PWD}/meson-private" [[ -f "$mpd/build.dat" && -f "$mpd/coredata.dat" ]] return $? } # TODO: implement build option completion (( $+functions[__meson_build_options] )) || __meson_build_options() {} # `meson introspect` currently can provide that information in JSON. # We can: # 1) pipe its output to python3 -m json.tool | grep "$alovelyregex" | cut <...> # 2) teach mintro.py to use a different output format # (or perhaps just to select the fields printed) (( $+functions[__meson_test_names] )) || __meson_test_names() { local rtests if rtests="$(_call_program meson meson test ${opt_args[-C]:+-C "$opt_args[-C]"} --list)"; then local -a tests=(${(@f)rtests}) _describe -t "tests" "Meson tests" tests else _message -r "current working directory is not a build directory" _message -r 'use -C $build_dir or cd $build_dir' fi } (( $+functions[_meson_commands] )) || _meson_commands() { _describe -t commands "Meson subcommands" meson_commands } (( $+functions[_meson-setup] )) || _meson-setup() { local firstd secondd if [[ -f "meson.build" ]]; then # if there's no second argument on the command line # cwd will implicitly be substituted: # - as the source directory if it has a file with the name "meson.build"; # - as the build directory otherwise # more info in mesonbuild/mesonmain.py firstd="build" secondd="source" else firstd="source" secondd="build" fi _arguments \ '*-D-[set the value of a build option]:build option:__meson_build_options' \ '--prefix=[installation prefix]: :_directories' \ '--libdir=[library directory]: :_directories' \ '--libexecdir=[library executable directory]: :_directories' \ '--bindir=[executable directory]: :_directories' \ '--sbindir=[system executable directory]: :_directories' \ '--includedir=[header file directory]: :_directories' \ '--datadir=[data file directory]: :_directories' \ '--mandir=[manual page directory]: :_directories' \ '--infodir=[info page directory]: :_directories' \ '--localedir=[locale data directory]: :_directories' \ '--sysconfdir=[system configuration directory]: :_directories' \ '--localstatedir=[local state data directory]: :_directories' \ '--sharedstatedir=[arch-independent data directory]: :_directories' \ '--backend=[backend to use]:Meson backend:'"$__meson_backends" \ '--buildtype=[build type to use]:Meson build type:'"$__meson_build_types" \ '--strip[strip targets on install]' \ '--unity=[unity builds on/off]:whether to do unity builds:(on off subprojects)' \ '--werror[treat warnings as errors]' \ '--layout=[build directory layout]:build directory layout:(flat mirror)' \ '--default-library=[default library type]:default library type:(shared static)' \ '--warnlevel=[compiler warning level]:compiler warning level:warning level:(1 2 3)' \ '--stdsplit=[split stdout and stderr in test logs]' \ '--errorlogs=[prints the logs from failing tests]' \ '--cross-file=[cross-compilation environment description]:cross file:_files' \ '--wrap-mode=[special wrap mode]:wrap mode:'"$__meson_wrap_modes" \ ":$firstd directory:_directories" \ "::$secondd directory:_directories" \ # } (( $+functions[_meson-configure] )) || _meson-configure() { local curcontext="$curcontext" # TODO: implement 'mesonconf @file' local -a specs=( '--clearcache[clear cached state]' '*-D-[set the value of a build option]:build option:__meson_build_options' '::build directory:_directories' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-test] )) || _meson-test() { local curcontext="$curcontext" # TODO: complete test suites local -a specs=( '(--quiet -q)'{'--quiet','-q'}'[produce less output to the terminal]' '(--verbose -v)'{'--verbose','-v'}'[do not redirect stdout and stderr]' '(--timeout-multiplier -t)'{'--timeout-multiplier','-t'}'[a multiplier for test timeouts]:Python floating-point number: ' '-C[directory to cd into]: :_directories' '--repeat[number of times to run the tests]:number of times to repeat: ' '--no-rebuild[do not rebuild before running tests]' '--gdb[run tests under gdb]' '--list[list available tests]' '(--wrapper --wrap)'{'--wrapper=','--wrap='}'[wrapper to run tests with]:wrapper program:_path_commands' '(--no-suite)--suite[only run tests from this suite]:test suite: ' '(--suite)--no-suite[do not run tests from this suite]:test suite: ' '--no-stdsplit[do not split stderr and stdout in logs]' '--print-errorlogs[print logs for failing tests]' '--benchmark[run benchmarks instead of tests]' '--logbase[base name for log file]:filename: ' '--num-processes[how many threads to use]:number of processes: ' '--setup[which test setup to use]:test setup: ' '--test-args[arguments to pass to the tests]: : ' '*:Meson tests:__meson_test_names' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-introspect] )) || _meson-introspect() { local curcontext="$curcontext" local -a specs=( '--targets[list top level targets]' '--installed[list all installed files and directories]' '--buildsystem-files[list files that belong to the build system]' '--buildoptions[list all build options]' '--tests[list all unit tests]' '--benchmarks[list all benchmarks]' '--dependencies[list external dependencies]' '--projectinfo[show project information]' '::build directory:_directories' ) _arguments \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ "${(@)specs}" } (( $+functions[_meson-wrap] )) || _meson-wrap() { # TODO } if [[ $service != meson ]]; then _call_function ret _$service return ret fi _arguments -C -R \ '(: -)'{'--help','-h'}'[show a help message and quit]' \ '(: -)'{'--version','-v'}'[show version information and quit]' \ '(-): :_meson_commands' \ '*:: :->post-command' \ # ret=$? [[ $ret = 300 ]] && case "$state" in post-command) service="meson-$words[1]" curcontext=${curcontext%:*:*}:$service: _call_function ret _$service ;; esac return ret meson-0.53.2/data/syntax-highlighting/0000755000175000017500000000000013625242350021220 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/syntax-highlighting/emacs/0000755000175000017500000000000013625242353022313 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/syntax-highlighting/emacs/meson.el0000644000175000017500000000162713340206727023763 0ustar jpakkanejpakkane00000000000000;; keywords for syntax coloring (setq meson-keywords `( ( ,(regexp-opt '("elif" "if" "else" "endif" "foreach" "endforeach") 'word) . font-lock-keyword-face) ) ) ;; syntax table (defvar meson-syntax-table nil "Syntax table for `meson-mode'.") (setq meson-syntax-table (let ((synTable (make-syntax-table))) ;; bash style comment: ā€œ# ā€¦ā€ (modify-syntax-entry ?# "< b" synTable) (modify-syntax-entry ?\n "> b" synTable) synTable)) ;; define the major mode. (define-derived-mode meson-mode prog-mode "meson-mode is a major mode for editing Meson build definition files." :syntax-table meson-syntax-table (setq font-lock-defaults '(meson-keywords)) (setq mode-name "meson") (setq-local comment-start "# ") (setq-local comment-end "")) (add-to-list 'auto-mode-alist '("meson.build" . meson-mode)) (provide 'meson) ;;; meson.el ends here meson-0.53.2/data/syntax-highlighting/vim/0000755000175000017500000000000013625242353022016 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/syntax-highlighting/vim/README0000644000175000017500000000020513403223113022656 0ustar jpakkanejpakkane00000000000000ftdetect sets the filetype ftplugin sets Meson indentation rules indent does Meson indentation syntax does Meson syntax highlighting meson-0.53.2/data/syntax-highlighting/vim/ftdetect/0000755000175000017500000000000013625242353023620 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/syntax-highlighting/vim/ftdetect/meson.vim0000644000175000017500000000016013612417061025447 0ustar jpakkanejpakkane00000000000000au BufNewFile,BufRead meson.build set filetype=meson au BufNewFile,BufRead meson_options.txt set filetype=meson meson-0.53.2/data/syntax-highlighting/vim/ftplugin/0000755000175000017500000000000013625242353023646 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/syntax-highlighting/vim/ftplugin/meson.vim0000644000175000017500000000062413571777336025524 0ustar jpakkanejpakkane00000000000000" Vim filetype plugin file " Language: meson " License: VIM License " Original Author: Laurent Pinchart " Last Change: 2018 Nov 27 if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 let s:keepcpo= &cpo set cpo&vim setlocal commentstring=#\ %s setlocal comments=:# setlocal shiftwidth=2 setlocal softtabstop=2 let &cpo = s:keepcpo unlet s:keepcpo meson-0.53.2/data/syntax-highlighting/vim/indent/0000755000175000017500000000000013625242353023277 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/syntax-highlighting/vim/indent/meson.vim0000644000175000017500000001215413571777336025156 0ustar jpakkanejpakkane00000000000000" Vim indent file " Language: Meson " License: VIM License " Maintainer: Nirbheek Chauhan " Original Authors: David Bustos " Bram Moolenaar " Last Change: 2015 Feb 23 " Only load this indent file when no other was loaded. if exists("b:did_indent") finish endif let b:did_indent = 1 " Some preliminary settings setlocal nolisp " Make sure lisp indenting doesn't supersede us setlocal autoindent " indentexpr isn't much help otherwise setlocal indentexpr=GetMesonIndent(v:lnum) setlocal indentkeys+==elif,=else,=endforeach,=endif,0) " Only define the function once. if exists("*GetMesonIndent") finish endif let s:keepcpo= &cpo setlocal cpo&vim " Come here when loading the script the first time. let s:maxoff = 50 " maximum number of lines to look backwards for () function GetMesonIndent(lnum) echom getline(line(".")) " If this line is explicitly joined: If the previous line was also joined, " line it up with that one, otherwise add two 'shiftwidth' if getline(a:lnum - 1) =~ '\\$' if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$' return indent(a:lnum - 1) endif return indent(a:lnum - 1) + (exists("g:mesonindent_continue") ? eval(g:mesonindent_continue) : (shiftwidth() * 2)) endif " If the start of the line is in a string don't change the indent. if has('syntax_items') \ && synIDattr(synID(a:lnum, 1, 1), "name") =~ "String$" return -1 endif " Search backwards for the previous non-empty line. let plnum = prevnonblank(v:lnum - 1) if plnum == 0 " This is the first non-empty line, use zero indent. return 0 endif " If the previous line is inside parenthesis, use the indent of the starting " line. " Trick: use the non-existing "dummy" variable to break out of the loop when " going too far back. call cursor(plnum, 1) let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW', \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :" \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") if parlnum > 0 let plindent = indent(parlnum) let plnumstart = parlnum else let plindent = indent(plnum) let plnumstart = plnum endif " When inside parenthesis: If at the first line below the parenthesis add " a 'shiftwidth', otherwise same as previous line. " i = (a " + b " + c) call cursor(a:lnum, 1) let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") if p > 0 if p == plnum " When the start is inside parenthesis, only indent one 'shiftwidth'. let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") if pp > 0 return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth()) endif return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : shiftwidth()) endif if plnumstart == p return indent(plnum) endif return plindent endif " Get the line and remove a trailing comment. " Use syntax highlighting attributes when possible. let pline = getline(plnum) let pline_len = strlen(pline) if has('syntax_items') " If the last character in the line is a comment, do a binary search for " the start of the comment. synID() is slow, a linear search would take " too long on a long line. if synIDattr(synID(plnum, pline_len, 1), "name") =~ "\\(Comment\\|Todo\\)$" let min = 1 let max = pline_len while min < max let col = (min + max) / 2 if synIDattr(synID(plnum, col, 1), "name") =~ "\\(Comment\\|Todo\\)$" let max = col else let min = col + 1 endif endwhile let pline = strpart(pline, 0, min - 1) endif else let col = 0 while col < pline_len if pline[col] == '#' let pline = strpart(pline, 0, col) break endif let col = col + 1 endwhile endif " If the previous line ended the conditional/loop if getline(plnum) =~ '^\s*\(endif\|endforeach\)\>\s*' " Maintain indent return -1 endif " If the previous line ended with a builtin, indent this line if pline =~ '^\s*\(foreach\|if\|else\|elif\)\>\s*' return plindent + shiftwidth() endif " If the current line begins with a header keyword, deindent if getline(a:lnum) =~ '^\s*\(else\|elif\|endif\|endforeach\)' " Unless the previous line was a one-liner if getline(plnumstart) =~ '^\s*\(foreach\|if\)\>\s*' return plindent endif " Or the user has already dedented if indent(a:lnum) <= plindent - shiftwidth() return -1 endif return plindent - shiftwidth() endif " When after a () construct we probably want to go back to the start line. " a = (b " + c) " here if parlnum > 0 return plindent endif return -1 endfunction let &cpo = s:keepcpo unlet s:keepcpo " vim:sw=2 meson-0.53.2/data/syntax-highlighting/vim/syntax/0000755000175000017500000000000013625242353023344 5ustar jpakkanejpakkane00000000000000meson-0.53.2/data/syntax-highlighting/vim/syntax/meson.vim0000644000175000017500000001003313602226377025202 0ustar jpakkanejpakkane00000000000000" Vim syntax file " Language: Meson " License: VIM License " Maintainer: Nirbheek Chauhan " Last Change: 2016 Dec 7 " Credits: Zvezdan Petkovic " Neil Schemenauer " Dmitry Vasiliev " " This version is copied and edited from python.vim " It's very basic, and doesn't do many things I'd like it to " For instance, it should show errors for syntax that is valid in " Python but not in Meson. " " Optional highlighting can be controlled using these variables. " " let meson_space_error_highlight = 1 " " For version 5.x: Clear all syntax items. " For version 6.x: Quit when a syntax file was already loaded. if version < 600 syntax clear elseif exists("b:current_syntax") finish endif " We need nocompatible mode in order to continue lines with backslashes. " Original setting will be restored. let s:cpo_save = &cpo set cpo&vim " http://mesonbuild.com/Syntax.html syn keyword mesonConditional elif else if endif syn keyword mesonRepeat foreach endforeach syn keyword mesonOperator and not or syn match mesonComment "#.*$" contains=mesonTodo,@Spell syn keyword mesonTodo FIXME NOTE NOTES TODO XXX contained " Strings can either be single quoted or triple counted across multiple lines, " but always with a ' syn region mesonString \ start="\z('\)" end="\z1" skip="\\\\\|\\\z1" \ contains=mesonEscape,@Spell syn region mesonString \ start="\z('''\)" end="\z1" keepend \ contains=mesonEscape,mesonSpaceError,@Spell syn match mesonEscape "\\[abfnrtv'\\]" contained syn match mesonEscape "\\\o\{1,3}" contained syn match mesonEscape "\\x\x\{2}" contained syn match mesonEscape "\%(\\u\x\{4}\|\\U\x\{8}\)" contained " Meson allows case-insensitive Unicode IDs: http://www.unicode.org/charts/ syn match mesonEscape "\\N{\a\+\%(\s\a\+\)*}" contained syn match mesonEscape "\\$" " Meson only supports integer numbers " http://mesonbuild.com/Syntax.html#numbers syn match mesonNumber "\<\d\+\>" " booleans syn keyword mesonConstant false true " Built-in functions syn keyword mesonBuiltin \ add_global_arguments \ add_global_link_arguments \ add_languages \ add_project_arguments \ add_project_link_arguments \ add_test_setup \ alias_target \ assert \ benchmark \ both_libraries \ build_machine \ build_target \ configuration_data \ configure_file \ custom_target \ declare_dependency \ dependency \ disabler \ environment \ error \ executable \ files \ find_library \ find_program \ generator \ get_option \ get_variable \ gettext \ host_machine \ import \ include_directories \ install_data \ install_headers \ install_man \ install_subdir \ is_disabler \ is_variable \ jar \ join_paths \ library \ meson \ message \ option \ project \ run_command \ run_target \ set_variable \ shared_library \ shared_module \ static_library \ subdir \ subdir_done \ subproject \ summary \ target_machine \ test \ vcs_tag \ warning if exists("meson_space_error_highlight") " trailing whitespace syn match mesonSpaceError display excludenl "\s\+$" " mixed tabs and spaces syn match mesonSpaceError display " \+\t" syn match mesonSpaceError display "\t\+ " endif if version >= 508 || !exists("did_meson_syn_inits") if version <= 508 let did_meson_syn_inits = 1 command -nargs=+ HiLink hi link else command -nargs=+ HiLink hi def link endif " The default highlight links. Can be overridden later. HiLink mesonStatement Statement HiLink mesonConditional Conditional HiLink mesonRepeat Repeat HiLink mesonOperator Operator HiLink mesonComment Comment HiLink mesonTodo Todo HiLink mesonString String HiLink mesonEscape Special HiLink mesonNumber Number HiLink mesonBuiltin Function HiLink mesonConstant Number if exists("meson_space_error_highlight") HiLink mesonSpaceError Error endif delcommand HiLink endif let b:current_syntax = "meson" let &cpo = s:cpo_save unlet s:cpo_save " vim:set sw=2 sts=2 ts=8 noet: meson-0.53.2/ghwt.py0000755000175000017500000000771213602226377015661 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ghwt - GitHub WrapTool # # An emergency wraptool(1) replacement downloader that downloads # directly from GitHub in case wrapdb.mesonbuild.com is down. import urllib.request, json, sys, os, shutil, subprocess import configparser, hashlib req_timeout = 600.0 private_repos = {'meson', 'wrapweb', 'meson-ci'} def gh_get(url): r = urllib.request.urlopen(url, timeout=req_timeout) jd = json.loads(r.read().decode('utf-8')) return jd def list_projects(): jd = gh_get('https://api.github.com/orgs/mesonbuild/repos') entries = [entry['name'] for entry in jd] entries = [e for e in entries if e not in private_repos] entries.sort() for i in entries: print(i) return 0 def unpack(sproj, branch, 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() config.read(usfile) us_url = config['wrap-file']['source_url'] us = urllib.request.urlopen(us_url, timeout=req_timeout).read() h = hashlib.sha256() h.update(us) dig = h.hexdigest() should = config['wrap-file']['source_hash'] if dig != should: print('Incorrect hash on download.') print(' expected:', dig) print(' obtained:', should) return 1 spdir = os.path.dirname(outdir) ofilename = os.path.join(spdir, config['wrap-file']['source_filename']) with open(ofilename, 'wb') as ofile: ofile.write(us) if 'lead_directory_missing' in config['wrap-file']: os.mkdir(outdir) shutil.unpack_archive(ofilename, outdir) else: shutil.unpack_archive(ofilename, spdir) extdir = os.path.join(spdir, config['wrap-file']['directory']) assert(os.path.isdir(extdir)) shutil.move(os.path.join(outdir, '.git'), extdir) subprocess.check_call(['git', 'reset', '--hard'], cwd=extdir) shutil.rmtree(outdir) shutil.move(extdir, outdir) shutil.rmtree(os.path.join(outdir, '.git')) os.unlink(ofilename) def install(sproj): sproj_dir = os.path.join('subprojects', sproj) if not os.path.isdir('subprojects'): print('Run this in your source root and make sure there is a subprojects directory in it.') return 1 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/{}/branches'.format(sproj)) blist = [b['name'] for b in blist] blist = [b for b in blist if b != 'master'] blist.sort() branch = blist[-1] print('Using branch', branch) return unpack(sproj, branch, sproj_dir) def run(args): if not args or args[0] == '-h' or args[0] == '--help': print(sys.argv[0], 'list/install', 'package_name') return 1 command = args[0] args = args[1:] if command == 'list': list_projects() return 0 elif command == 'install': if len(args) != 1: print('Install requires exactly one argument.') return 1 return install(args[0]) else: print('Unknown command') return 1 if __name__ == '__main__': print('This is an emergency wrap downloader. Use only when wrapdb is down.') sys.exit(run(sys.argv[1:])) meson-0.53.2/graphics/0000755000175000017500000000000013625242353016121 5ustar jpakkanejpakkane00000000000000meson-0.53.2/graphics/meson_logo.svg0000644000175000017500000013256013431063044021003 0ustar jpakkanejpakkane00000000000000 image/svg+xml meson-0.53.2/graphics/meson_logo_big.png0000644000175000017500000005260113431063044021606 0ustar jpakkanejpakkane00000000000000‰PNG  IHDRÅ„µA`sBIT|dˆ pHYsI‚I‚pß[tEXtSoftwarewww.inkscape.org›ī< IDATxœģŻyœu’ń×·zfrī#$™žIHAF’éIįDPŃx°"‚ŗ.*¢`’hI‚€*žü¼šbe½Ö BWqA93 ÄåG “é®ļļŹHęØīŖīoUõūłxōCīźw÷tWź{D¤a&wµMå‹=cēłeóÕė—­tIDźĆø ".½B[łķXūI`­’§Åņßó?rĒŚKw™NDjO€Hƒ)ä{Žū9ą !ī²(Nī½ļó×s}¹ŽŃD¤ŽTˆ4ˆĀä„ū’3ĒšvĀ}÷’d}óźÉ&"7{v±e§M„÷bYŽa|…W·€HF©ɰ®Ö%'Zć]“E<ŌF KV÷.’2`cˆ&"ީɠ¹mKöņ|ļN‹õĄ†•ÖēŻ«×-’k¬Ē‘ŗS ’-¦ŠÖsÖ~Ų­FĻ±ŁĄåόkŗōž{Š[jō"Rc*D2¢0­8æ’ĖXstžņn㙳nxŁ]uz>‰‘ ‘”ėč8»yŌ“{~ČB]×'·”¬1_|įÅ—Üżų'7Õõ¹E$")Ö9µgžńģW€Łn“Ų‡ńsgÆZÉoŻę‘°Tˆ¤PǤāŲę–ņĒ ö\’ó=¶¾ø„Æé‚5_pFD†—”‡ˆ„Ō™ļ™k°×3]gœ}ŲśŽ;“€H²©I‰­}żK-t9×y†e)YƧž×t‘f ˆ$“ ‘(“÷¼ß^ā:K…īņ §­\»ü>×ADd{*Dl!Ŧ-łŅł.Z\ē©Ņ‹>v{oÓ' č»#"" ÕŁŚ½æ1\ę:K<쯼ró™+)>ź:‰ˆ€ē:€ˆ¼\W[ĻŁĘ°†Ģüų˜Wū¹ŅŻ…öī×ŗN""jI”¹Ó‹;y„Ņ—·¹ĪRCÖb®zn\ī# (āŽ ‘„čjļ9ĢśöZ`šė,uałƒńyėķ,Ču‘F¤.÷L!ßżėŪ•4Ź?€įU6Ē;óKßā:ŠH#R €ˆC]ӊ{Śréąx×Yœ²|›ņ¦sVmøņE×QD… G:Ū»1>ßöv%!žH®é-«*>č:ˆH#P Rg‹X”ېŸµģ…č;ø£g­åŒÕė–ßą:ˆHÖ%{9Q‘Œ™³ļāŻžßm€Óя’`Fƛ'ļ|ų˜Āƽnŗ—{­ė@"Y„Ht¶.9ŌóC0yĒQŅā—9ætźmė/{Śu‘,Ņ,‘:(“õ¼Ćļ6żųWäų²×tW”½ē®ƒˆd‘ZDjha¾8z‹ķæŹs–ė,)ö"ƼgÕŚeßrD$KTˆŌČaӖNi*›s\gÉ{õØŽę÷ŻL±ä:‰HØ©®¶īć¬åZ`W×Y²Ä`o“„ę·®ŚP|Źu‘“Ó‘˜uµõœm-?C?ž±³˜ci*ŻYČ/žå:‹HŚ©@$&‹X”{$?ėÓū~×YĄSŽøŗwłĶ®ƒˆ¤• ‘Ģ›yĮĖØk±öD×YČ‹={uļŠk\I#"uMéžfsüŲßu–Fd1Ÿ[Ż›;оė,"i¢@$‚¹ķKē{¾¹ŲĆu–Ffła_īk-¾ą:‹HZØ©Rg[ĻYĘŚ/Ķ®³wųĘŻk/}Üu‘4Š,‘Ź™BkĻ'Œµ’żų'É\ĻšÕ­ŻźŠ A-"˜=»Ų²Ó¦Ņ7€S]g‘!=m}sŅźõĖVŗ"’d*DBZ8»8¾oSéząx×YdD/x–E+×-’¹ė "I„ķ€EB8,_ÜŪö—nøĪ"”4[xĖ”ųū†gnł×aD’H€Čŗ¦tOóLłw3Ūu©€ĮĆpņ䝼øać­źف ‘aŚ–ĪĮ˜ßaĢ×Y¤*Ę`Ž¼ó»nŲxĖÆ\‡IBgŪŅ“Œ5’ ŒuEb`łö–Ż’ł®5k®īwE$ Tˆ ¢ŠÖó|ū5 M®³HœĢOG‘{óͽÅĶ®“ˆø¦uDvŠÕÖs6Ö~C?žYdOź£ō‹…³‹ć]'qM-"Ū(“væĆU軑u·z£¶œøņ¾+žsDĵˆlՕļ¾Ćēя#XąoiłÅÜéŝ\qE€PČ÷|ĢĀe®sHYęåŹ„ßĶŁwńn®£ˆø +it¦ļł4Ųŗ"ĪüiKKÓ±kī/>į:ˆH=©Vō m„«±¼ĖuqīÆMÖ?śÖu—>ę:ˆH½Ø @Ņ"å:[K×čĒ_¶Śæd¼ß.h]²ė "õ¢@‘ِŸńEcx»ė ’(ū—ŒwÓܶ%{¹"R*¤Ń˜B~éĮœķ:ˆ$ŅLĻzæ.L.īź:ˆH­©Fb:Ū–~Ģ{\‘D;ˆ¦ŅoęOżč.®ƒˆŌ’ i…ÖīĖ5’ī:‡¤Ā!eÆéæµb d™ iłīĖ0|ÄuI•Bß¦Ņ “Ļć:ˆH-ؐĢėjėYaąB×9$•Ž¢i܏N˜~ī(×ADā¦@2­³µg™µv‰ė’jĒm,ķ|ķBŠŚJ2E€dVgėŅc»]ē,°očk-}-ž&’s@¤ŗŚzŽ|°%.†WN™xųŲ ĻÜr£ė("qP ™Shļ~->×bōł–˜ęMžøą¹ ĻÜŗŹu‘Øt‚”L™—_Śi­ł †Ń®³H6cŽ›¼ó‚Ž oż³ė,"QØyT2£kŚ’mŁ»Š.RkżĄÉ«z—’Ņu‘j©L˜?µŲ^öJ·ŚĢEźåcĶ1·Æ[¦īI%’z ¦/Ž£TŹŻ ĢtE‹±×YD*„i€’j gĒ—J¹_”qĄv÷­ż¹v”4R ©µˆE¹¾MåĪ"Ģ“{¾÷³ŽIű®“ˆTB€¤Öß[g^ öu®sˆ`xUKséŌ­*)¢i€’J…üŅbĢE®sˆü‹į€);a6l¼åf×QDĀP ©3Ƶū5֘o ,IžĆ§īrÄCl¼ån×ADF¢ę*I•ĪÖ%‡¼ßcŠ>ķ’T[Ą·ŖwŁļ]Ž IySŠ“|Æt†É®³ˆ ĒXž°MM…UtEd(jB•T˜7ó‚ å\éēśń—4°†Ż)—~²0_ÜŁu‘”ؐ(zž–Q×x„ė$"ŲæŅµ‹X¤±V’H*$ńŗŚJ—`퉮sˆTįų ł™Ė\‡Œ*SI“B¾ūõĄēŃxIÆłSvYpļ†·Žė:ˆČ¶tR•Ä*äĻ‚ÜĄN®³ˆDby޳¦såśe÷øŽ"2@]’Hó§~t¬÷Sōć/Y`o=nčhæp¢ė("TH½’×ōŒ™ī:‰H\,vĘ(æł[PŌyWADIœĪ|éRÆqC$nNījė_ā:‡h €$Lgk÷)ĘšōŁ”ģņ=ĖI+×-’¹ė ŅŲt’•Ę;uńž—»ē:‹H=ó›^uŪśāĆ®ƒHćR€$BaņycŒ—ūśń—ʰKŁ”®›=»Ųā:ˆ4.’¦iģµŅŸ4Ć«&¼PŗŌu i\źēŗņŻgXųŗė"Xƒ}Ćķ½+~ģ:ˆ4āŌ¼©=³}ĻŽ ŒuEđ§±‡Ü¾vÅ:×A¤±Ø @œ9hƏó=¾~ü„±ķb­łöBŠM®ƒHcQ Ό3ś `pC$ōµ–.rB‹ŗÄ‰Bk÷»0|Õu‘ń}ćĒŚKntDƒ ©»­óżļBM’";zĢäš¾ż”ā?]‘ģS€ŌÕ ÓĻåy¹ļ¢‘ĮģcĖeµŒI]ؐŗŚŲ?qp°ė"ÉeO*“væĖu É>uHŻĢkėYą[{sE$į6‘k:xÕCÅ]‘ģR €ŌEGū…}kæ~üE‡_śę"éū"5£@źb”mžŠź:‡HjXę=’Ÿq¾ė’]źšėj]śFkĢ\ēI”¾œ1so[»ģĻ®ƒHöؐš*L^ŗ/Męn`W×YDŅÉÜ;Š\ĒͽÅĶ®“H¶Ø @jØčŃĢ5čĒ_${ĄŹsB²G€ŌLWkł=Xs“ė"ig±ēwµö\ēlQ€ŌDWŪŅVkĶ_€ ®³ˆdƒłŪ(r‡Ø+@⢩ kł śń‰‘µ…ŅG]§ģP €Ä®ŠŚs&Ę~Ķu‘ Śbr~Ēķ]śæ®ƒHś©@bµ uÉ>ūI×9D2ŖÅ–½Æi ‰ƒ ‰UÉä¾ģā:‡H†ĶِŸq®ė’~źŲtå{Žj±×ŗĪ!Ņ^0eŗż‘å¹"鄉EnjāīūY×9DÄX›ćjt'ؐXŒź/}ŲÓu‘rT”­ē4×!$½T=Jd]mK·Ö܌>O"õöd¹æ<óĪæüI×A$}Ō ‘Ģž]l±Ö|żų‹ø°›×ā]ā:„¤“ ‰d§M„óż]ēiTƚ÷Ś–ĪqCŅG€Tm~{q*°Ōu‘ēaĶ用ó¹TD©ZŁ/ē:‡ˆpX”µüN×!$]Ōo+U)仏~į:‡ˆü‹JEŌ +L>o Ų/øĪ!"Ūр@©ˆ ©˜Ķ_¦ŻuŁžJ%THEŗ¦tO3Ę~Äu”‡5ŸAŻ»‚ ©ˆĶ™O£\ē‘!ŗņ=oqB’OU¢„Vh]Ś…1·”ĻHĀŁŽQ4ļsoq³ė$’\jŠ˜Ļ¢‘0ł>SŅ–Į2,Jg¾ü ÆrCDB²,é˜QÜŻu I.2¢ƒöśš8ƒ]į:‡H…¶øąŲĪĶ[Ź=®CHr©3ę`’ė"!żĆbĪš?øŁu— ö½sŪ»÷sC’I€ kīōād°vC$s}¹æ|ąźŽeß¼cķ„źm:øŅu*‡š=ß\ī:„$SĪuI¶Ö‰óætøĪ!2‚²%«z—šļĻŻöāĄ’ŁĖĶž†·üjŹĪGxĄó¹“ė.Güī‘·¬wD’E#ŗeH­K5Ęūśœ¤Ķ`Ųg̳ĘPźĪÖ2ģÖµĢ8`<éŚäéEą”U½Ė9ܝ łīĻØO¤Ä¹sUļņNĄŗ"É”» ©_śs0'øĪ!l6˜õ»xĖzcģ¾åIcrOX[śæ¦\Ė”6?·Ļś‡ž½žė‡ü±Æ€™?õ£;Ó4zB©o¾±{Ćųģ…aŠģ›óÉfc9ńöuĖ⾦+ßż# '×ų…ė³ģo1ŽĻ½27­\æģ^ø?v‹rŸ¶ßž¶”›ƒ±sĄvVŲĒĖmū®»oaµŻ…|Ļ `ßPĶcÓĶümrļߌ©›HRN€ģČtµuße­FžĒĄ~ƒ1ßĶ•ūzŪśĖžv(ÉęM)N²MżG[kŽ6p”…)CܵŹÆźżųßŖ}®ĪÖīż Ü”©Śc¤–1§ÆZ»ģ[®cˆ{*d;]mŻo²–Š}Ŗ2ØßČłM_½m}ńa×aŅŖ³µ{cx½1¼qŪ‚ŌĀå«{—4źń ł„_sfŌ椏}xĖn’7k͚«ū]'·Æś•!-bQnƒå×9RŹģo0ęź¾]’łc\£[½nł_æļj[Śź[sЇ=Róq?g¼Ļ•­mĄĄ“zjÆ3€«]'·Ō ’Ņ™ļy§Į~ĆuŽ”ń±üÜā_¼zŻ„tF*SČwÆęŗĪįĄ£”6M_µįŹG¾«d•Z€ŽŽ³›Ķ“¶āÕ l³5öė¾o>yēŗåk]‡‘*Ys5Ę6b0É6; øŹuqG{ĶOīq*Į‚.2Ėó.÷Ÿ_½vÅūōćŸn[Få~Cƒ˜ežå#³g[\ēwTPō f±ė ×öź&ü«{—ō޵—>ī:D·ęžāĄ®sø`aŹNĻ—ßī:‡ø£@čl+æ ˜é:GrŁ_”½ņ«zWœsėŗKsFāe­żo×\1† ±H›Ā5(ƒµK\‡HØõXūĮUėVü—ė R;9ϻշ¹&“ÅĪŲŠ6ćÖjźo#R @ƒėlė>ÉĄ+]ēH öjoŌ–õćŸ}›ūrk°”\ēpÅZ³ĶkH*œ±čź±Ē­ź]qĪŹū®xĪu©½5_ĄpÆė®xe!ßżj×9¤žT4°¹mKc΁Ź/ūZš]żšņßø"u÷'×Ӆ@RŠĄ<ė/u!!,Ų‹Wõ6øuTø4ūėŽ-˜Ū¾t¾ėR_Ų :§öĢ{„ė °ŁsśźµĖæļ:ˆ8d½19p€ńĶbąD×9¤~ŌŠ ŒĒł®3$ĄSX{ōźµĖōćßą<ć7ü¦MN˜;uń®sHżØh@sZ»ŪĄžģ:‡c=ϾzÕŗ·»"īõ[£…Ąxžw®ėR?*PĪš ‘’xŚZ’蕯ųƒė ’ ¦¹éI×’Į¼£0¹ø«ėR*ĢÜéŝ€3\ēpØß[¤ūd[wgʜć:ƒ+Ęš×$ “ĻMPČ,¼aĮōÅ{øĪ!ńSa‡å‹{cxė޼šģøÜ*×!$-Ęjœ”µ”ŹŽé®CHüTdXĪ–Ž4źÜęūļ¹§øÅuIßó4Żm8Ö¼µdŽ €Ģ*zĘŲ³\§pÅóė ’9SV0¼iłī#\‡x©ČØĪÖ-Æ“wĆ!’q× $EŒ·§ėIghŌŁDŁ„ £<ÓŲ}vƚ÷ņŻßėj[Ś ›I%,Ø`do˜;½Ų°[‰g‘ € źhæp¢…“]ēpĢo³Öo  Y!Ģ;\gxØČsŖė™`QŠ Æs#ƒöīŹ/Ńhē ›ųbł•Ą(×9RjÆõķ3“xRЩȀ-m„£¬aw×9²É{µėR;ַǸΐfžļ© ÅTd€µV_±š×¤¦4Ī#{ ź&K-)ōĮ™×»Ī‘aó50›ęͼ`hĮ§ˆ¦vµ÷¼Źu©Ž €”Ū:GĖ˜ÖŽW2^£o­œIžęęc€×9ŅĪ÷Õ™V*ŅĪ󹎐uą²ČóײĄØ 2µT¤ŲÖ)8op#ė¬5GvĢ(je†tL*޵šZ×92Į˜ésŪ–h*e ©H±GŪfu”ę’Ś34ŚR:Éu ‰OsK’IĄ8×9²Ā³‡”F*RĢ·”^/Žī:ƒÄĒÓ®™13:„ €4³VM˜õsäœÖnķ— Z—ģcį×92ę°®iEµF¦Œ €”šß^œŠį@×9ˆiņ“j”<ļ, ŁuŽŒńšūµhVŹØH)æ\Ö՝YŸÓŃ¢')Wō°öL×)²ČZ£V•”QRÖS’Ż3½sjŽI±ĪÖ-Æ“w#«^­ĶŅE@ &Ÿ7kµW½žēŸå:ƒTĻ3ę<×2l×G¦ĪźtBĀSB&7ę(`ŒėČbŽ2gßÅ»¹Ī!•›Ū¶ä ‹Ńę?5ä嬺RD@ļD×ؘ\KN}Č)d|ļ#h GMYMMN)¤ź³ö=PŌw'EęN/N6-ż[{Ļ›Rœä:„„£“XŹņ‹g­®s46ÓŽÕŗEM)’ė/]€¦žÕƒ)ēśuBĀQ2Ę6iš_X濇ė NaņŅ}­įŻ®s4 ƒ9Ņu G@Źų*’įųBkĻ!®CČČLĪ\Œv£QtŽJ ©Rō<ßį:…leģ‡]Gį-h]²5hźfY˜2j±Żu™ €élŻr°5h[ڤ°¼¹3_Ģ»Ž!C+ÆM™­»²)© T¤ˆńŒšÖ’ÄŠdl’ł®cČąęµuĻ“čźß ]g‘©H«¾µÄ1ęLķ‚–L¾å24ņß cP @ ØH‰…›ĄĢwC^f¬ļ—.pB¶×ÕŚS^ē:GŪwn{÷~®CČšT¤Äę©å¹Ą×9äåŒåß“.ŁĒułc½­śē”ē«Å2éT¤„ńü£]g!)ļB×!$Š™_ś`®ėNć’O@ZX³ĄuÖ9s§'»Ńč:Ś/œh0—¹Ī!`ąp×dx*R`‹r]Ń$ÜhÆTźv¢Ńµų-E`o×9€IóŪ‹S]‡”©HĒŚfˆś’Óą¬yS{f»ŃØęN]|Ų÷¹Ī!/)Łr§ė 24)P²\gPr¾±j~vĆx^īKhŚ_¢x‹‘h*RĄXŪå:ƒ„dxķܶ‹“Zuę»ßƒśœĒZ«€S V-)b¬’ (ź»U'ó¦'øŌuTĒ ÓĻå:„ N'©„[0}ń3Ķu ĻĄ+ ­åwŗĪŃ(|Æō`g×9dP£6–wz„ė28 ×_ö:т&écģeó§~t×1²®ŠŚs*†×ŗĪ!C3u$” €„3ÖS’:ķį{M+\‡Č²ySŠ“0ös®sČš,F@B©H<õ’§•…s:ó=]ĘĻõŲĶu‘ €„RhEK‡ėR5Ļ`ÆŅ€ĄųZ»’Ģ ®sH(m3Š»»!/§S‚ņ}30ŒwC"9¬+ß’®CdI!æx†+\ēšZ6ū˜@*ĢāéK“séœÖī6×9²`öģb 6÷m`¬ė,ž1žĮ®3ČĖ©H0ļP×$ćgßÅŚ»!AT$Š3vĀ~@Īu©ƕ…Ö„Śńń_Š^KKéŪhŠ_&555ĶpA^¢ ‰Jf¦ėR7Ķs­6K ņåO§øĪ!5bģ,×ä%*’Čcפ®¦Žź+ż×Ö®Ÿ†UČwŸöƒ®sHk®Õ9 IDATķXŒZD@ł¾Z5ĢßXžų×9\)ä»_4ģėo :·%ˆ €2 f²FdyWg¾ū<×1źm^ėEG×¢q/ ĄŖ AT$Į /Iƒ2š‰Ī¶„'¹ĪQ/…¶„s|ć’ķ:‹ŌÅōE,R”—*¦0yé$`'×9朱ęŗym= \©µ®iK̟\g‘ŗõŲŌŁ­®CH@@˜œś’…1¾µ?š7µg¶ė µR˜VœnĖŽÆĶ o0%³Eēø„P8Fż’°«oģ/³ø}šÜöīż(•n&¹Ī"õgŒ§.Ī„P0¾gµ  “Ė~é–Ī|1ļ:J\ę“/žįłÜ„a²ė,āŠÉ; [©Hć£ž1ŁV«”tsŠ€ymŻ3s~ī&`_×YÄ%›¹V­“R4F€¼L«±ż7Ī^LķUs”½ē¾å÷ØŁ_,*B@ņؐ—3fŗW*Ż2·½{?×Q*5Æ­g¾ż=°—ė,’F@RØHŽIűĄ®sHbµy>«ęå—vŗVg[÷ɾµævqEcĀäóĘø!*„¹¹Ō ×9$Ńvó1æžŪvѱ®ƒŒ¤«­ūŻĘr “½lĖ”[FOqBT$ŠQ’æ„3Į³ž›ē$ÓÜ©‹°–«Ńņ¾2œŗ@@‚XLŽqIfąĖ…üŅÆttœŻģ:ĢŽīX’ń{ĮüŌuI&S6*@@‚ ”Š™³[žÜó·]ӊ{ŗN²£œŸū °ŁuIc40 T$ŠU ÕX`˄ۓ¶tšmė‹WŗĪ!É㣙I  YR;Ļ[œ›ę{ööB{÷k]ŁV“õÆś]ēd1X­‘*’eo×$ÕvĀē'łžĻ&e\Ą­ė.} ŠXفI\—U#R,śRHTĘ`ßßņ䞷Ķiķns&ą]ķ:$ŽĪu   !N˜~ī(`¢ė’sr†?t嗾ĪuU½ŽĄc®sH¢ģŽÖó@’ĶX&øĪŠčT$„…Ō ³ÆµöCöC--~_Wk÷]ÖŲ{­å>ćńˆĮģ:Œ¼œ €é˜Qܽ¹Æücģ¹ĄD×yDDg…į¢UkWÜé:‰ M@ Ķ›yĮæÆåLą£ĄŽ®óˆˆ`Xéł^ĻŹu—Üä:ŠŒL@Š“×‡Ē3ś,ą4XPD\1¬¤ģ]¼jż%æuEĀS³g[&¾P~'Öv[˜ā:ˆ4ŒUÖŲÆ^»ā§®ƒHåTdHP”N·¾½@ėˆH ŻŽÅ«z/ł•ė R=™Tō:ŪśO4¾y?†c\§‘Œ0¬“ŲĖuş *2®ŠŚsŲó0¼ŠĘ"R)ĖĻńģ2źĻ bAė’}ŹĘ;ĒĀū]\ē‘ÄėĆņ}ĻcÅŹµĖļsFā§ ĮĢ›yĮ»eŌŪ°œo±3\ē‘ÄyÖb¾™+ē._łHńQ×a¤vT4؅›śZūO2†÷ZĢ1č³ ŅčīƘĻ{-}׬¼ļŠē\‡‘ŚÓI_(L+N·åŅYĪöpGDźĘĒņ;ėŁĻ­^»āg€uHźG€üĖ Óϵ±¼ÓÉųęlĶÉ“gĮž§µę3«×-’«ė0↠T!æx–%÷Ng£Aƒ"Yńš…Q㚾vó=Åē]‡·TȰ‚Aƒ-oµp:–.ō™I›ĶĘšCć{_[¹ī’›Q3æl„“¹„6æ½8Õ÷Ko³Ų³Į“»Ī#"Ć1÷ģ·śZš¾¶ęžā®ÓHņؐ*½¹ķż]žĻiXs*†ń®‰Ļ€½Ī÷½«ļXælė0’l*$’…³‹ć7o*æÉ`OŽ@Ÿ)‘zó1ö&|ļė£L{‹›]’tŠÉZb3wzq²W*½Ć"©5sÆĮ^_²\sēŗåk]§‘ōŃ Zjā°iK§4•Ķ)*DbµĪĀę ߊņ¼•NŹRsóŪ‹SĖ~é *DŖņØÅüĄzžõw<¼b%Å/1щXźjn{÷~žoßęd`.ą¹Ī$’<¶¼?Z՛»оėD’=*ę9ū.Ž-×ā…oNĀš:`'יDÜ1÷ZģO­g¦+}©’ óÅћ½Ņ||s’‡}ƒ…)®3‰Ō˜o ’ƒågĘp­śō„ŽTH™ĪÖ%‡c^‹1Ēį3C“ėP"QĖÖp#ĘüŅx¹_ŽžPńŸ®3IćR ‰wŠ^7vÜč>Ēx†c¬åPōŁ•t(ß|ĖošųĶ臛n¾™bÉu(ŠITRč°iK§4•¼c­±Ē8ma,IbـǯĄž*W.’ę¶õ—=ķ:’Č`THʽBkł•{8–łęūøN% eš{¬ł½Ÿ³·Žńšņ\ C€dμ)ÅI~S’ģ:‘H5tR”Ģ[0}ńå’×å³Ąó™k ‡ć\ē’Tx`¤ž{G³µ·ÜŗīŅĒ\‡‰ƒ i8‹X”{tź¬Y~Žké0Ęv`9ė:›8UsÖ®Į°Ę÷ģš]½gļśÅƒWõ¹&R *D€…›¶ä·h­×±Æs(–“ÕqfmīÅņ<{7Ö»kԸܚ›ļ)>ļ:˜H½ØƼ)ÅIåęŅĘg6Ų0f¶Z Rē1,÷Xcī5†5~™{Ęx¹{“m®4:"ZÄ¢Üśö™ķ¦Ģ+<Ļ`­Ł˜¾õ¶§ćxj3šš€…ŒåkĶßF?ō]‡I""1š7ó‚ ¶ÆiʛŽeÖN÷ Ó<Ģt ū¢Ķ¢xŲ¦×š-ß<kņøķįā#hķ|‘ŠØ©“…›^œĪ޹žņš'aŲ×Z3ŁĀ>Ę0•`ż‚ÉĄĒQ]xĢc`7€Ż`0XkÖĻn(—Ė^ģė_w÷ćŸÜä:¤H–ØI˜Žö '6Ѽg“ow³Öīf½ÜnÖŚŻ<ĆnÖŚŻ°fw »»g¬ŁÉĘą~j£<<ęy°›°<l“žż§±ŽžĻXž0Ö<īēģMåņ/ģžÄkÖ\Żļ8»HĆQ ’!s§wŹYF{żŒ÷½-;Ģč²gĘ{e”õĢö-MĘx†9Ü æĄųų~Ī<3šr¾}Ž·^_Īęž1-}Ļ•6o~~Ն+_¬Ķ«‘L3®ˆˆˆHõ¼*wF¬)d0]®ˆˆˆģčN`žė6ųėƒ8x°‡ė "’z{¹ŠčŖmŹ’š4ĮUŖ/Žlõ`pˆė ŪŲxČmż÷ū€ŪŪ€»€ū>7Ń^3AQ¶Š“õ’Ūl^ ų®J< Įwa,0ŒvŚę>ĻżĄS[oOĻÕ7f*¬Ž <ä:H£Ŗ¶ų;0 xšŸńÅ‚«’» N;;β­=žīĶCü÷2°Ž ųAp’ÖŪ†zl €c€Ws>3-ĆÜ3Š»õ¶–ąóõ§­’ūB s¦Y8x°0}›Ū˜*Ž÷,AŻKšŻøųĖÖŪ‹Ńć¦ŅSÅŅ‘Øp¢Śą9`<Įz:‰Ä釡)[’yW’uõ6› b+0£‚Ēm"(Ųz»x4ötÕłšæ®C„t$š.‚ĻG5?B;*ü-ž“õvĻÖ_ ”b8~šä~ģßz[@p…_kżĄ’«ßæ#ųQlϳ끅Ÿ»F7 ųp0Įļźó[oOüīüū³­|’žšĢÖcŒŻzœĮŽ=v›櫚€ą4ż[`q5‘AHpRxougHpAÓ¦Młķ[1æ7q3Ą¾¬õzOś€æ~üØęÆŅC€O“n¹ž,¼÷æŽģ]Ćם/šŅė^“¹“GRæĻڃÕœøĆAž#č“čn`ū÷ön㌨ IÓõI3Źķ›1æ'qźnÅż{“¹Ö/“Īv>JŠāįś½īV~MŠź6\OZmaū×Ū‹Š€½ ®čėńłz²š€S9ŠÕÕH¶³ćÕæ>ģ4Q8‡ņņ/ršn_‹’-‰¬(üø~,ŁÜ9 ų$ĮE‹ė÷“ŅŪć@7õé–Ø—m[’n½Ø˜ \HšYż-µ9æöŸ­6܎+“Üęź“Ųńźß_pš(¼eø?AV{ūj Ž(Ś ść£¼¦ø ‡“˜ |‰ %#Ī÷åE‚i=?ÆO“¬ĀÕČ1ōkģņ®‚%Štāi ¼8“ąSõb~CüwÕP8˜Į«įŸ» U‰Rźy"Œėö•¼Õ: x‚Źņo$čĘ8xĮ Ŗ€]l¼Ÿ`ÖĪS>‡_“W[{ĶWR›Øžóńp°”`,FA3mÓ6ĻÓDš>ļ ¼øœąū[«±±ż ®4ÅšÆo-*¶5ų#Õ^>Nõ ’mēøažä¤8ž żƒæŸuŖB_Äży5·/×āĶØĀ)„æšōÆFWń\£€7Œ>ū>„młļłSģ*ż<¼|Ÿ  šS–iEĮu#µćüü>SĪzĒČÆm-*¶ÕĮąŠ#ŻV3Ä÷·š/õ›€ė‡ųoōYH8‡,ˆ1Ųßb3A…o뚨:ĒæØąž?¤ŹQØU8˜`Īü`¾ü{r å­Ą·ŁžŖr(7̼¹#†ē5Ą9£ąGŗ’l&]£+ ^W%ē·[ Zƒ~Bmķi!øˆ:x-ń ī³³YΧʁ] “ޤ—`ŠąŗZ†I‘ß“Vā‚‹ĢXœĮšÕĘūćz¢ń#†?Ó2ĆbĮÜŌ°UéÉuĪ÷oĄ’ ’ćóuα£#wå’µ›r0šĻž? £ŠŪŠé°ŸAŸ ķt–`)ÜeÄ7öq‚¢" v#üėZ “ŗ‰™8ēPŁgā_ jį Ÿ"ųćŹČaä&4m ō’[@оcŸģēäŠNø“’*jœĶšcŖéjا©llĆ]@ĮIŅ—ōPY=Ō­L0[ é]6{QŁėz¬ČZÉ ßćŠāI?÷“fŌł½ü7gé*÷a’]ĢdūAa®>«M{)Œō>]ĻŠĖ/Ēķ8†>¹$y°ŁĀ÷>¼›˜DÅlO‚ÕōóīxūAa‘TūRłkRų3įß³+ć~ņ+B<é*[*¶Jø/z·«€U˜Oņ ęŲäų“£ Kł=ŗŽpćātÉY& ÷ ‡.#ügīn‚„Ė“īH‚fļØEĄ_Hīfžź^“V Ö. ū~õÄżä_łÄ?Žū‰3&lsyŖŹ>¤£Ųv1«O8xžIŒ<5ķwŌ’Ē‚žĀæ’'i Š‚…LĀ~޾E<ū'ŌĖD‚)›Q‹€¤^5O£ś×ōĮŚź\ĀæWēĒżäß­ąÉÓ8=„Ā^żü¤…G: €Ē¶ęøĢĮs•įߛ’#(\9}L»8̳#C0b?ģgķ³$æO|(K‰Ž%°–䳈öšziܖ€qXü“‚'’/ķ//©ä=\ė(cµĀž¬\+]YēēD°ÜpļĶ[źœiG£yłĀNIŲ»œšß^ÜŽD°ź`”ĢuƒN“b°e+½=D|k5¤Éž„b_Nž÷<¹%Ų¾T^RÉÕæ%”UÆA`q;BÕuąŹĒž}ł+É vŪēŚĆmœ9šßŸ, F>œŹWpÜńöĮćIp0Ń Kc.¼3 €J—#|Ų)ī)ö3*’§©©+ģjvX‚½Ļ‡{_Īv–n{'\=`‘¢$Œ˜GųõüoÄĶŠZšCōŒ’ņ¾¼Šx €F, įϳ‰ūÉ łÄŪŽVÄ"„Ŗ]ʱҕŸ\ ŪTوĄ+ł}™ę,]²µ2ņbE·IĪ•n܎'śīpŸŖ{ź—jOį<Š£ ģ—pŪŪ‹$oŠ ’Muī4u£„ŻĖŗ €0ė$$yī¶+ĮČa>W%‚«Ė,;•—o^é퓺§ŽŽ<¢åģö 0¹ž/Ā”{ ÷ž\0ÜAŖék¬¦94ĮnD¬8”ŹĒ¦©  ģ:@‚Ķ qŸ4MU«—s փćóĄj%¾G0–$Š/įö¼R‹qMÓĘ®äkpģ¤q²Cg ÕWg>ĮB1źēT’Ž}×AŽj=Z†fÆ4,TSO3 vč ó™ś;É«PA~”+ę›p7=ņ˜«¹­%ūEĄŻ„{/.ī •¶DĢg€O’ŽłøQtōŻUK-ég€żBÜof­ƒ¤Hųį[EĪ%Ųü¤ųĄ;ŗd«µ`sj91OPÜäkų®…=Ļū{[iu9й[Ÿ6šåD+|T¤_3į~Č©u9šöÜMŒ[ž¦Äc¼“hSµ®ĄĶŖzµž‰'h!Ł·ĘĻćJ,]õlpÉŽX$nÆbč½čĆŚ‹ō¼gNś¦R ģ–œĒÕ4EzŒ¦²~īˉöC˜Væ$P­ øY,©S§“d±{žµ Ž`2šĮŽ“ˈŽķaHOs–ZvE̹¤ēo]Kļ'ü•i/šżŚEI¼ó‰ÖõńVźßņTƵö#›E€“€øv[L°qLÖu­ļ[iéP Ąąž%˜¢6wż²I± šŃ ī%įŽŪ¬zœh³ Į…J=Õs1¢,NĘĵ¢ßx‚mG³®ć±ŅRØ`p>šHČū¾`oųFõ!Āo>T"ZxV\E°ŒtµN¤¾³“ź½a֊€ŌŽp&Įčų¬*½ļ[*Ņļΐ÷›@0p“¢²åožØQ–4)}ÅÕī8‚„¶K¬Ÿ`ėģ8ģG°»ŖĖ6ć¶ö7ŽUĄĄs_ćń’¦ā>żĄ-!—–@]C»©‚ūžE¼dZ¼™ŹZ?®ÆUśO‚ Ŗu0#¦,# »Šs;v>ÓóĪn&ż-©o€`ū,.S ÜhīkU˜–@-Cū1•Žż·.Ąū*øo™ą=•@™`6Dµ õRIĄ]ĄėßĒa ; Ķ-±œg]¶ ų4Į ƒYf@N?p)į+[é÷‚¹Éaķ ü‚ĘŠAøå’ÜF“…p²č[Dū”<ƒśL9®t Ą=cŠéłÓ^¤vąŽ¦ļ­Įq]éŽ qæo,Y¶˜HųQ.õ»p_®šžmW¹°Äķ™Ž’öš¤H·~‚sKµv!膩µj®‰)Ć Ņ[d¢ `ĄÅĄn5:v½…½śX|£’LihŲā:@Āż„`O€Jt\ķ¦½ßr8†Ź»W×"H|h?oŒ+Č0ŖšAw@\ū“NZjŃAÕŁS£c×SĮ&#ł:A5 Ł+Ō0<Ÿź¦‡ÜJøżŅh.•oåzG-‚dĄZ‚nÕ:–ŚėD™ų4AĘJŗÓ†“Ę" 3]ŽPĆć×C˜µ ¶½ś‡ģjŁØīĒ« XEø.¦“y]…÷ļ%XG÷ĶEķg D]ąyą$ą†²@śŠ'ƒkY4įfMźøtG‡øßW N^²VØ œjē\ļF°µōł1fI‚×Wx’°³gÕψ¶:b„Y„ĀĆķļŠG0^!ʘ‡mĶ =ėd®‚Š.­›”„YJs /_ūą)Ā’1UdĒo€ļTłŲ&‚­µÆ£öMµõ0˜UįcīÆE yš ĖØZµne »ŠHŹĄ»–ƒŽĆLŅQ$v/€ØĮ® ¾G½, XÓ`$;^żCšŽņyŅPØ ¼­ūĶĄ€ƒā‰ćLŲ-·µ>öŁó“Ż‹Śžoā\ Ų,]ÉžĆICŲą+ÕŁĘ+ 梦I˜‘’}ĄĒ‡ųoa»ņDßY°ÖŌŽ“Ą"cĮx‚ØĒqiN »ÆB#ūļˆÆ¦0 «{\œKJŠ:Qmæ{-ÜÓqžĢŽįXõ2šźŗ0ŌĪŖ­¦e&¬Zīų‚µ 6Ēp¬¤uļؤø‡ŹW<ŪŃyMŽI6Xā~W3ōÕ?dk&@R»ŽMšy’7’7pī9ąTā9aķOpŅS ĒŖ‡ƒ©|)š§ ¦ÉČVFxl-7ŖõvĄ?^CšŻŠ*‰E@¢[.žÆ‚ćļh4C÷™'E˜‘’›yƒŽ,Il˜ĢöÅd½÷"ćÄ׏?ų>šYĀļŗęŹžU<ę™ŲSdW”Å’v”vĖĒ1 p$7LĶŽc»č¤ Øū:a®šśyé*ęi¢ļ/ż‚«ģ$:’šW’į>YźHZ ĄĮ ļlūYrR©„« –qƒŽO°™Šī1³ņU<¦/īvOÄĒ·Ē’āåźU„ģ$8Ņ98ŒY$§ˆ„ ’?B˜€›[¾J0G³Ś¾$C0ß¹@ņNڇøĻf^>ļ0Ųš‚Å“ā–#ųĮŪ›ąĒ°A“±ōŸÕČ{)Ä·ĘŃĄ’t $qéÜÖ*£ ¼»PV;xøX_œ©g+ܽ’7¬9Å@pŃXFU÷sŲi?ĀĆŻÖņøAŲ‘;Üķm5zMÕ:’p¹Ć.NńŗĒź=N’Kˆö·®Ēm|Ķ^}<&"Ž×¼™`DŅÜLåÆE«Vę·T’¹©ÕōŅkC>”näķM°Wß§æāvFÖÕCäŚń¶bøƒÄŻ0Ų€‹UĄ·+xžĮ\A²¦7]ā>›O„<^%]SHvænŅŗc]Įs«bFŁ×}G£N_ŽśĻI‘Æā1Ig’dDxl­Ģŗ‡ó‚nŪ(3#Ģ"cąŖHä Ąg‡ų’/ ŚĄÉ³’ą(‚>„‘|‰š'šJŗrT¾kZ=„įäœō‚inĒļĄ9'®=c>n5rT·Å±ŗ*󏏭Uk™«ø; ž:†c¹,9pØ)n¾üp>J2_„½ś’dǬt”j’ĒÄņĮ¬±$ŲÖ½ŪKWŅBF`?õJ×ߏŪ8Ŗū!HC‘™$Q–›ĪZ°‰ …ķ1ĖUŖV*ūß žoGć 7ķ®–ŽSL»jęIDATqæ/PYóķSTöĆ© š“wOÅ|Ü6‚9āa>ϵ2®ŹĒ‰5Eö„¹ V­u[€·¬žÕĄĄĄz‰\høEJDoĘ?čˆxŒ(. qŸß÷?Ą'ü†@  Ŗ4 <žų[v~œóqĆŖv\OŅrJŗJĪ-;ŖÕ˜ž$Œc*gŸŠįXūSß" ī-a¾tƵ@°ź*xĪyTÖ“§cwµōEŖkrĖŹTĄ4i°£»¦2Žīh‚Eƒ\¬Xm @Ņgq$M”ńM±„Ų^Rć²Ą‡‰géłż źz¬»Ėf@µ^`0 ˜ć\mõæ`ŚÜ«||µĀ\żo¢ņ«’O¬6F’ €°{@ü„軕 eąd†^g Ąß6hł%šŠ›¾KšłżEŒĒIµMłcM‘}QMf½p9Įņҟ#ڦaL»Œk”ԽóNFžsųįĒŠ:WüAź;•éؐ¹FZņw8? ł· PŒä,½†0UTdš5(’¾„ņHv§ŗłó#Ż6 ź÷2XXeNŸź[Ń!T’™XR£L«C>’?kōüCł7‚ńQæK¦¶-—…Ģ1ģBtõīšq ·‚ēŽŃ4‚Óź„'Ä}6­/©’jq/’µ.¶āŲ†3.ŸįåG¾iöAQśł˜;ųõŪM°Ś+SCōŻI”A“q>“€ß%ŲIšÅˆĒ9ˆ Ė»VE@źnėEą#<÷`.¢>}-ĒīŖčóD«V+ąeHīN‰I°œķ×COū’€~ą\ąLāŁEpĄNĄQŸfö° ƒQ^”A“kcK±½¤?N Śēą•Ō®ˆe @=§īč&Ŗµ į®Ģ£ ³”Ń&ąÓŸ§ŅŽI“ Ÿķ›ĮŅ6`$ß ˜×_ŒĒ܏ų6%N”¬ė5 Ņ$ʠɇcK±½°@”žų(~O<żųµ*źŚą®Ļ­Ņ/ō‡ˆ6Bõß©mså« wõ’9¢÷Uee1 ¤ŒÆȕµ‚i‚‡|ćņFąŌ7˜(ĄÜŲRd_µ->°>Ī ŪHzš‚™_"§E@Ų–ĢXZ&Œt ­Āv ø—`Ś\µšCŌJ˜«’ē æéĻpTŌγĄC[’9jß^R½H0ĆęŸÉ8\ģÓ±ó,Õ/>ō꬗j[”vĖ.§”€`ӟDŪOā/źŚ¦łŖ«č/"ŚØö×ßÖ©Ū:ž`ŽõH>G<ėµ«Ø­ó źøĄuū6ĮĮÕ1kWjŪĶf .Ŗ±+p@ŒY²¬ŚZl< -ÖŒģb ˆ£Ø®k@Ų&¤J[ (Ā\iēJāT²4Ä}ž'iµõ3‚>½«]©ƒ^‚)vŸ#ś Ē÷RŪĻŚ=#ßeHõœ²˜fS«|Üķ±¦Ų^š w[Hō÷$®" ®+Ö²ą›ĄU>‚+3"<~G'īź’3Ä·[›Jœśŗ­K …`=…Z©¶‚Įdd­U>NĄö6“6G¼p0ы€ŗŽe:Ž‘ˆŚWŌAšćQķĀ ßŌ„0‹Tņ9†Ÿg@5Ķ’ŪZ\įń{FĢšĀ0ž,ń.’įWq¼$¶Ø yī#Xł—U>~µŪ0h՟;Z¶u•”`J[Em|ÓŲ0` š6ą«„% –ólœ]QM€`C†(;W}ˆ`•Ą(Ā\™>C|}’ŪŹĀ8É“‘ąĒņŪU>¾V@?ĮąĢj-Š+HFµQݲéQ6m #Ķē¹³‰¾9]µE@āĘDm€`.żĒ"<~°"ĀćĆ^ż†Ś,‘™•q’L%‚±2ߨā±ĒP»å§į±'ÜU1“ą°*c Vƒ¬„“¼O!śN‚Õ‰+āh€`IŻæDxü[7€o0‡øĻ3Ķ’µ…€$a%øry•φ ~Nõ³rPÉąŖł›ż‘Ś-4 l`Hžz—,Je`^„E@ā¦ĘŃĮUJŌQǟ¢ņ͉Ąœ÷»xŗāDįd”Hś—U‚Ū'ųį­D˜ļG5z v7¬ÖYćäå:ŖxĢcO±=CPø…•†‹Š/§meۃ 7ø¼® Ź`æ#ڇpĮ J„ķūs¹Õ©z)l}ZɕŽA5ŹŃTķEŠņ'ŪĖQyŠO0-»–*]³% Ą÷ĘŹDYmō‚–€‘Š€ŗ¶Ō³ `Ąy›ģTėrĀ÷Y¾–pW7Ÿ¦vW’Pł€<ÉūĮMĖ—U‚•¬Ÿ±o­‚7ķ»ÕC²w˜s”ģ\įc~@“•YĆČjĮ‚cĒķ÷0Lø1qu xųD„ĒO&˜F˜«’Ōöź*o ģ]‹ $­ ‘įżŽš#¾'Õ0ĒfŖŸ”Į†§Å”%+^SÅc¢ģĶV– €[€£ˆ¶HÜHE@] €zŽŲÖDŪśB`ŸīsįFŹ~ŠhSĆØ“’× ¶/«„Ÿ9ēĀWƒ¹œhͧ£±ŪŖt„?·Õ"Ȳ^@°®Ķį²Õ®Čä:;z‘`—j–pŸ0›l$˜PkÕģ=“@-éóąī÷«õ‰ųQ¢h%Ü(A÷ą>ęć5Č1˜F(žF°_ÅżŽqƒ Ģ|Ą€’¢śĢŽÉŠaN&ÜÕ’'©żÕ?d£H뗵х™‹_āīćDkø„ ūÆŃU:5ņĻĄõµ2ˆF)Ö“ü)Ā1ååE@ęnėCT?½Ācč՚ĀģBų$Į¾čõ…@M°étgˆūŌc•ĒǦTUkµ[§#-š3+|Ģ…Ōoƒ™F* Ų§ęH`e„cģX4Ä€%ڼ…¼|ē°×¾ļæ–ÅͶ6¬ƒP ‡†øO-VæĢĒ€  ĮĢžFõFū“­›‰¾Ć]%­€—vŒŅš½mP·%×[·ėPµ«ļ…5 °Ś—ä„5± ĮĻHy‚pÅOœ‘kŪ[”A’µp:įrk7Ąd™Ćȳ[ź˜ēäy†»=F°>@#ZIų÷©ŸŚ­š8”ż*Čg=ꜯ–Z€ėˆöŁ^C°A˜ūۚ¦² ūXĖ€ć/Žšųi¼4@(ģÕ’'©żėŚQ„ŻSšü’B-s‡ZÆž°õ6Ūi¢į…ŁV÷Įš§xÉOˆ¶ŲŽĄµT¶ā\¼ž`ēǰ.'Xś·ž*mČŅßp p*Ń»Jų)ņ‘Ē퓮ҨGS“!ø ©¶rzŲø+Ä}]\żü>D6ļ}XļC-E^žšvhē0ņßģ#uĪ“Į\ź(WKaĘłdEp/įߛ{Øn§ĄØ^QAFKeŻiaŠÆ(Ÿķ0·/"M-¼ óØ~°ŹĪ}]Æ qßOP’«Øn-€öŲSTO-Į*ļjöż®—W†øĻźš§ŲŽcWKQś;/&X™­œģņ¾e‚‚}µ‹3¤F°#K0š2źN‚#‰<pbČ'Ŗ×@¹5Ą×"<>L×ŌgE¬”ž»RłøCD  0ŲwkFŻS„wŌ’żĀĶˆŪ„Ū„s(MÓŪŖŁ'MŚ N kpG²ŒDĄK.ŽKżf`l'®€>‚¾zYLuWŹa]›«H’TĄ$Gpi°ļÖ¬ŗ§ē@`ę÷ł5n®.%Ų+ Zć_ >Ė¢&ą;„o­ż)ĮL WTlļĖsEŁIp(‘[\.4”'©Żų ¢ĶCŽ*ķˇż²fżK=Ųėė¬{ŠpĪqŸļÖ<ÅŠ,Asu”ÅTö ŲØ„–¹ņ1‚ĀųĮž N®8·Ŗ“h„VÅ’$˜¾e¬ĮD.ź½pX_žRƒć^Ī’oļĢC¬Ŗā8žy*cŽVęVV¦„ŅŖmžaJRQT¶`D™QYATmŠ^%d+‰T“0ŁBHE)„–š&S–V.ć¤ČŒĪōĒ÷=ę5¼ūī¹÷œ{Ļy濥ad¼ēwīr–ßł-šo×5% $Ӂ%ė¼ņiq:Vėƛ@ņō¬YspCĢßlE“§OŚQõOטˆB䶓%`p·įßv—”{铤 €a™h­Ąyäų|\Y|,ö”°¾‡×ü‡ÆÉH³8™pJ”š.Ęe©DJn^rt­ØoėRG×wÅSØŖdÜßģĶA—8žFd›Å5ŽF‘6'9ŃČ/—`ī«“åVX“:Ę €hV “Ä\&X‡>@|ØĮ ŪF,XRGƤbZ>8K¦‘Nw/ī<ø3}Ū Ė_ąäĒāŹ+÷1j÷ū/Ģk³ęZāŸÓVĢ6y2،ݷ¾ĘŽ˜‹e&}ŻM¼“gžĢ&ٳšķGMÆLB ]Ū9Ķ&ß ūøFZm±ąHd²·½QĶ9ė^‹cI§’]>”­ĮbĢuNZ°$+FŠ›erŖ£k>NtæßĒæÅęltŽ÷Œ®ó¤_‡#Ÿ›o¾x„ĘJ4S¢7oæI÷ēzŃ4š‹HöœęųQÓ;G!Ÿ ›wÜ&b€e,±mĒ{°»I=(æ@˜&^ź+yŌń6į ĢuފL²>ˆ<Ä{Š"ŠUÅ»'©ß÷V`Ø£¶’2Ē=ŸĻ»¼s ÉŽ·(ł„ĘH<eG4ķ×.`–MėsɞOŅĀFż‰‘(S£·€‰āuŪF,i֒ž&…²ū™7Óō”›0ĪՓÖkX?ĒøĄĀ*]uxķ§‰ļūJņuą@oeM“obtŽŗ„e0ŠP°]lGńŲ”F§\ŽŽLū³šN+˜d¬–ŪżØ ‡¢cö4ļõĖ6 ĮĢŌō¶M#ŽHjVŖ–Ū<čÅń¤ļGÖY„ā˜D:½÷¢j¦YĢ\pšy•]ČKßĻ`Ö÷vąz²Ÿx¦`>ˆģAGÄMHoŪ…Ą·„•4h²P$éĆ(åyØÜG²ž<äGĶ hĘĢßWŪ4:ß°ß!BŅÜ ?€!>”ąŅ^ėń3kZ žüŒWī@ß±³Ī Fū 4I¼€ óōmw‘Eµx®Fõd5Śå¹ĢĶ^Bż~ó3ćN·”ī‰(4Ųö܏ü4’ÕqI 9„~XGĒ(YHXεµXJ²>Y›±ū M$wz%mc͘›ÕóĪÅD”­,É ZąEÓhfa7x½†æ ­™ŹDv ³ęj4†vFKĖņJ» 9ـ̺&׎Œu|/žOŁĻķčĪG;і„ķŽFų³ĄĘ„mwŠø“…!hńµ7ļŻ ŗ*那ƒßŗz¶ŃŽņIv”ŃC8Ģ(av¼X‘WŅ4Ņ„Jiš6ŅM8ŽĀI*,m&Ÿ; 7a?h}OžfĢÓčķK\žżW˜‹œ°\č·Yw¾>FßęóeY„Ņä~ƒĪķÓ¶ŃFžuį³ä “1qõŽt Ż×ÜÅ„.ž Yæjé^$¼PĶ(.%y7ćĻa6DJ(zÅ䎽jrĮfT|”Éz4ʅ±Š—C';vżŽ¬%ćrÕ>lę”iŌ={-īY~¾BėJğGßģI·jfāĘsŁTö[ź<™ŸŽÅžƒö-V!2)"5l“{ŲŹ&äūr Y©f0Ź~h2ģSŚŠ€ļ;‰” 3ŠńŌrĢN%‘ntäuzn½ ›+‰ö}‹]d5uįÖ£9)S‰^ż†_Ż*¼Džƒˆķy÷ĆtĪBÖā7%ļtdp‘īÓō{\ŽŠĮ4Rę»,„’Ń|BżŻSŅ ¼‡ņų7ĀÄ_įK²æ7ē֛š™Mm cŻ=ƒ€_Qģ¹kVāÆ~8Čn2}÷åaüźVa%ѕŲ:Šä°©ü³ V‡¢3ėźŸ}%Ź4Ųü4l%a’ ķČā³*ŚWe¹ŸÓq·0ŁRnc kKSjŗ?²9ō-AQW 3śi„“łp Šį~eĢl4Lļć.ł² ɶ”ÅÄéļ@_ČVó ›ž’ū4Õ}%Tk2ś(:Ŗ~v”ūheщ&ƒŠī¹…› CNeŠŖ8­Fį,>ŽvzĆ«žķ7T4„č`,ŗēčH¦ y~§er†Ā’»Šł” cйy^ē{q_#{z?CdśO@ óÉČwcdYZčżØ;QxäNT)oš zƫʿ˜s Ć=§,®}fź±ųķj[ŃøÕČĢD‹Ś² Mü]’æ c-h«,BsO Y“vdփĘd z‡*©­ß®ń§Ž*%ƒ+RĖ"PPPPŠ— (żBt\°7G»€ļ…rp&eŽ/›ńhńß¼QļC1weÉ@“š‚v֕dAIiBģqhGŚLÆÉz(½9v¢x ķŻ†"6•/(Ȓ1hŃśŠ9 ™ŽŽ/ęłV¤      F ÜĄƒxaO5ł·­‚ńXŚØ“IEND®B`‚meson-0.53.2/graphics/wrap_logo.svg0000644000175000017500000001056212650745767020655 0ustar jpakkanejpakkane00000000000000 image/svg+xml meson-0.53.2/man/0000755000175000017500000000000013625242353015074 5ustar jpakkanejpakkane00000000000000meson-0.53.2/man/meson.10000644000175000017500000001234113625260316016277 0ustar jpakkanejpakkane00000000000000.TH MESON "1" "February 2020" "meson 0.53.2" "User Commands" .SH NAME meson - a high productivity build system .SH DESCRIPTION Meson is a build system designed to optimize programmer productivity. It aims to do this by providing simple, out-of-the-box support for modern software development tools and practices, such as unit tests, coverage reports, Valgrind, Ccache and the like. The main Meson executable provides many subcommands to access all the functionality. .SH The setup command Using Meson is simple and follows the common two-phase process of most build systems. First you run Meson to configure your build: .B meson setup [ .I options .B ] [ .I build directory .B ] [ .I source directory .B ] Note that the build directory must be different from the source directory. Meson does not support building inside the source directory and attempting to do that leads to an error. After a successful configuration step you can build the source by running the actual build command in the build directory. The default backend of Meson is Ninja, which can be invoked like this. \fBninja [\fR \fItarget\fR \fB]\fR You only need to run the Meson command once: when you first configure your build dir. After that you just run the build command. Meson will autodetect changes in your source tree and regenerate all files needed to build the project. The setup command is the default operation. If no actual command is specified, Meson will assume you meant to do a setup. That means that you can set up a build directory without the setup command like this: .B meson [ .I options .B ] [ .I build directory .B ] [ .I source directory .B ] .SS "options:" .TP \fB\-\-version\fR print version number .TP \fB\-\-help\fR print command line help .SH The configure command .B meson configure provides a way to configure a Meson project from the command line. Its usage is simple: .B meson configure [ .I build directory .B ] [ .I options to set .B ] If build directory is omitted, the current directory is used instead. If no parameters are set, .B meson configure will print the value of all build options to the console. To set values, use the \-D command line argument like this. .B meson configure \-Dopt1=value1 \-Dopt2=value2 .SH The introspect command Meson introspect is a command designed to make it simple to integrate with other tools, such as IDEs. The output of this command is in JSON. .B meson introspect [ .I build directory .B ] [ .I option .B ] If build directory is omitted, the current directory is used instead. .SS "options:" .TP \fB\-\-targets\fR print all top level targets (executables, libraries, etc) .TP \fB\-\-target\-files\fR print the source files of the given target .TP \fB\-\-buildsystem\-files\fR print all files that make up the build system (meson.build, meson_options.txt etc) .TP \fB\-\-tests\fR print all unit tests .TP \fB\-\-help\fR print command line help .SH The test command .B meson test is a helper tool for running test suites of projects using Meson. The default way of running tests is to invoke the default build command: \fBninja [\fR \fItest\fR \fB]\fR .B meson test provides a richer set of tools for invoking tests. .B meson test automatically rebuilds the necessary targets to run tests when used with the Ninja backend. Upon build failure, .B meson test will return an exit code of 125. This return code tells .B git bisect run to skip the current commit. Thus bisecting using git can be done conveniently like this. .B git bisect run meson test -C build_dir .SS "options:" .TP \fB\-\-repeat\fR run tests as many times as specified .TP \fB\-\-gdb\fR run tests under gdb .TP \fB\-\-list\fR list all available tests .TP \fB\-\-wrapper\fR invoke all tests via the given wrapper (e.g. valgrind) .TP \fB\-C\fR Change into the given directory before running tests (must be root of build directory). .TP \fB\-\-suite\fR run tests in this suite .TP \fB\-\-no\-suite\fR do not run tests in this suite .TP \fB\-\-no\-stdsplit\fR do not split stderr and stdout in test logs .TP \fB\-\-benchmark\fR run benchmarks instead of tests .TP \fB\-\-logbase\fR base of file name to use for writing test logs .TP \fB\-\-num-processes\fR how many parallel processes to use to run tests .TP \fB\-\-verbose\fR do not redirect stdout and stderr .TP \fB\-t\fR a multiplier to use for test timeout values (usually something like 100 for Valgrind) .TP \fB\-\-setup\fR use the specified test setup .SH The wrap command Wraptool is a helper utility to manage source dependencies using the online wrapdb service. .B meson wrap < .I command .B > [ .I options .B ] You should run this command in the top level source directory of your project. .SS "Commands:" .TP \fBlist\fR list all available projects .TP \fBsearch\fR search projects by name .TP \fBinstall\fR install a project with the given name .TP \fBupdate\fR update the specified project to latest available version .TP \fBinfo\fR show available versions of the specified project .TP \fBstatus\fR show installed and available versions of currently used subprojects .SH EXIT STATUS .TP .B 0 Successful. .TP .B 1 Usage error, or an error parsing or executing meson.build. .TP .B 2 Internal error. .TP .B 125 .B meson test could not rebuild the required targets. .TP .SH SEE ALSO http://mesonbuild.com/ https://wrapdb.mesonbuild.com/ meson-0.53.2/manual tests/0000755000175000017500000000000013625242350016716 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/1 wrap/0000755000175000017500000000000013625242353020013 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/1 wrap/main.c0000644000175000017500000000034113602226377021104 0ustar jpakkanejpakkane00000000000000#include #include int main(void) { sqlite3 *db; if(sqlite3_open(":memory:", &db) != SQLITE_OK) { printf("Sqlite failed.\n"); return 1; } sqlite3_close(db); return 0; } meson-0.53.2/manual tests/1 wrap/meson.build0000644000175000017500000000042112746700520022150 0ustar jpakkanejpakkane00000000000000project('downloader', 'c') cc = meson.get_compiler('c') s = subproject('sqlite').get_variable('sqlite_dep') th = dependency('threads') libdl = cc.find_library('dl', required : false) e = executable('dtest', 'main.c', dependencies : [th, libdl, s]) test('dltest', e) meson-0.53.2/manual tests/1 wrap/subprojects/0000755000175000017500000000000013625242353022356 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/1 wrap/subprojects/sqlite.wrap0000644000175000017500000000070312746700520024550 0ustar jpakkanejpakkane00000000000000[wrap-file] directory = sqlite-amalgamation-3080802 source_url = http://sqlite.com/2015/sqlite-amalgamation-3080802.zip source_filename = sqlite-amalgamation-3080802.zip source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663 patch_url = https://wrapdb.mesonbuild.com/v1/projects/sqlite/3080802/5/get_zip patch_filename = sqlite-3080802-5-wrap.zip patch_hash = d66469a73fa1344562d56a1d7627d5d0ee4044a77b32d16cf4bbb85741d4c9fd meson-0.53.2/manual tests/10 svn wrap/0000755000175000017500000000000013625242353020662 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/10 svn wrap/meson.build0000644000175000017500000000035513340206727023026 0ustar jpakkanejpakkane00000000000000project('Subversion outchecker', 'c') sp = subproject('samplesubproject') exe = executable('gitprog', 'prog.c', include_directories : sp.get_variable('subproj_inc'), link_with : sp.get_variable('subproj_lib'), ) test('maintest', exe) meson-0.53.2/manual tests/10 svn wrap/prog.c0000644000175000017500000000011613602226377021776 0ustar jpakkanejpakkane00000000000000#include"subproj.h" int main(void) { subproj_function(); return 0; } meson-0.53.2/manual tests/10 svn wrap/subprojects/0000755000175000017500000000000013625242353023225 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/10 svn wrap/subprojects/samplesubproject.wrap0000644000175000017500000000015513340206727027502 0ustar jpakkanejpakkane00000000000000[wrap-svn] directory=samplesubproject url=https://svn.code.sf.net/p/mesonsubproject/code/trunk revision=head meson-0.53.2/manual tests/11 wrap imposter/0000755000175000017500000000000013625242353021717 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/11 wrap imposter/meson.build0000644000175000017500000000040413602226377024062 0ustar jpakkanejpakkane00000000000000project('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')meson-0.53.2/manual tests/11 wrap imposter/subprojects/0000755000175000017500000000000013625242353024262 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/11 wrap imposter/subprojects/zlib.wrap0000644000175000017500000000062313602226377026121 0ustar jpakkanejpakkane00000000000000[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 = 886b67480dbe73b406ad83a1dd6d9596f93089d90c220ccfc91944c95f1c68c4meson-0.53.2/manual tests/12 wrap mirror/0000755000175000017500000000000013625242353021370 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/12 wrap mirror/meson.build0000644000175000017500000000017613602226377023541 0ustar jpakkanejpakkane00000000000000project('downloader') # this test will timeout, showing that a subdomain isn't caught as masquarading url subproject('zlib') meson-0.53.2/manual tests/12 wrap mirror/subprojects/0000755000175000017500000000000013625242353023733 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/12 wrap mirror/subprojects/zlib.wrap0000644000175000017500000000062313602226377025572 0ustar jpakkanejpakkane00000000000000[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 = 886b67480dbe73b406ad83a1dd6d9596f93089d90c220ccfc91944c95f1c68c4meson-0.53.2/manual tests/2 multiwrap/0000755000175000017500000000000013625242353021067 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/2 multiwrap/meson.build0000644000175000017500000000051613340206727023232 0ustar jpakkanejpakkane00000000000000project('multiwrap', 'c', default_options : 'c_std=c99') # Using multiple downloaded projects for great justice. cc = meson.get_compiler('c') luadep = dependency('lua', fallback : ['lua', 'lua_dep']) pngdep = dependency('libpng', fallback : ['libpng', 'png_dep']) executable('prog', 'prog.c', dependencies : [pngdep, luadep]) meson-0.53.2/manual tests/2 multiwrap/prog.c0000644000175000017500000000273712650745767022231 0ustar jpakkanejpakkane00000000000000#include #include #include #include #include #if !defined(_MSC_VER) #include #endif static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; if (nsize == 0) { free(ptr); return NULL; } else { return realloc(ptr, nsize); } } void open_image(const char *fname) { png_image image; memset(&image, 0, (sizeof image)); image.version = PNG_IMAGE_VERSION; if(png_image_begin_read_from_file(&image, fname) != 0) { png_bytep buffer; image.format = PNG_FORMAT_RGBA; buffer = malloc(PNG_IMAGE_SIZE(image)); if(png_image_finish_read(&image, NULL, buffer, 0, NULL) != 0) { printf("Image %s read failed: %s\n", fname, image.message); } // png_free_image(&image); free(buffer); } else { printf("Image %s open failed: %s", fname, image.message); } } int printer(lua_State *l) { if(!lua_isstring(l, 1)) { fprintf(stderr, "Incorrect call.\n"); return 0; } open_image(lua_tostring(l, 1)); return 0; } int main(int argc, char **argv) { lua_State *l = lua_newstate(l_alloc, NULL); if(!l) { printf("Lua state allocation failed.\n"); return 1; } lua_register(l, "printer", printer); lua_getglobal(l, "printer"); lua_pushliteral(l, "foobar.png"); lua_call(l, 1, 0); lua_close(l); return 0; } meson-0.53.2/manual tests/2 multiwrap/subprojects/0000755000175000017500000000000013625242353023432 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/2 multiwrap/subprojects/libpng.wrap0000644000175000017500000000066713340206727025610 0ustar jpakkanejpakkane00000000000000[wrap-file] directory = libpng-1.6.34 source_url = ftp://ftp-osl.osuosl.org/pub/libpng/src/libpng16/libpng-1.6.34.tar.xz source_filename = libpng-1.6.34.tar.xz source_hash = 2f1e960d92ce3b3abd03d06dfec9637dfbd22febf107a536b44f7a47c60659f6 patch_url = https://wrapdb.mesonbuild.com/v1/projects/libpng/1.6.34/1/get_zip patch_filename = libpng-1.6.34-1-wrap.zip patch_hash = 2123806eba8180c164e33a210f2892bbeb2473b69e56aecc786574e9221e6f20 meson-0.53.2/manual tests/2 multiwrap/subprojects/lua.wrap0000644000175000017500000000061213114053172025075 0ustar jpakkanejpakkane00000000000000[wrap-file] directory = lua-5.3.0 source_url = http://www.lua.org/ftp/lua-5.3.0.tar.gz source_filename = lua-5.3.0.tar.gz source_hash = ae4a5eb2d660515eb191bfe3e061f2b8ffe94dce73d32cfd0de090ddcc0ddb01 patch_url = https://wrapdb.mesonbuild.com/v1/projects/lua/5.3.0/5/get_zip patch_filename = lua-5.3.0-5-wrap.zip patch_hash = 439038309a0700adfb67d764b3fe935ed8601b31f819fc369e1438c6e79334dd meson-0.53.2/manual tests/2 multiwrap/subprojects/zlib.wrap0000644000175000017500000000061713114053172025261 0ustar jpakkanejpakkane00000000000000[wrap-file] directory = zlib-1.2.8 source_url = http://zlib.net/fossils/zlib-1.2.8.tar.gz source_filename = zlib-1.2.8.tar.gz source_hash = 36658cb768a54c1d4dec43c3116c27ed893e88b02ecfcb44f2166f9c0b7f2a0d patch_url = https://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.8/8/get_zip patch_filename = zlib-1.2.8-8-wrap.zip patch_hash = 17c52a0e0c59ce926d3959005d5cd8178c6c7e2c9a4a1304279a8320c955ac60 meson-0.53.2/manual tests/3 git wrap/0000755000175000017500000000000013625242353020561 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/3 git wrap/meson.build0000644000175000017500000000034712650745767022745 0ustar jpakkanejpakkane00000000000000project('git outcheckker', 'c') sp = subproject('samplesubproject') exe = executable('gitprog', 'prog.c', include_directories : sp.get_variable('subproj_inc'), link_with : sp.get_variable('subproj_lib'), ) test('maintest', exe) meson-0.53.2/manual tests/3 git wrap/prog.c0000644000175000017500000000011613602226377021675 0ustar jpakkanejpakkane00000000000000#include"subproj.h" int main(void) { subproj_function(); return 0; } meson-0.53.2/manual tests/3 git wrap/subprojects/0000755000175000017500000000000013625242353023124 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/3 git wrap/subprojects/samplesubproject.wrap0000644000175000017500000000015112650745767027414 0ustar jpakkanejpakkane00000000000000[wrap-git] directory=samplesubproject url=https://github.com/jpakkane/samplesubproject.git revision=head meson-0.53.2/manual tests/4 standalone binaries/0000755000175000017500000000000013625242353022752 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/4 standalone binaries/Info.plist0000644000175000017500000000141612650745767024742 0ustar jpakkanejpakkane00000000000000 CFBundleGetInfoString MyApp CFBundleExecutable myapp.sh CFBundleIdentifier com.example.me CFBundleName myapp CFBundleIconFile myapp.icns CFBundleShortVersionString 1.0 CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL IFMajorVersion 0 IFMinorVersion 1 meson-0.53.2/manual tests/4 standalone binaries/build_linux_package.sh0000755000175000017500000000044113140423077027275 0ustar jpakkanejpakkane00000000000000#!/bin/sh -eu curdir=`pwd` rm -rf buildtmp mkdir buildtmp LDFLAGS=-static-libstdc++ ~/meson/meson.py buildtmp --buildtype=release --prefix=/tmp/myapp --libdir=lib --strip ninja -C buildtmp install rm -rf buildtmp cd /tmp/ tar czf myapp.tar.gz myapp mv myapp.tar.gz "$curdir" rm -rf myapp meson-0.53.2/manual tests/4 standalone binaries/build_osx_package.sh0000755000175000017500000000121713140423077026751 0ustar jpakkanejpakkane00000000000000#!/bin/sh -eu rm -rf buildtmp mkdir buildtmp ~/meson/meson.py buildtmp --buildtype=release --prefix=/tmp/myapp.app --bindir=Contents/MacOS ninja -C buildtmp install rm -rf buildtmp mkdir -p mnttmp rm -f working.dmg gunzip < template.dmg.gz > working.dmg hdiutil attach working.dmg -noautoopen -quiet -mountpoint mnttmp rm -rf mnttmp/myapp.app mv /tmp/myapp.app mnttmp # NOTE: output of hdiutil changes every now and then. # Verify that this is still working. hdiutil detach $(hdiutil info|grep "mnttmp"|awk '{print $1}') rm -rf mnttmp rm -f myapp.dmg hdiutil convert working.dmg -quiet -format UDZO -imagekey zlib-level=9 -o myapp.dmg rm -f working.dmg meson-0.53.2/manual tests/4 standalone binaries/build_windows_package.py0000755000175000017500000000206713366273150027661 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import os, urllib.request, shutil, subprocess from glob import glob sdl_url = 'http://libsdl.org/release/SDL2-devel-2.0.3-VC.zip' sdl_filename = 'SDL2-devel-2.0.3-VC.zip' sdl_dir = 'SDL2-2.0.3' shutil.rmtree('build', ignore_errors=True) os.mkdir('build') if not os.path.exists(sdl_filename): response = urllib.request.urlopen(sdl_url, timeout=600.0) data = response.read() open(sdl_filename, 'wb').write(data) shutil.unpack_archive(sdl_filename, 'build') libs = glob(os.path.join('build', sdl_dir, 'lib/x86/*')) [shutil.copy(x, 'build') for x in libs] # Sorry for this hack but this needs to work during development # when Meson is not in path. subprocess.check_call(['python3', r'..\..\meson.py', 'build', '--backend=ninja', '--buildtype=release']) subprocess.check_call(['ninja'], cwd='build') shutil.copy('myapp.iss', 'build') subprocess.check_call([r'\Program Files\Inno Setup 5\ISCC.exe', 'myapp.iss'], cwd='build') shutil.copy('build/setup.exe', 'myapp 1.0.exe') shutil.rmtree('build') meson-0.53.2/manual tests/4 standalone binaries/linux_bundler.sh0000755000175000017500000000030713140423077026157 0ustar jpakkanejpakkane00000000000000#!/bin/sh -eu libdir="${MESON_INSTALL_PREFIX}/lib" mkdir -p $libdir sdlfile=`ldd ${MESON_INSTALL_PREFIX}/bin/myapp | grep libSDL | cut -d ' ' -f 3` cp $sdlfile "${libdir}" strip "${libdir}/libSDL"* meson-0.53.2/manual tests/4 standalone binaries/meson.build0000644000175000017500000000173213070746245025122 0ustar jpakkanejpakkane00000000000000project('myapp', 'cpp') sdl = dependency('sdl2', required : host_machine.system() != 'windows') if meson.get_compiler('cpp').get_id() != 'msvc' add_global_arguments('-std=c++11', language : 'cpp') endif if host_machine.system() == 'darwin' install_data('myapp.sh', install_dir : 'Contents/MacOS') install_data('myapp.icns', install_dir : 'Contents/Resources') install_data('Info.plist', install_dir : 'Contents') meson.add_install_script('osx_bundler.sh') endif if host_machine.system() == 'linux' install_data('myapp.sh', install_dir : '.') meson.add_install_script('linux_bundler.sh') endif extra_link_args = [] if host_machine.system() == 'windows' str = '-I@0@/@1@'.format(meson.current_build_dir(), 'SDL2-2.0.3/include') add_global_arguments(str, language : 'cpp') extra_link_args = ['/SUBSYSTEM:CONSOLE', 'SDL2main.lib', 'SDL2.lib'] endif prog = executable('myapp', 'myapp.cpp', dependencies : sdl, link_args : extra_link_args, install : true) meson-0.53.2/manual tests/4 standalone binaries/myapp.cpp0000644000175000017500000000204713602226377024612 0ustar jpakkanejpakkane00000000000000#include #include #include #include int main(void) { SDL_Surface *screenSurface; SDL_Event e; int keepGoing = 1; std::string message; if(SDL_Init( SDL_INIT_VIDEO ) < 0) { printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() ); } atexit(SDL_Quit); std::unique_ptr window(SDL_CreateWindow( "My application", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN), SDL_DestroyWindow); screenSurface = SDL_GetWindowSurface(window.get()); // Use iostream to make sure we have not screwed // up libstdc++ linking. message = "Window created."; message += " Starting main loop."; std::cout << message << std::endl; while(keepGoing) { while(SDL_PollEvent(&e) != 0) { if(e.type == SDL_QUIT) { keepGoing = 0; break; } } SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0xFF, 0x00, 0x00)); SDL_UpdateWindowSurface(window.get()); SDL_Delay(100); } return 0; } meson-0.53.2/manual tests/4 standalone binaries/myapp.icns0000644000175000017500000000344712650745767025004 0ustar jpakkanejpakkane00000000000000icns'TOC ic07ic07‰PNG  IHDR€€Ć>aĖsRGB®ĪéĮIDATxķœĮ®! †Õøæ{ߏéĘ·ŗ{Ÿ@Óh  ŚRęü&†3 “æž—™cŌš @@@@@@@@@@@@ą±>ZWöåē×_­˜ļo?Ģsµņ`nŽ€iSzĶgIO5A«ī[j 5Į̉F“r²į­GvŸ¬EžŠ×kDož”Ī¼µ„Ą£ˆØ·ķµę÷ł*Āć8ėÕ² -RkÆÆy³`ņģz/šøŁ“Zź13€d½Ę²:¶õõMZgj71Ąœ½3…bm›Ąö;€E)ĘŸ³;5Ypm·ü’Y“ą’kWQÆ©ū³+RćŽyfjÜ2€5ėx3 ^uķņ#@Ū,v²v=­ć=VM™‰§Õi„ķtœ­@_‚/?Kū^­ Ļū®؅ß`‚u}7^/@óŚŁ›oĮÓäiķܞĄ’¤šR“„ūRüWøežiX ӚĄ*ß ¦”Złw”Žåo#ÆŌ“‡™{§˜Mą”HŹ«=1f ·ÖZÖh«„ÕbNżø”˜vZ£Y×ĖqėüŌ p²HjĪĪ)šŠĶÕōK}h‚yÆA’ŽłAØ{¤:¾ĘmŁōR½h4æÄ’Ł«ń\‰h^8-EJ†£ū–łFuÕ÷¢óFä31@ j皊–L°vÆe,cĶÖŃ[æm€,Eyg·¶Żż½¦YĪoą†Ö ­'W\·4¦ü(5+Ó#Bœż~Jd‡ö$}0Ą“ŗ¹P‹h€Žqܛ_Špõ–Ū9Ø^OI9ń¬÷’ŁO 1`¦6ēŌč<½łv‰˜P=F¼ļ”پ„SŸ¾„#:€ |Š;„zó)ĶB˜ž'QfŖžśłķĖæ’rīķū»Jkļeļ†fXóÓÄSAÕ²^S6ŸckMĄė1ŹŅæŹ%ų¬x¦;Zą¹ÅQ'ĄHC“Īē5¦z Ō€÷1÷&­£ŚŅąF 7j®Ķpü …uü3 ­.Z­5ZŒĒ p `­Ī[MpÄ·B•tßh‚“Č S2Įm„p<ąją÷‡PHą²žŌ3,„:xŻ õ¤łx¬ŁĘjĀqOŒų£ąEź„aohtÆĢ4čA,A÷Š89ßÓ}RÓLīŠGĄJ33άMk‚Š—@µ nÅ@œÓzŌ֐Is‹Į-ĄZt Zķ“Öüźėc !Z„č“P5zOź+9i?5@Oäō)Ą#MT‡·®Ö_u³ųkn) @@[Ą½!SŽÖƖ–r·®Vó9’® Ņ| ä‚xō†Źy¤Qj¾“?ūżŠÆŁa¬čĖbŌķ“'ķ °ZPŌ¾ŪϜ\ 0zfqbĶøū|ÓäÖP£ėĒĄSšOµ›æZ5Ÿ#™Ą2Ÿ”‹5µĘ–ŽxeŽVl¾æ›Ćō eĮ–£u¾2Ž Ųr_Y_9?ƌįżY4@Y‹ÉZ ė³¹n«Z)žU,‹ś8Ęš[CąÅ<¶ę[s¼žęѲ.ĖXVL‡°Jā'#LMŁt› [QšF̬±®Ļ:ŽL-õZń Ž°z=zžeŅ«4ŽjčķėĶ[Ēėå‘ęĆ ±¾ÆiÖiće0Aˆ4Ͱ4€6_¹ī”8o©Å’…kū€ eæŖĢåĒmp½Q¶·¦7ßĖuūü „<4ÉŽģ(}d‚Ø\Ō÷@Óü'ÆYi&™ ź4€Ü·b’aW¬Š“š«,¼Mąj€pŹÉ’ VąU ąEv7“ `€A£i„?ā7Yķ±ĒėĖ®i÷ŅŚ?³¾Ģsņ3inÕī©Éõ؅kŠė­éĶ×9ųšÖk÷̬åų^#™ Ҽ” h£¦Œī­—bJ÷Wó޲oŪ+nmAoĶYA¤Ųü›cÖ×<Ÿe\įŗ¢}ł€²HézFĄģś™Ų£µ§ņŽ4õī1_ŗßŅ]ŽļÅę— P^1A×}ĶnEß~”AI¤—Š2}ŽŹ«®ÓūŚŌ,6Źy"Ęü"Ēįæ l=wJq8RŒ2Žč³&ķĪǚ[yµš9ʉqhŌ*ŒęgŠėÅ 8ŅÆ™<k'ÅXÉɹoEX“Ņ‹FĢäµČgÅ q@@@@@@@@@@@@@@@@@@@@`†Ąo(_¾ƒ³®ńIEND®B`‚meson-0.53.2/manual tests/4 standalone binaries/myapp.iss0000644000175000017500000000054213403223104024604 0ustar jpakkanejpakkane00000000000000; Innosetup file for My app. [Setup] AppName=My App AppVersion=1.0 DefaultDirName={pf}\My App DefaultGroupName=My App UninstallDisplayIcon={app}\myapp.exe Compression=lzma2 SolidCompression=yes OutputDir=. [Files] Source: "myapp.exe"; DestDir: "{app}" Source: "SDL2.dll"; DestDir: "{app}" ;[Icons] ;Name: "{group}\My App"; Filename: "{app}\myapp.exe" meson-0.53.2/manual tests/4 standalone binaries/myapp.sh0000755000175000017500000000020512650745767024452 0ustar jpakkanejpakkane00000000000000#!/bin/bash cd "${0%/*}" if [ `uname` == 'Darwin' ]; then ./myapp else export LD_LIBRARY_PATH="`pwd`/lib" bin/myapp fi meson-0.53.2/manual tests/4 standalone binaries/osx_bundler.sh0000755000175000017500000000050513140423077025631 0ustar jpakkanejpakkane00000000000000#!/bin/sh -eu mkdir -p ${MESON_INSTALL_PREFIX}/Contents/Frameworks cp -R /Library/Frameworks/SDL2.framework ${MESON_INSTALL_PREFIX}/Contents/Frameworks install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 @executable_path/../Frameworks/SDL2.framework/Versions/A/SDL2 ${MESON_INSTALL_PREFIX}/Contents/MacOS/myapp meson-0.53.2/manual tests/4 standalone binaries/readme.txt0000644000175000017500000000073512752712447024763 0ustar jpakkanejpakkane00000000000000This directory shows how you can build redistributable binaries. On OSX this menans building an app bundle and a .dmg installer. On Linux it means building an archive that bundles its dependencies. On Windows it means building an .exe installer. To build each package you run the corresponding build_ARCH.sh build script. On Linux you must build the package on the oldest distribution you plan to support (Debian stable/oldstable and old CentOS are the common choice here). meson-0.53.2/manual tests/4 standalone binaries/template.dmg.gz0000644000175000017500000011067712650745767025727 0ustar jpakkanejpakkane00000000000000‹…DžTtemplate.dmgģŻ|õų’Ļl6›’’B`!HHBhQDD[-?å,ZØ&$@4$¹$ˆ"jæö¾jÆÖóüy½žZγ\±Ōóėõz½j’{ÕV±¢½V-=Ūļ×ök-õOKO|?Ÿ™ĻģĢnfvg0^OĆĢNę=3ūžŁŁ™Ļ|>Bąvxpš-ŁrpÖŖģĆ’l÷y+.ˆÆZzÉj! ±VŽ9óž);Ō_ =…=×éśuLæ¾ļņ‹>óꊶ’æž?kŚŁ+"śļŗ»śĻoü’ążąx»tÅJ!vŚ=JŌ¶/óK›?Uæ|Öu’µā‘/5ŸuAeõ%³õdƒMk¢O\#ⲿY“ˆ¢żøÆ:'Š•sEt@L+W\z”|ŁWypǾŹ÷rÕßöU¾ųqŁ›(»˜å²Wš¾ģŖ„0¶›DZ•DÖŹn­ž‘:›ńŠ/śbWÜžCėU¹īsń ÄØµ:!FĖīŻ?Fó3ÖżüāV'Äi²»W÷€ćnŠĖ ĻIĖä_~~Ųė/Ńa]ő,ö PĄ{oµV/ųV$ØŸį˜ {[Žm¹ųĀm—5œ&^Ō-øŪ}ūD?.ÄæüՊB!G’sŒ0VĆč § ļē?ßł“:7ŠĻŖgŻĻĪĀŲézjsŽģĪÓ§<’é9æųˆ}žsŠČ¢^ˆ§ŽüqNŹß•ēūöÕ5š•k§=XØ_ĖĶwÖ;熽’»üGühˬЄ(’į9æųˆ-’!tī 1^XėeČ­}‘Ų.wŠ„¢Gž³¶*÷Q{ľʗŠ­ī½zļɒʱō·–VœŠ ³T‰ČŃk‘¼ŌÉę_‹Dh-b½øFl½¢[l]¢MN= £'Źuś£\Ÿuŗ;ßc<÷®Õ‡glՃNĮ— ę\ äR›Å„āJŁõĖeöŠv9v§žf¼\bļ¾Ź—›ķ.y‰7ļR/⚵›ŪK¬|[Ö%ÆĖl»M¹&ʶ¤5 ŪéBe¤Pfdƒč“yøVv]2+}‰­P"»±ÖžńΧuw«œŲ O ß­Pi×AQšŁd.³B.s„<²\*ęŹ½b•Ü ré-rŁķņu³|„¶Ėz½…¶›ćŌ_[䉼¶ÖĢé’Y¾Ł½f«ä¢›Ņecœ¹fłrĶ®6÷Å^™‹Ń)ĒŁ„Źå2ÖŖĪ{fZ®īķźÜ“”oīŖt˲95®Øą{&#Ā<”ņ1zH>®”[§Kī1ŻrØU¾ī6?ĮN–Fyn„õ_vYr>h†°Ž G÷r,9{Ķj™”łŁŁ$÷Ü>żłQĘxļ„öēg™śŒ$ŽO“kÖ®Ļcй¼b}$ķ”Ūb½łÉčŪ”K.ף§ļ«Ü?ŁŻ%/÷AóčŁ×ŁuM練ž€ļ¶D÷Õśī#i;ŲĒ2÷÷LĢŒõ-7 §šģ|Ć©.õųžī„źŽ!#kĶeŽM¼NwD³Ž^αė“ōĒ®&!²9v©ļ[5gė»Ęė(¦¦åš"čēZÅ©_9:.›w«bG»bęس¶Pb^C?qjб®)¼æ×fšS•Ėm7ō_X,—Ž(źåó›`ŠÜW^wwÖčÄo‚į»ĻĢ\ÆSæóŸÖ}gōśÅ‡"X~ź]ł™: łŃæōĢüōłÅ‡"X~øņ—99čī¬Ńņc—Só3S÷U~śżāC,? ®üL†üø÷Ÿ­~ń”ȜŸVł‹+?Óå÷Ō‡Ż5:P~žŃƒ©ł9[÷U~vųÅcd)}¼äžāž¢Õ… cņߏ6 æ9æ8ļ7yWÅŽĢ}1·-zNNMäžHÜ(÷‰ėDé !O/ä^tuĻžĒSw€/W,oøž÷xųĢƏp½6Īxb‘ūy©7<łėC®×æ:4ļyŸxżś~Ņä~ž¤”±xfāäFžż/¾ünyŲ×Ć8é»ļŃAĆ,ū>]ؒ'„eāŖÅłÆC9„NĘYåßͱ;ktR'‰R«‘”?ĶŠ}©ö‹…*;ØJņZ„#3eIM=^8e)½ž)PÓLNiDæ§&˜Ó„*”B?’ŠŖ»uÖč O%T½Ŗó’ßšū©¹Œ-bč¶ ŚO'Ź-ą•­Ń#ū]¹™“Ær’²;`uŽOlx-FęĘ.ĶMžKĪ Pq{üāC”ö*UŅŁŽóüˁ«)'%¦Ģ”O5µ*ī”õ*G­¦ŖpĶÓoæŸ"œORę’¶*bjõfD<‹ˆfÄ“,"̈é#¬{*¢2‹ˆV3bFĄˆ69½õĪ«²ˆ°ŽłĢŒrżČwŻ*š³²ˆh4#fŒX(׫֌8#‹k/™0ĀŁ‚s³ˆXš30l—¾Vś’ĻßXō‰Ās ņjc‡cĻĘīmŠ5Ę¢¹/ä>Ū•»$·0ś“čĆŃžčŖčœœr^ˆĮņÓčŹĻ¬aȏ{’ńEęüXĻĪ;ł™ķj•óÓv˾Įņ³¼L¦Ūnö‹E°üøļܞ1 łqļ?;żāC‘9?©wŽęøė÷É®ŽŸå·čĮtūĻ-~ń”–÷ńyī0äǽ’Üź@0…5„yoÅ~”ūhō®œ®ČÅF(]9WDD\¬\qé…Ā,įp‡ż-¦KŖņr1«č`Įū²;ĆüVRßIÖ÷’ś6æP/Ā÷›Źxč}±+n’”õŖ\w‰¹Ż7œŖ•@uVIĀ[t’ĶĻX{ōó‹[U¾ā^Ż½Ģšœ“lšš¹ƒžõ&D½FžāaÆA ³óēęŽ{;õ6ÄŽŠ%N•’r`Įösāa·W†²ž’˜Ęó¾ó;ɟ’Šå?~tVĮ§–’ųJjłM5³ĆŽ_ĄPĒØžOŻźå?¼ēĮå?ņ„čbŪēūXjłĒ*–ˆ7 õ ¹¹~ų©sžY9Æß}ĒgøžžßĻ_öņA×ėū/;÷óīņ#݃?|<_8æõ‹’5.ģż€“¾4Äé¬ BŒ„bƒčķāZŁu‰~9Ü&ŖÅłÆC9mŸS%DöU¾ū¤ŻY£ƒ“}^ł3§\@»ķQ©ö‹ELv愯Śi¦,©©Ē'¦ŽˆQ#šÅ„āJŁõ‹nŃ+£Ō4…Żž{DÉiZE‹X/®åŻr^]r^Ģé¼ęąl‹Š}•/­“]«īÖY£Ūb—z׬Ā7–Õ‡«^ՃyÉox‚Ż®«ÜFĘ1t[…Gķ§åšŹVč‘ż®ÜLŚW¹’Nٰŗ—›­ŃɹńZŒĢM‰Lić6gPØø=~ń”P{•ś,Ū{^±X*3Ņ#:å~¹^ę«_ö»e†śĢ)'%¦Ģ”O5õdįģ­…ā"±]ÄõÜkd¤ź«©*\óōŪļ§ē“T.j=žÕ‰År]E½RS³ˆØ7#āYD,0#¦eŃ`FLŃ*’o1#*³ˆh5#fŒh“Ó[ļ¼*‹ėĻĢŃ(ׁ|×­b”1+‹ˆF3bvĄˆ…r½j͈3²ˆ°ö’9#œ-87‹ėĻ Ń(§^¬×Ŗ:‹ˆś“ŸnpŹ;\śZé7J>_|cQŽ=y­yµ±Ć±gc÷Ē6ÅcŃÜrČķŹ]’[żIōįhtUtNĪ9/Dž0v×kŒ9ņæuę‘ē’ŖdæśäW©snU)ϧ>ģī¬ŃA®Ģ|F¦>xp¾īĖ8ćzæųPdĪõÜÉĻ ™“{ܝ5:H~fŃƒ©ł™§ū*?7ųŇ"X~øņS•œŸ·w[£*?īżēFæųP¤ĖūüŹÉĻĢ}•ļŌø;ktü,{T¦Ūnņ‹E°ü4ŗņ3kņćŽ|ćC‘9?Ö¹³“ŸŁ2'ŸvwÖč łY^¦Óķ?7ūŇ"X~ź\ł9cņćŽvśÅ‡"s~¬ė"N~樧AŻ5:P~nуéöŸ[üāC,?īćóÜaȏ{’¹Õ/>™ņc_órņ3Ļ}(»{DĶēźĮŌüTė¾ŹĻm~ń”–÷ļĆźaȏ{’ł¤_<€SEqWŃŅ5„yoÅ~”ūhō®œ®ČÅFyžo2¬£ˆŗĆ«śKō°Q."ź¾…Ŗ’Ą¼VP+ÄsĀŗĒxB;ö p”’§ĄŪĢsz³\ā a–VWõņģŽ]²×ŗzØźõ‹Xåż_*¶ŗwöZó²ÆU.żm€'†Ō5ūzĆŠ„NéJÄb@GO”ėōG]ö]uē{¬“ĻõÓ[õ sżt‚š+«ļ\±/—Ų«J‘Ū]ņӕ“Æ|[Ö%ÆĖl»t¹\c›zE7<Ŗ$¹*ė]ćń“ƒµFÉnlŹ“ OXĮ‰­š”Čü$ˆS'f“¹Ģ ¹Ģ•b…Üså^±Jn…¹tU~½]¾n–ÆŌvYÆ·Švsœśk‹(‘˲ó>ŚZ3§KZ|dłf÷š­’‹nJ—qęšåĖ5»ŚÜ{e.ZD§g?Q.—±VuŽ30ÓruoWē¦ }sW„[–-Qe¦œcĻdDPwņ"bō|\)·N—ÜcŗåP«|Żm~‚,ņÜ źæģ²ä|ŠĢņLb$ŻõpöšÕ2C-ņ³³Iī¹}śó£ŒńŽKķĻĻ2õI¼Ÿ&׬]ŸĒ‘ž¹g;œ¾Ær’dw—¼ÜĶ£g_g×5½›Zz¾[ū‰µ¾»ÅHŚö±Ģė¹g[Lv¾įT—z|O÷Ruǐ‘µę2Ē&^§;¢YG/ēŲuZścW“Ł»Ō÷­š³ż\ŠŠ£˜šb”kŠ Ÿk§ŽŽö“Aټ[;Ś{4Gż˜µ…óś‰SSŒīg˜¼¾×2—b³žJr~L‘ūŹėīĪØäz=˜ś’“ī«»ø½~ń”–÷]ī©Ć÷]ī>æųPĖ»d\ęä »³FŹ}\NĶĻLŻWłé÷‹E°üøK!M†üø÷Ÿ­~ń”V »Å•ŸéĆP ūlŻWłŁį‘„ōń’{Šū‹V6ŒÉ+’Łüüęüā¼ßä]{3÷Åܶč995‘{"q£TÜ'®„>ķ?˜„ō/u]ĄŻžĆ,³T‘Ójƒ*qūQ½xŚšœ_ÜźFbū^fxNZ6xųÜĮĆ^‰z<%ÄĆ^‚4"ffĻ..L½ųOKœ*’ä@×o~ŲõU€”¬ē?¦ńü‡ļüNņē? ¹i[…ų ¾õē©å?O)’±gqĶß,ŌÆåęūŲ_^ōL¢rłśgü~Ā®æ×¼pķ]\Æ’ūłĖ^{ądäS’ēÕ-{’ņ‘š”ņ«õ]~ŹxĪ/>bĖˆ#h’åŻ¬īˆŚ)I ąķæ¼ūcŻ=“¼Ä@ķæ,J^wū/‘Aū/“’ā ż—@«Bū/ “’āĶ>ŗo–G‹–`­æ¤ŻÓ}Ÿ4_2d$­æŠś ­æŠś ­æ8hż%=ZĮšYVśXÉŻÅ½E—Öœ–’fžņoĢ_–_˜÷FŽ'¼Ūɲż©žķä ē›ÉāaÆYˆꝮéB]{*õø*^-¶Črȹī4.å®ļ“Öč םw­")²Æ=ČøHµ_|(ŌŻu'Ļŗ?’)Kjźń¹›āU¦@M3Q8÷#üJ;L0§K_*”B—hÕŻ:ktR UÆźĮ¼ä7<Į.• ·‘±E ŻVįQūéD¹¼²U#zd£+7“öUīæSv¬Ī»Ä†×bdnģ»™)mÜę ź·Ē/>jÆRŸe{Ļ󿬦œ”˜2S>ÕŌźž°½·zŻGUÓTøęč·×OĪē(ó615‹ˆz3"žEÄ3bZ fÄō€Ö{Q™ED«1#`D›œŽzēUYDXļ|fʈF¹ž ä»n ͈YYD4š³F,”ėUkFœ‘E„µ—Ģ įlĮ¹YDXļ|^ ˆF9õb½VÕYDŌ§żlˆĆ„ƕ~£äóÅ7åŻwU^MģƒŲb÷Å6Äb‘Üēs?ŸŪ™{Vn~ō„č®hoōā蜜r^ˆjÆROķŲ{ž’sjŹI‰)3åSM­ŽöŽźUŽ^MSᚣß^?E8Ÿ£Ģ%­UÄŌ,"źĶˆx ̈iYD4˜ÓFX%6UDe­fȀmrzėWea½ó™#åś/ļŗU,4#feŃhF̱P®W­qFÖ^2'`„³ēfa½óy"åŌ‹õZUgamĮš€‹å;·Öj~G pĀ8\śZé7Jņž÷¼»ó®Ź«‰}ūAģ¾Ų†XC,’ū|īēs;sĻŹĶ¾Żķ^“óAĪ ‘'Œ]ĘõĘcŽüÅÆŸ—–ē’źL'Ų³G­®s«ŹaxöČżlÖõ~ń”ȜėWø“Ÿ2'÷ø;ktüĢ£Só3O÷U~nš‹E°üøŸ}¬JĪĻŪ»­ŃG•÷žs£_|(ŅåĒ}†åägę¾Źwjܝ5:H~–=ŖÓķ?7łÅ‡"X~]ł™5 łqļ?¾ń”ȜėģŁÉĻl™“O»;ktü,/ӃéöŸ›żāC,?īg÷φüø÷Ÿ~ń”ȜŸŌgÆēģ«|7ĒŻY£åē=˜n’¹Å/>Įņć>>φüø÷Ÿ[żāC‘)?öU/'?ó\µB™5:H~šĻՃ©ł©Ö}•ŸŪüāC,?ī߇ÕƐ÷žóIæųPdĪuEÓÉOūžbv÷›oӃ©ł¹\÷U~¶łÅ‡"X~ÜæęC~ÜūĻvæxœ(J-¹«ø«čāš‚Ņ¼·b?Ź}4zWNWäb£Ę<’7Ö^`×ĒŲ¤‡rQwTż굂Z!žÖ=ĘŚ”°W€ć ģ<ŽfžÓÓžķ?ųĖÜžƒŗ646łIwæmgÕžĆ˜ÄČ&AūŚ“*“’@ūŽh’öh’įhŃžCz“’ķ?¤Gū8BǬż³‰žĶ”žPw·’Pe– qZmPæqģ³Śšœ_ÜźFbū^fxNZ&’ņóĆ^‰z<%ÄĆ^‚4"f-fO7佟z šŸ+–8UžÉŖ]Ÿ- »¾J0”õüĒ4ž’šßÉżüN&E»‹®/ŗ¤°±°“ą7_Ļ ’ŗü5łÅyĻēŻ—wm6Ļķ’†š›žü«§¦s]Ÿ’³äĄ?ŗ>µŖĪ»ī>’žó‹ŲĻ’ b™ßŗ’æJ-’õ7KœŹGäęz䍟£Šy=}ķ»ŪÜåĆīŽŽ²7ģļ3NEžõæ.ń,*P6čYł« žWNƒ†Ł:¢ūæ"Ńžo¢µČńVlVķ’%†Ž¾ż_µfŗżßżwŚĒ:ej’7ńC6ķ’ī’†īv$/1Pūæ“×e‚}E­É?&­QŲ2·’«²;6}ū„Ś’uŽs“ ż_ķ’ZŚ’M ż_o“Ę{āµĘ;ݜŖŌć/Õ2[ä:“¹¾›Ē„’„k Óć{Čb·†'ć"Õ~ń”PTĒkɔ%5õxįģQ^ærŌ4ź·‰½Mü~M7§+õü[<ętÉ1ĪV™¤›Š]Źo4ė“×\}øŹ>š¤ÜcŹŌ*n_|(TÕÆ&;ĻžĒa5å¤Ä”™ņ i³śع„©’aOJżöÆ źšœ_|×’ 7ķ%Bģ=ōėSėų\Åį®ļį²Ļ¾ńO\Æ×t<Ūķ®’įŽā'_s×qī¦gLJ]¾€SSĄ,³ę’ü‡ŗļƟ’x©Ųźöė2xY=’Qœ:ĮŸ’xé4«;¢ē?¦&Ƌūł£[šüĻ8xž#ŠŖšüGĻx³eīļ™™ė[n@O5Łł†³:kto”Ŗ;†Œä™ž9į™ž9^Ćõ̉šZ}'8ŸÆc'€7O):Xō½ĀŻ…; ?QX[0&’­ügóņ›ó‹ó~“w•÷óv“a}Ęķg1N·‡ĖED)Ō7“śe žŠxNXĒ›ŚSaÆĒAŁ!qHló«’į%³~Wż±äśŒnW­ ©ϐś<ē¹õ?x™į9iŁąą€÷Lh’€Ķ®’ńĖæxėŌś’6„žĒ_õWÆs×’xYūÓŻõ?žī#Üė®’qŃ%ÆP’#ǁSĄ¬ēåÄŖ’QEėś_Z§»ó=Ö)SżNĮ‡lźģ±ŗ#Ŗ’qnņŗĢ¶Ÿ PkņhŅ…śŻØ’1õ?Aż#õ?R’#õ?šźœ`N—ž·Y…žŲŖ»uÖč æĶŖ^ՃyÉo8©nī-b$ÕĶM˜žĀ­SMUᚧ×^ #%ו\VR[)žIŃ׏Iż“ķaźąÄ•”žGó^¾–­®‡ŗė\$Ō=j§ÖFu·©JĻ–ś=ē?±źœ5ą5iŁąaŸĖ>Ō’Ąˆ6hȓ÷eB<ł‹ĮS:ų|Åį®ĻńOļŽw×9NüķŻõ?μ}õĆa?ĻĄ©Č³ü’ į„lpš{Ž…(’Ą öLŁ“’°ÅźŽØż‡šäuq·’`t Ś żķ?ZŚH żo“’@ū“’pth’öh’ö¾#o’Į§žGuœKS’£GÖ~čä†öCi?ō(Š~Ø?ŚUæTD<‹ˆfÄ“,"†m ĄIhhū…w^Q8»ąß)x ąŗ‚LĻÅŽ={$v]ī'¢ēj’q† żGNxvū‚ś’Ø’/Ģõ’å §ž?}ēņˆź’s®)5 ź’sP’_ U”žæź’óFżŌ’Ą)!}ż+ēŠč€üń±rÅ„ ó ’ą»ä©žÅQ$Ģßź§CĮū²[`–²Uæ;¬ßŖģą|½0ßßzĘCæč‹]qū­WåŗKĢåč~#ŖR Ŗ³Ź)Ü¢ūĒh~ĘŚ£Ÿ_Üź¬ė+÷ »-Å`ŠĖ ĻIĖä_¼gõ} ˆ‡½1hDĢ+8ÆĶ™ųŪŌBV,īöīķś‡ĒĆ®Æ e=’1ē?|ēw’?’aäQ/ij³ ßJ-’ńPjłóžåփ…śµÜ|/üćŸĀŽ€]žćØė’¬Õ„(’į9æųˆ-’!h’…ö_Ņ9¢ö_^^fÓžKŖ3-“’Bū/“’rÜŃž ķæpJHßžĖ !Oß.⋯ŲzŅł…Š%Āż¼Ēō‹_8‘Æ|äńīēCĪ9ó­…oø¦o\²¬3ģė[œ 咏°ü’ĖĶv—¼Ä@å’ė’×%©ü’6AłŹ’;(’hU(’Ÿ@łoGTž?õųNłŹ’0Ņe(’ļe†ēŒŹŸ{Ąó/Qϱ§‚xŲ+@Žõ?Z÷<ŅŌ’ø-„žĒz=;źōœ_|$×’ØD ó.„ŗ¤ÖĶ*Ż}+;Ś{4÷ļռƸę5ōŽ©šb¬k ļ 3Ķ©ŹE­Ēæ:±X.½Qī»u®ŅSöU¾ōŗ»³F'Jw ß»3×ėĮŌŅO뾌3zżāC,?õ®üL†üč2;f~śüāC,? \ł‰;„`¬Ī(?ööŌüĢŌ}•Ÿ~æųPĖOƒ+?ӆ!?īżg«_|(ŌwćXQźqdŖ[äæ9ääf\r)Ŗlr“(Ił“}-_ĘEŖżāC”Žąź;Ēŗ{)KjźńĀ)›ąUFOM3Q8ß ~„'˜Ó„/åW”˶źn5:H)æŖWõ`^ņž`ß'‘ŪČŲ"†n«šØżt¢Ü^ŁŖ=²æŃ•›Iū*÷ß)»Vē]Ņk127v頔{F9ŗ,©·Ē/>jÆR%‡ģ=Ļæ\•šrRbŹLłTS«ņVĪ/ÆrIjŖ ×<żöū)Āł$ež½£"¦fQoFijˆX`FLĖ"¢aŲ¶ œ„—Ž]Ś_zøäĶāmÅÆżØš‘‚Ā; Æ(œ]š‡‚ļ»qhł{>†u±Ūc˜­‡rQŸ u^_&¬ZžīŗśOPĆ^Žƒ²CāŲfž’Óž#ķ?śĖÜž£ŗK16åĪӑ“’č“sŲ$h’ŃAūV…öh’Ńķ?Ņž#§„ōķ?ś“’`–Ōæ8Ōļ9wūuf)I§ÕUB°Q/Œö<ē±ķ?dŁžē!ĻæŠž'#Ś 1Ÿ™śé̱æN-tš÷KœG åĄ¼Ęi’v}`(ėłi<’į;æ“üł]žć?ŖĘ¼‘ZžćįŌņó§¾öž †:Fõ.Ņ„(’į9æų.’‘'DÆLZĖæ\‘Zžć*–ˆ7 õ ¹¹¦}eŅ5\ÆĒ¬ūąŹƒ®×’vūźWÜåE~ÖłJM¢ń ł÷[ygü!×ōO.9öžĄÉĄ¾[?hˆń²?SvcE¹ØõųW'‹õ¢QŌ‹;uä“}•/twÖhć=łß!n>„;VžŁ£S œÆū2ĪŲźŠĢłi•’·øņ3]•¦qwÖč@łyF¦ęēlŻWłŁįŠ`łiuå§rņ掮÷‹Eęü“ÉģŌ»ņ3Cęäwg’ŸYcō`j~ęé¾ŹĻ ~ń”–Ÿ®üT C~ÜūĻ~ń”˜.T~JÅŃ'ŚÅµ²ėżrøMT‹-ņ_‡rr3N•ą;²ÜTžLFRžd· -ć"Õ~ń”ˆÉnœ°[£Ī”%5õųÄŌQ jD³øT\)»~Ń-ze”šf¢°÷ˆ(’Ó“Ź£ūzqŲ(§č–óź’óš`Nē5g[TČļĘu²kÕŻ:ktb[ģR/āšU8ҲśpÕ«z0/ł O°ŪŻ–ŪČŲ"†n«šØżt¢Ü^ŁŖ=²æŃ•›Iū*÷ß)»V÷r³5:97^‹‘¹)у)mē ź·Ē/>jÆ:]8{^±X*3Ņ#:å~¹^ę«_ö»e†śĢ)'%¦Ģ”O5õdįģ­…ā"±]ÄõÜkd¤ź«©*\óōŪļ§ē“”é÷`15‹ˆz3"žEÄ3bZ fÄō€Öļ6Q™ED«1#`„õŻ®"Ŗ²ˆXpLö:'Ć„w—>^ŗ­t^iaé/K¾S\“«Ø·Ø©Ø“š•ĀŻ…Ū WŽ)8Xšƒ‚Ļōę_–ל79v(öƒÜG£wåtE.6jä7ŠfXßź„źĻÓĆF¹ˆØć”zž”LXOE<'¬ļ°ŚĮ°W€ć ģ8$¶™ē’ę•ńACŒV½†<»w_9¶®œ«ēö#Öż¤—Š­næ¾Ęn_§_śŪ .N ©köõ†”K,ŅŻq1ĀŽž(×éśŽŠźĪ÷X'Ÿ{3¶źAēžßįw/ȹ[1^.±WŻ„°»ä%¦»“Sł¶¬K^—ŁöŻ ¹&Ę61ōŽdxŌ u/”Ęćnšµ d76åNćZ+8±ž™ļ4&F6™Ė¬Ė\)VČm0Wī«äVčKW÷GŚåėfłJm—õz m7Ē©æ¶ˆ¹,;5sŗ¤ÅG–ovÆŁ*¹č¦tŁg®Y¾\³«Ķ}±Wę¢EtŹqö½·r¹ŒµŖóžĮ€™–«{»:7mč›»*ݲl‰*4Ģą{&#‚upō|\)·N—ÜcŗåP«|Żm~‚,ņÜ źæģ²ä|Š ”Æ]łŪ:Ɯ½fµĢP‹üģl’{nŸžü(c¼÷Rūó³L}Fļ§É5k×ēĒ1E¤æÆčl‡ÓåQ|²»K^īƒęŃ³Æ³ėšŽM-=C–ć;#«Öw·IŪĮ>–yŻu¶ÅdēNu©Ē÷tß(Uw Yk.slāuŗ#šuōrŽ]§„?v5 ‘ͱK}ßŖ9Ū÷‡ÅŌ£\Sż\«8õĖĮ¾óœĶ»U±£]±GsŌY[(1Æ”Ÿ85ÅXį¾Gīõ½¬dė7Į¹Æ¼īī¬ŃJ±­×ƒ©ßłOė¾*…ŌėŠ`łq—b›: łq—Ņźó‹E°üøK±Å‡”ķLŻWłé÷‹pr)ī/Z]ŲP0&’­ügóņ›ó‹ó~“wUģĶÜsŪ¢ēäŌDī‰ÄRqŸøN”śŌ’h–Õæ8Ō}wżóĶR±N­ź8ó!½hźōœ_|äÖ’če†ē¤eƒ‡Ļ=ģł—ØēŲSA<ģ +Ö=AÆņźoAė…ą*3#Ė%ņ¬¾tЈ˜uä¼\9å7©Č©XāT)%~zł÷N»¾J0”U’Ć4źšßI^’ƒb™æūīć©å?¾˜Zž£ė§5ķZåę[]tļ{oø^?9łµ]aļϜŠŽQūKt)ŹxĪ/>bĖŚ„ż×tŽØż×·w[Į“’šjĄL ķæŅž+ķæw“’JūÆ“’zōh’5=Ś’lŚÕ!yž?^=r5øŽ\ӆįČå>²oõ‹Eęü“Ź’[\ł™.A~ŲŻY£åē=˜šŸ³u_åg‡_|(‚å§Õ•ŸŹaȏ{’¹Ž/>™óÓ&³ćžå4ùŖbuÖč ł™5F¦ęgžī«üÜąŠ`łq’rŖJĪOź•§#Ź{’¹Ń/>ӅŹO©Ē9KµjÆRW¢ģ=Ļ’:šrRbŹLłTS«ėwε Æė\jŖ ×<żöū)Āł$e¾¢"¦fQoFijˆX`FLĖ"¢ĮŒ˜0ĀśŻ¦"*³ˆh5#fŒ°¾ŪUDU ŽÉ^ą¤søōīŅĒK·•Ī+-,żeÉwŠ‹võ5•¾Rø»p[įŠĀ1 ~Pš¹‚ŽüĖņšó&ĒÅ~ūhō®œ®ČÅFj’CŽZ…ųĢ“gw¤ž Ž]±DøėwųöūŸZpĄõŗ|Ż+Wŗėƒųå/žļķīś"&aėĮÄĶKł÷Č쾿»¼ '#ūnż a–4£üz”’Oņ’éQž?=Ź’§—.?ņø³@›[ÅBW~fī«|§ĘŻY£ƒägŁ£z0Żžs“_|(‚å§Ń•ŸYƐ÷žćŠ#z~äHrĆó#÷v}|µzŲ(µØzT=ŖVÄē„u :” {8ʉCb›yžOż’Ō’ļ/sż’E"Q’æ}§čˆź’wöŒ&Aż’ź’“*Ō’Ÿ@ż’ŽØ’Ÿś’©’’čQ’zŌ’ $ŁŌ’ļŻž£UŅO’āPæÜķ?V›„ÕŃÄ:¢ĢĪORßc ķ?ĘÕŠˆk’qŠĖ ĻIĖŸ;8ąõ—Ø×ČSB<ģ ˆA#b>ćōbķč?¦^@žĒŠ%Ī#r`RÓχ]_ŹzžcĻųĪļ$žĆČ¢Wˆļžś’—ZžćK)å?»q‰ńF”~-7ߎ/’ūM\Æ‹Ļžś¹]Æ ZĻ’u¢ņłś”ļnŪ!×߯üļe {’ądąS’ē§Õ-z]žC•}p—’˜+„±ÓUjcŽģĪÓwõ)’į9æųˆ-’”E ³UēĢ5W[­;5WWī«|łĆīĪØęźgō`ŗš½Æ÷‹EęüXm4;ł™!sr»³FÉϬ1z05?ót_åēæųPĖ»ęóŖäü¤¶sDłqļ?7śÅ‡"]~Üķo;ł™é“ŖcuÖč łYöØL·’ÜäŠ`łitågÖ0äǽ’ųʇ"s~ŹOX­+?³Õ·¹»³FÉĻņ2=˜n’¹Ł/>Įņćn¹ćŒaȏ{’ŁéŠéBå§Ō£Ķ“j±EžėCNnĘéV½Ž 7‰V‰")²ė—q‘jæųPضaTKMVm晲¤¦/œ¶r¼ŚŒSÓLNk3~­ŁM0§Kßź\…nß®Uwė¬ŃAZ«zUę%æį v½ķr[ÄŠmµŸN”[Ą+[5¢Gö7ŗr3i_åž;ewĄź¼[äóZŒĢŻZUJö9ŗmC3n_|(Ō^„Z²²÷<’v¾Ō”“SfʧšZµ’响äÕN–šŖĀ5Oæż~Šp>I™[RRS³ˆØ7#āYD,0#¦eŃ`FL”Ī‹¬Ö¬*³ˆh5#fŒ°Ī-TDUÖ;Ÿ™1ĀżūSEĢŹ"¢ŃŒ˜0Āś¢"ĪČ""„ĶL(‡Kļ.-żRéu„+KĒ•ü²ä±’’‹K&’¦ų«ÅŸ,^]\[\XōJŃc…÷ÜZ°¶`qAaŽ[±å>½+§+r±Qc¶’j2¬Ļ½Żkƒ6ŹEDmużCżŚQWEžÖ1č„v0ģą8(;$‰męłæyesŠ0ÆfŸf¾Ž%]ł³®|Ŗz"Öż€—Š­næ¾Fj_g]śŪ .N ©köõ†”K,Ņ]17ĀŽž(×éśŚøźĪ÷X'Ÿkæ3¶źAēžĶįw-ß¹Ś<^.±W]e¶»ä%¦»_ł¶L¹–5Ū¾ś,×ÄŲ&†ŽQ ŗŅ¬®×xÜ ±¶‚ŗ‚>6åNŃ­Vpb+<%2ß)J\‹2k“‰ˆ ¹Ģ•b…Üså^±Jn…¹tu}»]¾n–ÆŌvYÆ·Švsœśk‹\##‘÷Ń֚9]Ņā#Ė7»×l•\tSŗlŒ3×,_®ŁÕę¾Ų+sŃ":å8ūŽI¹\ĘZÕyĻ`ĄLĖÕ½]›6ōĶ]•nY¶D*fpŽ=“AŻ ŽˆŃCņq„Ü:]ré–C­ņu·ł v²4Źsk$ Ø’²Ė’óA3„¾vyäoėsöšÕ2C-ņ³³Iī¹}śó£ŒńŽKķĻĻ2õI¼Ÿ&׬]ŸĒ‘ž¾³N—GńÉī.y¹šGϾήkz7µō|·ö5µ¾»ÅHŚö±Ģė¾–³-&;ßpŖK=¾§ūF©ŗcČČZs™cÆÓѬ£—sģ:-ż±«IˆlŽ]źūVĶŁ¾o8ō(¦¦åš"čēZÅ©_öĆlŽ­ŠķŠ=š£~ĢŚB‰y żÄ©)Ę ÷=NÆļµĢ„Ų¬»–Īo‚)r_yŻŻY£•‚\ÆSæóŸÖ}UФ×/>Įņć.9uņć.eÓēŠ`łq—‚ŒĖœtwÖč@ł±Ė©ł™©ū*?ż~ń”–ŸW~¦ C~ÜūĻVæųP+…ŻāŹĻōa(…}¶ī«üģš‹ĒČRśxÉ=ÅżE«  Ęäæ•’lž@~s~qŽoņ®Š½™ūbn[ōœœšČ=‘øQ*ī׉ŅA/3vUoūµ2tUKWūe}­żŪóMW–OŲ±cĮĀĘyńŗ††ęÅw4,–Ć µ oø”\äēO:cįŅ‹.ļ¹į/śĀ®æųłöw­wlś­NIÅ÷¬Tt¬æV§ĀxČNÅkN*ŠŠKJĖŹG6zĢŲqćGO˜8qŅ•å£[[Ö_³±W½åŻŻ½Ė:·“ÆéX߯uiĒuķkśŪ·õ«+ĖOK™ī’ö¶O8£Voļ‘ÓŒI™ęüŽöö®oģķhūč† }ķżk\ƗÆķ“i¼ æ}ó]ŗåüUŖ>ŚÓßŃŻÕwY{oŸģ_ŽŅŪŪҵ±}Łöu-­ķķZÖŻßß½łŹņ23V®¤N±9ßK{ZÖwtm¬<÷ •“ʦ•öĄl=`’©Üp¦²S˜Č_ŻÕŻÕ^PPŁt¹=FT‰‰fq‘h.n÷ˆÄń-ń¬ų©xS2 £ŠmL6¦³ŒZćLć,ć\£ÉXjGģm69y“Ź’ŠÅRŃ#’uб^“ˆ~Łļ]¢ļ‚Īīõz§Vßoke7uŠd—‰-r*5uæŒmm".6ČČN9Ō.z“£M²–+ś$ “š_ījŌń!®ūMŗ?`õ ż÷ˆīG]1åŗ׿&ݰś†ž.¢ūQŻĻ׿rŻė~“īX}}Š2ōɇ”—lč3£\÷ćŗß”Õ[N9VÆ\}’Ÿēžą$fD›/m^&'CØļڸ쮲„÷=­ś*ž œićŗß¤ūVŸĄń0iOOgĒśóFQŲ+† å’Pž?ahł’‡3•’Ÿ0ńōÓ'ŸŖå’#鏒—Ēą €%ĘRc™±Ü O<P‘¼ŁŒž8"”’ą‡ņ’ĄÉ‹ņ’(’œÄ>µźāóK OWēū%¬l¾Dž:žK9ü³|õ[śŁ…«dÆ gåå}BV!śEŸ×ĮEēåż<§`ܙ3Ī]ü?¾(GUt¬^Óæ¼{óęö.ėž’ņŽö–žö¶ų֎žMńó/øhU[M{ž9[.h^ŗzŪOūź77Ļ©ēķ[|aA’Š’Õē•ōÆ(ūlī_Üż‹O~sŹoö]ū§¼ż©¾óAĮ=Æ’śær’ņĄĻ–‹üqW;sćkÄĪ\s8œ9_cłcą 3Ķ„ķŠļĖ÷žšW×ušķm_»ī#{÷ę?²’Ē7ß|čūWtŒ»ėÖč??[0ź›Ó{oūŌų»nńŻg:F}sŁåó~ņ«Gņw޶aښ.Ļw®9(v~WüÓ¦?­o›¶ę;kž®ś‡Ėö¾Qõńūo»źA9ɦq;æūĖ–+nš8%ś?ļųŪv9É­[²tļӛīżĢmjUVŒS«ÓvǼņy­‹ĒN_3ćĪy?üĻĻń“ ņĪūuķŻ[|’Ƌ>śÅ±;«Īś«'?»āwwé²W¾śÉó~÷Žź¹Ń¢¢QߌüÆe{WĶ-Ÿ÷µG’ŖhœĒmW-=ūźļVž±å+?źw_æą+Ļ=|žŽļ}ōß¼ā;’¶wįłßŗą’|śŠ––ŗo}¦śńĖ®jyšéüq‹‹§Æyd¬j¼ł­ĮÓŽž÷Ķퟘ¶¦mׅ{zf4ļ)Ÿ'¾Łzń’ė^ͤĮŗŅ›īæeõ“5oŒY|Zdg®œņ»ł³KęŹ °į‹c÷ŒżhżSߊ”ĻkŚ+¢EņæoFŌ #ęp“ČņĒĄ‹¹œóæĒ’Gޜi?½·ńoŌ'ó‚ó.n~tŁU;Ć9č‹.’Öķ:Õ//öž4cłõGŹ’pb ü??”’NnÖ¹ū‰ūüo]Żāyń†Å ĢēkėēÅė«ē£ß·Sńóņ²!O²Ÿž4¹bŠ÷3ĄŁüŃQ‘Ćźµü_Ķcm/ķéńÜK÷Uܱr®Č•ƒKÕ«ééŚxū¼˜“Æņ÷{ģÖÓ¼%‘”iŠjœåØļ“|µ/~\že”5¼’Na}M”ė?ŻZż³\ag‰”U-Sd×*ZÄzqŲ(zE·łüq›Ø=²æQ”ÉæĒÄEb»üś³žh>MLšļšēüŌw?Z”Ķ欻sĖęö¾łvĒ©· ’—ļ*ŚŪŻķw5nßø/O–y•ļiöÕÅr’čéléoÆiŪ|DYU÷¤ÜN×µµ_ŪŪÖÖw•ׂxŹT„ńī¾mńVł:ŪufĒŻż“ŁÆ03;F­•Čßśˆģī±éėD䳿“ļč|õ†Īś³>¹ēž%®īi¹ęyp8KČtwÉ^Kז–Īx{_æüsņĀĪÉļ±Tœ.ŠEæh›ĶgĒ[Ģį¹=6›Ū¢Pn]µŗåųÓÄŁę"ēŪKœo.p¾{yó“7?yi£…1_ˆ±ņ”©ĢØ.ńx½|ćgˆs冿RīżāSā>ńeńÆāūāEńkńŽ~0¾"ńhü‡Œfć"ć2ćcĘåĘ'¢WY³H< ?59ćŃ35=Ė–ÕźŠ ^ĢQĻ~“~·åčēĄģa5›1*$&Ä#ņ#÷øģžŅ}Õż«°~~µ×-n­m9³„qĮśŚśE ‹ŚkŪohhÆoiØ[ßR×^W׎Ö^’”Zm耄¾öCė»7דōōt¶«’«ūZŗŚZ»·Õō¶·“Uoķķčo·#ź>T[g4¦Ģ£®õCóÆÕƒĶŪćr.i?5ĻŹ÷pXī ęOŪ\]’M¹U?€’+‡×Ćårų=ÜTnÅšä®żl®Ī½ž­‡såpTo‹ņøž¬ön9°R?MMƇGĖįÅz8.‡ūõp“¾Ēž¹ū¼Ųėó¼ó{{@nĆ7r›ŚŚŹ×X[9÷•Öīīköę™Ū¶¼Vdö„˜k[X…ŖÆK}|‘G&ėµ}œ)ү݇ŹR=.5ć*Ćj*·'Ōś4 ėHT.ļ”EÖ:ŲÆŻ7Ōė‰)Æ'ŁŁŠóU‡ø[ewģvééŌ›YśµG×Ŗ#µ*¾ØöZūCRęńž\k9F:äńbž|×±µŖ¾V¾ėł®u{’.±NzYWß3t×.\øpQc]õ‚E+«¬h<ÆzYƂEÕK—7,ZŠŠP·āĢŚ:{½Z"ÖIŠļĘ;'Cz¶ęöx@®p®žÆy ŅĖUÆķC’żwóČ$T­śµėeoŸ”ĆpbZ÷1k‚Īķrü^Ł=%»ēe÷KŁ}`8yųŻg#IŪfŻōXŅė»¶ę'½~$åõÕ³G%½~²Īzm/æVξIv«dw•ģzd7IĪū®xūÓaēī=½®īķÕļW}™$¶§gœ•“=œųk{6,«[ŗhĮyÕĶ õ+Ŗœ¹ø¹śĢŚEĖåg.=ó¼ś‹—6ŲŪófį½= =/µ=§§]¼aa[cK}{K{Cķ¢ŗ†Åė-jXŌ²øķĢE‹ž¹ qQ[Ć¢…ZźĖ‘“Į5ŗŗu­>4ĖŃ}ÓżDXG×ō‡LmMut-×jutżK=œztݫǫ#j›žfRGŌWģéåš›zXQ'čiŌõÆŽØłz¼:¢6ėįŚøs5ž’ū³=Ÿ§¬żŪœ~Ž^VŹ‘¶GĻ§ĢŽ†)?¼®Ņļ[}³®ŒZĒĻįxö5Qs턽]ŻęÆ`µžEņĒ‹ĒĻĖ gwEźß:»+P’̳»zU»S½U»Ó¢EµņLo:»{źĻīÖdĢ“}yH’¤ėł)æ·ĖéUlÕO©Wč#:āń©f {ĻŅĻ’ūŻ’p;fĻ’Ū7ōO³Łz\āŌcÄÜ ąüŸóĪ’€š!DŽģE„ÕoŅĆF¹ˆDe“ģJÕėZ!ž“żXXėy¬ {8ŹÉSąmę9½4Ädٟ.»±rģŃ'ŚÅµ²ėżrøMT‹-ņ_‡Šˆ:jܾŹ?¾Æņ½\»³FļÉ’Ęqó€0/, µśpåĻō`$åO3t_ĘEŖżāC”®yŒ“]Ō|•)Kjźń‰©#¢@Ԉfq©øRvż¢[ōŹ(5ĶDa]qQÓÉiZE‹X/®åŻr^]r^Ģé¼ęąl‹Š}•/­“]«īÖY£Ūb—z×D¹ó¶V®zUę%æį Q= ·‘±E ŻVįQūéD¹¼²U#zd£+7“öUīæSv¬īŻg¬ŃɹńZŒĢM‰Œ&’%gPØø=~ń”P{ÕéĀŁóŠÅR™‘Ń)÷Ėõ2_ż²ß-3ŌgN9)1e¦|Ŗ©Õ1ĀŽ[ Äf±]NÆę]£ūjš ׿öś)Āł•‹Zub±\“FQ/‡TÄŌ,"źĶˆx ̈iYD4˜ÓF“Ź’[̈Ź,"Z͈#ŚäōÖ;ÆŹ"Āzē33F4Źõ_ ßu«XhFĢŹ"¢ŃŒ˜0b”\ÆZ3āŒ,"¬½dNĄg ĪĶ"ĀzēóE4ʩ뵪Ī"ĀŚ‚5#Ėwn­Õü,"=Žą„qøōµŅo”äż!ļ;ywē]•Wū öƒŲ}± ±†X$÷łÜĻēvꞕ›})ŗ+ڽ8:'烜"O»Œė5ĘóüßüÕ Ļ’ÕŁźiBÉÄÄEņ—}\Ÿ7Xg6…²‹Xēūļ¾`uļģµÖĮ>ZśŪ+\’RæZģņC—:Y¤;#6ĀŽž(×鏶ÜWuē{¬“Ļ¹ŻŒ­z0'1r‚š;WwĪ&ĒĖ%öī«|/Ēź¼Ļ&½Ļ“+ßփg'ÆĖlūģR®‰Ń“FaSg’¹õk<®vX[A• ›|%čŻo[Į‰­š”Č|%hLbd“¹Ģ ¹Ģ•b…Üså^±Jn…¹tužŚ._7ĖWj»¬×[h»9NżµEīcF"5sŗ¤ÅG–ovÆŁ*¹č¦tŁg®Y¾\³«Ķ}±Wę¢EžYG×FŹå2ÖŖĪ{fZ®īķźÜ“”oīŖt˲å'ēŲ3Ō¹PDī©łøRn.¹ĒtĖ”VłŗŪü;Yå¹5ŌŁeÉł B—]:ņ·uŒ9{Ķj™”łŁŁ$÷Ü>żłQĘxļ„öēg™śŒ$ŽO“kÖ®ĻcŠHŻĒ٧ļ«Ü?ŁŻ%/÷AóčŁ×ŁuM練ž€ļÖ>Ā«õŻ-FŅv°īCÆ[9[Bfį„b§K=ŗ§ū>i¾dČČZs‰cÆÓϬc—sä:-ż‘«IˆlŽ\źŪVĶŁ¾*8ō¦¦åš"č§ZÅ©ß öuĮlŽ­ŠķŠ=šc~ĢŚB‰y ż¼©)Ęŗ¦šžV›)‚]•t~L‘ūŹėīĪä>ČĢõz0õ’iŻ—qFÆ_|(‚å§Ž•Ÿ©Ćż;ĻĢOŸ_|(‚åg+?q™“ƒīĪ(?öQ95?3u_å§ß/>ĮņÓąŹĻ“aȏ{’ŁźŠĢł±ī&8ł™¾Æņå»;kt üčļ·!ł±ĻPT~vųÅcd™YVśXÉŻÅ½E—Öœ–’fžņoĢ_–_˜÷FŽ'bo澘Ū='§&rO$n”ŠūÄu‰ū’źŪPķ^ē’źoĮöÉV”~=)CĄžĄńpøDžÕ›ĻōĖ.2h˜÷m‚žē;מ*‡įŚ“ūŚÜõ~ń”Ȝ«®“Ÿ2'÷ø;ktü̲ęgžī«üÜąŠ`łq_ū®JĪĻŪ»­ŃG•÷žs£_|(ŅåĒ]ĀŚÉĻĢ}•ļŌø;ktü,{T¦Ūnņ‹E°ü4ŗņ3kņćŽ|ćC‘9?Véy'?³eN>ķī¬ŃAņ³¼L¦Ūnö‹E°üøļŻž1 łqļ?;żāC‘9?©÷Žęģ«|7ĒŻY£åē=˜n’¹Å/>Įņć>>φüø÷Ÿ[żāC‘)?öS/N~ęɜ<éī¬ŃAņÓ|®LĶOµī«üÜęŠ`łq’>üģŻ p×} ų× @&‡’©OcÅ8¦,˜†ų ×+¤h1%Ł”)Q_äR#300$Ek•„o6v.*Ÿ¤dćD{¦å(W±„l“{9;uęĘqTI)µQ®’]Õ%µå­³wS‘Ÿļā*Åŗ×3=ć)+’ķe’~¬ž÷ļžžzļõ¼ī7=hv’ŹgįńóóÆ“üāÕ˧łMóåÓ³šļ‹_Ūßļü—Yø“|ögiZ>÷¾Ņņoˆ\ł,¼žéż!”ĻĀćēÄ+-Ļ›ÅšĻæåÕÕU7¬ģY±ę‚æYžÕŽĻ·?°¬ŚvCҳąž?|’±£“…ŗbŲšinõ¹gķ̆ļҶ`†$.jć1śöųĢTe®žŽ_ą#i&«ŽŲŻĪCiūŠ•„#Yz²™&ŁūmYھ`™\–veéH–žl¦I6_[–¶gig–沓+KG²ōd3Ķ­$ė|$Ł–“¬‡’䲓+KG^S–įĒJ³ļŽ3~|nf|ja’=Ÿ’‹¤mY{Ēņ :W¬lČ­[yēŽ»kĒ÷ÖKõ£sc„ŁŪc•ÉņxßTŖß݊o®Õ¦ĪĘ„ń}•ņń¹;jÕz©R-Ļ.XōŽ[*ÕÉŚń±ŚŃźäÜŁÄ[*“õ»ä.¼i¶|,.zS©ZŽW™«ŒW¦*õ r›ī»ÆP¼¦«8“õžkŗī+ęū®éź+Ž.tv^zÕÖŃ=ūgī’裟śōg>ū}ł+Ķ·Z°aIQüa³(*Dz¢hŖU™[;_«VæeĶŚÜŗu6^xŃ[7]|É„—]~Ł܆ńŅđói&vŌ¦j³cSGĖwN•ĘĖS7VĒjõzmś@nķ\Ģõī‰Z5ĖÕķ‡g+“{gJ•źį[ėå{ė{+,Č­_²Ŗ÷•'tó‰™8ĻĘ%ó¼{¶\®6Öwć”Csåś­ āżw4¶[/OﮪÅõ§Ū¾q¦^©Uēö•gēbŗæ4;[Ŗ.X“źŻÓ„ĆåŃ©JiīÖJÜķt÷6_ūb³øV¬Ų<²ænŁ’­7smgĆĶ­ņ=t꒛«µjłĘumßIĒćklĶ—ļ9Ń5:3sĪ£ōŁĶ/ŽwżÕ”#†ƙ߽ž™źį×q̇KŸŻü·Ÿk¼…š–¶%󬟙ßNzNėL÷ā¹Ūć;ėšńŸżRh¾.Žūes÷·-Xl[X²«kĀq„0Ž„Ća6ŌĀŃP “”'ĢÄōpXß_ö„ńō7§Ķ„õįŅŽėģ]šū amļ¾ŚŌŃéņ\o«7&¦YˆÆ1Wķ³µŚ+}÷ģE_Ė5ęiĖ=«ćń13UŖ—{&§_W©®+|)ÖÓ'ĖĒf''ēŽ4ĖuEג¹Ö tÕęīķY˜*g%{у/Ķ—ģs·5JvcŗW”óųcqx ,æņĪŠöŠ 1GļN3“ķżsńČŻī™)9‡m!@­“RõhiŖ«^ž«Ē·ol[XœĒ5į’°:ŌC9LĒ’žŠõ’Ę=±>¦u±2ÖnZGµ8}}xWc“½­-ö66Ų»p{½‹7×»xkBŅĀ…1kӒI‡Ķ#×gÅŅ® ×Ɗ?ŒzųHųÕšxųbx*<¾¾™¬L6$—%—'W$ļHņÉp²=Ł™ģIö%·$ū“»Ś6WŃÖjŲŽ¶øÄŪ+āģ™Ė7¶ä¹eĖā“›×m8ĢĒéj6¦‹,į±ų‘{2§³4¾š—_åĀŠx¾4\čŸČ÷ ‹ƒÅr~ ›¾>?‹7Äx(‹»b\Ļā‘?ÜŗÜ=ĀK­ż93½}2Öį×;ĪVu³–4k¹ćłńZķČ4ź6—Æī·–/8"b §‹¦§Ė¬}‰-Ss¼ÕάŹĘ6•k²iKK<-įōˆŹ5 .¤ū³34/@ŚćölīCk|įĶ…tüā%ć—¶J#[oŚÄ}8ĒįÓŁ|ifFæšł;Ņ–zShµ­ÉŚsä?éhn'YĀ”Jl/z{“­oļĖĒ\÷.Ų‡šÄ'ĪīS¶­ŪÓ3ÄOde0”ßŗuėą@”»p×@w’®ėŗĒŠżƒŻ£;ŠƒżÅba×p¾ŠŚÆR[³ōĀ[ē;CŁjõq*īpG¶ŽFC”m7o5I­÷-SŒW·Ę“Q­śYŅ Ÿwa›µ)+ŪSqśq8‡3qųZ^JęĖį…‡ŚÕĶW._4žĄńĪEć-ægĖŗEć_*4Ē[ŪĻĒՏÄį¦8ŒĆLN¶-.÷Ū,ßśt“Źī[پ.¬×ö,æéÉäl}†pÕ¶EõłÉ‹_ZPŸÅ±Āč`’uŻ;‹}»ŗū‡‡vvēwėįŃįėśv [õł”pīśL²u„ĒŃ3ټC‡¶N”śŹ„r1?X(M KC“Ćƒƒ[‡ū'‹ƒ[•ś¶žPZŅā‚u ż…ńCŪ{~gŗ?ĶÖõTö!Kk3m]sه:m]?–ÅK[×'²éi‹:™™ŅõłÖü1žė,N[ŌMٚģų»ņįÆ|ęÄŪ?žöįß¼jeåŪĆWżęu«å¦woMžkŗĖ/æ¼,LŸŁõ_ŽņJ aq’’ŖźŽ—+_9}śŌæŽ÷Čmæņk·¼ļ‘G<ņ©_ä·ģÖßĻæü»ķĖ6ęū®™Ł˜öøÓī÷ÖoŻžÉmoh€Wµø’’Gw?ó’Ŗtš`:!ķŽ¾ó§nš§š# {žśwéw?”żWēžõUŸ’Ÿ„Ös?>Ņģ¹!|ļG¢-yŠĀ®Šü»āäĶō 8xž?šJ<’~teĻ}ŹeĻ’{„ž?š#ģ5?’/„W}öߦóueéH–žl¦.ą„Åæ’’ĄĘ3µ?~šą™÷\}C÷{žäź«nx¶÷«Ļīłź3Ż×_SśŻćwül²rÓųyč£éé<óūOųū8Ļ-ī’’öÆ’Žē·’|Ņł3Ÿ-F’‡ž—÷Ģüó™Ż?óŽw~ł—W’Āc;–ż\ķ3?;1ś”ōŁü_ž?꿐æ`ٲ‰jłŹ›ė×>˜ž?żF`äé[īųž›ž[Ü’’ĘUWæT}„ē’ĻtožÅōž’ēÜ’’Ą·ævŅżxsČžžæ+ūū’œ‡žĆŸ×ü÷’Æö  ģ[²ił0æÜH–žl¦oŠ3Ź=“Ӈӏ^V‡z(‡é0¦B©÷„É8~8¬ +枤$­ÅéėĆ»Ž?Wžė½g¦täH©Zī.ĻÕŖ½Ó„źŃŅTW½Q›ī)ĶĢL•Ó×ī¹Rur¼voĻl¹4Ł}|¶R/·–(lĻĮĄ’uĘ·÷«M•Ņ;}¢+®„·g¼4qäšl-ÖEļ|Ų3SuńtĢĆw^~łåĘ£­:šĻ¬j/­±uÄųÉ,ĪÅųł,É5—mˆGÕÓYŁĒxKwÄø=«‹\Wöų‹h] ®Ļ¦ÆOēĻā 1Źā®׳x$Ę·Žš3!¼Ōڟ3óĻŪ:ėšėg«ŗYĖGšµÜńüx­vä‰ u›;ū!~,-¾’ÕæųOūģ3”żćæńöM§Nī~ęķC’ģwāK[~ł“ŽłĪß?s:/½ė’ļ¾÷O{ߥ^“Åż’—~åOæāļ’æždū²ł¾ĖvĶlLļE¤ß¼ė'\ē÷’pž[Ü’žÉ}÷üQhæō™ŸŹ$B³“ōŚŃ§/~C÷ų~,ī’’Åææż¾pį²e?w×møg’=wķžĄGęTg¦::¾āē¾}bÅņ-'Ÿ™æ’äļ¹’ē¹%Ļ’?ö±’üŽ? ķ·’ōæŻtźäŠŠģäß’›·ž÷’ąĶkq’’öüēūŌG?ō”ŃŽĻ ż»k¶>žé”ė¾4ōīĮįk’·®ßžšxŖŲų’’žłŗĖ®K—Hæxņ«Ss’ĪsKžž’½Ē~yǃIēWżPažļ’’Ļ’ž’ģs’޼÷’’vżÜ3æ=~šą™÷\}C÷{žäź«nx¶÷«Ļīłź3Ż×_SśŻƒæö•Šń?­~ė‚ū’7¬’/Ϲ’ē¹%ż’Æ>ō…ōł’|h’ź›N·‡¬“?ż/’Ężxóz Ļ’ßńŪū/Z¶1ß÷p׊GÓ%ŅÆn{ź½ī’Ąynq’’ćßś›æZ»{yׯגÉųɶŸL§§½ü ’ļæē𦵸’æūŚCvš+§OŸś×ū¹ķW~ķ–÷=ņčG>õė|āöŻśū3’tkćł’7,ø’ן®ø’ēædģčd!„®¦ß¤inõ¹gķ̆ļҶ`†$.jć1śöųĢTe®žŽ_ą#i&«ŽŲŻĪCiūŠ•„#Yz²™&ŁūmYھ`™\–veéH–žl¦I6_[–¶gig–沓+KG²ōd3Ķ­$ė|$Ł–“¬‡’䲓+KG^S–įĒJ³ļŽ3~|nf|ja’=Ÿ’‹¤mY{Ēņ :W¬lČ­[yēŽ»kĒ÷ÖKõ£sc„ŁŪc•ÉņxßTŖß݊o®Õ¦ĪĘ„ń}•ņń¹;jÕz©R-Ļ.XōŽ[*ÕÉŚń±ŚŃźäÜŁÄ[*“õ»ä.¼i¶|,.zS©ZŽW™«ŒW¦*õ r›ī»ÆėĄ5]żł¾ūÆéŗÆ˜ļ»¦«Æ8x’ż¹ŠŁyéU[G÷쟹’£~źÓŸłģo<öåÆ4sÜjA†%Eń‡Ķ¢ØLˊ¢ż©VQüenķ|a¬Zż–5ksėÖmŲxįEoŻtń%—^vłrĘKGϦ™ŲQ›ŖĶŽM-ß9U/OŻX«Õėµé¹µs1×»'jÕ,W·ž­Lī)MTŖ‡o­—ļ­ļ­|°| ·~ÉŖŽWž¼k~ŅĶ'fā<—ĢóīŁr¹ŚXߍ‡Ķ•ė·.ˆ÷ßŃŲn½<½»zØןnūʙz„VŪWž‹éžŅģl©zøQ›ī)ĶĢL•Ó×ī¹Rur¼voĻl¹4Ł}|¶R/·–(lĻĮĄ’uĘ·÷Ė>Ó'ŗāZ¾ē§ę阇ļÄ“qiŪѼfm/wdeÖć'³8ćē³x$×\¶!ŚOwdeć-YÜćö¬.r]ŁupztĒąślśśtž,Žć”,īŠq=‹Gbüpėr÷L/µöēĢüõöÉX‡_ļ8[ÕĶZ>ҬåŽēĒkµ#O\ŠØŪ\>¼ŗßZ¾ąˆˆ5œ.šž.³ö%¶LĶńV;³*_ŲT®É¦--ń“„Ó#*×,øīĻĪŠ¼iŪ{t°¹­ń…7Ņń‹—Œ_Ś*l½i÷į8<‡Og󄙿ĀēļH[źM”yŌ¶>$kĻ‘’¤£¹dE‡*±½čķ]ж¾½/sŻ»`ĀŸ8»OٶnOĻ?‘•ĮP~ėÖ­ƒ…īžĮ]Żż»®ė+övī(ö‹…]ĆłBkæJmĶNŠ oļ e«mŌĒ©øĆŁz Q¶Żt¼Õ$µŽo“L1^Ż_ŠFµźgI3|vŽ…mÖ¦¬lOÅéOÄįtĪÄįkqx)™/‡j[T7w^¹|ŃųĒ;?¶düž-ė©Šom?W?‡›āp03q8ٶøÜo[°|ėÓŃ*»oeūŗ°^Ū³ü¦'“³õĀUŪÕē'/~iA}Ē £ƒż× tļ,öķźīŚŁ=œÜ_†G‡ÆėŪ54ZlÕē‡Ā¹ė3É֕GĻdóŚ:9Pź+—ŹÅü`”8418X, Mnīœ,n=TźŪśCiI‹ ÖQ(ōĘmļ=śżéž<4[×Sه,­Ķ“uĶeź“użX/m]ŸČ¦§-źdvfJ[Ōē[óĒųƳ8mQ7eó¤-źßgÓÓµ3›ž¶Ø;³8ß5ߊ&§ćńÜZĻéęńŻXOŒĻ“¶µ¤„ÉÖ³¶U‡K.¼fłNϬ׷7ŪĻF>Zßy„žc{g«SµĘUpŗ’«āÅĖ9./_„w·*żwõīV¤’½»¾“w×W,¦½»ĮĮü5]±õŒ½»ÓƳw·:»¦ž •XDéÕ^%Q5ĢķžŖMdĮ䚘Ę&1üNz­\tEŽ—ŒéāeĀOgĖ\-ó&Š:²ŅÓųuÆ|’ų–“ļÜ»s,Ģ_/•žŽŗāp°µ@ųŽ7²K³-Ł“³]óęf€žæžæž?š&4600ZܕßÕŻæµXģ.^W(tõw vōõķܵs ’ŽGąū–Œ,„ŠĆĪŠLs«Ļ=kg6|—¶3$qłPŃ·Ēg¦*sõšž?I3é\õĘīpJŪ‡®,ÉŅ“Ķ4ÉŽoĖŅöĖ䲓+KG²ōd3M²łŚ²“=K;³4—„]Y:’„'›iÖh%Yē#ɶœd=”$—„]Y:ņš² ?Vš}÷žńćs3ćS ūļłü_$mĖŚ;–_йbeCnŻŹ;÷Ž];¾·^Ŗ+ĶŽŽ«L–dzų¦RżīV|s­6u6.ļ«”ČmÜQ«ÖK•jyvĮ¢wÜR©N֎ÕŽV'ēīČ&ŽR™¬ß} wįM³åcqћJÕņ¾Ź\e¼2U©Ÿčl8Ūtß}…Āš5]Å”žūÆéŗÆ˜ļ»¦«Æ8x’ż¹ŠŁyéU[G÷쟹’£~źÓŸłģo<öåÆ4sÜjA†%Eń‡Ķ¢ØLˊ¢ż©VQüenķ|a¬Zż–5ksėÖmŲxįEoŻtń%—^vłrĘKGϦ™ŲQ›ŖĶŽM-ß9U/OŻX«Õėµé¹µs1×»'jÕ,W·ž­Lī)MTŖ‡o­—ļ­ļ­|°| ·~ÉŖŽWž¼k~ŅĶ'fā<—ĢóīŁr¹ŚXߍ‡Ķ•ė·.ˆ÷ßŃŲn½<½»zØןnūʙz„VŪWž‹éžŅģl©zøQ›ī)ĶĢL•Ó×ī¹Rur¼voĻl¹4Ł}|¶R/·–(lĻĮĄ’uĘ·÷Ė>Ó'ŗāZ¾ē§ę阇ļÄ“qiŪѼfm/wdeÖć'³8ćē³x$×\¶!ŚOwdeć-YÜćö¬.r]ŁupztĒąślśśtž,Žć”,īŠq=‹Gbüpėr÷L/µöēĢüõöÉX‡_ļ8[ÕĶZ>ҬåŽēĒkµ#O\ŠØŪ\>¼ŗßZ¾ąˆˆ5œ.šž.³ö%¶LĶńV;³*_ŲT®É¦--ń“„Ó#*×,øīĻĪŠ¼iŪ{t°¹­ń…7Ņń‹—Œ_Ś*l½i÷į8<‡Og󄙿ĀēļH[źM”yŌ¶>$kĻ‘’¤£¹dE‡*±½čķ]ж¾½/sŻ»`ĀŸ8»OٶnOĻ?‘•ĮP~ėÖ­ƒ…īžĮ]Żż»®ė+övī(ö‹…]ĆłBkæJmĶNŠ oļ e«mŌĒ©øĆŁz Q¶Żt¼Õ$µŽo“L1^Ż_ŠFµźgI3|vŽ…mÖ¦¬lOÅéOÄįtĪÄįkqx)™/‡j[T7w^¹|ŃųĒ;?¶düž-ė©Šom?W?‡›āp03q8ٶøÜo[°|ėÓŃ*»oeūŗ°^Ū³ü¦'“³õĀUŪÕē'/~iA}Ē £ƒż× tļ,öķźīŚŁ=œÜ_†G‡ÆėŪ54ZlÕē‡Ā¹ė3É֕GĻdóŚ:9Pź+—ŹÅü`”8418X, Mnīœ,n=TźŪśCiI‹ ÖQ(ōĘmļ=śżéž<4[×Sه,­Ķ“uĶeź“użX/m]ŸČ¦§-źdvfJ[Ōē[óĒųƳ8mQ7eó¤-źßgÓÓµ3›ž¶Ø;³8ß5ߊ&§ćńÜZĻéęńŻXOŒĻ“¶µ¤„ÉÖ³¶U‡K.¼fłNϬ׷7ŪĻF>Zßy„žc{g«SµĘUpŗ’«āÅĖ9./_„w·*żwõīV¤’½»¾­i®˜öīó±§×ŸöīNæĪŽŻźģšz*Tb„W{•XDÕ0·{Ŗ6‘P<“kb›Äš;é5Z“"^žˆó§Ėö4ÓÅK„ŸĪ–x2[āM”ud„§ńė^łž?š#,iß¹wēX˜æ6^*=uÅį`kš½od—f[²ig»ēĶĶżżżąĒKöū’ōŗ'½Xn\’¬<÷¬Æśū’ĘW©~’o:ĶĻī›÷÷?żé7ąę7ÄÅ”ó[Pæ’I>Ū*Š’ė»~ż³¾õėŸK.;÷oĪž`ę|łaĻkł1ŅüwZ_P¼ĪŸų,ų‘P<‡¼=l;ƞ0>~!<N…Ļ…ßżé’ž:ü}’d_s“¾äŲ–üÓd4Kv4?ūõĘ勫-Iæ{’G~³ßčßæķ嗛æM 靜ōI:w=.[“±·~(.9£r˜]r_ąī˜n[°ō›œß’ÆÄļ’įGWvß'—Ż’„ž?š#ģv’?›7=o óóveéH–žl¦.ą’g€ü_AUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU„»W©#ˆ|VD±Só×ÜBQ”«„ AŒ‹¢˜4ž4B$ØXˆ]l’2MŠÖBDÄ×°|!„Eźk”{ݵˆžņ}p8Ģ™™3»óÆg¤+ź7¢-z+=•lXwZž·vZ>›©Ķ¹._ٜEÓeŸ²Rw$Ł0¹™h½×.łß9ÉĪłjĆōĻć»^Ķ·ė“Ēö=IRÉ#āC›E~”~Éģóū•ņČļźO<¼3€×õ%‰ŲoŁo‰ŹüŠÅĮņƾ”öÕtļąs’h¹{²£Xv5žpŪ·XˆÕXŠR–—c.¾Ēü›:¼Ćéhibpņkķ ĘŚC‡‡ÕĪæµzūD>ū0ćĒ"7õ­©±ßi_ŗ{T=éoH‹śF‹+ėŪoņ<Ė5ÜP meson-0.53.2/manual tests/5 rpm/0000755000175000017500000000000013625242353017644 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/5 rpm/lib.c0000644000175000017500000000010712650745767020572 0ustar jpakkanejpakkane00000000000000#include"lib.h" char *meson_print(void) { return "Hello, world!"; } meson-0.53.2/manual tests/5 rpm/lib.h0000644000175000017500000000003112650745767020573 0ustar jpakkanejpakkane00000000000000char *meson_print(void); meson-0.53.2/manual tests/5 rpm/main.c0000644000175000017500000000015713602226377020742 0ustar jpakkanejpakkane00000000000000#include #include int main(void) { char *t = meson_print(); printf("%s", t); return 0; } meson-0.53.2/manual tests/5 rpm/meson.build0000644000175000017500000000060612650745767022026 0ustar jpakkanejpakkane00000000000000project('test spec', 'c') rpm = import('rpm') dependency('zlib') find_program('nonexistprog', required : false) lib = shared_library('mesontest_shared', ['lib.c', 'lib.h'], version : '0.1', soversion : '0', install : true) executable('mesontest-bin', 'main.c', link_with : lib, install : true) rpm.generate_spec_template() meson-0.53.2/manual tests/6 hg wrap/0000755000175000017500000000000013625242353020377 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/6 hg wrap/meson.build0000644000175000017500000000035513016624375022546 0ustar jpakkanejpakkane00000000000000project('Mercurial outcheckker', 'c') sp = subproject('samplesubproject') exe = executable('gitprog', 'prog.c', include_directories : sp.get_variable('subproj_inc'), link_with : sp.get_variable('subproj_lib'), ) test('maintest', exe) meson-0.53.2/manual tests/6 hg wrap/prog.c0000644000175000017500000000011613602226377021513 0ustar jpakkanejpakkane00000000000000#include"subproj.h" int main(void) { subproj_function(); return 0; } meson-0.53.2/manual tests/6 hg wrap/subprojects/0000755000175000017500000000000013625242353022742 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/6 hg wrap/subprojects/samplesubproject.wrap0000644000175000017500000000014613016624375027222 0ustar jpakkanejpakkane00000000000000[wrap-hg] directory=samplesubproject url=https://bitbucket.org/jpakkane/samplesubproject revision=tip meson-0.53.2/manual tests/7 vala composite widgets/0000755000175000017500000000000013625242353023405 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/7 vala composite widgets/meson.build0000644000175000017500000000062312650745767025566 0ustar jpakkanejpakkane00000000000000project('composite', 'vala', 'c') gnome = import('gnome') deps = [ dependency('glib-2.0', version : '>=2.38'), dependency('gobject-2.0'), dependency('gtk+-3.0'), ] res = files('my-resources.xml') gres = gnome.compile_resources( 'my', res, source_dir : '.', ) executable( 'demo', sources : [ 'mywidget.vala', gres, ], dependencies : deps, vala_args : ['--gresources', res], ) meson-0.53.2/manual tests/7 vala composite widgets/my-resources.xml0000644000175000017500000000030012650745767026573 0ustar jpakkanejpakkane00000000000000 mywidget.ui meson-0.53.2/manual tests/7 vala composite widgets/mywidget.ui0000644000175000017500000000535412650745767025622 0ustar jpakkanejpakkane00000000000000 meson-0.53.2/manual tests/7 vala composite widgets/mywidget.vala0000644000175000017500000000154713366273150026113 0ustar jpakkanejpakkane00000000000000using Gtk; [GtkTemplate (ui = "/org/foo/my/mywidget.ui")] public class MyWidget : Box { public string text { get { return entry.text; } set { entry.text = value; } } [GtkChild] private Entry entry; public MyWidget (string text) { this.text = text; } [GtkCallback] private void on_button_clicked (Button button) { print ("The button was clicked with entry text: %s\n", entry.text); } [GtkCallback] private void on_entry_changed (Editable editable) { print ("The entry text changed: %s\n", entry.text); notify_property ("text"); } } void main(string[] args) { Gtk.init (ref args); var win = new Window(); win.destroy.connect (Gtk.main_quit); var widget = new MyWidget ("The entry text!"); win.add (widget); win.show_all (); Gtk.main (); } meson-0.53.2/manual tests/8 timeout/0000755000175000017500000000000013625242353020537 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/8 timeout/meson.build0000644000175000017500000000041312650745767022715 0ustar jpakkanejpakkane00000000000000project('timeout', 'c') # This creates a test that times out. It is a manual test # because currently there is no test suite for test that are expected # to fail during unit test phase. exe = executable('sleepprog', 'sleepprog.c') test('timeout', exe, timeout : 1) meson-0.53.2/manual tests/8 timeout/sleepprog.c0000644000175000017500000000010613602226377022703 0ustar jpakkanejpakkane00000000000000#include int main(void) { sleep(1000); return 0; } meson-0.53.2/manual tests/9 nostdlib/0000755000175000017500000000000013625242353020670 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/9 nostdlib/meson.build0000644000175000017500000000066712740763357023054 0ustar jpakkanejpakkane00000000000000project('own libc', 'c') # Not related to this test, but could not find a better place for this test. assert(meson.get_cross_property('nonexisting', 'defaultvalue') == 'defaultvalue', 'Cross prop getting is broken.') # A simple project that uses its own libc. # Note that we don't need to specify anything, the flags to use # stdlib come from the cross file. exe = executable('selfcontained', 'prog.c') test('standalone test', exe) meson-0.53.2/manual tests/9 nostdlib/prog.c0000644000175000017500000000022213571777336022015 0ustar jpakkanejpakkane00000000000000 #include int main(void) { const char *message = "Hello without stdlib.\n"; return simple_print(message, simple_strlen(message)); } meson-0.53.2/manual tests/9 nostdlib/subprojects/0000755000175000017500000000000013625242350023230 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/9 nostdlib/subprojects/mylibc/0000755000175000017500000000000013625242353024512 5ustar jpakkanejpakkane00000000000000meson-0.53.2/manual tests/9 nostdlib/subprojects/mylibc/libc.c0000644000175000017500000000135212722326652025572 0ustar jpakkanejpakkane00000000000000/* Do not use this as the basis of your own libc. * The code is probably unoptimal or wonky, as I * had no prior experience with this, but instead * just fiddled with the code until it worked. */ #include #define STDOUT 1 #define SYS_WRITE 4 int simple_print(const char *msg, const long bufsize) { int count; long total_written = 0; while(total_written < bufsize) { asm( "int $0x80\n\t" : "=a"(count) : "0"(SYS_WRITE), "b"(STDOUT), "c"(msg+total_written), "d"(bufsize-total_written) :); if(count == 0) { return 1; } total_written += count; } return 0; } int simple_strlen(const char *str) { int len = 0; while(str[len] != '\0') { len++; } return len; } meson-0.53.2/manual tests/9 nostdlib/subprojects/mylibc/meson.build0000644000175000017500000000044012722326652026654 0ustar jpakkanejpakkane00000000000000project('own libc', 'c') # A very simple libc implementation # Do not specify -nostdlib & co. They come from cross specifications. libc = static_library('c', 'libc.c', 'stubstart.s') mylibc_dep = declare_dependency(link_with : libc, include_directories : include_directories('.') ) meson-0.53.2/manual tests/9 nostdlib/subprojects/mylibc/stdio.h0000644000175000017500000000015212722326652026005 0ustar jpakkanejpakkane00000000000000#pragma once int simple_print(const char *msg, const long bufsize); int simple_strlen(const char *str); meson-0.53.2/manual tests/9 nostdlib/subprojects/mylibc/stubstart.s0000644000175000017500000000013212722326652026727 0ustar jpakkanejpakkane00000000000000.globl _start _start: call main movl %eax, %ebx movl $1, %eax int $0x80 meson-0.53.2/meson.egg-info/0000755000175000017500000000000013625242353017134 5ustar jpakkanejpakkane00000000000000meson-0.53.2/meson.egg-info/PKG-INFO0000644000175000017500000000251513625242347020237 0ustar jpakkanejpakkane00000000000000Metadata-Version: 2.1 Name: meson Version: 0.53.2 Summary: A high performance build system Home-page: https://mesonbuild.com Author: Jussi Pakkanen Author-email: jpakkane@gmail.com License: Apache License, Version 2.0 Description: Meson is a cross-platform build system designed to be both as fast and as user friendly as possible. It supports many languages and compilers, including GCC, Clang, PGI, Intel, and Visual Studio. Its build definitions are written in a simple non-Turing complete DSL. Keywords: meson,mesonbuild,build system,cmake Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: Natural Language :: English Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX :: BSD Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Topic :: Software Development :: Build Tools Requires-Python: >=3.5.2 Provides-Extra: progress meson-0.53.2/meson.egg-info/SOURCES.txt0000644000175000017500000044064113625242347021034 0ustar jpakkanejpakkane00000000000000COPYING MANIFEST.in README.md __main__.py ghwt.py meson.py pyproject.toml run_cross_test.py run_meson_command_tests.py run_project_tests.py run_tests.py run_unittests.py setup.cfg setup.py cross/armcc.txt cross/armclang-linux.txt cross/armclang.txt cross/ccrx.txt cross/iphone.txt cross/linux-mingw-w64-32bit.txt cross/linux-mingw-w64-64bit.txt cross/ownstdlib.txt cross/tvos.txt cross/ubuntu-armhf.txt cross/ubuntu-faketarget.txt cross/wasm.txt data/com.mesonbuild.install.policy data/macros.meson data/shell-completions/bash/meson data/shell-completions/zsh/_meson data/syntax-highlighting/emacs/meson.el data/syntax-highlighting/vim/README data/syntax-highlighting/vim/ftdetect/meson.vim data/syntax-highlighting/vim/ftplugin/meson.vim data/syntax-highlighting/vim/indent/meson.vim data/syntax-highlighting/vim/syntax/meson.vim graphics/meson_logo.svg graphics/meson_logo_big.png graphics/wrap_logo.svg man/meson.1 manual tests/1 wrap/main.c manual tests/1 wrap/meson.build manual tests/1 wrap/subprojects/sqlite.wrap manual tests/10 svn wrap/meson.build manual tests/10 svn wrap/prog.c manual tests/10 svn wrap/subprojects/samplesubproject.wrap manual tests/11 wrap imposter/meson.build manual tests/11 wrap imposter/subprojects/zlib.wrap manual tests/12 wrap mirror/meson.build manual tests/12 wrap mirror/subprojects/zlib.wrap manual tests/2 multiwrap/meson.build manual tests/2 multiwrap/prog.c manual tests/2 multiwrap/subprojects/libpng.wrap manual tests/2 multiwrap/subprojects/lua.wrap manual tests/2 multiwrap/subprojects/zlib.wrap manual tests/3 git wrap/meson.build manual tests/3 git wrap/prog.c manual tests/3 git wrap/subprojects/samplesubproject.wrap manual tests/4 standalone binaries/Info.plist manual tests/4 standalone binaries/build_linux_package.sh manual tests/4 standalone binaries/build_osx_package.sh manual tests/4 standalone binaries/build_windows_package.py manual tests/4 standalone binaries/linux_bundler.sh manual tests/4 standalone binaries/meson.build manual tests/4 standalone binaries/myapp.cpp manual tests/4 standalone binaries/myapp.icns manual tests/4 standalone binaries/myapp.iss manual tests/4 standalone binaries/myapp.sh manual tests/4 standalone binaries/osx_bundler.sh manual tests/4 standalone binaries/readme.txt manual tests/4 standalone binaries/template.dmg.gz manual tests/5 rpm/lib.c manual tests/5 rpm/lib.h manual tests/5 rpm/main.c manual tests/5 rpm/meson.build manual tests/6 hg wrap/meson.build manual tests/6 hg wrap/prog.c manual tests/6 hg wrap/subprojects/samplesubproject.wrap manual tests/7 vala composite widgets/meson.build manual tests/7 vala composite widgets/my-resources.xml manual tests/7 vala composite widgets/mywidget.ui manual tests/7 vala composite widgets/mywidget.vala manual tests/8 timeout/meson.build manual tests/8 timeout/sleepprog.c manual tests/9 nostdlib/meson.build manual tests/9 nostdlib/prog.c manual tests/9 nostdlib/subprojects/mylibc/libc.c manual tests/9 nostdlib/subprojects/mylibc/meson.build manual tests/9 nostdlib/subprojects/mylibc/stdio.h manual tests/9 nostdlib/subprojects/mylibc/stubstart.s meson.egg-info/PKG-INFO meson.egg-info/SOURCES.txt meson.egg-info/dependency_links.txt meson.egg-info/entry_points.txt meson.egg-info/requires.txt meson.egg-info/top_level.txt mesonbuild/__init__.py mesonbuild/build.py mesonbuild/coredata.py mesonbuild/depfile.py mesonbuild/envconfig.py mesonbuild/environment.py mesonbuild/interpreter.py mesonbuild/interpreterbase.py mesonbuild/linkers.py mesonbuild/mconf.py mesonbuild/mdist.py mesonbuild/mesonlib.py mesonbuild/mesonmain.py mesonbuild/minit.py mesonbuild/minstall.py mesonbuild/mintro.py mesonbuild/mlog.py mesonbuild/mparser.py mesonbuild/msetup.py mesonbuild/msubprojects.py mesonbuild/mtest.py mesonbuild/munstable_coredata.py mesonbuild/optinterpreter.py mesonbuild/rewriter.py mesonbuild/ast/__init__.py mesonbuild/ast/interpreter.py mesonbuild/ast/introspection.py mesonbuild/ast/postprocess.py mesonbuild/ast/printer.py mesonbuild/ast/visitor.py mesonbuild/backend/__init__.py mesonbuild/backend/backends.py mesonbuild/backend/ninjabackend.py mesonbuild/backend/vs2010backend.py mesonbuild/backend/vs2015backend.py mesonbuild/backend/vs2017backend.py mesonbuild/backend/vs2019backend.py mesonbuild/backend/xcodebackend.py mesonbuild/cmake/__init__.py mesonbuild/cmake/client.py mesonbuild/cmake/common.py mesonbuild/cmake/executor.py mesonbuild/cmake/fileapi.py mesonbuild/cmake/generator.py mesonbuild/cmake/interpreter.py mesonbuild/cmake/traceparser.py mesonbuild/cmake/data/preload.cmake mesonbuild/cmake/data/run_ctgt.py mesonbuild/compilers/__init__.py mesonbuild/compilers/c.py mesonbuild/compilers/c_function_attributes.py mesonbuild/compilers/compilers.py mesonbuild/compilers/cpp.py mesonbuild/compilers/cs.py mesonbuild/compilers/cuda.py mesonbuild/compilers/d.py mesonbuild/compilers/fortran.py mesonbuild/compilers/java.py mesonbuild/compilers/objc.py mesonbuild/compilers/objcpp.py mesonbuild/compilers/rust.py mesonbuild/compilers/swift.py mesonbuild/compilers/vala.py mesonbuild/compilers/mixins/__init__.py mesonbuild/compilers/mixins/arm.py mesonbuild/compilers/mixins/ccrx.py mesonbuild/compilers/mixins/clang.py mesonbuild/compilers/mixins/clike.py mesonbuild/compilers/mixins/elbrus.py mesonbuild/compilers/mixins/emscripten.py mesonbuild/compilers/mixins/gnu.py mesonbuild/compilers/mixins/intel.py mesonbuild/compilers/mixins/islinker.py mesonbuild/compilers/mixins/pgi.py mesonbuild/compilers/mixins/visualstudio.py mesonbuild/dependencies/__init__.py mesonbuild/dependencies/base.py mesonbuild/dependencies/boost.py mesonbuild/dependencies/coarrays.py mesonbuild/dependencies/cuda.py mesonbuild/dependencies/dev.py mesonbuild/dependencies/hdf5.py mesonbuild/dependencies/misc.py mesonbuild/dependencies/mpi.py mesonbuild/dependencies/platform.py mesonbuild/dependencies/scalapack.py mesonbuild/dependencies/ui.py mesonbuild/dependencies/data/CMakeLists.txt mesonbuild/dependencies/data/CMakeListsLLVM.txt mesonbuild/dependencies/data/CMakePathInfo.txt mesonbuild/modules/__init__.py mesonbuild/modules/cmake.py mesonbuild/modules/dlang.py mesonbuild/modules/fs.py mesonbuild/modules/gnome.py mesonbuild/modules/hotdoc.py mesonbuild/modules/i18n.py mesonbuild/modules/modtest.py mesonbuild/modules/pkgconfig.py mesonbuild/modules/python.py mesonbuild/modules/python3.py mesonbuild/modules/qt.py mesonbuild/modules/qt4.py mesonbuild/modules/qt5.py mesonbuild/modules/rpm.py mesonbuild/modules/sourceset.py mesonbuild/modules/unstable_cuda.py mesonbuild/modules/unstable_icestorm.py mesonbuild/modules/unstable_kconfig.py mesonbuild/modules/unstable_simd.py mesonbuild/modules/windows.py mesonbuild/scripts/__init__.py mesonbuild/scripts/clangformat.py mesonbuild/scripts/clangtidy.py mesonbuild/scripts/cleantrees.py mesonbuild/scripts/commandrunner.py mesonbuild/scripts/coverage.py mesonbuild/scripts/delwithsuffix.py mesonbuild/scripts/depfixer.py mesonbuild/scripts/dirchanger.py mesonbuild/scripts/gettext.py mesonbuild/scripts/gtkdochelper.py mesonbuild/scripts/hotdochelper.py mesonbuild/scripts/meson_exe.py mesonbuild/scripts/msgfmthelper.py mesonbuild/scripts/regen_checker.py mesonbuild/scripts/scanbuild.py mesonbuild/scripts/symbolextractor.py mesonbuild/scripts/tags.py mesonbuild/scripts/uninstall.py mesonbuild/scripts/vcstagger.py mesonbuild/scripts/yelphelper.py mesonbuild/templates/__init__.py mesonbuild/templates/cpptemplates.py mesonbuild/templates/ctemplates.py mesonbuild/templates/dlangtemplates.py mesonbuild/templates/fortrantemplates.py mesonbuild/templates/objctemplates.py mesonbuild/templates/rusttemplates.py mesonbuild/wrap/__init__.py mesonbuild/wrap/wrap.py mesonbuild/wrap/wraptool.py test cases/cmake/1 basic/main.cpp test cases/cmake/1 basic/meson.build test cases/cmake/1 basic/subprojects/cmMod/CMakeLists.txt test cases/cmake/1 basic/subprojects/cmMod/cmMod.cpp test cases/cmake/1 basic/subprojects/cmMod/cmMod.hpp test cases/cmake/10 header only/main.cpp test cases/cmake/10 header only/meson.build test cases/cmake/10 header only/subprojects/cmMod/CMakeLists.txt test cases/cmake/10 header only/subprojects/cmMod/include/cmMod.hpp test cases/cmake/11 cmake_module_path/meson.build test cases/cmake/11 cmake_module_path/cmake/FindSomethingLikePython.cmake test cases/cmake/12 generator expressions/main.cpp test cases/cmake/12 generator expressions/meson.build test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt test cases/cmake/12 generator expressions/subprojects/cmMod/include/cmMod.hpp test cases/cmake/13 system includes/main.cpp test cases/cmake/13 system includes/meson.build test cases/cmake/13 system includes/subprojects/cmMod/CMakeLists.txt test cases/cmake/13 system includes/subprojects/cmMod/cmMod.cpp test cases/cmake/13 system includes/subprojects/cmMod/cmMod.hpp test cases/cmake/13 system includes/subprojects/cmMod/sysInc/triggerWarn.hpp test cases/cmake/14 fortran threads/meson.build test cases/cmake/15 object library advanced/main.cpp test cases/cmake/15 object library advanced/meson.build test cases/cmake/15 object library advanced/subprojects/cmObjLib/CMakeLists.txt test cases/cmake/15 object library advanced/subprojects/cmObjLib/genC.cpp test cases/cmake/15 object library advanced/subprojects/cmObjLib/libA.cpp test cases/cmake/15 object library advanced/subprojects/cmObjLib/libA.hpp test cases/cmake/15 object library advanced/subprojects/cmObjLib/libB.cpp test cases/cmake/15 object library advanced/subprojects/cmObjLib/libB.hpp test cases/cmake/16 threads/main.cpp test cases/cmake/16 threads/meson.build test cases/cmake/16 threads/meson_options.txt test cases/cmake/16 threads/test_matrix.json test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt test cases/cmake/16 threads/subprojects/cmMod/cmMod.cpp test cases/cmake/16 threads/subprojects/cmMod/cmMod.hpp test cases/cmake/16 threads/subprojects/cmMod/main.cpp test cases/cmake/2 advanced/installed_files.txt test cases/cmake/2 advanced/main.cpp test cases/cmake/2 advanced/meson.build test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt test cases/cmake/2 advanced/subprojects/cmMod/config.h.in test cases/cmake/2 advanced/subprojects/cmMod/main.cpp test cases/cmake/2 advanced/subprojects/cmMod/lib/cmMod.cpp test cases/cmake/2 advanced/subprojects/cmMod/lib/cmMod.hpp test cases/cmake/3 advanced no dep/installed_files.txt test cases/cmake/3 advanced no dep/main.cpp test cases/cmake/3 advanced no dep/meson.build test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt test cases/cmake/3 advanced no dep/subprojects/cmMod/config.h.in test cases/cmake/3 advanced no dep/subprojects/cmMod/main.cpp test cases/cmake/3 advanced no dep/subprojects/cmMod/lib/cmMod.cpp test cases/cmake/3 advanced no dep/subprojects/cmMod/lib/cmMod.hpp test cases/cmake/4 code gen/main.cpp test cases/cmake/4 code gen/meson.build test cases/cmake/4 code gen/test.hpp test cases/cmake/4 code gen/subprojects/cmCodeGen/CMakeLists.txt test cases/cmake/4 code gen/subprojects/cmCodeGen/main.cpp test cases/cmake/5 object library/main.cpp test cases/cmake/5 object library/meson.build test cases/cmake/5 object library/subprojects/cmObjLib/CMakeLists.txt test cases/cmake/5 object library/subprojects/cmObjLib/libA.cpp test cases/cmake/5 object library/subprojects/cmObjLib/libA.hpp test cases/cmake/5 object library/subprojects/cmObjLib/libB.cpp test cases/cmake/5 object library/subprojects/cmObjLib/libB.hpp test cases/cmake/6 object library no dep/main.cpp test cases/cmake/6 object library no dep/meson.build test cases/cmake/6 object library no dep/subprojects/cmObjLib/CMakeLists.txt test cases/cmake/6 object library no dep/subprojects/cmObjLib/libA.cpp test cases/cmake/6 object library no dep/subprojects/cmObjLib/libA.hpp test cases/cmake/6 object library no dep/subprojects/cmObjLib/libB.cpp test cases/cmake/6 object library no dep/subprojects/cmObjLib/libB.hpp test cases/cmake/7 cmake options/meson.build test cases/cmake/7 cmake options/subprojects/cmOpts/CMakeLists.txt test cases/cmake/8 custom command/main.cpp test cases/cmake/8 custom command/meson.build test cases/cmake/8 custom command/subprojects/cmMod/CMakeLists.txt test cases/cmake/8 custom command/subprojects/cmMod/args_test.cpp test cases/cmake/8 custom command/subprojects/cmMod/cmMod.cpp test cases/cmake/8 custom command/subprojects/cmMod/cmMod.hpp test cases/cmake/8 custom command/subprojects/cmMod/cp.cpp test cases/cmake/8 custom command/subprojects/cmMod/cpyBase.cpp.am test cases/cmake/8 custom command/subprojects/cmMod/cpyBase.hpp.am test cases/cmake/8 custom command/subprojects/cmMod/cpyNext.cpp.am test cases/cmake/8 custom command/subprojects/cmMod/cpyNext.hpp.am test cases/cmake/8 custom command/subprojects/cmMod/cpyTest.cpp test cases/cmake/8 custom command/subprojects/cmMod/macro_name.cpp test cases/cmake/8 custom command/subprojects/cmMod/main.cpp test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/CMakeLists.txt test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest.hpp test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest2.hpp test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest3.hpp test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest4.hpp test cases/cmake/9 disabled subproject/meson.build test cases/common/1 trivial/meson.build test cases/common/1 trivial/trivial.c test cases/common/10 man install/bar.2 test cases/common/10 man install/baz.1.in test cases/common/10 man install/foo.1 test cases/common/10 man install/installed_files.txt test cases/common/10 man install/meson.build test cases/common/10 man install/vanishing/meson.build test cases/common/10 man install/vanishing/vanishing.1 test cases/common/10 man install/vanishing/vanishing.2 test cases/common/100 stringdef/meson.build test cases/common/100 stringdef/stringdef.c test cases/common/101 find program path/meson.build test cases/common/101 find program path/program.py test cases/common/102 subproject subdir/meson.build test cases/common/102 subproject subdir/prog.c test cases/common/102 subproject subdir/subprojects/sub/meson.build test cases/common/102 subproject subdir/subprojects/sub/lib/meson.build test cases/common/102 subproject subdir/subprojects/sub/lib/sub.c test cases/common/102 subproject subdir/subprojects/sub/lib/sub.h test cases/common/103 postconf/meson.build test cases/common/103 postconf/postconf.py test cases/common/103 postconf/prog.c test cases/common/103 postconf/raw.dat test cases/common/104 postconf with args/meson.build test cases/common/104 postconf with args/postconf.py test cases/common/104 postconf with args/prog.c test cases/common/104 postconf with args/raw.dat test cases/common/105 testframework options/meson.build test cases/common/105 testframework options/meson_options.txt test cases/common/105 testframework options/test_args.txt test cases/common/106 extract same name/lib.c test cases/common/106 extract same name/main.c test cases/common/106 extract same name/meson.build test cases/common/106 extract same name/src/lib.c test cases/common/107 has header symbol/meson.build test cases/common/108 has arg/meson.build test cases/common/109 generatorcustom/catter.py test cases/common/109 generatorcustom/gen.py test cases/common/109 generatorcustom/main.c test cases/common/109 generatorcustom/meson.build test cases/common/109 generatorcustom/res1.txt test cases/common/109 generatorcustom/res2.txt test cases/common/11 subdir/meson.build test cases/common/11 subdir/subdir/meson.build test cases/common/11 subdir/subdir/prog.c test cases/common/110 multiple dir configure file/meson.build test cases/common/110 multiple dir configure file/subdir/foo.txt test cases/common/110 multiple dir configure file/subdir/meson.build test cases/common/110 multiple dir configure file/subdir/someinput.in test cases/common/111 spaces backslash/comparer-end-notstring.c test cases/common/111 spaces backslash/comparer-end.c test cases/common/111 spaces backslash/comparer.c test cases/common/111 spaces backslash/meson.build test cases/common/111 spaces backslash/asm output/meson.build test cases/common/111 spaces backslash/include/comparer.h test cases/common/112 ternary/meson.build test cases/common/113 custom target capture/data_source.txt test cases/common/113 custom target capture/installed_files.txt test cases/common/113 custom target capture/meson.build test cases/common/113 custom target capture/my_compiler.py test cases/common/114 allgenerate/converter.py test cases/common/114 allgenerate/foobar.cpp.in test cases/common/114 allgenerate/meson.build test cases/common/115 pathjoin/meson.build test cases/common/116 subdir subproject/meson.build test cases/common/116 subdir subproject/prog/meson.build test cases/common/116 subdir subproject/prog/prog.c test cases/common/116 subdir subproject/subprojects/sub/meson.build test cases/common/116 subdir subproject/subprojects/sub/sub.c test cases/common/116 subdir subproject/subprojects/sub/sub.h test cases/common/117 interpreter copy mutable var on assignment/meson.build test cases/common/118 skip/meson.build test cases/common/119 subproject project arguments/exe.c test cases/common/119 subproject project arguments/exe.cpp test cases/common/119 subproject project arguments/meson.build test cases/common/119 subproject project arguments/subprojects/subexe/meson.build test cases/common/119 subproject project arguments/subprojects/subexe/subexe.c test cases/common/12 data/datafile.dat test cases/common/12 data/etcfile.dat test cases/common/12 data/fileobject_datafile.dat test cases/common/12 data/installed_files.txt test cases/common/12 data/meson.build test cases/common/12 data/runscript.sh test cases/common/12 data/somefile.txt test cases/common/12 data/to_be_renamed_1.txt test cases/common/12 data/to_be_renamed_3.txt test cases/common/12 data/to_be_renamed_4.txt test cases/common/12 data/vanishing/meson.build test cases/common/12 data/vanishing/to_be_renamed_2.txt test cases/common/12 data/vanishing/vanishing.dat test cases/common/12 data/vanishing/vanishing2.dat test cases/common/120 test skip/meson.build test cases/common/120 test skip/test_skip.c test cases/common/121 shared module/installed_files.txt test cases/common/121 shared module/meson.build test cases/common/121 shared module/module.c test cases/common/121 shared module/nosyms.c test cases/common/121 shared module/prog.c test cases/common/121 shared module/runtime.c test cases/common/122 llvm ir and assembly/main.c test cases/common/122 llvm ir and assembly/main.cpp test cases/common/122 llvm ir and assembly/meson.build test cases/common/122 llvm ir and assembly/square-arm.S test cases/common/122 llvm ir and assembly/square-x86.S test cases/common/122 llvm ir and assembly/square-x86_64.S test cases/common/122 llvm ir and assembly/square.ll test cases/common/122 llvm ir and assembly/symbol-underscore.h test cases/common/123 cpp and asm/meson.build test cases/common/123 cpp and asm/retval-arm.S test cases/common/123 cpp and asm/retval-x86.S test cases/common/123 cpp and asm/retval-x86_64.S test cases/common/123 cpp and asm/symbol-underscore.h test cases/common/123 cpp and asm/trivial.cc test cases/common/124 extract all shared library/extractor.h test cases/common/124 extract all shared library/four.c test cases/common/124 extract all shared library/func1234.def test cases/common/124 extract all shared library/meson.build test cases/common/124 extract all shared library/one.c test cases/common/124 extract all shared library/prog.c test cases/common/124 extract all shared library/three.c test cases/common/124 extract all shared library/two.c test cases/common/125 object only target/installed_files.txt test cases/common/125 object only target/meson.build test cases/common/125 object only target/obj_generator.py test cases/common/125 object only target/prog.c test cases/common/125 object only target/source.c test cases/common/125 object only target/source2.c test cases/common/125 object only target/source2.def test cases/common/125 object only target/source3.c test cases/common/126 no buildincdir/meson.build test cases/common/126 no buildincdir/prog.c test cases/common/126 no buildincdir/include/header.h test cases/common/127 custom target directory install/docgen.py test cases/common/127 custom target directory install/installed_files.txt test cases/common/127 custom target directory install/meson.build test cases/common/128 dependency file generation/main .c test cases/common/128 dependency file generation/meson.build test cases/common/129 configure file in generator/meson.build test cases/common/129 configure file in generator/inc/confdata.in test cases/common/129 configure file in generator/inc/meson.build test cases/common/129 configure file in generator/src/gen.py test cases/common/129 configure file in generator/src/main.c test cases/common/129 configure file in generator/src/meson.build test cases/common/129 configure file in generator/src/source test cases/common/13 pch/meson.build test cases/common/13 pch/c/meson.build test cases/common/13 pch/c/prog.c test cases/common/13 pch/c/pch/prog.h test cases/common/13 pch/cpp/meson.build test cases/common/13 pch/cpp/prog.cc test cases/common/13 pch/cpp/pch/prog.hh test cases/common/13 pch/generated/gen_custom.py test cases/common/13 pch/generated/gen_generator.py test cases/common/13 pch/generated/generated_generator.in test cases/common/13 pch/generated/meson.build test cases/common/13 pch/generated/prog.c test cases/common/13 pch/generated/pch/prog.h test cases/common/13 pch/mixed/func.c test cases/common/13 pch/mixed/main.cc test cases/common/13 pch/mixed/meson.build test cases/common/13 pch/mixed/pch/func.h test cases/common/13 pch/mixed/pch/main.h test cases/common/13 pch/userDefined/meson.build test cases/common/13 pch/userDefined/prog.c test cases/common/13 pch/userDefined/pch/pch.c test cases/common/13 pch/userDefined/pch/pch.h test cases/common/13 pch/withIncludeDirectories/meson.build test cases/common/13 pch/withIncludeDirectories/prog.c test cases/common/13 pch/withIncludeDirectories/include/lib/lib.h test cases/common/13 pch/withIncludeDirectories/pch/prog.h test cases/common/130 generated llvm ir/copyfile.py test cases/common/130 generated llvm ir/main.c test cases/common/130 generated llvm ir/meson.build test cases/common/130 generated llvm ir/square.ll.in test cases/common/131 generated assembly/copyfile.py test cases/common/131 generated assembly/main.c test cases/common/131 generated assembly/meson.build test cases/common/131 generated assembly/square-arm.S.in test cases/common/131 generated assembly/square-x86.S.in test cases/common/131 generated assembly/square-x86_64.S.in test cases/common/131 generated assembly/symbol-underscore.h test cases/common/132 build by default targets in tests/main.c test cases/common/132 build by default targets in tests/meson.build test cases/common/132 build by default targets in tests/write_file.py test cases/common/133 build by default/checkexists.py test cases/common/133 build by default/foo.c test cases/common/133 build by default/meson.build test cases/common/133 build by default/mygen.py test cases/common/133 build by default/source.txt test cases/common/134 include order/meson.build test cases/common/134 include order/ordertest.c test cases/common/134 include order/ctsub/copyfile.py test cases/common/134 include order/ctsub/emptyfile.c test cases/common/134 include order/ctsub/main.h test cases/common/134 include order/ctsub/meson.build test cases/common/134 include order/inc1/hdr.h test cases/common/134 include order/inc2/hdr.h test cases/common/134 include order/sub1/main.h test cases/common/134 include order/sub1/meson.build test cases/common/134 include order/sub1/some.c test cases/common/134 include order/sub1/some.h test cases/common/134 include order/sub2/main.h test cases/common/134 include order/sub2/meson.build test cases/common/134 include order/sub3/main.h test cases/common/134 include order/sub3/meson.build test cases/common/134 include order/sub4/main.c test cases/common/134 include order/sub4/main.h test cases/common/134 include order/sub4/meson.build test cases/common/135 override options/four.c test cases/common/135 override options/meson.build test cases/common/135 override options/one.c test cases/common/135 override options/three.c test cases/common/135 override options/two.c test cases/common/136 get define/concat.h test cases/common/136 get define/meson.build test cases/common/136 get define/meson_options.txt test cases/common/137 c cpp and asm/main.c test cases/common/137 c cpp and asm/main.cpp test cases/common/137 c cpp and asm/meson.build test cases/common/137 c cpp and asm/retval-arm.S test cases/common/137 c cpp and asm/retval-x86.S test cases/common/137 c cpp and asm/retval-x86_64.S test cases/common/137 c cpp and asm/somelib.c test cases/common/137 c cpp and asm/symbol-underscore.h test cases/common/138 compute int/config.h.in test cases/common/138 compute int/foobar.h test cases/common/138 compute int/meson.build test cases/common/138 compute int/prog.c.in test cases/common/139 custom target object output/meson.build test cases/common/139 custom target object output/obj_generator.py test cases/common/139 custom target object output/objdir/meson.build test cases/common/139 custom target object output/objdir/source.c test cases/common/139 custom target object output/progdir/meson.build test cases/common/139 custom target object output/progdir/prog.c test cases/common/14 configure file/basename.py test cases/common/14 configure file/check_file.py test cases/common/14 configure file/check_inputs.py test cases/common/14 configure file/config.h test cases/common/14 configure file/config.h.in test cases/common/14 configure file/config4a.h.in test cases/common/14 configure file/config4b.h.in test cases/common/14 configure file/config5.h.in test cases/common/14 configure file/config6.h.in test cases/common/14 configure file/config7.h.in test cases/common/14 configure file/config8.h.in test cases/common/14 configure file/depfile test cases/common/14 configure file/differentafterbasename1.in test cases/common/14 configure file/differentafterbasename2.in test cases/common/14 configure file/dummy.dat test cases/common/14 configure file/dumpprog.c test cases/common/14 configure file/file_contains.py test cases/common/14 configure file/generator-deps.py test cases/common/14 configure file/generator-without-input-file.py test cases/common/14 configure file/generator.py test cases/common/14 configure file/installed_files.txt test cases/common/14 configure file/invalid-utf8.bin.in test cases/common/14 configure file/meson.build test cases/common/14 configure file/nosubst-nocopy1.txt.in test cases/common/14 configure file/nosubst-nocopy2.txt.in test cases/common/14 configure file/prog.c test cases/common/14 configure file/prog2.c test cases/common/14 configure file/prog4.c test cases/common/14 configure file/prog5.c test cases/common/14 configure file/prog6.c test cases/common/14 configure file/prog7.c test cases/common/14 configure file/prog9.c test cases/common/14 configure file/sameafterbasename.in test cases/common/14 configure file/sameafterbasename.in2 test cases/common/14 configure file/test.py.in test cases/common/14 configure file/touch.py test cases/common/14 configure file/subdir/meson.build test cases/common/140 empty build file/meson.build test cases/common/140 empty build file/subdir/meson.build test cases/common/141 whole archive/func1.c test cases/common/141 whole archive/func2.c test cases/common/141 whole archive/meson.build test cases/common/141 whole archive/mylib.h test cases/common/141 whole archive/prog.c test cases/common/141 whole archive/exe/meson.build test cases/common/141 whole archive/exe2/meson.build test cases/common/141 whole archive/exe3/meson.build test cases/common/141 whole archive/exe4/meson.build test cases/common/141 whole archive/sh_func2_dep_func1/meson.build test cases/common/141 whole archive/sh_func2_linked_func1/meson.build test cases/common/141 whole archive/sh_func2_transdep_func1/meson.build test cases/common/141 whole archive/sh_only_link_whole/meson.build test cases/common/141 whole archive/st_func1/meson.build test cases/common/141 whole archive/st_func2/meson.build test cases/common/142 C and CPP link/dummy.c test cases/common/142 C and CPP link/foo.c test cases/common/142 C and CPP link/foo.cpp test cases/common/142 C and CPP link/foo.h test cases/common/142 C and CPP link/foo.hpp test cases/common/142 C and CPP link/foobar.c test cases/common/142 C and CPP link/foobar.h test cases/common/142 C and CPP link/meson.build test cases/common/142 C and CPP link/sub.c test cases/common/142 C and CPP link/sub.h test cases/common/143 mesonintrospect from scripts/check_env.py test cases/common/143 mesonintrospect from scripts/check_introspection.py test cases/common/143 mesonintrospect from scripts/meson.build test cases/common/144 custom target multiple outputs/generator.py test cases/common/144 custom target multiple outputs/installed_files.txt test cases/common/144 custom target multiple outputs/meson.build test cases/common/145 special characters/check_quoting.py test cases/common/145 special characters/installed_files.txt test cases/common/145 special characters/meson.build test cases/common/146 nested links/meson.build test cases/common/146 nested links/xephyr.c test cases/common/147 list of file sources/foo test cases/common/147 list of file sources/gen.py test cases/common/147 list of file sources/meson.build test cases/common/148 link depends custom target/foo.c test cases/common/148 link depends custom target/make_file.py test cases/common/148 link depends custom target/meson.build test cases/common/149 recursive linking/lib.h test cases/common/149 recursive linking/main.c test cases/common/149 recursive linking/meson.build test cases/common/149 recursive linking/3rdorderdeps/lib.c.in test cases/common/149 recursive linking/3rdorderdeps/main.c.in test cases/common/149 recursive linking/3rdorderdeps/meson.build test cases/common/149 recursive linking/circular/lib1.c test cases/common/149 recursive linking/circular/lib2.c test cases/common/149 recursive linking/circular/lib3.c test cases/common/149 recursive linking/circular/main.c test cases/common/149 recursive linking/circular/meson.build test cases/common/149 recursive linking/circular/prop1.c test cases/common/149 recursive linking/circular/prop2.c test cases/common/149 recursive linking/circular/prop3.c test cases/common/149 recursive linking/edge-cases/libsto.c test cases/common/149 recursive linking/edge-cases/meson.build test cases/common/149 recursive linking/edge-cases/shstmain.c test cases/common/149 recursive linking/edge-cases/stobuilt.c test cases/common/149 recursive linking/edge-cases/stomain.c test cases/common/149 recursive linking/shnodep/lib.c test cases/common/149 recursive linking/shnodep/meson.build test cases/common/149 recursive linking/shshdep/lib.c test cases/common/149 recursive linking/shshdep/meson.build test cases/common/149 recursive linking/shstdep/lib.c test cases/common/149 recursive linking/shstdep/meson.build test cases/common/149 recursive linking/stnodep/lib.c test cases/common/149 recursive linking/stnodep/meson.build test cases/common/149 recursive linking/stshdep/lib.c test cases/common/149 recursive linking/stshdep/meson.build test cases/common/149 recursive linking/ststdep/lib.c test cases/common/149 recursive linking/ststdep/meson.build test cases/common/15 if/meson.build test cases/common/15 if/prog.c test cases/common/150 library at root/lib.c test cases/common/150 library at root/meson.build test cases/common/150 library at root/main/main.c test cases/common/150 library at root/main/meson.build test cases/common/151 simd/fallback.c test cases/common/151 simd/meson.build test cases/common/151 simd/simd_avx.c test cases/common/151 simd/simd_avx2.c test cases/common/151 simd/simd_mmx.c test cases/common/151 simd/simd_neon.c test cases/common/151 simd/simd_sse.c test cases/common/151 simd/simd_sse2.c test cases/common/151 simd/simd_sse3.c test cases/common/151 simd/simd_sse41.c test cases/common/151 simd/simd_sse42.c test cases/common/151 simd/simd_ssse3.c test cases/common/151 simd/simdchecker.c test cases/common/151 simd/simdfuncs.h test cases/common/151 simd/include/simdheader.h test cases/common/152 shared module resolving symbol in executable/meson.build test cases/common/152 shared module resolving symbol in executable/module.c test cases/common/152 shared module resolving symbol in executable/prog.c test cases/common/153 dotinclude/dotproc.c test cases/common/153 dotinclude/meson.build test cases/common/153 dotinclude/stdio.h test cases/common/154 reserved targets/meson.build test cases/common/154 reserved targets/test.c test cases/common/154 reserved targets/all/meson.build test cases/common/154 reserved targets/benchmark/meson.build test cases/common/154 reserved targets/clean/meson.build test cases/common/154 reserved targets/clean-ctlist/meson.build test cases/common/154 reserved targets/clean-gcda/meson.build test cases/common/154 reserved targets/clean-gcno/meson.build test cases/common/154 reserved targets/coverage/meson.build test cases/common/154 reserved targets/coverage-html/meson.build test cases/common/154 reserved targets/coverage-text/meson.build test cases/common/154 reserved targets/coverage-xml/meson.build test cases/common/154 reserved targets/dist/meson.build test cases/common/154 reserved targets/distcheck/meson.build test cases/common/154 reserved targets/install/meson.build test cases/common/154 reserved targets/phony/meson.build test cases/common/154 reserved targets/reconfigure/meson.build test cases/common/154 reserved targets/runtarget/meson.build test cases/common/154 reserved targets/scan-build/meson.build test cases/common/154 reserved targets/test/meson.build test cases/common/154 reserved targets/uninstall/meson.build test cases/common/155 duplicate source names/meson.build test cases/common/155 duplicate source names/dir1/file.c test cases/common/155 duplicate source names/dir1/meson.build test cases/common/155 duplicate source names/dir2/file.c test cases/common/155 duplicate source names/dir2/meson.build test cases/common/155 duplicate source names/dir2/dir1/file.c test cases/common/155 duplicate source names/dir3/file.c test cases/common/155 duplicate source names/dir3/meson.build test cases/common/155 duplicate source names/dir3/dir1/file.c test cases/common/156 index customtarget/check_args.py test cases/common/156 index customtarget/gen_sources.py test cases/common/156 index customtarget/lib.c test cases/common/156 index customtarget/meson.build test cases/common/156 index customtarget/subdir/foo.c test cases/common/156 index customtarget/subdir/meson.build test cases/common/157 wrap file should not failed/meson.build test cases/common/157 wrap file should not failed/src/meson.build test cases/common/157 wrap file should not failed/src/subprojects/prog.c test cases/common/157 wrap file should not failed/src/subprojects/foo/prog2.c test cases/common/157 wrap file should not failed/subprojects/foo.wrap test cases/common/157 wrap file should not failed/subprojects/zlib.wrap test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build test cases/common/157 wrap file should not failed/subprojects/packagecache/foo-1.0-patch.tar.xz test cases/common/157 wrap file should not failed/subprojects/packagecache/foo-1.0.tar.xz test cases/common/157 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-wrap.zip test cases/common/157 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.tar.gz test cases/common/157 wrap file should not failed/subprojects/zlib-1.2.8/foo.c test cases/common/157 wrap file should not failed/subprojects/zlib-1.2.8/meson.build test cases/common/158 includedir subproj/meson.build test cases/common/158 includedir subproj/prog.c test cases/common/158 includedir subproj/subprojects/inctest/meson.build test cases/common/158 includedir subproj/subprojects/inctest/include/incfile.h test cases/common/159 subproject dir name collision/a.c test cases/common/159 subproject dir name collision/meson.build test cases/common/159 subproject dir name collision/custom_subproject_dir/B/b.c test cases/common/159 subproject dir name collision/custom_subproject_dir/B/meson.build test cases/common/159 subproject dir name collision/custom_subproject_dir/C/c.c test cases/common/159 subproject dir name collision/custom_subproject_dir/C/meson.build test cases/common/159 subproject dir name collision/other_subdir/meson.build test cases/common/159 subproject dir name collision/other_subdir/custom_subproject_dir/other.c test cases/common/16 else/meson.build test cases/common/16 else/prog.c test cases/common/160 config tool variable/meson.build test cases/common/161 custom target subdir depend files/copyfile.py test cases/common/161 custom target subdir depend files/meson.build test cases/common/161 custom target subdir depend files/subdir/dep.dat test cases/common/161 custom target subdir depend files/subdir/foo.c.in test cases/common/161 custom target subdir depend files/subdir/meson.build test cases/common/162 external program shebang parsing/input.txt test cases/common/162 external program shebang parsing/main.c test cases/common/162 external program shebang parsing/meson.build test cases/common/162 external program shebang parsing/script.int.in test cases/common/163 disabler/meson.build test cases/common/164 array option/meson.build test cases/common/164 array option/meson_options.txt test cases/common/165 custom target template substitution/checkcopy.py test cases/common/165 custom target template substitution/foo.c.in test cases/common/165 custom target template substitution/meson.build test cases/common/166 not-found dependency/meson.build test cases/common/166 not-found dependency/testlib.c test cases/common/166 not-found dependency/sub/meson.build test cases/common/166 not-found dependency/subprojects/trivial/meson.build test cases/common/166 not-found dependency/subprojects/trivial/trivial.c test cases/common/167 subdir if_found/meson.build test cases/common/167 subdir if_found/subdir/meson.build test cases/common/168 default options prefix dependent defaults/meson.build test cases/common/169 dependency factory/meson.build test cases/common/17 comparison/meson.build test cases/common/17 comparison/prog.c test cases/common/170 get project license/bar.c test cases/common/170 get project license/meson.build test cases/common/171 yield/meson.build test cases/common/171 yield/meson_options.txt test cases/common/171 yield/subprojects/sub/meson.build test cases/common/171 yield/subprojects/sub/meson_options.txt test cases/common/172 subproject nested subproject dirs/meson.build test cases/common/172 subproject nested subproject dirs/prog.c test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/a.c test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/meson.build test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/var/subprojects/wrap_files_might_be_here test cases/common/172 subproject nested subproject dirs/contrib/subprojects/beta/b.c test cases/common/172 subproject nested subproject dirs/contrib/subprojects/beta/meson.build test cases/common/173 preserve gendir/base.inp test cases/common/173 preserve gendir/genprog.py test cases/common/173 preserve gendir/meson.build test cases/common/173 preserve gendir/testprog.c test cases/common/173 preserve gendir/com/mesonbuild/subbie.inp test cases/common/174 source in dep/bar.cpp test cases/common/174 source in dep/foo.c test cases/common/174 source in dep/meson.build test cases/common/174 source in dep/generated/funname test cases/common/174 source in dep/generated/genheader.py test cases/common/174 source in dep/generated/main.c test cases/common/174 source in dep/generated/meson.build test cases/common/175 generator link whole/export.h test cases/common/175 generator link whole/generator.py test cases/common/175 generator link whole/main.c test cases/common/175 generator link whole/meson.build test cases/common/175 generator link whole/meson_test_function.tmpl test cases/common/175 generator link whole/pull_meson_test_function.c test cases/common/176 initial c_args/meson.build test cases/common/176 initial c_args/test_args.txt test cases/common/177 identical target name in subproject flat layout/foo.c test cases/common/177 identical target name in subproject flat layout/main.c test cases/common/177 identical target name in subproject flat layout/meson.build test cases/common/177 identical target name in subproject flat layout/subprojects/subproj/foo.c test cases/common/177 identical target name in subproject flat layout/subprojects/subproj/meson.build test cases/common/178 as-needed/config.h test cases/common/178 as-needed/libA.cpp test cases/common/178 as-needed/libA.h test cases/common/178 as-needed/libB.cpp test cases/common/178 as-needed/main.cpp test cases/common/178 as-needed/meson.build test cases/common/179 ndebug if-release enabled/main.c test cases/common/179 ndebug if-release enabled/meson.build test cases/common/18 array/func.c test cases/common/18 array/meson.build test cases/common/18 array/prog.c test cases/common/180 ndebug if-release disabled/main.c test cases/common/180 ndebug if-release disabled/meson.build test cases/common/181 subproject version/meson.build test cases/common/181 subproject version/subprojects/a/meson.build test cases/common/182 subdir_done/meson.build test cases/common/183 bothlibraries/libfile.c test cases/common/183 bothlibraries/main.c test cases/common/183 bothlibraries/meson.build test cases/common/183 bothlibraries/mylib.h test cases/common/184 escape and unicode/file.c.in test cases/common/184 escape and unicode/file.py test cases/common/184 escape and unicode/find.py test cases/common/184 escape and unicode/fun.c test cases/common/184 escape and unicode/main.c test cases/common/184 escape and unicode/meson.build test cases/common/185 has link arg/meson.build test cases/common/186 same target name flat layout/foo.c test cases/common/186 same target name flat layout/main.c test cases/common/186 same target name flat layout/meson.build test cases/common/186 same target name flat layout/subdir/foo.c test cases/common/186 same target name flat layout/subdir/meson.build test cases/common/187 find override/meson.build test cases/common/187 find override/otherdir/main.c test cases/common/187 find override/otherdir/main2.c test cases/common/187 find override/otherdir/meson.build test cases/common/187 find override/otherdir/source.desc test cases/common/187 find override/otherdir/source2.desc test cases/common/187 find override/subdir/converter.py test cases/common/187 find override/subdir/gencodegen.py.in test cases/common/187 find override/subdir/meson.build test cases/common/188 partial dependency/meson.build test cases/common/188 partial dependency/declare_dependency/main.c test cases/common/188 partial dependency/declare_dependency/meson.build test cases/common/188 partial dependency/declare_dependency/other.c test cases/common/188 partial dependency/declare_dependency/headers/foo.c test cases/common/188 partial dependency/declare_dependency/headers/foo.h test cases/common/189 openmp/main.c test cases/common/189 openmp/main.cpp test cases/common/189 openmp/main.f90 test cases/common/189 openmp/meson.build test cases/common/19 includedir/meson.build test cases/common/19 includedir/include/func.h test cases/common/19 includedir/src/func.c test cases/common/19 includedir/src/meson.build test cases/common/19 includedir/src/prog.c test cases/common/190 same target name/file.c test cases/common/190 same target name/meson.build test cases/common/190 same target name/sub/file2.c test cases/common/190 same target name/sub/meson.build test cases/common/191 test depends/gen.py test cases/common/191 test depends/main.c test cases/common/191 test depends/meson.build test cases/common/191 test depends/test.py test cases/common/192 args flattening/meson.build test cases/common/193 dict/meson.build test cases/common/193 dict/prog.c test cases/common/194 check header/meson.build test cases/common/194 check header/ouagadougou.h test cases/common/195 install_mode/config.h.in test cases/common/195 install_mode/data_source.txt test cases/common/195 install_mode/foo.1 test cases/common/195 install_mode/installed_files.txt test cases/common/195 install_mode/meson.build test cases/common/195 install_mode/rootdir.h test cases/common/195 install_mode/runscript.sh test cases/common/195 install_mode/stat.c test cases/common/195 install_mode/trivial.c test cases/common/195 install_mode/sub1/second.dat test cases/common/195 install_mode/sub2/stub test cases/common/196 subproject array version/meson.build test cases/common/196 subproject array version/subprojects/foo/meson.build test cases/common/197 feature option/meson.build test cases/common/197 feature option/meson_options.txt test cases/common/198 feature option disabled/meson.build test cases/common/198 feature option disabled/meson_options.txt test cases/common/199 static threads/lib1.c test cases/common/199 static threads/lib2.c test cases/common/199 static threads/meson.build test cases/common/199 static threads/prog.c test cases/common/2 cpp/meson.build test cases/common/2 cpp/something.txt test cases/common/2 cpp/trivial.cc test cases/common/20 header in file list/header.h test cases/common/20 header in file list/meson.build test cases/common/20 header in file list/prog.c test cases/common/200 generator in subdir/meson.build test cases/common/200 generator in subdir/com/mesonbuild/genprog.py test cases/common/200 generator in subdir/com/mesonbuild/meson.build test cases/common/200 generator in subdir/com/mesonbuild/subbie.inp test cases/common/200 generator in subdir/com/mesonbuild/testprog.c test cases/common/201 override with exe/main2.input test cases/common/201 override with exe/meson.build test cases/common/201 override with exe/subprojects/sub/foobar.c test cases/common/201 override with exe/subprojects/sub/meson.build test cases/common/202 subproject with features/meson.build test cases/common/202 subproject with features/meson_options.txt test cases/common/202 subproject with features/nothing.c test cases/common/202 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build test cases/common/202 subproject with features/subprojects/disabled_sub/meson.build test cases/common/202 subproject with features/subprojects/disabled_sub/lib/meson.build test cases/common/202 subproject with features/subprojects/disabled_sub/lib/sub.c test cases/common/202 subproject with features/subprojects/disabled_sub/lib/sub.h test cases/common/202 subproject with features/subprojects/sub/meson.build test cases/common/202 subproject with features/subprojects/sub/lib/meson.build test cases/common/202 subproject with features/subprojects/sub/lib/sub.c test cases/common/202 subproject with features/subprojects/sub/lib/sub.h test cases/common/203 function attributes/meson.build test cases/common/204 broken subproject/meson.build test cases/common/204 broken subproject/subprojects/broken/broken.c test cases/common/204 broken subproject/subprojects/broken/meson.build test cases/common/205 argument syntax/meson.build test cases/common/206 install name_prefix name_suffix/installed_files.txt test cases/common/206 install name_prefix name_suffix/libfile.c test cases/common/206 install name_prefix name_suffix/meson.build test cases/common/207 kwarg entry/installed_files.txt test cases/common/207 kwarg entry/meson.build test cases/common/207 kwarg entry/prog.c test cases/common/207 kwarg entry/inc/prog.h test cases/common/208 custom target build by default/docgen.py test cases/common/208 custom target build by default/installed_files.txt test cases/common/208 custom target build by default/meson.build test cases/common/209 find_library and headers/foo.h test cases/common/209 find_library and headers/meson.build test cases/common/21 global arg/meson.build test cases/common/21 global arg/prog.c test cases/common/21 global arg/prog.cc test cases/common/210 line continuation/meson.build test cases/common/211 cmake module/installed_files.txt test cases/common/211 cmake module/meson.build test cases/common/211 cmake module/projectConfig.cmake.in test cases/common/211 cmake module/cmake_project/CMakeLists.txt test cases/common/212 native file path override/installed_files.txt test cases/common/212 native file path override/main.cpp test cases/common/212 native file path override/meson.build test cases/common/212 native file path override/nativefile.ini test cases/common/213 tap tests/meson.build test cases/common/213 tap tests/tester.c test cases/common/214 warning level 0/main.cpp test cases/common/214 warning level 0/meson.build test cases/common/215 link custom/custom_stlib.py test cases/common/215 link custom/lib.c test cases/common/215 link custom/meson.build test cases/common/215 link custom/prog.c test cases/common/216 link custom_i single from multiple/generate_conflicting_stlibs.py test cases/common/216 link custom_i single from multiple/meson.build test cases/common/216 link custom_i single from multiple/prog.c test cases/common/217 link custom_i multiple from multiple/generate_stlibs.py test cases/common/217 link custom_i multiple from multiple/meson.build test cases/common/217 link custom_i multiple from multiple/prog.c test cases/common/218 dependency get_variable method/meson.build test cases/common/219 source set configuration_data/a.c test cases/common/219 source set configuration_data/all.h test cases/common/219 source set configuration_data/f.c test cases/common/219 source set configuration_data/g.c test cases/common/219 source set configuration_data/meson.build test cases/common/219 source set configuration_data/nope.c test cases/common/219 source set configuration_data/subdir/b.c test cases/common/219 source set configuration_data/subdir/meson.build test cases/common/22 target arg/func.c test cases/common/22 target arg/func2.c test cases/common/22 target arg/meson.build test cases/common/22 target arg/prog.cc test cases/common/22 target arg/prog2.cc test cases/common/220 source set dictionary/a.c test cases/common/220 source set dictionary/all.h test cases/common/220 source set dictionary/f.c test cases/common/220 source set dictionary/g.c test cases/common/220 source set dictionary/meson.build test cases/common/220 source set dictionary/nope.c test cases/common/220 source set dictionary/subdir/b.c test cases/common/220 source set dictionary/subdir/meson.build test cases/common/221 source set custom target/a.c test cases/common/221 source set custom target/all.h test cases/common/221 source set custom target/cp.py test cases/common/221 source set custom target/f.c test cases/common/221 source set custom target/g.c test cases/common/221 source set custom target/meson.build test cases/common/222 source set realistic example/common.h test cases/common/222 source set realistic example/main.cc test cases/common/222 source set realistic example/meson.build test cases/common/222 source set realistic example/not-found.cc test cases/common/222 source set realistic example/was-found.cc test cases/common/222 source set realistic example/zlib.cc test cases/common/222 source set realistic example/boards/meson.build test cases/common/222 source set realistic example/boards/arm/aarch64.cc test cases/common/222 source set realistic example/boards/arm/arm.cc test cases/common/222 source set realistic example/boards/arm/arm.h test cases/common/222 source set realistic example/boards/arm/arm32.cc test cases/common/222 source set realistic example/boards/arm/versatilepb.cc test cases/common/222 source set realistic example/boards/arm/virt.cc test cases/common/222 source set realistic example/boards/arm/xlnx_zcu102.cc test cases/common/222 source set realistic example/boards/x86/pc.cc test cases/common/222 source set realistic example/config/aarch64 test cases/common/222 source set realistic example/config/arm test cases/common/222 source set realistic example/config/x86 test cases/common/222 source set realistic example/devices/meson.build test cases/common/222 source set realistic example/devices/virtio-mmio.cc test cases/common/222 source set realistic example/devices/virtio-pci.cc test cases/common/222 source set realistic example/devices/virtio.cc test cases/common/222 source set realistic example/devices/virtio.h test cases/common/223 custom target input extracted objects/check_object.py test cases/common/223 custom target input extracted objects/meson.build test cases/common/223 custom target input extracted objects/libdir/meson.build test cases/common/223 custom target input extracted objects/libdir/source.c test cases/common/224 test priorities/meson.build test cases/common/224 test priorities/testprog.py test cases/common/225 include_dir dot/meson.build test cases/common/225 include_dir dot/rone.h test cases/common/225 include_dir dot/src/main.c test cases/common/225 include_dir dot/src/meson.build test cases/common/225 include_dir dot/src/rone.c test cases/common/226 include_type dependency/meson.build test cases/common/226 include_type dependency/subprojects/subDep/meson.build test cases/common/227 fs module/a_symlink test cases/common/227 fs module/meson.build test cases/common/227 fs module/subdir/meson.build test cases/common/227 fs module/subdir/subdirfile.txt test cases/common/227 fs module/subprojects/subbie/meson.build test cases/common/227 fs module/subprojects/subbie/subprojectfile.txt test cases/common/227 fs module/subprojects/subbie/subsub/meson.build test cases/common/227 fs module/subprojects/subbie/subsub/subsubfile.txt test cases/common/23 object extraction/lib.c test cases/common/23 object extraction/lib2.c test cases/common/23 object extraction/main.c test cases/common/23 object extraction/meson.build test cases/common/23 object extraction/src/lib.c test cases/common/24 endian/meson.build test cases/common/24 endian/prog.c test cases/common/25 library versions/installed_files.txt test cases/common/25 library versions/lib.c test cases/common/25 library versions/meson.build test cases/common/25 library versions/subdir/meson.build test cases/common/26 config subdir/meson.build test cases/common/26 config subdir/include/config.h.in test cases/common/26 config subdir/include/meson.build test cases/common/26 config subdir/src/meson.build test cases/common/26 config subdir/src/prog.c test cases/common/27 pipeline/input_src.dat test cases/common/27 pipeline/meson.build test cases/common/27 pipeline/prog.c test cases/common/27 pipeline/srcgen.c test cases/common/27 pipeline/depends/copyrunner.py test cases/common/27 pipeline/depends/filecopier.c test cases/common/27 pipeline/depends/libsrc.c.in test cases/common/27 pipeline/depends/meson.build test cases/common/27 pipeline/depends/prog.c test cases/common/27 pipeline/src/input_src.dat test cases/common/27 pipeline/src/meson.build test cases/common/27 pipeline/src/prog.c test cases/common/27 pipeline/src/srcgen.c test cases/common/28 find program/meson.build test cases/common/28 find program/print-version-with-prefix.py test cases/common/28 find program/print-version.py test cases/common/28 find program/source.in test cases/common/28 find program/scripts/test_subdir.py test cases/common/29 multiline string/meson.build test cases/common/3 static/libfile.c test cases/common/3 static/libfile2.c test cases/common/3 static/meson.build test cases/common/3 static/meson_options.txt test cases/common/30 try compile/invalid.c test cases/common/30 try compile/meson.build test cases/common/30 try compile/valid.c test cases/common/31 compiler id/meson.build test cases/common/32 sizeof/config.h.in test cases/common/32 sizeof/meson.build test cases/common/32 sizeof/prog.c.in test cases/common/33 define10/config.h.in test cases/common/33 define10/meson.build test cases/common/33 define10/prog.c test cases/common/34 has header/meson.build test cases/common/34 has header/ouagadougou.h test cases/common/35 run program/get-version.py test cases/common/35 run program/meson.build test cases/common/35 run program/scripts/hello.bat test cases/common/35 run program/scripts/hello.sh test cases/common/36 tryrun/error.c test cases/common/36 tryrun/meson.build test cases/common/36 tryrun/no_compile.c test cases/common/36 tryrun/ok.c test cases/common/37 logic ops/meson.build test cases/common/38 string operations/meson.build test cases/common/39 has function/meson.build test cases/common/4 shared/libfile.c test cases/common/4 shared/meson.build test cases/common/40 has member/meson.build test cases/common/41 alignment/meson.build test cases/common/42 library chain/installed_files.txt test cases/common/42 library chain/main.c test cases/common/42 library chain/meson.build test cases/common/42 library chain/subdir/lib1.c test cases/common/42 library chain/subdir/meson.build test cases/common/42 library chain/subdir/subdir2/lib2.c test cases/common/42 library chain/subdir/subdir2/meson.build test cases/common/42 library chain/subdir/subdir3/lib3.c test cases/common/42 library chain/subdir/subdir3/meson.build test cases/common/43 options/meson.build test cases/common/43 options/meson_options.txt test cases/common/44 test args/cmd_args.c test cases/common/44 test args/copyfile.py test cases/common/44 test args/env2vars.c test cases/common/44 test args/envvars.c test cases/common/44 test args/meson.build test cases/common/44 test args/tester.c test cases/common/44 test args/tester.py test cases/common/44 test args/testfile.txt test cases/common/45 subproject/installed_files.txt test cases/common/45 subproject/meson.build test cases/common/45 subproject/user.c test cases/common/45 subproject/subprojects/sublib/meson.build test cases/common/45 subproject/subprojects/sublib/simpletest.c test cases/common/45 subproject/subprojects/sublib/sublib.c test cases/common/45 subproject/subprojects/sublib/include/subdefs.h test cases/common/46 subproject options/meson.build test cases/common/46 subproject options/meson_options.txt test cases/common/46 subproject options/subprojects/subproject/meson.build test cases/common/46 subproject options/subprojects/subproject/meson_options.txt test cases/common/47 pkgconfig-gen/installed_files.txt test cases/common/47 pkgconfig-gen/meson.build test cases/common/47 pkgconfig-gen/simple.c test cases/common/47 pkgconfig-gen/simple.h test cases/common/47 pkgconfig-gen/dependencies/custom.c test cases/common/47 pkgconfig-gen/dependencies/exposed.c test cases/common/47 pkgconfig-gen/dependencies/internal.c test cases/common/47 pkgconfig-gen/dependencies/meson.build test cases/common/48 custom install dirs/datafile.cat test cases/common/48 custom install dirs/installed_files.txt test cases/common/48 custom install dirs/meson.build test cases/common/48 custom install dirs/prog.1 test cases/common/48 custom install dirs/prog.c test cases/common/48 custom install dirs/sample.h test cases/common/48 custom install dirs/subdir/datafile.dog test cases/common/49 subproject subproject/meson.build test cases/common/49 subproject subproject/prog.c test cases/common/49 subproject subproject/subprojects/a/a.c test cases/common/49 subproject subproject/subprojects/a/meson.build test cases/common/49 subproject subproject/subprojects/b/b.c test cases/common/49 subproject subproject/subprojects/b/meson.build test cases/common/49 subproject subproject/subprojects/c/meson.build test cases/common/5 linkstatic/libfile.c test cases/common/5 linkstatic/libfile2.c test cases/common/5 linkstatic/libfile3.c test cases/common/5 linkstatic/libfile4.c test cases/common/5 linkstatic/main.c test cases/common/5 linkstatic/meson.build test cases/common/50 same file name/meson.build test cases/common/50 same file name/prog.c test cases/common/50 same file name/d1/file.c test cases/common/50 same file name/d2/file.c test cases/common/51 file grabber/a.c test cases/common/51 file grabber/b.c test cases/common/51 file grabber/c.c test cases/common/51 file grabber/grabber.bat test cases/common/51 file grabber/grabber.sh test cases/common/51 file grabber/grabber2.bat test cases/common/51 file grabber/meson.build test cases/common/51 file grabber/prog.c test cases/common/51 file grabber/subdir/meson.build test cases/common/51 file grabber/subdir/suba.c test cases/common/51 file grabber/subdir/subb.c test cases/common/51 file grabber/subdir/subc.c test cases/common/51 file grabber/subdir/subprog.c test cases/common/52 custom target/data_source.txt test cases/common/52 custom target/installed_files.txt test cases/common/52 custom target/meson.build test cases/common/52 custom target/my_compiler.py test cases/common/52 custom target/depfile/dep.py test cases/common/52 custom target/depfile/meson.build test cases/common/53 custom target chain/data_source.txt test cases/common/53 custom target chain/installed_files.txt test cases/common/53 custom target chain/meson.build test cases/common/53 custom target chain/my_compiler.py test cases/common/53 custom target chain/my_compiler2.py test cases/common/53 custom target chain/usetarget/meson.build test cases/common/53 custom target chain/usetarget/myexe.c test cases/common/53 custom target chain/usetarget/subcomp.py test cases/common/54 run target/check_exists.py test cases/common/54 run target/configure.in test cases/common/54 run target/converter.py test cases/common/54 run target/fakeburner.py test cases/common/54 run target/helloprinter.c test cases/common/54 run target/meson.build test cases/common/55 object generator/meson.build test cases/common/55 object generator/obj_generator.py test cases/common/55 object generator/prog.c test cases/common/55 object generator/source.c test cases/common/55 object generator/source2.c test cases/common/55 object generator/source3.c test cases/common/56 install script/installed_files.txt test cases/common/56 install script/meson.build test cases/common/56 install script/myinstall.py test cases/common/56 install script/no-installed-files test cases/common/56 install script/prog.c test cases/common/56 install script/src/meson.build test cases/common/56 install script/src/myinstall.py test cases/common/57 custom target source output/generator.py test cases/common/57 custom target source output/main.c test cases/common/57 custom target source output/meson.build test cases/common/58 exe static shared/meson.build test cases/common/58 exe static shared/prog.c test cases/common/58 exe static shared/shlib2.c test cases/common/58 exe static shared/stat.c test cases/common/58 exe static shared/stat2.c test cases/common/58 exe static shared/subdir/exports.h test cases/common/58 exe static shared/subdir/meson.build test cases/common/58 exe static shared/subdir/shlib.c test cases/common/59 array methods/meson.build test cases/common/6 linkshared/cpplib.cpp test cases/common/6 linkshared/cppmain.cpp test cases/common/6 linkshared/installed_files.txt test cases/common/6 linkshared/libfile.c test cases/common/6 linkshared/main.c test cases/common/6 linkshared/meson.build test cases/common/60 custom header generator/input.def test cases/common/60 custom header generator/makeheader.py test cases/common/60 custom header generator/meson.build test cases/common/60 custom header generator/prog.c test cases/common/60 custom header generator/somefile.txt test cases/common/61 multiple generators/data2.dat test cases/common/61 multiple generators/main.cpp test cases/common/61 multiple generators/meson.build test cases/common/61 multiple generators/mygen.py test cases/common/61 multiple generators/subdir/data.dat test cases/common/61 multiple generators/subdir/meson.build test cases/common/62 install subdir/installed_files.txt test cases/common/62 install subdir/meson.build test cases/common/62 install subdir/nested_elided/sub/eighth.dat test cases/common/62 install subdir/nested_elided/sub/dircheck/ninth.dat test cases/common/62 install subdir/sub/sub1/third.dat test cases/common/62 install subdir/sub1/second.dat test cases/common/62 install subdir/sub2/excluded-three.dat test cases/common/62 install subdir/sub2/one.dat test cases/common/62 install subdir/sub2/dircheck/excluded-three.dat test cases/common/62 install subdir/sub2/excluded/two.dat test cases/common/62 install subdir/sub_elided/fourth.dat test cases/common/62 install subdir/sub_elided/dircheck/fifth.dat test cases/common/62 install subdir/subdir/meson.build test cases/common/62 install subdir/subdir/sub1/data1.dat test cases/common/62 install subdir/subdir/sub1/sub2/data2.dat test cases/common/62 install subdir/subdir/sub_elided/sixth.dat test cases/common/62 install subdir/subdir/sub_elided/dircheck/seventh.dat test cases/common/63 foreach/installed_files.txt test cases/common/63 foreach/meson.build test cases/common/63 foreach/prog1.c test cases/common/63 foreach/prog2.c test cases/common/63 foreach/prog3.c test cases/common/64 number arithmetic/meson.build test cases/common/65 string arithmetic/meson.build test cases/common/66 array arithmetic/meson.build test cases/common/67 arithmetic bidmas/meson.build test cases/common/68 build always/main.c test cases/common/68 build always/meson.build test cases/common/68 build always/version.c.in test cases/common/68 build always/version.h test cases/common/68 build always/version_gen.py test cases/common/69 vcstag/meson.build test cases/common/69 vcstag/tagprog.c test cases/common/69 vcstag/vcstag.c.in test cases/common/7 mixed/func.c test cases/common/7 mixed/main.cc test cases/common/7 mixed/meson.build test cases/common/70 modules/meson.build test cases/common/71 should fail/failing.c test cases/common/71 should fail/meson.build test cases/common/72 configure file in custom target/meson.build test cases/common/72 configure file in custom target/inc/confdata.in test cases/common/72 configure file in custom target/inc/meson.build test cases/common/72 configure file in custom target/src/meson.build test cases/common/72 configure file in custom target/src/mycompiler.py test cases/common/73 external test program/meson.build test cases/common/73 external test program/mytest.py test cases/common/74 ctarget dependency/gen1.py test cases/common/74 ctarget dependency/gen2.py test cases/common/74 ctarget dependency/input.dat test cases/common/74 ctarget dependency/meson.build test cases/common/75 shared subproject/a.c test cases/common/75 shared subproject/meson.build test cases/common/75 shared subproject/subprojects/B/b.c test cases/common/75 shared subproject/subprojects/B/meson.build test cases/common/75 shared subproject/subprojects/C/c.c test cases/common/75 shared subproject/subprojects/C/meson.build test cases/common/76 shared subproject 2/a.c test cases/common/76 shared subproject 2/meson.build test cases/common/76 shared subproject 2/subprojects/B/b.c test cases/common/76 shared subproject 2/subprojects/B/meson.build test cases/common/76 shared subproject 2/subprojects/C/c.c test cases/common/76 shared subproject 2/subprojects/C/meson.build test cases/common/77 file object/lib.c test cases/common/77 file object/meson.build test cases/common/77 file object/prog.c test cases/common/77 file object/subdir1/lib.c test cases/common/77 file object/subdir1/meson.build test cases/common/77 file object/subdir1/prog.c test cases/common/77 file object/subdir2/lib.c test cases/common/77 file object/subdir2/meson.build test cases/common/77 file object/subdir2/prog.c test cases/common/78 custom subproject dir/a.c test cases/common/78 custom subproject dir/meson.build test cases/common/78 custom subproject dir/custom_subproject_dir/B/b.c test cases/common/78 custom subproject dir/custom_subproject_dir/B/meson.build test cases/common/78 custom subproject dir/custom_subproject_dir/C/c.c test cases/common/78 custom subproject dir/custom_subproject_dir/C/meson.build test cases/common/79 has type/meson.build test cases/common/8 install/installed_files.txt test cases/common/8 install/meson.build test cases/common/8 install/prog.c test cases/common/8 install/stat.c test cases/common/80 extract from nested subdir/meson.build test cases/common/80 extract from nested subdir/src/meson.build test cases/common/80 extract from nested subdir/src/first/lib_first.c test cases/common/80 extract from nested subdir/src/first/meson.build test cases/common/80 extract from nested subdir/tst/meson.build test cases/common/80 extract from nested subdir/tst/first/exe_first.c test cases/common/80 extract from nested subdir/tst/first/meson.build test cases/common/81 internal dependency/meson.build test cases/common/81 internal dependency/proj1/meson.build test cases/common/81 internal dependency/proj1/proj1f1.c test cases/common/81 internal dependency/proj1/proj1f2.c test cases/common/81 internal dependency/proj1/proj1f3.c test cases/common/81 internal dependency/proj1/include/proj1.h test cases/common/81 internal dependency/src/main.c test cases/common/81 internal dependency/src/meson.build test cases/common/82 same basename/exe1.c test cases/common/82 same basename/exe2.c test cases/common/82 same basename/lib.c test cases/common/82 same basename/meson.build test cases/common/82 same basename/sharedsub/meson.build test cases/common/82 same basename/staticsub/meson.build test cases/common/83 declare dep/main.c test cases/common/83 declare dep/meson.build test cases/common/83 declare dep/entity/entity.h test cases/common/83 declare dep/entity/entity1.c test cases/common/83 declare dep/entity/entity2.c test cases/common/83 declare dep/entity/meson.build test cases/common/84 extract all/extractor.h test cases/common/84 extract all/four.c test cases/common/84 extract all/meson.build test cases/common/84 extract all/one.c test cases/common/84 extract all/prog.c test cases/common/84 extract all/three.c test cases/common/84 extract all/two.c test cases/common/85 add language/meson.build test cases/common/85 add language/prog.c test cases/common/85 add language/prog.cc test cases/common/86 identical target name in subproject/bar.c test cases/common/86 identical target name in subproject/meson.build test cases/common/86 identical target name in subproject/subprojects/foo/bar.c test cases/common/86 identical target name in subproject/subprojects/foo/meson.build test cases/common/87 plusassign/meson.build test cases/common/88 skip subdir/meson.build test cases/common/88 skip subdir/subdir1/meson.build test cases/common/88 skip subdir/subdir1/subdir2/meson.build test cases/common/89 private include/meson.build test cases/common/89 private include/stlib/compiler.py test cases/common/89 private include/stlib/foo1.def test cases/common/89 private include/stlib/foo2.def test cases/common/89 private include/stlib/meson.build test cases/common/89 private include/user/libuser.c test cases/common/89 private include/user/meson.build test cases/common/9 header install/installed_files.txt test cases/common/9 header install/meson.build test cases/common/9 header install/rootdir.h test cases/common/9 header install/subdir.h test cases/common/9 header install/sub/fileheader.h test cases/common/9 header install/sub/meson.build test cases/common/9 header install/vanishing_subdir/meson.build test cases/common/9 header install/vanishing_subdir/vanished.h test cases/common/90 default options/meson.build test cases/common/91 dep fallback/gensrc.py test cases/common/91 dep fallback/meson.build test cases/common/91 dep fallback/tester.c test cases/common/91 dep fallback/subprojects/boblib/bob.c test cases/common/91 dep fallback/subprojects/boblib/bob.h test cases/common/91 dep fallback/subprojects/boblib/genbob.py test cases/common/91 dep fallback/subprojects/boblib/meson.build test cases/common/91 dep fallback/subprojects/dummylib/meson.build test cases/common/92 default library/ef.cpp test cases/common/92 default library/ef.h test cases/common/92 default library/eftest.cpp test cases/common/92 default library/meson.build test cases/common/93 selfbuilt custom/data.dat test cases/common/93 selfbuilt custom/mainprog.cpp test cases/common/93 selfbuilt custom/meson.build test cases/common/93 selfbuilt custom/tool.cpp test cases/common/94 gen extra/meson.build test cases/common/94 gen extra/name.dat test cases/common/94 gen extra/name.l test cases/common/94 gen extra/plain.c test cases/common/94 gen extra/srcgen.py test cases/common/94 gen extra/srcgen2.py test cases/common/94 gen extra/srcgen3.py test cases/common/94 gen extra/upper.c test cases/common/95 benchmark/delayer.c test cases/common/95 benchmark/meson.build test cases/common/96 test workdir/meson.build test cases/common/96 test workdir/opener.c test cases/common/96 test workdir/subdir/checker.py test cases/common/96 test workdir/subdir/meson.build test cases/common/97 suites/exe1.c test cases/common/97 suites/exe2.c test cases/common/97 suites/meson.build test cases/common/97 suites/subprojects/sub/meson.build test cases/common/97 suites/subprojects/sub/sub1.c test cases/common/97 suites/subprojects/sub/sub2.c test cases/common/98 threads/meson.build test cases/common/98 threads/threadprog.c test cases/common/98 threads/threadprog.cpp test cases/common/99 manygen/depuser.c test cases/common/99 manygen/meson.build test cases/common/99 manygen/subdir/funcinfo.def test cases/common/99 manygen/subdir/manygen.py test cases/common/99 manygen/subdir/meson.build test cases/csharp/1 basic/installed_files.txt test cases/csharp/1 basic/meson.build test cases/csharp/1 basic/prog.cs test cases/csharp/1 basic/text.cs test cases/csharp/2 library/helper.cs test cases/csharp/2 library/installed_files.txt test cases/csharp/2 library/meson.build test cases/csharp/2 library/prog.cs test cases/csharp/3 resource/TestRes.resx test cases/csharp/3 resource/meson.build test cases/csharp/3 resource/resprog.cs test cases/csharp/4 external dep/hello.txt test cases/csharp/4 external dep/installed_files.txt test cases/csharp/4 external dep/meson.build test cases/csharp/4 external dep/prog.cs test cases/cuda/1 simple/meson.build test cases/cuda/1 simple/prog.cu test cases/cuda/10 cuda dependency/meson.build test cases/cuda/10 cuda dependency/c/meson.build test cases/cuda/10 cuda dependency/c/prog.c test cases/cuda/10 cuda dependency/cpp/meson.build test cases/cuda/10 cuda dependency/cpp/prog.cc test cases/cuda/10 cuda dependency/modules/meson.build test cases/cuda/10 cuda dependency/modules/prog.cc test cases/cuda/10 cuda dependency/version_reqs/meson.build test cases/cuda/10 cuda dependency/version_reqs/prog.cc test cases/cuda/11 cuda dependency (nvcc)/meson.build test cases/cuda/11 cuda dependency (nvcc)/modules/meson.build test cases/cuda/11 cuda dependency (nvcc)/modules/prog.cu test cases/cuda/11 cuda dependency (nvcc)/version_reqs/meson.build test cases/cuda/11 cuda dependency (nvcc)/version_reqs/prog.cu test cases/cuda/12 cuda dependency (mixed)/kernel.cu test cases/cuda/12 cuda dependency (mixed)/meson.build test cases/cuda/12 cuda dependency (mixed)/prog.cpp test cases/cuda/2 split/lib.cu test cases/cuda/2 split/main.cpp test cases/cuda/2 split/meson.build test cases/cuda/2 split/static/lib.cu test cases/cuda/2 split/static/libsta.cu test cases/cuda/2 split/static/main_static.cpp test cases/cuda/2 split/static/meson.build test cases/cuda/3 cudamodule/meson.build test cases/cuda/3 cudamodule/prog.cu test cases/cuda/4 shared/main.cu test cases/cuda/4 shared/meson.build test cases/cuda/4 shared/shared/kernels.cu test cases/cuda/4 shared/shared/kernels.h test cases/cuda/4 shared/shared/meson.build test cases/cuda/5 threads/main.cu test cases/cuda/5 threads/meson.build test cases/cuda/5 threads/shared/kernels.cu test cases/cuda/5 threads/shared/kernels.h test cases/cuda/5 threads/shared/meson.build test cases/cuda/6 std/main.cu test cases/cuda/6 std/meson.build test cases/cuda/7 static vs runtime/main.cu test cases/cuda/7 static vs runtime/meson.build test cases/cuda/8 release/main.cu test cases/cuda/8 release/meson.build test cases/cuda/9 optimize for space/main.cu test cases/cuda/9 optimize for space/meson.build test cases/d/1 simple/app.d test cases/d/1 simple/installed_files.txt test cases/d/1 simple/meson.build test cases/d/1 simple/utils.d test cases/d/10 d cpp/cppmain.cpp test cases/d/10 d cpp/dmain.d test cases/d/10 d cpp/libfile.cpp test cases/d/10 d cpp/libfile.d test cases/d/10 d cpp/meson.build test cases/d/11 dub/meson.build test cases/d/11 dub/test.d test cases/d/2 static library/app.d test cases/d/2 static library/installed_files.txt test cases/d/2 static library/libstuff.d test cases/d/2 static library/meson.build test cases/d/3 shared library/app.d test cases/d/3 shared library/installed_files.txt test cases/d/3 shared library/libstuff.d test cases/d/3 shared library/libstuff.di test cases/d/3 shared library/meson.build test cases/d/4 library versions/installed_files.txt test cases/d/4 library versions/lib.d test cases/d/4 library versions/meson.build test cases/d/5 mixed/app.d test cases/d/5 mixed/installed_files.txt test cases/d/5 mixed/libstuff.c test cases/d/5 mixed/meson.build test cases/d/6 unittest/app.d test cases/d/6 unittest/installed_files.txt test cases/d/6 unittest/meson.build test cases/d/6 unittest/second_unit.d test cases/d/7 multilib/app.d test cases/d/7 multilib/installed_files.txt test cases/d/7 multilib/meson.build test cases/d/7 multilib/say1.d test cases/d/7 multilib/say1.di test cases/d/7 multilib/say2.d test cases/d/7 multilib/say2.di test cases/d/8 has multi arguments/meson.build test cases/d/9 features/app.d test cases/d/9 features/extra.d test cases/d/9 features/meson.build test cases/d/9 features/data/food.txt test cases/d/9 features/data/people.txt test cases/failing build/1 vala c werror/meson.build test cases/failing build/1 vala c werror/prog.vala test cases/failing build/1 vala c werror/unused-var.c test cases/failing build/2 hidden symbol/bob.c test cases/failing build/2 hidden symbol/bob.h test cases/failing build/2 hidden symbol/bobuser.c test cases/failing build/2 hidden symbol/meson.build test cases/failing build/3 pch disabled/meson.build test cases/failing build/3 pch disabled/c/meson.build test cases/failing build/3 pch disabled/c/prog.c test cases/failing build/3 pch disabled/c/pch/prog.h test cases/failing build/3 pch disabled/c/pch/prog_pch.c test cases/failing build/4 cmake subproject isolation/main.cpp test cases/failing build/4 cmake subproject isolation/meson.build test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp test cases/failing test/1 trivial/main.c test cases/failing test/1 trivial/meson.build test cases/failing test/2 signal/main.c test cases/failing test/2 signal/meson.build test cases/failing test/3 ambiguous/main.c test cases/failing test/3 ambiguous/meson.build test cases/failing test/3 ambiguous/test_runner.sh test cases/failing test/4 hard error/main.c test cases/failing test/4 hard error/meson.build test cases/failing test/5 tap tests/meson.build test cases/failing test/5 tap tests/tester.c test cases/failing test/6 xpass/meson.build test cases/failing test/6 xpass/xpass.c test cases/failing/1 project not first/meson.build test cases/failing/1 project not first/prog.c test cases/failing/10 out of bounds/meson.build test cases/failing/11 object arithmetic/meson.build test cases/failing/12 string arithmetic/meson.build test cases/failing/13 array arithmetic/meson.build test cases/failing/14 invalid option name/meson.build test cases/failing/14 invalid option name/meson_options.txt test cases/failing/15 kwarg before arg/meson.build test cases/failing/15 kwarg before arg/prog.c test cases/failing/16 extract from subproject/main.c test cases/failing/16 extract from subproject/meson.build test cases/failing/16 extract from subproject/subprojects/sub_project/meson.build test cases/failing/16 extract from subproject/subprojects/sub_project/sub_lib.c test cases/failing/17 same target/file.c test cases/failing/17 same target/meson.build test cases/failing/18 wrong plusassign/meson.build test cases/failing/19 target clash/clash.c test cases/failing/19 target clash/meson.build test cases/failing/2 missing file/meson.build test cases/failing/20 version/meson.build test cases/failing/21 subver/meson.build test cases/failing/21 subver/subprojects/foo/meson.build test cases/failing/22 assert/meson.build test cases/failing/23 rel testdir/meson.build test cases/failing/23 rel testdir/simple.c test cases/failing/24 int conversion/meson.build test cases/failing/25 badlang/meson.build test cases/failing/26 output subdir/foo.in test cases/failing/26 output subdir/meson.build test cases/failing/26 output subdir/subdir/dummy.txt test cases/failing/27 noprog use/meson.build test cases/failing/28 no crossprop/meson.build test cases/failing/29 nested ternary/meson.build test cases/failing/3 missing subdir/meson.build test cases/failing/30 invalid man extension/meson.build test cases/failing/31 no man extension/meson.build test cases/failing/32 exe static shared/meson.build test cases/failing/32 exe static shared/prog.c test cases/failing/32 exe static shared/shlib2.c test cases/failing/32 exe static shared/stat.c test cases/failing/33 non-root subproject/meson.build test cases/failing/33 non-root subproject/some/meson.build test cases/failing/34 dependency not-required then required/meson.build test cases/failing/35 project argument after target/exe.c test cases/failing/35 project argument after target/meson.build test cases/failing/36 pkgconfig dependency impossible conditions/meson.build test cases/failing/37 has function external dependency/meson.build test cases/failing/37 has function external dependency/mylib.c test cases/failing/38 libdir must be inside prefix/meson.build test cases/failing/39 prefix absolute/meson.build test cases/failing/4 missing meson.build/meson.build test cases/failing/4 missing meson.build/subdir/dummy.txt test cases/failing/40 kwarg assign/dummy.c test cases/failing/40 kwarg assign/meson.build test cases/failing/40 kwarg assign/prog.c test cases/failing/41 custom target plainname many inputs/1.txt test cases/failing/41 custom target plainname many inputs/2.txt test cases/failing/41 custom target plainname many inputs/catfiles.py test cases/failing/41 custom target plainname many inputs/meson.build test cases/failing/42 custom target outputs not matching install_dirs/generator.py test cases/failing/42 custom target outputs not matching install_dirs/installed_files.txt test cases/failing/42 custom target outputs not matching install_dirs/meson.build test cases/failing/43 project name colon/meson.build test cases/failing/44 abs subdir/meson.build test cases/failing/44 abs subdir/bob/meson.build test cases/failing/45 abspath to srcdir/meson.build test cases/failing/46 pkgconfig variables reserved/meson.build test cases/failing/46 pkgconfig variables reserved/simple.c test cases/failing/46 pkgconfig variables reserved/simple.h test cases/failing/47 pkgconfig variables zero length/meson.build test cases/failing/47 pkgconfig variables zero length/simple.c test cases/failing/47 pkgconfig variables zero length/simple.h test cases/failing/48 pkgconfig variables zero length value/meson.build test cases/failing/48 pkgconfig variables zero length value/simple.c test cases/failing/48 pkgconfig variables zero length value/simple.h test cases/failing/49 pkgconfig variables not key value/meson.build test cases/failing/49 pkgconfig variables not key value/simple.c test cases/failing/49 pkgconfig variables not key value/simple.h test cases/failing/5 misplaced option/meson.build test cases/failing/50 executable comparison/meson.build test cases/failing/50 executable comparison/prog.c test cases/failing/51 inconsistent comparison/meson.build test cases/failing/52 slashname/meson.build test cases/failing/52 slashname/sub/meson.build test cases/failing/52 slashname/sub/prog.c test cases/failing/53 reserved meson prefix/meson.build test cases/failing/53 reserved meson prefix/meson-foo/meson.build test cases/failing/54 wrong shared crate type/foo.rs test cases/failing/54 wrong shared crate type/meson.build test cases/failing/55 wrong static crate type/foo.rs test cases/failing/55 wrong static crate type/meson.build test cases/failing/56 or on new line/meson.build test cases/failing/56 or on new line/meson_options.txt test cases/failing/57 kwarg in module/meson.build test cases/failing/58 link with executable/meson.build test cases/failing/58 link with executable/module.c test cases/failing/58 link with executable/prog.c test cases/failing/59 assign custom target index/meson.build test cases/failing/6 missing incdir/meson.build test cases/failing/60 getoption prefix/meson.build test cases/failing/60 getoption prefix/subprojects/abc/meson.build test cases/failing/60 getoption prefix/subprojects/abc/meson_options.txt test cases/failing/61 bad option argument/meson.build test cases/failing/61 bad option argument/meson_options.txt test cases/failing/62 subproj filegrab/meson.build test cases/failing/62 subproj filegrab/prog.c test cases/failing/62 subproj filegrab/subprojects/a/meson.build test cases/failing/63 grab subproj/meson.build test cases/failing/63 grab subproj/subprojects/foo/meson.build test cases/failing/63 grab subproj/subprojects/foo/sub.c test cases/failing/64 grab sibling/meson.build test cases/failing/64 grab sibling/subprojects/a/meson.build test cases/failing/64 grab sibling/subprojects/b/meson.build test cases/failing/64 grab sibling/subprojects/b/sneaky.c test cases/failing/65 string as link target/meson.build test cases/failing/65 string as link target/prog.c test cases/failing/66 dependency not-found and required/meson.build test cases/failing/67 subproj different versions/main.c test cases/failing/67 subproj different versions/meson.build test cases/failing/67 subproj different versions/subprojects/a/a.c test cases/failing/67 subproj different versions/subprojects/a/a.h test cases/failing/67 subproj different versions/subprojects/a/meson.build test cases/failing/67 subproj different versions/subprojects/b/b.c test cases/failing/67 subproj different versions/subprojects/b/b.h test cases/failing/67 subproj different versions/subprojects/b/meson.build test cases/failing/67 subproj different versions/subprojects/c/c.h test cases/failing/67 subproj different versions/subprojects/c/meson.build test cases/failing/68 wrong boost module/meson.build test cases/failing/69 install_data rename bad size/file1.txt test cases/failing/69 install_data rename bad size/file2.txt test cases/failing/69 install_data rename bad size/meson.build test cases/failing/7 go to subproject/meson.build test cases/failing/7 go to subproject/subprojects/meson.build test cases/failing/70 skip only subdir/meson.build test cases/failing/70 skip only subdir/subdir/meson.build test cases/failing/71 invalid escape char/meson.build test cases/failing/72 dual override/meson.build test cases/failing/72 dual override/overrides.py test cases/failing/73 override used/meson.build test cases/failing/73 override used/other.py test cases/failing/73 override used/something.py test cases/failing/74 run_command unclean exit/meson.build test cases/failing/74 run_command unclean exit/returncode.py test cases/failing/75 int literal leading zero/meson.build test cases/failing/76 configuration immutable/input test cases/failing/76 configuration immutable/meson.build test cases/failing/77 link with shared module on osx/meson.build test cases/failing/77 link with shared module on osx/module.c test cases/failing/77 link with shared module on osx/prog.c test cases/failing/78 non ascii in ascii encoded configure file/config9.h.in test cases/failing/78 non ascii in ascii encoded configure file/meson.build test cases/failing/79 subproj dependency not-found and required/meson.build test cases/failing/8 recursive/meson.build test cases/failing/8 recursive/subprojects/a/meson.build test cases/failing/8 recursive/subprojects/b/meson.build test cases/failing/80 unfound run/meson.build test cases/failing/81 framework dependency with version/meson.build test cases/failing/82 override exe config/foo.c test cases/failing/82 override exe config/meson.build test cases/failing/83 gl dependency with version/meson.build test cases/failing/84 threads dependency with version/meson.build test cases/failing/85 gtest dependency with version/meson.build test cases/failing/86 dub libray/meson.build test cases/failing/87 dub executable/meson.build test cases/failing/88 dub compiler/meson.build test cases/failing/89 subproj not-found dep/meson.build test cases/failing/89 subproj not-found dep/subprojects/somesubproj/meson.build test cases/failing/9 missing extra file/meson.build test cases/failing/9 missing extra file/prog.c test cases/failing/90 invalid configure file/input test cases/failing/90 invalid configure file/meson.build test cases/failing/91 kwarg dupe/meson.build test cases/failing/91 kwarg dupe/prog.c test cases/failing/92 missing pch file/meson.build test cases/failing/92 missing pch file/prog.c test cases/failing/93 pch source different folder/meson.build test cases/failing/93 pch source different folder/prog.c test cases/failing/93 pch source different folder/include/pch.h test cases/failing/93 pch source different folder/src/pch.c test cases/failing/94 vala without c/meson.build test cases/failing/95 unknown config tool/meson.build test cases/failing/96 custom target install data/Info.plist.cpp test cases/failing/96 custom target install data/meson.build test cases/failing/96 custom target install data/preproc.py test cases/failing/97 add dict non string key/meson.build test cases/failing/98 add dict duplicate keys/meson.build test cases/fortran/1 basic/meson.build test cases/fortran/1 basic/simple.f90 test cases/fortran/10 find library/gzip.f90 test cases/fortran/10 find library/main.f90 test cases/fortran/10 find library/meson.build test cases/fortran/11 compiles links runs/meson.build test cases/fortran/12 submodule/a1.f90 test cases/fortran/12 submodule/a2.f90 test cases/fortran/12 submodule/a3.f90 test cases/fortran/12 submodule/child.f90 test cases/fortran/12 submodule/meson.build test cases/fortran/12 submodule/parent.f90 test cases/fortran/13 coarray/main.f90 test cases/fortran/13 coarray/meson.build test cases/fortran/14 fortran links c/clib.c test cases/fortran/14 fortran links c/clib.def test cases/fortran/14 fortran links c/f_call_c.f90 test cases/fortran/14 fortran links c/meson.build test cases/fortran/15 include/inc1.f90 test cases/fortran/15 include/inc2.f90 test cases/fortran/15 include/include_hierarchy.f90 test cases/fortran/15 include/include_syntax.f90 test cases/fortran/15 include/include_tests.f90 test cases/fortran/15 include/meson.build test cases/fortran/15 include/timestwo.f90 test cases/fortran/16 openmp/main.f90 test cases/fortran/16 openmp/meson.build test cases/fortran/17 add_languages/meson.build test cases/fortran/18 first_arg/meson.build test cases/fortran/19 fortran_std/legacy.f test cases/fortran/19 fortran_std/meson.build test cases/fortran/19 fortran_std/std2003.f90 test cases/fortran/19 fortran_std/std2008.f90 test cases/fortran/19 fortran_std/std2018.f90 test cases/fortran/19 fortran_std/std95.f90 test cases/fortran/2 modules/comment_mod.f90 test cases/fortran/2 modules/meson.build test cases/fortran/2 modules/mymod.f90 test cases/fortran/2 modules/prog.f90 test cases/fortran/20 buildtype/main.f90 test cases/fortran/20 buildtype/meson.build test cases/fortran/3 module procedure/meson.build test cases/fortran/3 module procedure/use_syntax.f90 test cases/fortran/4 self dependency/meson.build test cases/fortran/4 self dependency/selfdep.f90 test cases/fortran/4 self dependency/src/selfdep_mod.f90 test cases/fortran/4 self dependency/subprojects/sub1/main.f90 test cases/fortran/4 self dependency/subprojects/sub1/meson.build test cases/fortran/5 static/main.f90 test cases/fortran/5 static/meson.build test cases/fortran/5 static/static_hello.f90 test cases/fortran/6 dynamic/dynamic.f90 test cases/fortran/6 dynamic/main.f90 test cases/fortran/6 dynamic/meson.build test cases/fortran/7 generated/meson.build test cases/fortran/7 generated/mod1.fpp test cases/fortran/7 generated/mod2.fpp test cases/fortran/7 generated/prog.f90 test cases/fortran/8 module names/meson.build test cases/fortran/8 module names/mod1.f90 test cases/fortran/8 module names/mod2.f90 test cases/fortran/8 module names/test.f90 test cases/fortran/9 cpp/fortran.f test cases/fortran/9 cpp/main.cpp test cases/fortran/9 cpp/meson.build test cases/fpga/1 simple/meson.build test cases/fpga/1 simple/spin.pcf test cases/fpga/1 simple/spin.v test cases/frameworks/1 boost/extralib.cpp test cases/frameworks/1 boost/linkexe.cc test cases/frameworks/1 boost/meson.build test cases/frameworks/1 boost/nomod.cpp test cases/frameworks/1 boost/python_module.cpp test cases/frameworks/1 boost/test_python_module.py test cases/frameworks/1 boost/unit_test.cpp test cases/frameworks/1 boost/partial_dep/foo.cpp test cases/frameworks/1 boost/partial_dep/foo.hpp test cases/frameworks/1 boost/partial_dep/main.cpp test cases/frameworks/1 boost/partial_dep/meson.build test cases/frameworks/10 gtk-doc/installed_files.txt test cases/frameworks/10 gtk-doc/meson.build test cases/frameworks/10 gtk-doc/doc/foobar-docs.sgml test cases/frameworks/10 gtk-doc/doc/meson.build test cases/frameworks/10 gtk-doc/doc/version.xml.in test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-docs.sgml test cases/frameworks/10 gtk-doc/doc/foobar1/meson.build test cases/frameworks/10 gtk-doc/doc/foobar2/foobar-docs.sgml test cases/frameworks/10 gtk-doc/doc/foobar2/meson.build test cases/frameworks/10 gtk-doc/doc/foobar3/foobar-docs.sgml test cases/frameworks/10 gtk-doc/doc/foobar3/meson.build test cases/frameworks/10 gtk-doc/doc/foobar4/foobar-docs.sgml test cases/frameworks/10 gtk-doc/doc/foobar4/meson.build test cases/frameworks/10 gtk-doc/include/foo-version.h.in test cases/frameworks/10 gtk-doc/include/foo.h test cases/frameworks/10 gtk-doc/include/generate-enums-docbook.py test cases/frameworks/10 gtk-doc/include/meson.build test cases/frameworks/11 gir subproject/installed_files.txt test cases/frameworks/11 gir subproject/meson.build test cases/frameworks/11 gir subproject/gir/meson-subsample.c test cases/frameworks/11 gir subproject/gir/meson-subsample.h test cases/frameworks/11 gir subproject/gir/meson.build test cases/frameworks/11 gir subproject/gir/prog.c test cases/frameworks/11 gir subproject/gir/prog.py test cases/frameworks/11 gir subproject/subprojects/mesongir/meson-sample.c test cases/frameworks/11 gir subproject/subprojects/mesongir/meson-sample.h test cases/frameworks/11 gir subproject/subprojects/mesongir/meson.build test cases/frameworks/12 multiple gir/installed_files.txt test cases/frameworks/12 multiple gir/meson.build test cases/frameworks/12 multiple gir/gir/meson-subsample.c test cases/frameworks/12 multiple gir/gir/meson-subsample.h test cases/frameworks/12 multiple gir/gir/meson.build test cases/frameworks/12 multiple gir/gir/prog.c test cases/frameworks/12 multiple gir/mesongir/meson-sample.c test cases/frameworks/12 multiple gir/mesongir/meson-sample.h.in test cases/frameworks/12 multiple gir/mesongir/meson.build test cases/frameworks/13 yelp/installed_files.txt test cases/frameworks/13 yelp/meson.build test cases/frameworks/13 yelp/help/LINGUAS test cases/frameworks/13 yelp/help/meson.build test cases/frameworks/13 yelp/help/C/index.page test cases/frameworks/13 yelp/help/C/media/test.txt test cases/frameworks/13 yelp/help/de/de.po test cases/frameworks/13 yelp/help/es/es.po test cases/frameworks/13 yelp/help/es/media/test.txt test cases/frameworks/14 doxygen/installed_files.txt test cases/frameworks/14 doxygen/meson.build test cases/frameworks/14 doxygen/doc/Doxyfile.in test cases/frameworks/14 doxygen/doc/meson.build test cases/frameworks/14 doxygen/include/comedian.h test cases/frameworks/14 doxygen/include/spede.h test cases/frameworks/14 doxygen/src/spede.cpp test cases/frameworks/15 llvm/meson.build test cases/frameworks/15 llvm/sum.c test cases/frameworks/16 sdl2/meson.build test cases/frameworks/16 sdl2/sdl2prog.c test cases/frameworks/17 mpi/main.c test cases/frameworks/17 mpi/main.cpp test cases/frameworks/17 mpi/main.f90 test cases/frameworks/17 mpi/meson.build test cases/frameworks/18 vulkan/meson.build test cases/frameworks/18 vulkan/vulkanprog.c test cases/frameworks/19 pcap/meson.build test cases/frameworks/19 pcap/pcap_prog.c test cases/frameworks/2 gtest/meson.build test cases/frameworks/2 gtest/test.cc test cases/frameworks/2 gtest/test_nomain.cc test cases/frameworks/20 cups/cups_prog.c test cases/frameworks/20 cups/meson.build test cases/frameworks/21 libwmf/libwmf_prog.c test cases/frameworks/21 libwmf/meson.build test cases/frameworks/22 gir link order/meson-sample.c test cases/frameworks/22 gir link order/meson-sample.h test cases/frameworks/22 gir link order/meson.build test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.c test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.h test cases/frameworks/22 gir link order/fake-gthread/meson.build test cases/frameworks/22 gir link order/get-prgname/get-prgname.c test cases/frameworks/22 gir link order/get-prgname/get-prgname.h test cases/frameworks/22 gir link order/get-prgname/meson.build test cases/frameworks/23 hotdoc/installed_files.txt test cases/frameworks/23 hotdoc/meson.build test cases/frameworks/23 hotdoc/doc/index.md test cases/frameworks/23 hotdoc/doc/meson.build test cases/frameworks/23 hotdoc/doc/sitemap.txt test cases/frameworks/24 libgcrypt/libgcrypt_prog.c test cases/frameworks/24 libgcrypt/meson.build test cases/frameworks/25 hdf5/main.c test cases/frameworks/25 hdf5/main.cpp test cases/frameworks/25 hdf5/main.f90 test cases/frameworks/25 hdf5/meson.build test cases/frameworks/26 netcdf/main.c test cases/frameworks/26 netcdf/main.cpp test cases/frameworks/26 netcdf/main.f90 test cases/frameworks/26 netcdf/meson.build test cases/frameworks/27 gpgme/gpgme_prog.c test cases/frameworks/27 gpgme/meson.build test cases/frameworks/28 gir link order 2/meson-sample.c test cases/frameworks/28 gir link order 2/meson-sample.h test cases/frameworks/28 gir link order 2/meson.build test cases/frameworks/28 gir link order 2/samelibname/meson.build test cases/frameworks/29 blocks/main.c test cases/frameworks/29 blocks/meson.build test cases/frameworks/3 gmock/gmocktest.cc test cases/frameworks/3 gmock/meson.build test cases/frameworks/30 scalapack/main.c test cases/frameworks/30 scalapack/main.f90 test cases/frameworks/30 scalapack/meson.build test cases/frameworks/30 scalapack/cmake/FindSCALAPACK.cmake test cases/frameworks/4 qt/main.cpp test cases/frameworks/4 qt/mainWindow.cpp test cases/frameworks/4 qt/mainWindow.h test cases/frameworks/4 qt/mainWindow.ui test cases/frameworks/4 qt/manualinclude.cpp test cases/frameworks/4 qt/manualinclude.h test cases/frameworks/4 qt/meson.build test cases/frameworks/4 qt/meson_options.txt test cases/frameworks/4 qt/q5core.cpp test cases/frameworks/4 qt/qt4core_fr.ts test cases/frameworks/4 qt/qt5core_fr.ts test cases/frameworks/4 qt/qtinterface.cpp test cases/frameworks/4 qt/stuff.qrc test cases/frameworks/4 qt/stuff2.qrc test cases/frameworks/4 qt/thing.png test cases/frameworks/4 qt/thing2.png test cases/frameworks/4 qt/plugin/plugin.cpp test cases/frameworks/4 qt/plugin/plugin.h test cases/frameworks/4 qt/plugin/plugin.json test cases/frameworks/4 qt/pluginInterface/plugin_if.h test cases/frameworks/4 qt/subfolder/generator.py test cases/frameworks/4 qt/subfolder/main.cpp test cases/frameworks/4 qt/subfolder/meson.build test cases/frameworks/4 qt/subfolder/resources/stuff3.qrc test cases/frameworks/4 qt/subfolder/resources/stuff4.qrc.in test cases/frameworks/4 qt/subfolder/resources/thing.png test cases/frameworks/5 protocol buffers/defs.proto test cases/frameworks/5 protocol buffers/main.cpp test cases/frameworks/5 protocol buffers/meson.build test cases/frameworks/5 protocol buffers/asubdir/defs.proto test cases/frameworks/5 protocol buffers/asubdir/main.cpp test cases/frameworks/5 protocol buffers/asubdir/meson.build test cases/frameworks/5 protocol buffers/sidedir/meson.build test cases/frameworks/5 protocol buffers/sidedir/sideprog.cpp test cases/frameworks/5 protocol buffers/withpath/meson.build test cases/frameworks/5 protocol buffers/withpath/pathprog.cpp test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/simple.proto test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/subsite/complex.proto test cases/frameworks/6 gettext/installed_files.txt test cases/frameworks/6 gettext/meson.build test cases/frameworks/6 gettext/data/meson.build test cases/frameworks/6 gettext/data/test.desktop.in test cases/frameworks/6 gettext/data/test2.desktop.in test cases/frameworks/6 gettext/data/data3/meson.build test cases/frameworks/6 gettext/data/data3/test.desktop.in test cases/frameworks/6 gettext/data2/meson.build test cases/frameworks/6 gettext/data2/test.desktop.in test cases/frameworks/6 gettext/generated/desktopgenerator.py test cases/frameworks/6 gettext/generated/meson.build test cases/frameworks/6 gettext/generated/something.desktop.in.in test cases/frameworks/6 gettext/po/LINGUAS test cases/frameworks/6 gettext/po/POTFILES test cases/frameworks/6 gettext/po/de.po test cases/frameworks/6 gettext/po/fi.po test cases/frameworks/6 gettext/po/intltest.pot test cases/frameworks/6 gettext/po/meson.build test cases/frameworks/6 gettext/po/ru.po test cases/frameworks/6 gettext/src/intlmain.c test cases/frameworks/6 gettext/src/meson.build test cases/frameworks/7 gnome/installed_files.txt test cases/frameworks/7 gnome/meson.build test cases/frameworks/7 gnome/gdbus/gdbusprog.c test cases/frameworks/7 gnome/gdbus/meson.build test cases/frameworks/7 gnome/gdbus/data/com.example.Sample.xml test cases/frameworks/7 gnome/genmarshal/main.c test cases/frameworks/7 gnome/genmarshal/marshaller.list test cases/frameworks/7 gnome/genmarshal/meson.build test cases/frameworks/7 gnome/gir/meson-sample.c test cases/frameworks/7 gnome/gir/meson-sample.h test cases/frameworks/7 gnome/gir/meson-sample2.c test cases/frameworks/7 gnome/gir/meson-sample2.h test cases/frameworks/7 gnome/gir/meson.build test cases/frameworks/7 gnome/gir/prog.c test cases/frameworks/7 gnome/gir/prog.py test cases/frameworks/7 gnome/gir/dep1/dep1.c test cases/frameworks/7 gnome/gir/dep1/dep1.h test cases/frameworks/7 gnome/gir/dep1/meson.build test cases/frameworks/7 gnome/gir/dep1/dep2/dep2.c test cases/frameworks/7 gnome/gir/dep1/dep2/dep2.h test cases/frameworks/7 gnome/gir/dep1/dep2/meson.build test cases/frameworks/7 gnome/mkenums/enums.c.in test cases/frameworks/7 gnome/mkenums/enums.h.in test cases/frameworks/7 gnome/mkenums/enums2.c.in test cases/frameworks/7 gnome/mkenums/enums2.h.in test cases/frameworks/7 gnome/mkenums/main.c test cases/frameworks/7 gnome/mkenums/main4.c test cases/frameworks/7 gnome/mkenums/main5.c test cases/frameworks/7 gnome/mkenums/meson-decls.h test cases/frameworks/7 gnome/mkenums/meson-sample.h test cases/frameworks/7 gnome/mkenums/meson.build test cases/frameworks/7 gnome/resources/copyfile.py test cases/frameworks/7 gnome/resources/generated-main.c test cases/frameworks/7 gnome/resources/generated.gresource.xml test cases/frameworks/7 gnome/resources/meson.build test cases/frameworks/7 gnome/resources/myresource.gresource.xml test cases/frameworks/7 gnome/resources/res3.txt test cases/frameworks/7 gnome/resources/resources.py test cases/frameworks/7 gnome/resources/simple-main.c test cases/frameworks/7 gnome/resources/simple.gresource.xml test cases/frameworks/7 gnome/resources-data/meson.build test cases/frameworks/7 gnome/resources-data/res1.txt test cases/frameworks/7 gnome/resources-data/res3.txt.in test cases/frameworks/7 gnome/resources-data/subdir/meson.build test cases/frameworks/7 gnome/resources-data/subdir/res2.txt test cases/frameworks/7 gnome/resources-data/subdir/res4.txt.in test cases/frameworks/7 gnome/schemas/com.github.meson.gschema.xml test cases/frameworks/7 gnome/schemas/meson.build test cases/frameworks/7 gnome/schemas/schemaprog.c test cases/frameworks/8 flex/lexer.l test cases/frameworks/8 flex/meson.build test cases/frameworks/8 flex/parser.y test cases/frameworks/8 flex/prog.c test cases/frameworks/8 flex/test.txt test cases/frameworks/9 wxwidgets/mainwin.h test cases/frameworks/9 wxwidgets/meson.build test cases/frameworks/9 wxwidgets/wxprog.cpp test cases/frameworks/9 wxwidgets/wxstc.cpp test cases/java/1 basic/installed_files.txt test cases/java/1 basic/meson.build test cases/java/1 basic/com/mesonbuild/Simple.java test cases/java/2 subdir/meson.build test cases/java/2 subdir/sub/meson.build test cases/java/2 subdir/sub/com/mesonbuild/Simple.java test cases/java/2 subdir/sub/com/mesonbuild/TextPrinter.java test cases/java/3 args/meson.build test cases/java/3 args/com/mesonbuild/Simple.java test cases/java/4 inner class/meson.build test cases/java/4 inner class/com/mesonbuild/Simple.java test cases/java/5 includedirs/meson.build test cases/java/5 includedirs/com/mesonbuild/Simple.java test cases/java/5 includedirs/com/mesonbuild/TextPrinter.java test cases/java/6 codegen/meson.build test cases/java/6 codegen/com/mesonbuild/Config.java.in test cases/java/6 codegen/com/mesonbuild/Simple.java test cases/java/6 codegen/com/mesonbuild/TextPrinter.java test cases/java/6 codegen/com/mesonbuild/meson.build test cases/java/7 linking/meson.build test cases/java/7 linking/com/mesonbuild/Linking.java test cases/java/7 linking/sub/meson.build test cases/java/7 linking/sub/com/mesonbuild/SimpleLib.java test cases/java/8 codegen custom target/meson.build test cases/java/8 codegen custom target/com/mesonbuild/Config.java.in test cases/java/8 codegen custom target/com/mesonbuild/Simple.java test cases/java/8 codegen custom target/com/mesonbuild/TextPrinter.java test cases/java/8 codegen custom target/com/mesonbuild/meson.build test cases/kconfig/1 basic/.config test cases/kconfig/1 basic/meson.build test cases/kconfig/2 subdir/.config test cases/kconfig/2 subdir/meson.build test cases/kconfig/2 subdir/dir/meson.build test cases/kconfig/3 load_config files/meson.build test cases/kconfig/3 load_config files/dir/config test cases/kconfig/3 load_config files/dir/meson.build test cases/kconfig/4 load_config builddir/config test cases/kconfig/4 load_config builddir/meson.build test cases/linuxlike/1 pkg-config/meson.build test cases/linuxlike/1 pkg-config/prog-checkver.c test cases/linuxlike/1 pkg-config/prog.c test cases/linuxlike/1 pkg-config/incdir/myinc.h test cases/linuxlike/10 large file support/meson.build test cases/linuxlike/11 runpath rpath ldlibrarypath/lib.c test cases/linuxlike/11 runpath rpath ldlibrarypath/main.c test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build test cases/linuxlike/11 runpath rpath ldlibrarypath/lib1/meson.build test cases/linuxlike/11 runpath rpath ldlibrarypath/lib2/meson.build test cases/linuxlike/12 subprojects in subprojects/main.c test cases/linuxlike/12 subprojects in subprojects/meson.build test cases/linuxlike/12 subprojects in subprojects/subprojects/a/a.c test cases/linuxlike/12 subprojects in subprojects/subprojects/a/a.h test cases/linuxlike/12 subprojects in subprojects/subprojects/a/meson.build test cases/linuxlike/12 subprojects in subprojects/subprojects/b/b.c test cases/linuxlike/12 subprojects in subprojects/subprojects/b/b.h test cases/linuxlike/12 subprojects in subprojects/subprojects/b/meson.build test cases/linuxlike/12 subprojects in subprojects/subprojects/c/c.h test cases/linuxlike/12 subprojects in subprojects/subprojects/c/meson.build test cases/linuxlike/13 cmake dependency/meson.build test cases/linuxlike/13 cmake dependency/prog-checkver.c test cases/linuxlike/13 cmake dependency/prog.c test cases/linuxlike/13 cmake dependency/setup_env.json test cases/linuxlike/13 cmake dependency/testFlagSet.c test cases/linuxlike/13 cmake dependency/cmake/FindImportedTarget.cmake test cases/linuxlike/13 cmake dependency/cmake/FindSomethingLikeZLIB.cmake test cases/linuxlike/13 cmake dependency/cmake_pref_env/lib/cmake/cmMesonTestDep/cmMesonTestDepConfig.cmake test cases/linuxlike/13 cmake dependency/incdir/myinc.h test cases/linuxlike/14 static dynamic linkage/main.c test cases/linuxlike/14 static dynamic linkage/meson.build test cases/linuxlike/14 static dynamic linkage/verify_static.py test cases/linuxlike/15 ld binary/meson.build test cases/linuxlike/2 external library/meson.build test cases/linuxlike/2 external library/prog.c test cases/linuxlike/3 linker script/bob.c test cases/linuxlike/3 linker script/bob.h test cases/linuxlike/3 linker script/bob.map test cases/linuxlike/3 linker script/bob.map.in test cases/linuxlike/3 linker script/copy.py test cases/linuxlike/3 linker script/meson.build test cases/linuxlike/3 linker script/prog.c test cases/linuxlike/3 linker script/sub/foo.map test cases/linuxlike/3 linker script/sub/meson.build test cases/linuxlike/4 extdep static lib/lib.c test cases/linuxlike/4 extdep static lib/meson.build test cases/linuxlike/4 extdep static lib/prog.c test cases/linuxlike/5 dependency versions/meson.build test cases/linuxlike/5 dependency versions/subprojects/somelib/lib.c test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build test cases/linuxlike/5 dependency versions/subprojects/somelibnover/lib.c test cases/linuxlike/5 dependency versions/subprojects/somelibnover/meson.build test cases/linuxlike/5 dependency versions/subprojects/somelibver/lib.c test cases/linuxlike/5 dependency versions/subprojects/somelibver/meson.build test cases/linuxlike/6 subdir include order/meson.build test cases/linuxlike/6 subdir include order/prog.c test cases/linuxlike/6 subdir include order/subdir/glib.h test cases/linuxlike/7 library versions/exe.orig.c test cases/linuxlike/7 library versions/installed_files.txt test cases/linuxlike/7 library versions/lib.c test cases/linuxlike/7 library versions/meson.build test cases/linuxlike/8 subproject library install/installed_files.txt test cases/linuxlike/8 subproject library install/meson.build test cases/linuxlike/8 subproject library install/subprojects/sublib/meson.build test cases/linuxlike/8 subproject library install/subprojects/sublib/sublib.c test cases/linuxlike/8 subproject library install/subprojects/sublib/include/subdefs.h test cases/linuxlike/9 compiler checks with dependencies/meson.build test cases/nasm/1 configure file/hello.asm test cases/nasm/1 configure file/meson.build test cases/objc/1 simple/meson.build test cases/objc/1 simple/prog.m test cases/objc/2 nsstring/meson.build test cases/objc/2 nsstring/stringprog.m test cases/objc/3 objc args/meson.build test cases/objc/3 objc args/prog.m test cases/objc/4 c++ project objc subproject/master.cpp test cases/objc/4 c++ project objc subproject/meson.build test cases/objc/4 c++ project objc subproject/subprojects/foo/foo.m test cases/objc/4 c++ project objc subproject/subprojects/foo/meson.build test cases/objcpp/1 simple/meson.build test cases/objcpp/1 simple/prog.mm test cases/objcpp/2 objc++ args/meson.build test cases/objcpp/2 objc++ args/prog.mm test cases/osx/1 basic/main.c test cases/osx/1 basic/meson.build test cases/osx/2 library versions/CMakeLists.txt test cases/osx/2 library versions/exe.orig.c test cases/osx/2 library versions/installed_files.txt test cases/osx/2 library versions/lib.c test cases/osx/2 library versions/meson.build test cases/osx/2 library versions/require_pkgconfig.py test cases/osx/3 has function xcode8/meson.build test cases/osx/4 framework/installed_files.txt test cases/osx/4 framework/meson.build test cases/osx/4 framework/prog.c test cases/osx/4 framework/stat.c test cases/osx/4 framework/xcode-frameworks.png test cases/osx/5 extra frameworks/installed_files.txt test cases/osx/5 extra frameworks/meson.build test cases/osx/5 extra frameworks/prog.c test cases/osx/5 extra frameworks/stat.c test cases/osx/6 multiframework/main.m test cases/osx/6 multiframework/meson.build test cases/osx/7 bitcode/libbar.mm test cases/osx/7 bitcode/libfile.c test cases/osx/7 bitcode/libfoo.m test cases/osx/7 bitcode/meson.build test cases/osx/7 bitcode/vis.h test cases/osx/8 pie/main.c test cases/osx/8 pie/meson.build test cases/python/1 basic/meson.build test cases/python/1 basic/prog.py test cases/python/1 basic/gluon/__init__.py test cases/python/1 basic/gluon/gluonator.py test cases/python/1 basic/subdir/meson.build test cases/python/1 basic/subdir/subprog.py test cases/python/2 extmodule/blaster.py test cases/python/2 extmodule/meson.build test cases/python/2 extmodule/ext/meson.build test cases/python/2 extmodule/ext/tachyon_module.c test cases/python/3 cython/cytest.py test cases/python/3 cython/meson.build test cases/python/3 cython/libdir/cstorer.pxd test cases/python/3 cython/libdir/meson.build test cases/python/3 cython/libdir/storer.c test cases/python/3 cython/libdir/storer.h test cases/python/3 cython/libdir/storer.pyx test cases/python/4 custom target depends extmodule/blaster.py test cases/python/4 custom target depends extmodule/meson.build test cases/python/4 custom target depends extmodule/ext/meson.build test cases/python/4 custom target depends extmodule/ext/tachyon_module.c test cases/python/4 custom target depends extmodule/ext/lib/meson-tachyonlib.c test cases/python/4 custom target depends extmodule/ext/lib/meson-tachyonlib.h test cases/python/4 custom target depends extmodule/ext/lib/meson.build test cases/python/5 modules kwarg/meson.build test cases/python3/1 basic/meson.build test cases/python3/1 basic/prog.py test cases/python3/1 basic/gluon/__init__.py test cases/python3/1 basic/gluon/gluonator.py test cases/python3/1 basic/subdir/meson.build test cases/python3/1 basic/subdir/subprog.py test cases/python3/2 extmodule/blaster.py test cases/python3/2 extmodule/meson.build test cases/python3/2 extmodule/ext/meson.build test cases/python3/2 extmodule/ext/tachyon_module.c test cases/python3/3 cython/cytest.py test cases/python3/3 cython/meson.build test cases/python3/3 cython/libdir/cstorer.pxd test cases/python3/3 cython/libdir/meson.build test cases/python3/3 cython/libdir/storer.c test cases/python3/3 cython/libdir/storer.h test cases/python3/3 cython/libdir/storer.pyx test cases/python3/4 custom target depends extmodule/blaster.py test cases/python3/4 custom target depends extmodule/meson.build test cases/python3/4 custom target depends extmodule/ext/meson.build test cases/python3/4 custom target depends extmodule/ext/tachyon_module.c test cases/python3/4 custom target depends extmodule/ext/lib/meson-tachyonlib.c test cases/python3/4 custom target depends extmodule/ext/lib/meson-tachyonlib.h test cases/python3/4 custom target depends extmodule/ext/lib/meson.build test cases/rewrite/1 basic/addSrc.json test cases/rewrite/1 basic/addTgt.json test cases/rewrite/1 basic/info.json test cases/rewrite/1 basic/meson.build test cases/rewrite/1 basic/rmSrc.json test cases/rewrite/1 basic/rmTgt.json test cases/rewrite/2 subdirs/addSrc.json test cases/rewrite/2 subdirs/addTgt.json test cases/rewrite/2 subdirs/info.json test cases/rewrite/2 subdirs/meson.build test cases/rewrite/2 subdirs/rmTgt.json test cases/rewrite/2 subdirs/sub1/meson.build test cases/rewrite/2 subdirs/sub2/meson.build test cases/rewrite/3 kwargs/add.json test cases/rewrite/3 kwargs/defopts_delete.json test cases/rewrite/3 kwargs/defopts_set.json test cases/rewrite/3 kwargs/delete.json test cases/rewrite/3 kwargs/info.json test cases/rewrite/3 kwargs/meson.build test cases/rewrite/3 kwargs/remove.json test cases/rewrite/3 kwargs/remove_regex.json test cases/rewrite/3 kwargs/set.json test cases/rewrite/4 same name targets/addSrc.json test cases/rewrite/4 same name targets/info.json test cases/rewrite/4 same name targets/meson.build test cases/rewrite/4 same name targets/sub1/meson.build test cases/rewrite/5 sorting/meson.build test cases/rust/1 basic/installed_files.txt test cases/rust/1 basic/meson.build test cases/rust/1 basic/prog.rs test cases/rust/1 basic/subdir/meson.build test cases/rust/1 basic/subdir/prog.rs test cases/rust/2 sharedlib/installed_files.txt test cases/rust/2 sharedlib/meson.build test cases/rust/2 sharedlib/prog.rs test cases/rust/2 sharedlib/stuff.rs test cases/rust/3 staticlib/installed_files.txt test cases/rust/3 staticlib/meson.build test cases/rust/3 staticlib/prog.rs test cases/rust/3 staticlib/stuff.rs test cases/rust/4 polyglot/installed_files.txt test cases/rust/4 polyglot/meson.build test cases/rust/4 polyglot/prog.c test cases/rust/4 polyglot/stuff.rs test cases/rust/5 polyglot static/installed_files.txt test cases/rust/5 polyglot static/meson.build test cases/rust/5 polyglot static/prog.c test cases/rust/5 polyglot static/stuff.rs test cases/rust/6 named staticlib/installed_files.txt test cases/rust/6 named staticlib/meson.build test cases/rust/6 named staticlib/prog.rs test cases/rust/6 named staticlib/stuff.rs test cases/rust/7 private crate collision/installed_files.txt test cases/rust/7 private crate collision/meson.build test cases/rust/7 private crate collision/prog.rs test cases/rust/7 private crate collision/rand.rs test cases/rust/8 many files/foo.rs test cases/rust/8 many files/main.rs test cases/rust/8 many files/meson.build test cases/swift/1 exe/meson.build test cases/swift/1 exe/prog.swift test cases/swift/2 multifile/libfile.swift test cases/swift/2 multifile/main.swift test cases/swift/2 multifile/meson.build test cases/swift/3 library/meson.build test cases/swift/3 library/exe/main.swift test cases/swift/3 library/exe/meson.build test cases/swift/3 library/lib/datasource.swift test cases/swift/3 library/lib/meson.build test cases/swift/3 library/lib/othersource.swift test cases/swift/4 generate/meson.build test cases/swift/4 generate/gen/main.swift test cases/swift/4 generate/gen/meson.build test cases/swift/4 generate/user/main.swift test cases/swift/4 generate/user/meson.build test cases/swift/5 mixed/main.swift test cases/swift/5 mixed/meson.build test cases/swift/5 mixed/mylib.c test cases/swift/5 mixed/mylib.h test cases/swift/6 modulemap/main.swift test cases/swift/6 modulemap/meson.build test cases/swift/6 modulemap/module.modulemap test cases/swift/6 modulemap/mylib.c test cases/swift/6 modulemap/mylib.h test cases/swift/7 modulemap subdir/main.swift test cases/swift/7 modulemap subdir/meson.build test cases/swift/7 modulemap subdir/mylib/meson.build test cases/swift/7 modulemap subdir/mylib/module.modulemap test cases/swift/7 modulemap subdir/mylib/mylib.c test cases/swift/7 modulemap subdir/mylib/mylib.h test cases/unit/1 soname/CMakeLists.txt test cases/unit/1 soname/meson.build test cases/unit/1 soname/versioned.c test cases/unit/10 build_rpath/meson.build test cases/unit/10 build_rpath/prog.c test cases/unit/10 build_rpath/prog.cc test cases/unit/10 build_rpath/sub/meson.build test cases/unit/10 build_rpath/sub/stuff.c test cases/unit/11 cross prog/meson.build test cases/unit/11 cross prog/some_cross_tool.py test cases/unit/11 cross prog/sometool.py test cases/unit/12 promote/meson.build test cases/unit/12 promote/subprojects/s1/meson.build test cases/unit/12 promote/subprojects/s1/s1.c test cases/unit/12 promote/subprojects/s1/subprojects/s3/meson.build test cases/unit/12 promote/subprojects/s1/subprojects/s3/s3.c test cases/unit/12 promote/subprojects/s1/subprojects/scommon/meson.build test cases/unit/12 promote/subprojects/s1/subprojects/scommon/scommon_broken.c test cases/unit/12 promote/subprojects/s2/meson.build test cases/unit/12 promote/subprojects/s2/s2.c test cases/unit/12 promote/subprojects/s2/subprojects/athing.wrap test cases/unit/12 promote/subprojects/s2/subprojects/scommon/meson.build test cases/unit/12 promote/subprojects/s2/subprojects/scommon/scommon_ok.c test cases/unit/13 reconfigure/meson.build test cases/unit/14 testsetup selection/main.c test cases/unit/14 testsetup selection/meson.build test cases/unit/14 testsetup selection/subprojects/bar/bar.c test cases/unit/14 testsetup selection/subprojects/bar/meson.build test cases/unit/14 testsetup selection/subprojects/foo/foo.c test cases/unit/14 testsetup selection/subprojects/foo/meson.build test cases/unit/15 prebuilt object/main.c test cases/unit/15 prebuilt object/meson.build test cases/unit/15 prebuilt object/source.c test cases/unit/16 prebuilt static/main.c test cases/unit/16 prebuilt static/meson.build test cases/unit/16 prebuilt static/libdir/best.c test cases/unit/16 prebuilt static/libdir/best.h test cases/unit/16 prebuilt static/libdir/meson.build test cases/unit/17 prebuilt shared/alexandria.c test cases/unit/17 prebuilt shared/alexandria.h test cases/unit/17 prebuilt shared/another_visitor.c test cases/unit/17 prebuilt shared/meson.build test cases/unit/17 prebuilt shared/patron.c test cases/unit/18 pkgconfig static/foo.c test cases/unit/18 pkgconfig static/foo.pc.in test cases/unit/18 pkgconfig static/main.c test cases/unit/18 pkgconfig static/meson.build test cases/unit/18 pkgconfig static/include/foo.h test cases/unit/19 array option/meson.build test cases/unit/19 array option/meson_options.txt test cases/unit/2 testsetups/buggy.c test cases/unit/2 testsetups/envcheck.py test cases/unit/2 testsetups/impl.c test cases/unit/2 testsetups/impl.h test cases/unit/2 testsetups/meson.build test cases/unit/20 subproj dep variables/meson.build test cases/unit/20 subproj dep variables/subprojects/failingsubproj/meson.build test cases/unit/20 subproj dep variables/subprojects/nestedsubproj/meson.build test cases/unit/20 subproj dep variables/subprojects/nestedsubproj/subprojects/subsubproject.wrap test cases/unit/20 subproj dep variables/subprojects/somesubproj/meson.build test cases/unit/21 exit status/meson.build test cases/unit/22 warning location/a.c test cases/unit/22 warning location/b.c test cases/unit/22 warning location/conf.in test cases/unit/22 warning location/main.c test cases/unit/22 warning location/meson.build test cases/unit/22 warning location/sub/c.c test cases/unit/22 warning location/sub/d.c test cases/unit/22 warning location/sub/meson.build test cases/unit/22 warning location/sub/sub.c test cases/unit/23 unfound pkgconfig/meson.build test cases/unit/23 unfound pkgconfig/some.c test cases/unit/24 compiler run_command/meson.build test cases/unit/25 non-permitted kwargs/meson.build test cases/unit/26 install umask/datafile.cat test cases/unit/26 install umask/meson.build test cases/unit/26 install umask/myinstall.py test cases/unit/26 install umask/prog.1 test cases/unit/26 install umask/prog.c test cases/unit/26 install umask/sample.h test cases/unit/26 install umask/subdir/datafile.dog test cases/unit/26 install umask/subdir/sayhello test cases/unit/27 pkgconfig usage/dependee/meson.build test cases/unit/27 pkgconfig usage/dependee/pkguser.c test cases/unit/27 pkgconfig usage/dependency/meson.build test cases/unit/27 pkgconfig usage/dependency/pkgdep.c test cases/unit/27 pkgconfig usage/dependency/pkgdep.h test cases/unit/27 pkgconfig usage/dependency/privatelib.c test cases/unit/28 ndebug if-release/main.c test cases/unit/28 ndebug if-release/meson.build test cases/unit/29 guessed linker dependencies/exe/app.c test cases/unit/29 guessed linker dependencies/exe/meson.build test cases/unit/29 guessed linker dependencies/lib/lib.c test cases/unit/29 guessed linker dependencies/lib/meson.build test cases/unit/29 guessed linker dependencies/lib/meson_options.txt test cases/unit/3 subproject defaults/meson.build test cases/unit/3 subproject defaults/meson_options.txt test cases/unit/3 subproject defaults/subprojects/foob/meson.build test cases/unit/3 subproject defaults/subprojects/foob/meson_options.txt test cases/unit/30 shared_mod linking/libfile.c test cases/unit/30 shared_mod linking/main.c test cases/unit/30 shared_mod linking/meson.build test cases/unit/31 forcefallback/meson.build test cases/unit/31 forcefallback/test_not_zlib.c test cases/unit/31 forcefallback/subprojects/notzlib/meson.build test cases/unit/31 forcefallback/subprojects/notzlib/notzlib.c test cases/unit/31 forcefallback/subprojects/notzlib/notzlib.h test cases/unit/32 pkgconfig use libraries/app/app.c test cases/unit/32 pkgconfig use libraries/app/meson.build test cases/unit/32 pkgconfig use libraries/lib/liba.c test cases/unit/32 pkgconfig use libraries/lib/libb.c test cases/unit/32 pkgconfig use libraries/lib/meson.build test cases/unit/33 cross file overrides always args/meson.build test cases/unit/33 cross file overrides always args/test.c test cases/unit/33 cross file overrides always args/ubuntu-armhf-overrides.txt test cases/unit/34 command line/meson.build test cases/unit/34 command line/meson_options.txt test cases/unit/34 command line/subprojects/subp/meson.build test cases/unit/34 command line/subprojects/subp/meson_options.txt test cases/unit/35 dist script/meson.build test cases/unit/35 dist script/prog.c test cases/unit/35 dist script/replacer.py test cases/unit/36 exe_wrapper behaviour/broken-cross.txt test cases/unit/36 exe_wrapper behaviour/meson.build test cases/unit/36 exe_wrapper behaviour/meson_options.txt test cases/unit/36 exe_wrapper behaviour/prog.c test cases/unit/37 mixed command line args/meson.build test cases/unit/37 mixed command line args/meson_options.txt test cases/unit/38 pkgconfig format/meson.build test cases/unit/38 pkgconfig format/somelib.c test cases/unit/38 pkgconfig format/someret.c test cases/unit/39 python extmodule/blaster.py test cases/unit/39 python extmodule/meson.build test cases/unit/39 python extmodule/meson_options.txt test cases/unit/39 python extmodule/ext/meson.build test cases/unit/39 python extmodule/ext/tachyon_module.c test cases/unit/4 suite selection/failing_test.c test cases/unit/4 suite selection/meson.build test cases/unit/4 suite selection/successful_test.c test cases/unit/4 suite selection/subprojects/subprjfail/failing_test.c test cases/unit/4 suite selection/subprojects/subprjfail/meson.build test cases/unit/4 suite selection/subprojects/subprjmix/failing_test.c test cases/unit/4 suite selection/subprojects/subprjmix/meson.build test cases/unit/4 suite selection/subprojects/subprjmix/successful_test.c test cases/unit/4 suite selection/subprojects/subprjsucc/meson.build test cases/unit/4 suite selection/subprojects/subprjsucc/successful_test.c test cases/unit/40 external, internal library rpath/built library/bar.c test cases/unit/40 external, internal library rpath/built library/meson.build test cases/unit/40 external, internal library rpath/built library/meson_options.txt test cases/unit/40 external, internal library rpath/built library/prog.c test cases/unit/40 external, internal library rpath/external library/bar.c test cases/unit/40 external, internal library rpath/external library/faa.c test cases/unit/40 external, internal library rpath/external library/foo.c test cases/unit/40 external, internal library rpath/external library/meson.build test cases/unit/41 featurenew subprojects/meson.build test cases/unit/41 featurenew subprojects/subprojects/bar/meson.build test cases/unit/41 featurenew subprojects/subprojects/baz/meson.build test cases/unit/41 featurenew subprojects/subprojects/foo/meson.build test cases/unit/42 rpath order/meson.build test cases/unit/42 rpath order/myexe.c test cases/unit/42 rpath order/subprojects/sub1/lib.c test cases/unit/42 rpath order/subprojects/sub1/meson.build test cases/unit/42 rpath order/subprojects/sub2/lib.c test cases/unit/42 rpath order/subprojects/sub2/meson.build test cases/unit/43 dep order/lib1.c test cases/unit/43 dep order/lib2.c test cases/unit/43 dep order/meson.build test cases/unit/43 dep order/myexe.c test cases/unit/44 promote wrap/meson.build test cases/unit/44 promote wrap/subprojects/s1/meson.build test cases/unit/44 promote wrap/subprojects/s1/subprojects/ambiguous/meson.build test cases/unit/44 promote wrap/subprojects/s2/meson.build test cases/unit/44 promote wrap/subprojects/s2/subprojects/ambiguous.wrap test cases/unit/45 vscpp17/main.cpp test cases/unit/45 vscpp17/meson.build test cases/unit/46 native dep pkgconfig var/cross_pkgconfig.py test cases/unit/46 native dep pkgconfig var/meson.build test cases/unit/46 native dep pkgconfig var/meson_options.txt test cases/unit/46 native dep pkgconfig var/cross_pkgconfig/dep_tester.pc test cases/unit/46 native dep pkgconfig var/native_pkgconfig/dep_tester.pc test cases/unit/47 native file binary/meson.build test cases/unit/47 native file binary/meson_options.txt test cases/unit/48 reconfigure/main.c test cases/unit/48 reconfigure/meson.build test cases/unit/48 reconfigure/meson_options.txt test cases/unit/49 testsetup default/envcheck.py test cases/unit/49 testsetup default/meson.build test cases/unit/5 compiler detection/compiler wrapper.py test cases/unit/5 compiler detection/meson.build test cases/unit/5 compiler detection/trivial.c test cases/unit/5 compiler detection/trivial.cc test cases/unit/5 compiler detection/trivial.m test cases/unit/5 compiler detection/trivial.mm test cases/unit/50 pkgconfig csharp library/meson.build test cases/unit/50 pkgconfig csharp library/somelib.cs test cases/unit/51 noncross options/meson.build test cases/unit/51 noncross options/prog.c test cases/unit/51 noncross options/ylib.pc test cases/unit/52 ldflagdedup/bob.c test cases/unit/52 ldflagdedup/meson.build test cases/unit/52 ldflagdedup/prog.c test cases/unit/53 pkgconfig static link order/meson.build test cases/unit/54 clang-format/.clang-format test cases/unit/54 clang-format/header_expected_h test cases/unit/54 clang-format/header_orig_h test cases/unit/54 clang-format/meson.build test cases/unit/54 clang-format/prog_expected_c test cases/unit/54 clang-format/prog_orig_c test cases/unit/55 introspect buildoptions/subprojects/projectBad/meson.build test cases/unit/55 introspect buildoptions/subprojects/projectBad/meson_options.txt test cases/unit/56 dedup compiler libs/meson.build test cases/unit/56 dedup compiler libs/app/app.c test cases/unit/56 dedup compiler libs/app/meson.build test cases/unit/56 dedup compiler libs/liba/liba.c test cases/unit/56 dedup compiler libs/liba/liba.h test cases/unit/56 dedup compiler libs/liba/meson.build test cases/unit/56 dedup compiler libs/libb/libb.c test cases/unit/56 dedup compiler libs/libb/libb.h test cases/unit/56 dedup compiler libs/libb/meson.build test cases/unit/57 introspection/meson.build test cases/unit/57 introspection/meson_options.txt test cases/unit/57 introspection/t1.cpp test cases/unit/57 introspection/t2.cpp test cases/unit/57 introspection/t3.cpp test cases/unit/57 introspection/sharedlib/meson.build test cases/unit/57 introspection/sharedlib/shared.cpp test cases/unit/57 introspection/sharedlib/shared.hpp test cases/unit/57 introspection/staticlib/meson.build test cases/unit/57 introspection/staticlib/static.c test cases/unit/57 introspection/staticlib/static.h test cases/unit/58 pkg_config_path option/meson.build test cases/unit/58 pkg_config_path option/build_extra_path/totally_made_up_dep.pc test cases/unit/58 pkg_config_path option/host_extra_path/totally_made_up_dep.pc test cases/unit/59 introspect buildoptions/c_compiler.py test cases/unit/59 introspect buildoptions/main.c test cases/unit/59 introspect buildoptions/meson.build test cases/unit/59 introspect buildoptions/meson_options.txt test cases/unit/59 introspect buildoptions/subprojects/evilFile.txt test cases/unit/59 introspect buildoptions/subprojects/projectA/meson.build test cases/unit/59 introspect buildoptions/subprojects/projectA/meson_options.txt test cases/unit/59 introspect buildoptions/subprojects/projectBad/meson.build test cases/unit/59 introspect buildoptions/subprojects/projectBad/meson_options.txt test cases/unit/6 std override/meson.build test cases/unit/6 std override/prog11.cpp test cases/unit/6 std override/prog98.cpp test cases/unit/6 std override/progp.cpp test cases/unit/60 native file override/crossfile test cases/unit/60 native file override/crossfile2 test cases/unit/60 native file override/meson.build test cases/unit/60 native file override/meson_options.txt test cases/unit/60 native file override/nativefile test cases/unit/61 identity cross/build_wrapper.py test cases/unit/61 identity cross/host_wrapper.py test cases/unit/61 identity cross/meson.build test cases/unit/61 identity cross/stuff.h test cases/unit/62 pkgconfig relative paths/pkgconfig/librelativepath.pc test cases/unit/63 test env does not stack/meson.build test cases/unit/63 test env does not stack/script.py test cases/unit/64 cmake_prefix_path/meson.build test cases/unit/64 cmake_prefix_path/prefix/lib/cmake/mesontest/mesontest-config.cmake test cases/unit/65 cmake parser/meson.build test cases/unit/65 cmake parser/prefix/lib/cmake/mesontest/mesontest-config.cmake test cases/unit/66 alias target/main.c test cases/unit/66 alias target/meson.build test cases/unit/68 static archive stripping/app/appA.c test cases/unit/68 static archive stripping/app/appB.c test cases/unit/68 static archive stripping/app/meson.build test cases/unit/68 static archive stripping/lib/libA.c test cases/unit/68 static archive stripping/lib/libA.h test cases/unit/68 static archive stripping/lib/libB.c test cases/unit/68 static archive stripping/lib/libB.h test cases/unit/68 static archive stripping/lib/meson.build test cases/unit/69 static link/meson.build test cases/unit/69 static link/test1.c test cases/unit/69 static link/test2.c test cases/unit/69 static link/test3.c test cases/unit/69 static link/test4.c test cases/unit/69 static link/test5.c test cases/unit/69 static link/lib/func1.c test cases/unit/69 static link/lib/func10.c test cases/unit/69 static link/lib/func11.c test cases/unit/69 static link/lib/func12.c test cases/unit/69 static link/lib/func14.c test cases/unit/69 static link/lib/func15.c test cases/unit/69 static link/lib/func16.c test cases/unit/69 static link/lib/func17.c test cases/unit/69 static link/lib/func18.c test cases/unit/69 static link/lib/func19.c test cases/unit/69 static link/lib/func2.c test cases/unit/69 static link/lib/func3.c test cases/unit/69 static link/lib/func4.c test cases/unit/69 static link/lib/func5.c test cases/unit/69 static link/lib/func6.c test cases/unit/69 static link/lib/func7.c test cases/unit/69 static link/lib/func8.c test cases/unit/69 static link/lib/func9.c test cases/unit/69 static link/lib/meson.build test cases/unit/69 test env value/meson.build test cases/unit/69 test env value/test.py test cases/unit/7 run installed/meson.build test cases/unit/7 run installed/prog.c test cases/unit/7 run installed/foo/foo.c test cases/unit/7 run installed/foo/meson.build test cases/unit/70 clang-tidy/.clang-tidy test cases/unit/70 clang-tidy/cttest.cpp test cases/unit/70 clang-tidy/meson.build test cases/unit/71 cross/crossfile.in test cases/unit/71 cross/meson.build test cases/unit/71 cross/meson_options.txt test cases/unit/73 wrap file url/meson.build test cases/unit/73 wrap file url/subprojects/foo-patch.tar.xz test cases/unit/73 wrap file url/subprojects/foo.tar.xz test cases/unit/74 summary/meson.build test cases/unit/74 summary/subprojects/sub/meson.build test cases/unit/74 summary/subprojects/sub2/meson.build test cases/unit/8 -L -l order/first.pc test cases/unit/8 -L -l order/meson.build test cases/unit/8 -L -l order/prog.c test cases/unit/8 -L -l order/second.pc test cases/unit/9 d dedup/meson.build test cases/unit/9 d dedup/prog.c test cases/vala/1 basic/meson.build test cases/vala/1 basic/prog.vala test cases/vala/10 mixed sources/meson.build test cases/vala/10 mixed sources/c/foo.c test cases/vala/10 mixed sources/c/meson.build test cases/vala/10 mixed sources/c/writec.py test cases/vala/10 mixed sources/vala/bar.vala test cases/vala/11 generated vapi/installed_files.txt test cases/vala/11 generated vapi/main.vala test cases/vala/11 generated vapi/meson.build test cases/vala/11 generated vapi/libbar/bar.c test cases/vala/11 generated vapi/libbar/bar.h test cases/vala/11 generated vapi/libbar/meson.build test cases/vala/11 generated vapi/libfoo/foo.c test cases/vala/11 generated vapi/libfoo/foo.h test cases/vala/11 generated vapi/libfoo/meson.build test cases/vala/12 custom output/bar.vala test cases/vala/12 custom output/foo.vala test cases/vala/12 custom output/meson.build test cases/vala/13 find library/meson.build test cases/vala/13 find library/test.vala test cases/vala/14 target glib version and gresources/meson.build test cases/vala/14 target glib version and gresources/test.vala test cases/vala/14 target glib version and gresources/gres/meson.build test cases/vala/14 target glib version and gresources/gres/test-resources.xml test cases/vala/14 target glib version and gresources/gres/test.ui test cases/vala/15 static vapi in source tree/meson.build test cases/vala/15 static vapi in source tree/test.vala test cases/vala/15 static vapi in source tree/vapi/config.vapi test cases/vala/16 mixed dependence/app.vala test cases/vala/16 mixed dependence/meson.build test cases/vala/16 mixed dependence/mixer-glue.c test cases/vala/16 mixed dependence/mixer.vala test cases/vala/17 plain consumer/app.c test cases/vala/17 plain consumer/badger.vala test cases/vala/17 plain consumer/meson.build test cases/vala/18 vapi consumed twice/app.vala test cases/vala/18 vapi consumed twice/beer.vala test cases/vala/18 vapi consumed twice/meson.build test cases/vala/18 vapi consumed twice/person.vala test cases/vala/19 genie/meson.build test cases/vala/19 genie/prog.gs test cases/vala/2 multiple files/class1.vala test cases/vala/2 multiple files/class2.vala test cases/vala/2 multiple files/main.vala test cases/vala/2 multiple files/meson.build test cases/vala/20 genie multiple mixed sources/c_test_one.c test cases/vala/20 genie multiple mixed sources/c_test_two.c test cases/vala/20 genie multiple mixed sources/init.gs test cases/vala/20 genie multiple mixed sources/meson.build test cases/vala/20 genie multiple mixed sources/test_one.gs test cases/vala/20 genie multiple mixed sources/test_two.gs test cases/vala/20 genie multiple mixed sources/vala_test_one.vala test cases/vala/20 genie multiple mixed sources/vala_test_two.vala test cases/vala/21 type module/foo.vala test cases/vala/21 type module/meson.build test cases/vala/21 type module/plugin-bar.vala test cases/vala/21 type module/plugin-module.vala test cases/vala/21 type module/plugin.vala test cases/vala/22 same target in directories/Test.vala test cases/vala/22 same target in directories/meson.build test cases/vala/22 same target in directories/prog.vala test cases/vala/22 same target in directories/Subdir/Test.vala test cases/vala/22 same target in directories/Subdir/Subdir2/Test.vala test cases/vala/22 same target in directories/Subdir2/Test.vala test cases/vala/23 thread flags/meson.build test cases/vala/23 thread flags/prog.vala test cases/vala/24 export dynamic shared module/app.vala test cases/vala/24 export dynamic shared module/meson.build test cases/vala/24 export dynamic shared module/module.vala test cases/vala/25 extract_all_objects/meson.build test cases/vala/25 extract_all_objects/prog.vala test cases/vala/26 vala and asm/meson.build test cases/vala/26 vala and asm/prog.vala test cases/vala/26 vala and asm/retval-arm.S test cases/vala/26 vala and asm/retval-x86.S test cases/vala/26 vala and asm/retval-x86_64.S test cases/vala/26 vala and asm/symbol-underscore.h test cases/vala/3 dep/gioprog.vala test cases/vala/3 dep/meson.build test cases/vala/4 config/config.vapi test cases/vala/4 config/meson-something-else.vapi test cases/vala/4 config/meson.build test cases/vala/4 config/prog.vala test cases/vala/5 target glib/GLib.Thread.vala test cases/vala/5 target glib/meson.build test cases/vala/5 target glib/retcode.c test cases/vala/6 static library/installed_files.txt test cases/vala/6 static library/meson.build test cases/vala/6 static library/mylib.vala test cases/vala/6 static library/prog.vala test cases/vala/7 shared library/installed_files.txt test cases/vala/7 shared library/meson.build test cases/vala/7 shared library/lib/meson.build test cases/vala/7 shared library/lib/mylib.vala test cases/vala/7 shared library/prog/meson.build test cases/vala/7 shared library/prog/prog.vala test cases/vala/8 generated sources/installed_files.txt test cases/vala/8 generated sources/meson.build test cases/vala/8 generated sources/dependency-generated/enum-types.c.template test cases/vala/8 generated sources/dependency-generated/enum-types.h.template test cases/vala/8 generated sources/dependency-generated/enums.h test cases/vala/8 generated sources/dependency-generated/lib.vala test cases/vala/8 generated sources/dependency-generated/main.vala test cases/vala/8 generated sources/dependency-generated/meson.build test cases/vala/8 generated sources/dependency-generated/null.c test cases/vala/8 generated sources/onlygen/maingen.in test cases/vala/8 generated sources/onlygen/meson.build test cases/vala/8 generated sources/src/config.vala.in test cases/vala/8 generated sources/src/copy_file.py test cases/vala/8 generated sources/src/meson.build test cases/vala/8 generated sources/src/returncode.in test cases/vala/8 generated sources/src/test.vala test cases/vala/8 generated sources/src/write_wrapper.py test cases/vala/8 generated sources/tools/meson.build test cases/vala/9 gir/foo.vala test cases/vala/9 gir/installed_files.txt test cases/vala/9 gir/meson.build test cases/warning/1 version for string div/meson.build test cases/warning/1 version for string div/a/b.c test cases/wasm/1 basic/hello.cpp test cases/wasm/1 basic/hello.html test cases/wasm/1 basic/meson.build test cases/windows/1 basic/installed_files.txt test cases/windows/1 basic/meson.build test cases/windows/1 basic/prog.c test cases/windows/10 vs module defs generated custom target/meson.build test cases/windows/10 vs module defs generated custom target/prog.c test cases/windows/10 vs module defs generated custom target/subdir/make_def.py test cases/windows/10 vs module defs generated custom target/subdir/meson.build test cases/windows/10 vs module defs generated custom target/subdir/somedll.c test cases/windows/11 exe implib/installed_files.txt test cases/windows/11 exe implib/meson.build test cases/windows/11 exe implib/prog.c test cases/windows/12 resources with custom targets/meson.build test cases/windows/12 resources with custom targets/prog.c test cases/windows/12 resources with custom targets/res/gen-res.py test cases/windows/12 resources with custom targets/res/meson.build test cases/windows/12 resources with custom targets/res/myres.rc.in test cases/windows/12 resources with custom targets/res/myres_static.rc test cases/windows/12 resources with custom targets/res/resource.h test cases/windows/12 resources with custom targets/res/sample.ico test cases/windows/13 test argument extra paths/meson.build test cases/windows/13 test argument extra paths/exe/main.c test cases/windows/13 test argument extra paths/exe/meson.build test cases/windows/13 test argument extra paths/lib/foo.c test cases/windows/13 test argument extra paths/lib/foo.h test cases/windows/13 test argument extra paths/lib/meson.build test cases/windows/13 test argument extra paths/test/meson.build test cases/windows/13 test argument extra paths/test/test_run_exe.py test cases/windows/14 resources with custom target depend_files/meson.build test cases/windows/14 resources with custom target depend_files/prog.c test cases/windows/14 resources with custom target depend_files/ico/gen-ico.py test cases/windows/14 resources with custom target depend_files/ico/meson.build test cases/windows/14 resources with custom target depend_files/ico/sample.ico.in test cases/windows/14 resources with custom target depend_files/res/meson.build test cases/windows/14 resources with custom target depend_files/res/myres.rc test cases/windows/15 resource scripts with duplicate filenames/meson.build test cases/windows/15 resource scripts with duplicate filenames/rsrc.rc test cases/windows/15 resource scripts with duplicate filenames/verify.c test cases/windows/15 resource scripts with duplicate filenames/a/meson.build test cases/windows/15 resource scripts with duplicate filenames/a/rsrc.rc test cases/windows/15 resource scripts with duplicate filenames/b/meson.build test cases/windows/15 resource scripts with duplicate filenames/b/rsrc.rc test cases/windows/15 resource scripts with duplicate filenames/c/meson.build test cases/windows/15 resource scripts with duplicate filenames/c/rsrc.rc test cases/windows/15 resource scripts with duplicate filenames/exe3/meson.build test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/version.rc test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/version.rc test cases/windows/15 resource scripts with duplicate filenames/exe4/meson.build test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/version.rc test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/version.rc test cases/windows/16 gui app/console_prog.c test cases/windows/16 gui app/dummy.c test cases/windows/16 gui app/gui_app_tester.py test cases/windows/16 gui app/gui_prog.c test cases/windows/16 gui app/meson.build test cases/windows/2 winmain/meson.build test cases/windows/2 winmain/prog.c test cases/windows/3 cpp/meson.build test cases/windows/3 cpp/prog.cpp test cases/windows/4 winmaincpp/meson.build test cases/windows/4 winmaincpp/prog.cpp test cases/windows/5 resources/meson.build test cases/windows/5 resources/prog.c test cases/windows/5 resources/inc/meson.build test cases/windows/5 resources/inc/resource/resource.h test cases/windows/5 resources/res/dummy.c test cases/windows/5 resources/res/meson.build test cases/windows/5 resources/res/myres.rc test cases/windows/5 resources/res/sample.ico test cases/windows/6 vs module defs/meson.build test cases/windows/6 vs module defs/prog.c test cases/windows/6 vs module defs/subdir/meson.build test cases/windows/6 vs module defs/subdir/somedll.c test cases/windows/6 vs module defs/subdir/somedll.def test cases/windows/7 dll versioning/copyfile.py test cases/windows/7 dll versioning/exe.orig.c test cases/windows/7 dll versioning/installed_files.txt test cases/windows/7 dll versioning/lib.c test cases/windows/7 dll versioning/meson.build test cases/windows/8 find program/meson.build test cases/windows/8 find program/test-script test cases/windows/8 find program/test-script-ext.py test cases/windows/9 vs module defs generated/meson.build test cases/windows/9 vs module defs generated/prog.c test cases/windows/9 vs module defs generated/subdir/meson.build test cases/windows/9 vs module defs generated/subdir/somedll.c test cases/windows/9 vs module defs generated/subdir/somedll.def.in tools/ac_converter.py tools/boost_names.py tools/cmake2meson.py tools/dircondenser.pymeson-0.53.2/meson.egg-info/dependency_links.txt0000644000175000017500000000000113625242347023205 0ustar jpakkanejpakkane00000000000000 meson-0.53.2/meson.egg-info/entry_points.txt0000644000175000017500000000006513625242347022436 0ustar jpakkanejpakkane00000000000000[console_scripts] meson = mesonbuild.mesonmain:main meson-0.53.2/meson.egg-info/requires.txt0000644000175000017500000000002113625242347021530 0ustar jpakkanejpakkane00000000000000 [progress] tqdm meson-0.53.2/meson.egg-info/top_level.txt0000644000175000017500000000001313625242347021663 0ustar jpakkanejpakkane00000000000000mesonbuild meson-0.53.2/meson.py0000755000175000017500000000201313340206727016012 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys from pathlib import Path # If we're run uninstalled, add the script directory to sys.path to ensure that # we always import the correct mesonbuild modules even if PYTHONPATH is mangled meson_exe = Path(sys.argv[0]).resolve() if (meson_exe.parent / 'mesonbuild').is_dir(): sys.path.insert(0, str(meson_exe.parent)) from mesonbuild import mesonmain if __name__ == '__main__': sys.exit(mesonmain.main()) meson-0.53.2/mesonbuild/0000755000175000017500000000000013625242354016463 5ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/__init__.py0000644000175000017500000000000012650745767020577 0ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/ast/0000755000175000017500000000000013625242354017252 5ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/ast/__init__.py0000644000175000017500000000222613440031012021343 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. __all__ = [ 'AstConditionLevel', 'AstInterpreter', 'AstIDGenerator', 'AstIndentationGenerator', 'AstVisitor', 'AstPrinter', 'IntrospectionInterpreter', 'build_target_functions', ] from .interpreter import AstInterpreter from .introspection import IntrospectionInterpreter, build_target_functions from .visitor import AstVisitor from .postprocess import AstConditionLevel, AstIDGenerator, AstIndentationGenerator from .printer import AstPrinter meson-0.53.2/mesonbuild/ast/interpreter.py0000644000175000017500000003467713612313307022201 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. from .visitor import AstVisitor from .. import interpreterbase, mparser, mesonlib from .. import environment from ..interpreterbase import InvalidArguments, BreakRequest, ContinueRequest from ..mparser import ( ArgumentNode, ArithmeticNode, ArrayNode, AssignmentNode, BaseNode, ElementaryNode, EmptyNode, IdNode, MethodNode, PlusAssignmentNode, TernaryNode, ) import os, sys import typing as T class DontCareObject(interpreterbase.InterpreterObject): pass class MockExecutable(interpreterbase.InterpreterObject): pass class MockStaticLibrary(interpreterbase.InterpreterObject): pass class MockSharedLibrary(interpreterbase.InterpreterObject): pass class MockCustomTarget(interpreterbase.InterpreterObject): pass class MockRunTarget(interpreterbase.InterpreterObject): pass ADD_SOURCE = 0 REMOVE_SOURCE = 1 class AstInterpreter(interpreterbase.InterpreterBase): def __init__(self, source_root: str, subdir: str, visitors: T.Optional[T.List[AstVisitor]] = None): super().__init__(source_root, subdir) self.visitors = visitors if visitors is not None else [] self.visited_subdirs = {} self.assignments = {} self.assign_vals = {} self.reverse_assignment = {} self.funcs.update({'project': self.func_do_nothing, 'test': self.func_do_nothing, 'benchmark': self.func_do_nothing, 'install_headers': self.func_do_nothing, 'install_man': self.func_do_nothing, 'install_data': self.func_do_nothing, 'install_subdir': self.func_do_nothing, 'configuration_data': self.func_do_nothing, 'configure_file': self.func_do_nothing, 'find_program': self.func_do_nothing, 'include_directories': self.func_do_nothing, 'add_global_arguments': self.func_do_nothing, 'add_global_link_arguments': self.func_do_nothing, 'add_project_arguments': self.func_do_nothing, 'add_project_link_arguments': self.func_do_nothing, 'message': self.func_do_nothing, 'generator': self.func_do_nothing, 'error': self.func_do_nothing, 'run_command': self.func_do_nothing, 'assert': self.func_do_nothing, 'subproject': self.func_do_nothing, 'dependency': self.func_do_nothing, 'get_option': self.func_do_nothing, 'join_paths': self.func_do_nothing, 'environment': self.func_do_nothing, 'import': self.func_do_nothing, 'vcs_tag': self.func_do_nothing, 'add_languages': self.func_do_nothing, 'declare_dependency': self.func_do_nothing, 'files': self.func_do_nothing, 'executable': self.func_do_nothing, 'static_library': self.func_do_nothing, 'shared_library': self.func_do_nothing, 'library': self.func_do_nothing, 'build_target': self.func_do_nothing, 'custom_target': self.func_do_nothing, 'run_target': self.func_do_nothing, 'subdir': self.func_subdir, 'set_variable': self.func_do_nothing, 'get_variable': self.func_do_nothing, 'is_disabler': self.func_do_nothing, 'is_variable': self.func_do_nothing, 'disabler': self.func_do_nothing, 'gettext': self.func_do_nothing, 'jar': self.func_do_nothing, 'warning': self.func_do_nothing, 'shared_module': self.func_do_nothing, 'option': self.func_do_nothing, 'both_libraries': self.func_do_nothing, 'add_test_setup': self.func_do_nothing, 'find_library': self.func_do_nothing, 'subdir_done': self.func_do_nothing, 'alias_target': self.func_do_nothing, 'summary': self.func_do_nothing, }) def func_do_nothing(self, node, args, kwargs): return True def load_root_meson_file(self): super().load_root_meson_file() for i in self.visitors: self.ast.accept(i) def func_subdir(self, node, args, kwargs): args = self.flatten_args(args) if len(args) != 1 or not isinstance(args[0], str): sys.stderr.write('Unable to evaluate subdir({}) in AstInterpreter --> Skipping\n'.format(args)) return prev_subdir = self.subdir subdir = os.path.join(prev_subdir, args[0]) absdir = os.path.join(self.source_root, subdir) buildfilename = os.path.join(subdir, environment.build_filename) absname = os.path.join(self.source_root, buildfilename) symlinkless_dir = os.path.realpath(absdir) if symlinkless_dir in self.visited_subdirs: sys.stderr.write('Trying to enter {} which has already been visited --> Skipping\n'.format(args[0])) return self.visited_subdirs[symlinkless_dir] = True if not os.path.isfile(absname): sys.stderr.write('Unable to find build file {} --> Skipping\n'.format(buildfilename)) return with open(absname, encoding='utf8') as f: code = f.read() assert(isinstance(code, str)) try: codeblock = mparser.Parser(code, subdir).parse() except mesonlib.MesonException as me: me.file = buildfilename raise me self.subdir = subdir for i in self.visitors: codeblock.accept(i) self.evaluate_codeblock(codeblock) self.subdir = prev_subdir def method_call(self, node): return True def evaluate_arithmeticstatement(self, cur): self.evaluate_statement(cur.left) self.evaluate_statement(cur.right) return 0 def evaluate_uminusstatement(self, cur): self.evaluate_statement(cur.value) return 0 def evaluate_ternary(self, node): assert(isinstance(node, TernaryNode)) self.evaluate_statement(node.condition) self.evaluate_statement(node.trueblock) self.evaluate_statement(node.falseblock) def evaluate_plusassign(self, node): assert(isinstance(node, PlusAssignmentNode)) if node.var_name not in self.assignments: self.assignments[node.var_name] = [] self.assign_vals[node.var_name] = [] self.assignments[node.var_name] += [node.value] # Save a reference to the value node if hasattr(node.value, 'ast_id'): self.reverse_assignment[node.value.ast_id] = node self.assign_vals[node.var_name] += [self.evaluate_statement(node.value)] def evaluate_indexing(self, node): return 0 def unknown_function_called(self, func_name): pass def reduce_arguments(self, args): if isinstance(args, ArgumentNode): if args.incorrect_order(): raise InvalidArguments('All keyword arguments must be after positional arguments.') return self.flatten_args(args.arguments), args.kwargs else: return self.flatten_args(args), {} def evaluate_comparison(self, node): self.evaluate_statement(node.left) self.evaluate_statement(node.right) return False def evaluate_andstatement(self, cur): self.evaluate_statement(cur.left) self.evaluate_statement(cur.right) return False def evaluate_orstatement(self, cur): self.evaluate_statement(cur.left) self.evaluate_statement(cur.right) return False def evaluate_foreach(self, node): try: self.evaluate_codeblock(node.block) except ContinueRequest: pass except BreakRequest: pass def evaluate_if(self, node): for i in node.ifs: self.evaluate_codeblock(i.block) if not isinstance(node.elseblock, EmptyNode): self.evaluate_codeblock(node.elseblock) def get_variable(self, varname): return 0 def assignment(self, node): assert(isinstance(node, AssignmentNode)) self.assignments[node.var_name] = [node.value] # Save a reference to the value node if hasattr(node.value, 'ast_id'): self.reverse_assignment[node.value.ast_id] = node self.assign_vals[node.var_name] = [self.evaluate_statement(node.value)] # Evaluate the value just in case def resolve_node(self, node: BaseNode, include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.Optional[T.Any]: def quick_resolve(n: BaseNode, loop_detect: T.Optional[T.List[str]] = None) -> T.Any: if loop_detect is None: loop_detect = [] if isinstance(n, IdNode): if n.value in loop_detect or n.value not in self.assignments: return [] return quick_resolve(self.assignments[n.value][0], loop_detect = loop_detect + [n.value]) elif isinstance(n, ElementaryNode): return n.value else: return n if id_loop_detect is None: id_loop_detect = [] result = None if not isinstance(node, BaseNode): return None assert(hasattr(node, 'ast_id')) if node.ast_id in id_loop_detect: return None # Loop detected id_loop_detect += [node.ast_id] # Try to evealuate the value of the node if isinstance(node, IdNode): result = quick_resolve(node) elif isinstance(node, ElementaryNode): result = node.value elif isinstance(node, ArrayNode): result = [x for x in node.args.arguments] elif isinstance(node, ArgumentNode): result = [x for x in node.arguments] elif isinstance(node, ArithmeticNode): if node.operation != 'add': return None # Only handle string and array concats l = quick_resolve(node.left) r = quick_resolve(node.right) if isinstance(l, str) and isinstance(r, str): result = l + r # String concatenation detected else: result = self.flatten_args(l, include_unknown_args, id_loop_detect) + self.flatten_args(r, include_unknown_args, id_loop_detect) elif isinstance(node, MethodNode): src = quick_resolve(node.source_object) margs = self.flatten_args(node.args, include_unknown_args, id_loop_detect) try: if isinstance(src, str): result = self.string_method_call(src, node.name, margs) elif isinstance(src, bool): result = self.bool_method_call(src, node.name, margs) elif isinstance(src, int): result = self.int_method_call(src, node.name, margs) elif isinstance(src, list): result = self.array_method_call(src, node.name, margs) elif isinstance(src, dict): result = self.dict_method_call(src, node.name, margs) except mesonlib.MesonException: return None # Ensure that the result is fully resolved (no more nodes) if isinstance(result, BaseNode): result = self.resolve_node(result, include_unknown_args, id_loop_detect) elif isinstance(result, list): new_res = [] for i in result: if isinstance(i, BaseNode): resolved = self.resolve_node(i, include_unknown_args, id_loop_detect) if resolved is not None: new_res += self.flatten_args(resolved, include_unknown_args, id_loop_detect) else: new_res += [i] result = new_res return result def flatten_args(self, args: T.Any, include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.List[T.Any]: # Make sure we are always dealing with lists if not isinstance(args, list): args = [args] flattend_args = [] # Resolve the contents of args for i in args: if isinstance(i, BaseNode): resolved = self.resolve_node(i, include_unknown_args, id_loop_detect) if resolved is not None: if not isinstance(resolved, list): resolved = [resolved] flattend_args += resolved elif isinstance(i, (str, bool, int, float)) or include_unknown_args: flattend_args += [i] return flattend_args def flatten_kwargs(self, kwargs: object, include_unknown_args: bool = False): flattend_kwargs = {} for key, val in kwargs.items(): if isinstance(val, BaseNode): resolved = self.resolve_node(val, include_unknown_args) if resolved is not None: flattend_kwargs[key] = resolved elif isinstance(val, (str, bool, int, float)) or include_unknown_args: flattend_kwargs[key] = val return flattend_kwargs meson-0.53.2/mesonbuild/ast/introspection.py0000644000175000017500000003102113602226377022523 0ustar jpakkanejpakkane00000000000000# Copyright 2018 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool from . import AstInterpreter from .. import compilers, environment, mesonlib, optinterpreter from .. import coredata as cdata from ..mesonlib import MachineChoice from ..interpreterbase import InvalidArguments from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode import os build_target_functions = ['executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries'] class IntrospectionHelper: # mimic an argparse namespace def __init__(self, cross_file): self.cross_file = cross_file self.native_file = None self.cmd_line_options = {} class IntrospectionInterpreter(AstInterpreter): # Interpreter to detect the options without a build directory # Most of the code is stolen from interpreter.Interpreter def __init__(self, source_root, subdir, backend, visitors=None, cross_file=None, subproject='', subproject_dir='subprojects', env=None): visitors = visitors if visitors is not None else [] super().__init__(source_root, subdir, visitors=visitors) options = IntrospectionHelper(cross_file) self.cross_file = cross_file if env is None: self.environment = environment.Environment(source_root, None, options) else: self.environment = env self.subproject = subproject self.subproject_dir = subproject_dir self.coredata = self.environment.get_coredata() self.option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt') self.backend = backend self.default_options = {'backend': self.backend} self.project_data = {} self.targets = [] self.dependencies = [] self.project_node = None self.funcs.update({ 'add_languages': self.func_add_languages, 'dependency': self.func_dependency, 'executable': self.func_executable, 'jar': self.func_jar, 'library': self.func_library, 'project': self.func_project, 'shared_library': self.func_shared_lib, 'shared_module': self.func_shared_module, 'static_library': self.func_static_lib, 'both_libraries': self.func_both_lib, }) def func_project(self, node, args, kwargs): if self.project_node: raise InvalidArguments('Second call to project()') self.project_node = node if len(args) < 1: raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.') proj_name = args[0] proj_vers = kwargs.get('version', 'undefined') proj_langs = self.flatten_args(args[1:]) if isinstance(proj_vers, ElementaryNode): proj_vers = proj_vers.value if not isinstance(proj_vers, str): proj_vers = 'undefined' self.project_data = {'descriptive_name': proj_name, 'version': proj_vers} if os.path.exists(self.option_file): oi = optinterpreter.OptionInterpreter(self.subproject) oi.process(self.option_file) self.coredata.merge_user_options(oi.options) def_opts = self.flatten_args(kwargs.get('default_options', [])) self.project_default_options = mesonlib.stringlistify(def_opts) self.project_default_options = cdata.create_options_dict(self.project_default_options) self.default_options.update(self.project_default_options) self.coredata.set_default_options(self.default_options, self.subproject, self.environment) if not self.is_subproject() and 'subproject_dir' in kwargs: spdirname = kwargs['subproject_dir'] if isinstance(spdirname, ElementaryNode): self.subproject_dir = spdirname.value if not self.is_subproject(): self.project_data['subprojects'] = [] subprojects_dir = os.path.join(self.source_root, self.subproject_dir) if os.path.isdir(subprojects_dir): for i in os.listdir(subprojects_dir): if os.path.isdir(os.path.join(subprojects_dir, i)): self.do_subproject(i) self.coredata.init_backend_options(self.backend) options = {k: v for k, v in self.environment.cmd_line_options.items() if k.startswith('backend_')} self.coredata.set_options(options) self.func_add_languages(None, proj_langs, None) def do_subproject(self, dirname): subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir) subpr = os.path.join(subproject_dir_abs, dirname) try: subi = IntrospectionInterpreter(subpr, '', self.backend, cross_file=self.cross_file, subproject=dirname, subproject_dir=self.subproject_dir, env=self.environment, visitors=self.visitors) subi.analyze() subi.project_data['name'] = dirname self.project_data['subprojects'] += [subi.project_data] except (mesonlib.MesonException, RuntimeError): return def func_add_languages(self, node, args, kwargs): args = self.flatten_args(args) for for_machine in [MachineChoice.BUILD, MachineChoice.HOST]: for lang in sorted(args, key=compilers.sort_clink): lang = lang.lower() if lang not in self.coredata.compilers[for_machine]: self.environment.detect_compiler_for(lang, for_machine) def func_dependency(self, node, args, kwargs): args = self.flatten_args(args) kwargs = self.flatten_kwargs(kwargs) if not args: return name = args[0] has_fallback = 'fallback' in kwargs required = kwargs.get('required', True) version = kwargs.get('version', []) if not isinstance(version, list): version = [version] condition_level = node.condition_level if hasattr(node, 'condition_level') else 0 if isinstance(required, ElementaryNode): required = required.value if not isinstance(required, bool): required = False self.dependencies += [{ 'name': name, 'required': required, 'version': version, 'has_fallback': has_fallback, 'conditional': condition_level > 0, 'node': node, }] def build_target(self, node, args, kwargs, targetclass): args = self.flatten_args(args) if not args or not isinstance(args[0], str): return name = args[0] srcqueue = [node] # Process the sources BEFORE flattening the kwargs, to preserve the original nodes if 'sources' in kwargs: srcqueue += mesonlib.listify(kwargs['sources']) kwargs = self.flatten_kwargs(kwargs, True) source_nodes = [] while srcqueue: curr = srcqueue.pop(0) arg_node = None assert(isinstance(curr, BaseNode)) if isinstance(curr, FunctionNode): arg_node = curr.args elif isinstance(curr, ArrayNode): arg_node = curr.args elif isinstance(curr, IdNode): # Try to resolve the ID and append the node to the queue var_name = curr.value if var_name in self.assignments and self.assignments[var_name]: tmp_node = self.assignments[var_name][0] if isinstance(tmp_node, (ArrayNode, IdNode, FunctionNode)): srcqueue += [tmp_node] elif isinstance(curr, ArithmeticNode): srcqueue += [curr.left, curr.right] if arg_node is None: continue arg_nodes = arg_node.arguments.copy() # Pop the first element if the function is a build target function if isinstance(curr, FunctionNode) and curr.func_name in build_target_functions: arg_nodes.pop(0) elemetary_nodes = [x for x in arg_nodes if isinstance(x, (str, StringNode))] srcqueue += [x for x in arg_nodes if isinstance(x, (FunctionNode, ArrayNode, IdNode, ArithmeticNode))] if elemetary_nodes: source_nodes += [curr] # Make sure nothing can crash when creating the build class kwargs_reduced = {k: v for k, v in kwargs.items() if k in targetclass.known_kwargs and k in ['install', 'build_by_default', 'build_always']} kwargs_reduced = {k: v.value if isinstance(v, ElementaryNode) else v for k, v in kwargs_reduced.items()} kwargs_reduced = {k: v for k, v in kwargs_reduced.items() if not isinstance(v, BaseNode)} for_machine = MachineChoice.HOST objects = [] empty_sources = [] # Passing the unresolved sources list causes errors target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, objects, self.environment, kwargs_reduced) new_target = { 'name': target.get_basename(), 'id': target.get_id(), 'type': target.get_typename(), 'defined_in': os.path.normpath(os.path.join(self.source_root, self.subdir, environment.build_filename)), 'subdir': self.subdir, 'build_by_default': target.build_by_default, 'installed': target.should_install(), 'outputs': target.get_outputs(), 'sources': source_nodes, 'kwargs': kwargs, 'node': node, } self.targets += [new_target] return new_target def build_library(self, node, args, kwargs): default_library = self.coredata.get_builtin_option('default_library') if default_library == 'shared': return self.build_target(node, args, kwargs, SharedLibrary) elif default_library == 'static': return self.build_target(node, args, kwargs, StaticLibrary) elif default_library == 'both': return self.build_target(node, args, kwargs, SharedLibrary) def func_executable(self, node, args, kwargs): return self.build_target(node, args, kwargs, Executable) def func_static_lib(self, node, args, kwargs): return self.build_target(node, args, kwargs, StaticLibrary) def func_shared_lib(self, node, args, kwargs): return self.build_target(node, args, kwargs, SharedLibrary) def func_both_lib(self, node, args, kwargs): return self.build_target(node, args, kwargs, SharedLibrary) def func_shared_module(self, node, args, kwargs): return self.build_target(node, args, kwargs, SharedModule) def func_library(self, node, args, kwargs): return self.build_library(node, args, kwargs) def func_jar(self, node, args, kwargs): return self.build_target(node, args, kwargs, Jar) def func_build_target(self, node, args, kwargs): if 'target_type' not in kwargs: return target_type = kwargs.pop('target_type') if isinstance(target_type, ElementaryNode): target_type = target_type.value if target_type == 'executable': return self.build_target(node, args, kwargs, Executable) elif target_type == 'shared_library': return self.build_target(node, args, kwargs, SharedLibrary) elif target_type == 'static_library': return self.build_target(node, args, kwargs, StaticLibrary) elif target_type == 'both_libraries': return self.build_target(node, args, kwargs, SharedLibrary) elif target_type == 'library': return self.build_library(node, args, kwargs) elif target_type == 'jar': return self.build_target(node, args, kwargs, Jar) def is_subproject(self): return self.subproject != '' def analyze(self): self.load_root_meson_file() self.sanity_check_ast() self.parse_project() self.run() meson-0.53.2/mesonbuild/ast/postprocess.py0000644000175000017500000000722613440031012022175 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool from . import AstVisitor from .. import mparser class AstIndentationGenerator(AstVisitor): def __init__(self): self.level = 0 def visit_default_func(self, node: mparser.BaseNode): # Store the current level in the node node.level = self.level def visit_ArrayNode(self, node: mparser.ArrayNode): self.visit_default_func(node) self.level += 1 node.args.accept(self) self.level -= 1 def visit_DictNode(self, node: mparser.DictNode): self.visit_default_func(node) self.level += 1 node.args.accept(self) self.level -= 1 def visit_MethodNode(self, node: mparser.MethodNode): self.visit_default_func(node) node.source_object.accept(self) self.level += 1 node.args.accept(self) self.level -= 1 def visit_FunctionNode(self, node: mparser.FunctionNode): self.visit_default_func(node) self.level += 1 node.args.accept(self) self.level -= 1 def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode): self.visit_default_func(node) self.level += 1 node.items.accept(self) node.block.accept(self) self.level -= 1 def visit_IfClauseNode(self, node: mparser.IfClauseNode): self.visit_default_func(node) for i in node.ifs: i.accept(self) if node.elseblock: self.level += 1 node.elseblock.accept(self) self.level -= 1 def visit_IfNode(self, node: mparser.IfNode): self.visit_default_func(node) self.level += 1 node.condition.accept(self) node.block.accept(self) self.level -= 1 class AstIDGenerator(AstVisitor): def __init__(self): self.counter = {} def visit_default_func(self, node: mparser.BaseNode): name = type(node).__name__ if name not in self.counter: self.counter[name] = 0 node.ast_id = name + '#' + str(self.counter[name]) self.counter[name] += 1 class AstConditionLevel(AstVisitor): def __init__(self): self.condition_level = 0 def visit_default_func(self, node: mparser.BaseNode): node.condition_level = self.condition_level def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode): self.visit_default_func(node) self.condition_level += 1 node.items.accept(self) node.block.accept(self) self.condition_level -= 1 def visit_IfClauseNode(self, node: mparser.IfClauseNode): self.visit_default_func(node) for i in node.ifs: i.accept(self) if node.elseblock: self.condition_level += 1 node.elseblock.accept(self) self.condition_level -= 1 def visit_IfNode(self, node: mparser.IfNode): self.visit_default_func(node) self.condition_level += 1 node.condition.accept(self) node.block.accept(self) self.condition_level -= 1 meson-0.53.2/mesonbuild/ast/printer.py0000644000175000017500000001534713602226377021323 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool from .. import mparser from . import AstVisitor import re arithmic_map = { 'add': '+', 'sub': '-', 'mod': '%', 'mul': '*', 'div': '/' } class AstPrinter(AstVisitor): def __init__(self, indent: int = 2, arg_newline_cutoff: int = 5): self.result = '' self.indent = indent self.arg_newline_cutoff = arg_newline_cutoff self.ci = '' self.is_newline = True self.last_level = 0 def post_process(self): self.result = re.sub(r'\s+\n', '\n', self.result) def append(self, data: str, node: mparser.BaseNode): level = 0 if node and hasattr(node, 'level'): level = node.level else: level = self.last_level self.last_level = level if self.is_newline: self.result += ' ' * (level * self.indent) self.result += data self.is_newline = False def append_padded(self, data: str, node: mparser.BaseNode): if self.result[-1] not in [' ', '\n']: data = ' ' + data self.append(data + ' ', node) def newline(self): self.result += '\n' self.is_newline = True def visit_BooleanNode(self, node: mparser.BooleanNode): self.append('true' if node.value else 'false', node) def visit_IdNode(self, node: mparser.IdNode): self.append(node.value, node) def visit_NumberNode(self, node: mparser.NumberNode): self.append(str(node.value), node) def visit_StringNode(self, node: mparser.StringNode): self.append("'" + node.value + "'", node) def visit_ContinueNode(self, node: mparser.ContinueNode): self.append('continue', node) def visit_BreakNode(self, node: mparser.BreakNode): self.append('break', node) def visit_ArrayNode(self, node: mparser.ArrayNode): self.append('[', node) node.args.accept(self) self.append(']', node) def visit_DictNode(self, node: mparser.DictNode): self.append('{', node) node.args.accept(self) self.append('}', node) def visit_OrNode(self, node: mparser.OrNode): node.left.accept(self) self.append_padded('or', node) node.right.accept(self) def visit_AndNode(self, node: mparser.AndNode): node.left.accept(self) self.append_padded('and', node) node.right.accept(self) def visit_ComparisonNode(self, node: mparser.ComparisonNode): node.left.accept(self) self.append_padded(node.ctype, node) node.right.accept(self) def visit_ArithmeticNode(self, node: mparser.ArithmeticNode): node.left.accept(self) self.append_padded(arithmic_map[node.operation], node) node.right.accept(self) def visit_NotNode(self, node: mparser.NotNode): self.append_padded('not', node) node.value.accept(self) def visit_CodeBlockNode(self, node: mparser.CodeBlockNode): for i in node.lines: i.accept(self) self.newline() def visit_IndexNode(self, node: mparser.IndexNode): node.iobject.accept(self) self.append('[', node) node.index.accept(self) self.append(']', node) def visit_MethodNode(self, node: mparser.MethodNode): node.source_object.accept(self) self.append('.' + node.name + '(', node) node.args.accept(self) self.append(')', node) def visit_FunctionNode(self, node: mparser.FunctionNode): self.append(node.func_name + '(', node) node.args.accept(self) self.append(')', node) def visit_AssignmentNode(self, node: mparser.AssignmentNode): self.append(node.var_name + ' = ', node) node.value.accept(self) def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode): self.append(node.var_name + ' += ', node) node.value.accept(self) def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode): varnames = [x.value for x in node.varnames] self.append_padded('foreach', node) self.append_padded(', '.join(varnames), node) self.append_padded(':', node) node.items.accept(self) self.newline() node.block.accept(self) self.append('endforeach', node) def visit_IfClauseNode(self, node: mparser.IfClauseNode): prefix = '' for i in node.ifs: self.append_padded(prefix + 'if', node) prefix = 'el' i.accept(self) if node.elseblock: self.append('else', node) node.elseblock.accept(self) self.append('endif', node) def visit_UMinusNode(self, node: mparser.UMinusNode): self.append_padded('-', node) node.value.accept(self) def visit_IfNode(self, node: mparser.IfNode): node.condition.accept(self) self.newline() node.block.accept(self) def visit_TernaryNode(self, node: mparser.TernaryNode): node.condition.accept(self) self.append_padded('?', node) node.trueblock.accept(self) self.append_padded(':', node) node.falseblock.accept(self) def visit_ArgumentNode(self, node: mparser.ArgumentNode): break_args = (len(node.arguments) + len(node.kwargs)) > self.arg_newline_cutoff for i in node.arguments + list(node.kwargs.values()): if not isinstance(i, (mparser.ElementaryNode, mparser.IndexNode)): break_args = True if break_args: self.newline() for i in node.arguments: i.accept(self) self.append(', ', node) if break_args: self.newline() for key, val in node.kwargs.items(): if isinstance(key, str): self.append(key, node) else: key.accept(self) self.append_padded(':', node) val.accept(self) self.append(', ', node) if break_args: self.newline() if break_args: self.result = re.sub(r', \n$', '\n', self.result) else: self.result = re.sub(r', $', '', self.result) meson-0.53.2/mesonbuild/ast/visitor.py0000644000175000017500000001071713531533273021330 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool from .. import mparser class AstVisitor: def __init__(self): pass def visit_default_func(self, node: mparser.BaseNode): pass def visit_BooleanNode(self, node: mparser.BooleanNode): self.visit_default_func(node) def visit_IdNode(self, node: mparser.IdNode): self.visit_default_func(node) def visit_NumberNode(self, node: mparser.NumberNode): self.visit_default_func(node) def visit_StringNode(self, node: mparser.StringNode): self.visit_default_func(node) def visit_ContinueNode(self, node: mparser.ContinueNode): self.visit_default_func(node) def visit_BreakNode(self, node: mparser.BreakNode): self.visit_default_func(node) def visit_ArrayNode(self, node: mparser.ArrayNode): self.visit_default_func(node) node.args.accept(self) def visit_DictNode(self, node: mparser.DictNode): self.visit_default_func(node) node.args.accept(self) def visit_EmptyNode(self, node: mparser.EmptyNode): self.visit_default_func(node) def visit_OrNode(self, node: mparser.OrNode): self.visit_default_func(node) node.left.accept(self) node.right.accept(self) def visit_AndNode(self, node: mparser.AndNode): self.visit_default_func(node) node.left.accept(self) node.right.accept(self) def visit_ComparisonNode(self, node: mparser.ComparisonNode): self.visit_default_func(node) node.left.accept(self) node.right.accept(self) def visit_ArithmeticNode(self, node: mparser.ArithmeticNode): self.visit_default_func(node) node.left.accept(self) node.right.accept(self) def visit_NotNode(self, node: mparser.NotNode): self.visit_default_func(node) node.value.accept(self) def visit_CodeBlockNode(self, node: mparser.CodeBlockNode): self.visit_default_func(node) for i in node.lines: i.accept(self) def visit_IndexNode(self, node: mparser.IndexNode): self.visit_default_func(node) node.iobject.accept(self) node.index.accept(self) def visit_MethodNode(self, node: mparser.MethodNode): self.visit_default_func(node) node.source_object.accept(self) node.args.accept(self) def visit_FunctionNode(self, node: mparser.FunctionNode): self.visit_default_func(node) node.args.accept(self) def visit_AssignmentNode(self, node: mparser.AssignmentNode): self.visit_default_func(node) node.value.accept(self) def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode): self.visit_default_func(node) node.value.accept(self) def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode): self.visit_default_func(node) node.items.accept(self) node.block.accept(self) def visit_IfClauseNode(self, node: mparser.IfClauseNode): self.visit_default_func(node) for i in node.ifs: i.accept(self) if node.elseblock: node.elseblock.accept(self) def visit_UMinusNode(self, node: mparser.UMinusNode): self.visit_default_func(node) node.value.accept(self) def visit_IfNode(self, node: mparser.IfNode): self.visit_default_func(node) node.condition.accept(self) node.block.accept(self) def visit_TernaryNode(self, node: mparser.TernaryNode): self.visit_default_func(node) node.condition.accept(self) node.trueblock.accept(self) node.falseblock.accept(self) def visit_ArgumentNode(self, node: mparser.ArgumentNode): self.visit_default_func(node) for i in node.arguments: i.accept(self) for val in node.kwargs.values(): val.accept(self) meson-0.53.2/mesonbuild/backend/0000755000175000017500000000000013625242354020052 5ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/backend/__init__.py0000644000175000017500000000000012650745767022166 0ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/backend/backends.py0000644000175000017500000017142313612313307022177 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os, pickle, re import textwrap from .. import build from .. import dependencies from .. import mesonlib from .. import mlog import json import subprocess from ..mesonlib import MachineChoice, MesonException, OrderedSet, OptionOverrideProxy from ..mesonlib import classify_unity_sources from ..mesonlib import File from ..compilers import CompilerArgs, VisualStudioLikeCompiler from collections import OrderedDict import shlex from functools import lru_cache import typing as T class CleanTrees: ''' Directories outputted by custom targets that have to be manually cleaned because on Linux `ninja clean` only deletes empty directories. ''' def __init__(self, build_dir, trees): self.build_dir = build_dir self.trees = trees class InstallData: def __init__(self, source_dir, build_dir, prefix, strip_bin, install_umask, mesonintrospect): self.source_dir = source_dir self.build_dir = build_dir self.prefix = prefix self.strip_bin = strip_bin self.install_umask = install_umask self.targets = [] self.headers = [] self.man = [] self.data = [] self.po_package_name = '' self.po = [] self.install_scripts = [] self.install_subdirs = [] self.mesonintrospect = mesonintrospect class TargetInstallData: def __init__(self, fname, outdir, aliases, strip, install_name_mappings, install_rpath, install_mode, optional=False): self.fname = fname self.outdir = outdir self.aliases = aliases self.strip = strip self.install_name_mappings = install_name_mappings self.install_rpath = install_rpath self.install_mode = install_mode self.optional = optional class ExecutableSerialisation: def __init__(self, cmd_args, env=None, exe_wrapper=None, workdir=None, extra_paths=None, capture=None): self.cmd_args = cmd_args self.env = env or {} if exe_wrapper is not None: assert(isinstance(exe_wrapper, dependencies.ExternalProgram)) self.exe_runner = exe_wrapper self.workdir = workdir self.extra_paths = extra_paths self.capture = capture class TestSerialisation: def __init__(self, name: str, project: str, suite: str, fname: T.List[str], is_cross_built: bool, exe_wrapper: T.Optional[build.Executable], needs_exe_wrapper: bool, is_parallel: bool, cmd_args: T.List[str], env: build.EnvironmentVariables, should_fail: bool, timeout: T.Optional[int], workdir: T.Optional[str], extra_paths: T.List[str], protocol: str, priority: int): self.name = name self.project_name = project self.suite = suite self.fname = fname self.is_cross_built = is_cross_built if exe_wrapper is not None: assert(isinstance(exe_wrapper, dependencies.ExternalProgram)) self.exe_runner = exe_wrapper self.is_parallel = is_parallel self.cmd_args = cmd_args self.env = env self.should_fail = should_fail self.timeout = timeout self.workdir = workdir self.extra_paths = extra_paths self.protocol = protocol self.priority = priority self.needs_exe_wrapper = needs_exe_wrapper def get_backend_from_name(backend, build): if backend == 'ninja': from . import ninjabackend return ninjabackend.NinjaBackend(build) elif backend == 'vs': from . import vs2010backend return vs2010backend.autodetect_vs_version(build) elif backend == 'vs2010': from . import vs2010backend return vs2010backend.Vs2010Backend(build) elif backend == 'vs2015': from . import vs2015backend return vs2015backend.Vs2015Backend(build) elif backend == 'vs2017': from . import vs2017backend return vs2017backend.Vs2017Backend(build) elif backend == 'vs2019': from . import vs2019backend return vs2019backend.Vs2019Backend(build) elif backend == 'xcode': from . import xcodebackend return xcodebackend.XCodeBackend(build) return None # This class contains the basic functionality that is needed by all backends. # Feel free to move stuff in and out of it as you see fit. class Backend: def __init__(self, build): # Make it possible to construct a dummy backend # This is used for introspection without a build directory if build is None: self.environment = None return self.build = build self.environment = build.environment self.processed_targets = {} self.build_dir = self.environment.get_build_dir() self.source_dir = self.environment.get_source_dir() self.build_to_src = mesonlib.relpath(self.environment.get_source_dir(), self.environment.get_build_dir()) def get_target_filename(self, t): if isinstance(t, build.CustomTarget): if len(t.get_outputs()) != 1: mlog.warning('custom_target {!r} has more than one output! ' 'Using the first one.'.format(t.name)) filename = t.get_outputs()[0] elif isinstance(t, build.CustomTargetIndex): filename = t.get_outputs()[0] else: assert(isinstance(t, build.BuildTarget)) filename = t.get_filename() return os.path.join(self.get_target_dir(t), filename) def get_target_filename_abs(self, target): return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target)) def get_builtin_options_for_target(self, target): return OptionOverrideProxy(target.option_overrides, self.environment.coredata.builtins) def get_base_options_for_target(self, target): return OptionOverrideProxy(target.option_overrides, self.environment.coredata.builtins, self.environment.coredata.base_options) def get_compiler_options_for_target(self, target): return OptionOverrideProxy( target.option_overrides, self.environment.coredata.compiler_options[target.for_machine]) def get_option_for_target(self, option_name, target): if option_name in target.option_overrides: override = target.option_overrides[option_name] return self.environment.coredata.validate_option_value(option_name, override) return self.environment.coredata.get_builtin_option(option_name) def get_target_filename_for_linking(self, target): # On some platforms (msvc for instance), the file that is used for # dynamic linking is not the same as the dynamic library itself. This # file is called an import library, and we want to link against that. # On all other platforms, we link to the library directly. if isinstance(target, build.SharedLibrary): link_lib = target.get_import_filename() or target.get_filename() return os.path.join(self.get_target_dir(target), link_lib) elif isinstance(target, build.StaticLibrary): return os.path.join(self.get_target_dir(target), target.get_filename()) elif isinstance(target, (build.CustomTarget, build.CustomTargetIndex)): if not target.is_linkable_target(): raise MesonException('Tried to link against custom target "%s", which is not linkable.' % target.name) return os.path.join(self.get_target_dir(target), target.get_filename()) elif isinstance(target, build.Executable): if target.import_filename: return os.path.join(self.get_target_dir(target), target.get_import_filename()) else: return None raise AssertionError('BUG: Tried to link to {!r} which is not linkable'.format(target)) @lru_cache(maxsize=None) def get_target_dir(self, target): if self.environment.coredata.get_builtin_option('layout') == 'mirror': dirname = target.get_subdir() else: dirname = 'meson-out' return dirname def get_target_dir_relative_to(self, t, o): '''Get a target dir relative to another target's directory''' target_dir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(t)) othert_dir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(o)) return os.path.relpath(target_dir, othert_dir) def get_target_source_dir(self, target): # if target dir is empty, avoid extraneous trailing / from os.path.join() target_dir = self.get_target_dir(target) if target_dir: return os.path.join(self.build_to_src, target_dir) return self.build_to_src def get_target_private_dir(self, target): return os.path.join(self.get_target_dir(target), target.get_id()) def get_target_private_dir_abs(self, target): return os.path.join(self.environment.get_build_dir(), self.get_target_private_dir(target)) @lru_cache(maxsize=None) def get_target_generated_dir(self, target, gensrc, src): """ Takes a BuildTarget, a generator source (CustomTarget or GeneratedList), and a generated source filename. Returns the full path of the generated source relative to the build root """ # CustomTarget generators output to the build dir of the CustomTarget if isinstance(gensrc, (build.CustomTarget, build.CustomTargetIndex)): return os.path.join(self.get_target_dir(gensrc), src) # GeneratedList generators output to the private build directory of the # target that the GeneratedList is used in return os.path.join(self.get_target_private_dir(target), src) def get_unity_source_file(self, target, suffix): # There is a potential conflict here, but it is unlikely that # anyone both enables unity builds and has a file called foo-unity.cpp. osrc = target.name + '-unity.' + suffix return mesonlib.File.from_built_file(self.get_target_private_dir(target), osrc) def generate_unity_files(self, target, unity_src): abs_files = [] result = [] compsrcs = classify_unity_sources(target.compilers.values(), unity_src) def init_language_file(suffix): unity_src = self.get_unity_source_file(target, suffix) outfileabs = unity_src.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) outfileabs_tmp = outfileabs + '.tmp' abs_files.append(outfileabs) outfileabs_tmp_dir = os.path.dirname(outfileabs_tmp) if not os.path.exists(outfileabs_tmp_dir): os.makedirs(outfileabs_tmp_dir) result.append(unity_src) return open(outfileabs_tmp, 'w') # For each language, generate a unity source file and return the list for comp, srcs in compsrcs.items(): with init_language_file(comp.get_default_suffix()) as ofile: for src in srcs: ofile.write('#include<%s>\n' % src) [mesonlib.replace_if_different(x, x + '.tmp') for x in abs_files] return result def relpath(self, todir, fromdir): return os.path.relpath(os.path.join('dummyprefixdir', todir), os.path.join('dummyprefixdir', fromdir)) def flatten_object_list(self, target, proj_dir_to_build_root=''): obj_list = self._flatten_object_list(target, target.get_objects(), proj_dir_to_build_root) return list(dict.fromkeys(obj_list)) def _flatten_object_list(self, target, objects, proj_dir_to_build_root): obj_list = [] for obj in objects: if isinstance(obj, str): o = os.path.join(proj_dir_to_build_root, self.build_to_src, target.get_subdir(), obj) obj_list.append(o) elif isinstance(obj, mesonlib.File): obj_list.append(obj.rel_to_builddir(self.build_to_src)) elif isinstance(obj, build.ExtractedObjects): if obj.recursive: obj_list += self._flatten_object_list(obj.target, obj.objlist, proj_dir_to_build_root) obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root) else: raise MesonException('Unknown data type in object list.') return obj_list def as_meson_exe_cmdline(self, tname, exe, cmd_args, workdir=None, for_machine=MachineChoice.BUILD, extra_bdeps=None, capture=None, force_serialize=False): ''' Serialize an executable for running with a generator or a custom target ''' import hashlib machine = self.environment.machines[for_machine] if machine.is_windows() or machine.is_cygwin(): extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps or []) else: extra_paths = [] if isinstance(exe, dependencies.ExternalProgram): exe_cmd = exe.get_command() exe_for_machine = exe.for_machine elif isinstance(exe, (build.BuildTarget, build.CustomTarget)): exe_cmd = [self.get_target_filename_abs(exe)] exe_for_machine = exe.for_machine else: exe_cmd = [exe] exe_for_machine = MachineChoice.BUILD is_cross_built = not self.environment.machines.matches_build_machine(exe_for_machine) if is_cross_built and self.environment.need_exe_wrapper(): exe_wrapper = self.environment.get_exe_wrapper() if not exe_wrapper.found(): msg = 'The exe_wrapper {!r} defined in the cross file is ' \ 'needed by target {!r}, but was not found. Please ' \ 'check the command and/or add it to PATH.' raise MesonException(msg.format(exe_wrapper.name, tname)) else: if exe_cmd[0].endswith('.jar'): exe_cmd = ['java', '-jar'] + exe_cmd elif exe_cmd[0].endswith('.exe') and not (mesonlib.is_windows() or mesonlib.is_cygwin()): exe_cmd = ['mono'] + exe_cmd exe_wrapper = None force_serialize = force_serialize or extra_paths or workdir or \ exe_wrapper or any('\n' in c for c in cmd_args) if not force_serialize: if not capture: return None return (self.environment.get_build_command() + ['--internal', 'exe', '--capture', capture, '--'] + exe_cmd + cmd_args) workdir = workdir or self.environment.get_build_dir() env = {} if isinstance(exe, (dependencies.ExternalProgram, build.BuildTarget, build.CustomTarget)): basename = exe.name else: basename = os.path.basename(exe) # Can't just use exe.name here; it will likely be run more than once # Take a digest of the cmd args, env, workdir, and capture. This avoids # collisions and also makes the name deterministic over regenerations # which avoids a rebuild by Ninja because the cmdline stays the same. data = bytes(str(sorted(env.items())) + str(cmd_args) + str(workdir) + str(capture), encoding='utf-8') digest = hashlib.sha1(data).hexdigest() scratch_file = 'meson_exe_{0}_{1}.dat'.format(basename, digest) exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file) with open(exe_data, 'wb') as f: es = ExecutableSerialisation(exe_cmd + cmd_args, env, exe_wrapper, workdir, extra_paths, capture) pickle.dump(es, f) return self.environment.get_build_command() + ['--internal', 'exe', '--unpickle', exe_data] def serialize_tests(self): test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') with open(test_data, 'wb') as datafile: self.write_test_file(datafile) benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat') with open(benchmark_data, 'wb') as datafile: self.write_benchmark_file(datafile) return test_data, benchmark_data def determine_linker_and_stdlib_args(self, target): ''' If we're building a static library, there is only one static linker. Otherwise, we query the target for the dynamic linker. ''' if isinstance(target, build.StaticLibrary): return self.build.static_linker[target.for_machine], [] l, stdlib_args = target.get_clink_dynamic_linker_and_stdlibs() return l, stdlib_args @staticmethod def _libdir_is_system(libdir, compilers, env): libdir = os.path.normpath(libdir) for cc in compilers.values(): if libdir in cc.get_library_dirs(env): return True return False def rpaths_for_bundled_shared_libraries(self, target, exclude_system=True): paths = [] for dep in target.external_deps: if not isinstance(dep, (dependencies.ExternalLibrary, dependencies.PkgConfigDependency)): continue la = dep.link_args if len(la) != 1 or not os.path.isabs(la[0]): continue # The only link argument is an absolute path to a library file. libpath = la[0] libdir = os.path.dirname(libpath) if exclude_system and self._libdir_is_system(libdir, target.compilers, self.environment): # No point in adding system paths. continue # Windows doesn't support rpaths, but we use this function to # emulate rpaths by setting PATH, so also accept DLLs here if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so', '.dylib']: continue if libdir.startswith(self.environment.get_source_dir()): rel_to_src = libdir[len(self.environment.get_source_dir()) + 1:] assert not os.path.isabs(rel_to_src), 'rel_to_src: {} is absolute'.format(rel_to_src) paths.append(os.path.join(self.build_to_src, rel_to_src)) else: paths.append(libdir) return paths def determine_rpath_dirs(self, target): if self.environment.coredata.get_builtin_option('layout') == 'mirror': result = target.get_link_dep_subdirs() else: result = OrderedSet() result.add('meson-out') result.update(self.rpaths_for_bundled_shared_libraries(target)) return tuple(result) def object_filename_from_source(self, target, source): assert isinstance(source, mesonlib.File) build_dir = self.environment.get_build_dir() rel_src = source.rel_to_builddir(self.build_to_src) # foo.vala files compile down to foo.c and then foo.c.o, not foo.vala.o if rel_src.endswith(('.vala', '.gs')): # See description in generate_vala_compile for this logic. if source.is_built: if os.path.isabs(rel_src): rel_src = rel_src[len(build_dir) + 1:] rel_src = os.path.relpath(rel_src, self.get_target_private_dir(target)) else: rel_src = os.path.basename(rel_src) # A meson- prefixed directory is reserved; hopefully no-one creates a file name with such a weird prefix. source = 'meson-generated_' + rel_src[:-5] + '.c' elif source.is_built: if os.path.isabs(rel_src): rel_src = rel_src[len(build_dir) + 1:] targetdir = self.get_target_private_dir(target) # A meson- prefixed directory is reserved; hopefully no-one creates a file name with such a weird prefix. source = 'meson-generated_' + os.path.relpath(rel_src, targetdir) else: if os.path.isabs(rel_src): # Not from the source directory; hopefully this doesn't conflict with user's source files. source = os.path.basename(rel_src) else: source = os.path.relpath(os.path.join(build_dir, rel_src), os.path.join(self.environment.get_source_dir(), target.get_subdir())) machine = self.environment.machines[target.for_machine] return source.replace('/', '_').replace('\\', '_') + '.' + machine.get_object_suffix() def determine_ext_objs(self, extobj, proj_dir_to_build_root): result = [] # Merge sources and generated sources sources = list(extobj.srclist) for gensrc in extobj.genlist: for s in gensrc.get_outputs(): path = self.get_target_generated_dir(extobj.target, gensrc, s) dirpart, fnamepart = os.path.split(path) sources.append(File(True, dirpart, fnamepart)) # Filter out headers and all non-source files filtered_sources = [] for s in sources: if self.environment.is_source(s) and not self.environment.is_header(s): filtered_sources.append(s) elif self.environment.is_object(s): result.append(s.relative_name()) sources = filtered_sources # extobj could contain only objects and no sources if not sources: return result targetdir = self.get_target_private_dir(extobj.target) # With unity builds, there's just one object that contains all the # sources, and we only support extracting all the objects in this mode, # so just return that. if self.is_unity(extobj.target): compsrcs = classify_unity_sources(extobj.target.compilers.values(), sources) sources = [] for comp in compsrcs.keys(): osrc = self.get_unity_source_file(extobj.target, comp.get_default_suffix()) sources.append(osrc) for osrc in sources: objname = self.object_filename_from_source(extobj.target, osrc) objpath = os.path.join(proj_dir_to_build_root, targetdir, objname) result.append(objpath) return result def get_pch_include_args(self, compiler, target): args = [] pchpath = self.get_target_private_dir(target) includeargs = compiler.get_include_args(pchpath, False) p = target.get_pch(compiler.get_language()) if p: args += compiler.get_pch_use_args(pchpath, p[0]) return includeargs + args def create_msvc_pch_implementation(self, target, lang, pch_header): # We have to include the language in the file name, otherwise # pch.c and pch.cpp will both end up as pch.obj in VS backends. impl_name = 'meson_pch-%s.%s' % (lang, lang) pch_rel_to_build = os.path.join(self.get_target_private_dir(target), impl_name) # Make sure to prepend the build dir, since the working directory is # not defined. Otherwise, we might create the file in the wrong path. pch_file = os.path.join(self.build_dir, pch_rel_to_build) os.makedirs(os.path.dirname(pch_file), exist_ok=True) content = '#include "%s"' % os.path.basename(pch_header) pch_file_tmp = pch_file + '.tmp' with open(pch_file_tmp, 'w') as f: f.write(content) mesonlib.replace_if_different(pch_file, pch_file_tmp) return pch_rel_to_build @staticmethod def escape_extra_args(compiler, args): # No extra escaping/quoting needed when not running on Windows if not mesonlib.is_windows(): return args extra_args = [] # Compiler-specific escaping is needed for -D args but not for any others if isinstance(compiler, VisualStudioLikeCompiler): # MSVC needs escaping when a -D argument ends in \ or \" for arg in args: if arg.startswith('-D') or arg.startswith('/D'): # Without extra escaping for these two, the next character # gets eaten if arg.endswith('\\'): arg += '\\' elif arg.endswith('\\"'): arg = arg[:-2] + '\\\\"' extra_args.append(arg) else: # MinGW GCC needs all backslashes in defines to be doubly-escaped # FIXME: Not sure about Cygwin or Clang for arg in args: if arg.startswith('-D') or arg.startswith('/D'): arg = arg.replace('\\', '\\\\') extra_args.append(arg) return extra_args def generate_basic_compiler_args(self, target, compiler, no_warn_args=False): # Create an empty commands list, and start adding arguments from # various sources in the order in which they must override each other # starting from hard-coded defaults followed by build options and so on. commands = CompilerArgs(compiler) copt_proxy = self.get_compiler_options_for_target(target) # First, the trivial ones that are impossible to override. # # Add -nostdinc/-nostdinc++ if needed; can't be overridden commands += self.get_cross_stdlib_args(target, compiler) # Add things like /NOLOGO or -pipe; usually can't be overridden commands += compiler.get_always_args() # Only add warning-flags by default if the buildtype enables it, and if # we weren't explicitly asked to not emit warnings (for Vala, f.ex) if no_warn_args: commands += compiler.get_no_warn_args() elif self.get_option_for_target('buildtype', target) != 'plain': commands += compiler.get_warn_args(self.get_option_for_target('warning_level', target)) # Add -Werror if werror=true is set in the build options set on the # command-line or default_options inside project(). This only sets the # action to be done for warnings if/when they are emitted, so it's ok # to set it after get_no_warn_args() or get_warn_args(). if self.get_option_for_target('werror', target): commands += compiler.get_werror_args() # Add compile args for c_* or cpp_* build options set on the # command-line or default_options inside project(). commands += compiler.get_option_compile_args(copt_proxy) # Add buildtype args: optimization level, debugging, etc. commands += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target)) commands += compiler.get_optimization_args(self.get_option_for_target('optimization', target)) commands += compiler.get_debug_args(self.get_option_for_target('debug', target)) # Add compile args added using add_project_arguments() commands += self.build.get_project_args(compiler, target.subproject, target.for_machine) # Add compile args added using add_global_arguments() # These override per-project arguments commands += self.build.get_global_args(compiler, target.for_machine) # Compile args added from the env: CFLAGS/CXXFLAGS, etc, or the cross # file. We want these to override all the defaults, but not the # per-target compile args. commands += self.environment.coredata.get_external_args(target.for_machine, compiler.get_language()) # Always set -fPIC for shared libraries if isinstance(target, build.SharedLibrary): commands += compiler.get_pic_args() # Set -fPIC for static libraries by default unless explicitly disabled if isinstance(target, build.StaticLibrary) and target.pic: commands += compiler.get_pic_args() if isinstance(target, build.Executable) and target.pie: commands += compiler.get_pie_args() # Add compile args needed to find external dependencies. Link args are # added while generating the link command. # NOTE: We must preserve the order in which external deps are # specified, so we reverse the list before iterating over it. for dep in reversed(target.get_external_deps()): if not dep.found(): continue if compiler.language == 'vala': if isinstance(dep, dependencies.PkgConfigDependency): if dep.name == 'glib-2.0' and dep.version_reqs is not None: for req in dep.version_reqs: if req.startswith(('>=', '==')): commands += ['--target-glib', req[2:]] break commands += ['--pkg', dep.name] elif isinstance(dep, dependencies.ExternalLibrary): commands += dep.get_link_args('vala') else: commands += compiler.get_dependency_compile_args(dep) # Qt needs -fPIC for executables # XXX: We should move to -fPIC for all executables if isinstance(target, build.Executable): commands += dep.get_exe_args(compiler) # For 'automagic' deps: Boost and GTest. Also dependency('threads'). # pkg-config puts the thread flags itself via `Cflags:` # Fortran requires extra include directives. if compiler.language == 'fortran': for lt in target.link_targets: priv_dir = self.get_target_private_dir(lt) commands += compiler.get_include_args(priv_dir, False) return commands def build_target_link_arguments(self, compiler, deps): args = [] for d in deps: if not (d.is_linkable_target()): raise RuntimeError('Tried to link with a non-library target "%s".' % d.get_basename()) arg = self.get_target_filename_for_linking(d) if not arg: continue if compiler.get_language() == 'd': arg = '-Wl,' + arg else: arg = compiler.get_linker_lib_prefix() + arg args.append(arg) return args def get_mingw_extra_paths(self, target): paths = OrderedSet() # The cross bindir root = self.environment.properties[target.for_machine].get_root() if root: paths.add(os.path.join(root, 'bin')) # The toolchain bindir sys_root = self.environment.properties[target.for_machine].get_sys_root() if sys_root: paths.add(os.path.join(sys_root, 'bin')) # Get program and library dirs from all target compilers if isinstance(target, build.BuildTarget): for cc in target.compilers.values(): paths.update(cc.get_program_dirs(self.environment)) paths.update(cc.get_library_dirs(self.environment)) return list(paths) def determine_windows_extra_paths(self, target: T.Union[build.BuildTarget, str], extra_bdeps): '''On Windows there is no such thing as an rpath. We must determine all locations of DLLs that this exe links to and return them so they can be used in unit tests.''' result = set() prospectives = set() if isinstance(target, build.BuildTarget): prospectives.update(target.get_transitive_link_deps()) # External deps for deppath in self.rpaths_for_bundled_shared_libraries(target, exclude_system=False): result.add(os.path.normpath(os.path.join(self.environment.get_build_dir(), deppath))) for bdep in extra_bdeps: prospectives.update(bdep.get_transitive_link_deps()) # Internal deps for ld in prospectives: if ld == '' or ld == '.': continue dirseg = os.path.join(self.environment.get_build_dir(), self.get_target_dir(ld)) result.add(dirseg) if (isinstance(target, build.BuildTarget) and not self.environment.machines.matches_build_machine(target.for_machine)): result.update(self.get_mingw_extra_paths(target)) return list(result) def write_benchmark_file(self, datafile): self.write_test_serialisation(self.build.get_benchmarks(), datafile) def write_test_file(self, datafile): self.write_test_serialisation(self.build.get_tests(), datafile) def create_test_serialisation(self, tests): arr = [] for t in sorted(tests, key=lambda tst: -1 * tst.priority): exe = t.get_exe() if isinstance(exe, dependencies.ExternalProgram): cmd = exe.get_command() else: cmd = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(t.get_exe()))] if isinstance(exe, (build.BuildTarget, dependencies.ExternalProgram)): test_for_machine = exe.for_machine else: # E.g. an external verifier or simulator program run on a generated executable. # Can always be run without a wrapper. test_for_machine = MachineChoice.BUILD is_cross = not self.environment.machines.matches_build_machine(test_for_machine) if is_cross and self.environment.need_exe_wrapper(): exe_wrapper = self.environment.get_exe_wrapper() else: exe_wrapper = None machine = self.environment.machines[exe.for_machine] if machine.is_windows() or machine.is_cygwin(): extra_bdeps = [] if isinstance(exe, build.CustomTarget): extra_bdeps = exe.get_transitive_build_target_deps() extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps) else: extra_paths = [] cmd_args = [] for a in t.cmd_args: if hasattr(a, 'held_object'): a = a.held_object if isinstance(a, build.BuildTarget): extra_paths += self.determine_windows_extra_paths(a, []) if isinstance(a, mesonlib.File): a = os.path.join(self.environment.get_build_dir(), a.rel_to_builddir(self.build_to_src)) cmd_args.append(a) elif isinstance(a, str): cmd_args.append(a) elif isinstance(a, build.Target): cmd_args.append(self.construct_target_rel_path(a, t.workdir)) else: raise MesonException('Bad object in test command.') ts = TestSerialisation(t.get_name(), t.project_name, t.suite, cmd, is_cross, exe_wrapper, self.environment.need_exe_wrapper(), t.is_parallel, cmd_args, t.env, t.should_fail, t.timeout, t.workdir, extra_paths, t.protocol, t.priority) arr.append(ts) return arr def write_test_serialisation(self, tests, datafile): pickle.dump(self.create_test_serialisation(tests), datafile) def construct_target_rel_path(self, a, workdir): if workdir is None: return self.get_target_filename(a) assert(os.path.isabs(workdir)) abs_path = self.get_target_filename_abs(a) return os.path.relpath(abs_path, workdir) def generate_depmf_install(self, d): if self.build.dep_manifest_name is None: return ifilename = os.path.join(self.environment.get_build_dir(), 'depmf.json') ofilename = os.path.join(self.environment.get_prefix(), self.build.dep_manifest_name) mfobj = {'type': 'dependency manifest', 'version': '1.0', 'projects': self.build.dep_manifest} with open(ifilename, 'w') as f: f.write(json.dumps(mfobj)) # Copy file from, to, and with mode unchanged d.data.append([ifilename, ofilename, None]) def get_regen_filelist(self): '''List of all files whose alteration means that the build definition needs to be regenerated.''' deps = [os.path.join(self.build_to_src, df) for df in self.interpreter.get_build_def_files()] if self.environment.is_cross_build(): deps.extend(self.environment.coredata.cross_files) deps.extend(self.environment.coredata.config_files) deps.append('meson-private/coredata.dat') if os.path.exists(os.path.join(self.environment.get_source_dir(), 'meson_options.txt')): deps.append(os.path.join(self.build_to_src, 'meson_options.txt')) for sp in self.build.subprojects.keys(): fname = os.path.join(self.environment.get_source_dir(), sp, 'meson_options.txt') if os.path.isfile(fname): deps.append(os.path.join(self.build_to_src, sp, 'meson_options.txt')) return deps def exe_object_to_cmd_array(self, exe): if isinstance(exe, build.BuildTarget): if exe.for_machine is not MachineChoice.BUILD: if (self.environment.is_cross_build() and self.environment.exe_wrapper is None and self.environment.need_exe_wrapper()): s = textwrap.dedent(''' Cannot use target {} as a generator because it is built for the host machine and no exe wrapper is defined or needs_exe_wrapper is true. You might want to set `native: true` instead to build it for the build machine.'''.format(exe.name)) raise MesonException(s) exe_arr = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))] else: exe_arr = exe.get_command() return exe_arr def replace_extra_args(self, args, genlist): final_args = [] for a in args: if a == '@EXTRA_ARGS@': final_args += genlist.get_extra_args() else: final_args.append(a) return final_args def replace_outputs(self, args, private_dir, output_list): newargs = [] regex = re.compile(r'@OUTPUT(\d+)@') for arg in args: m = regex.search(arg) while m is not None: index = int(m.group(1)) src = '@OUTPUT%d@' % index arg = arg.replace(src, os.path.join(private_dir, output_list[index])) m = regex.search(arg) newargs.append(arg) return newargs def get_build_by_default_targets(self): result = OrderedDict() # Get all build and custom targets that must be built by default for name, t in self.build.get_targets().items(): if t.build_by_default: result[name] = t # Get all targets used as test executables and arguments. These must # also be built by default. XXX: Sometime in the future these should be # built only before running tests. for t in self.build.get_tests(): exe = t.exe if hasattr(exe, 'held_object'): exe = exe.held_object if isinstance(exe, (build.CustomTarget, build.BuildTarget)): result[exe.get_id()] = exe for arg in t.cmd_args: if hasattr(arg, 'held_object'): arg = arg.held_object if not isinstance(arg, (build.CustomTarget, build.BuildTarget)): continue result[arg.get_id()] = arg for dep in t.depends: assert isinstance(dep, (build.CustomTarget, build.BuildTarget)) result[dep.get_id()] = dep return result @lru_cache(maxsize=None) def get_custom_target_provided_by_generated_source(self, generated_source): libs = [] for f in generated_source.get_outputs(): if self.environment.is_library(f): libs.append(os.path.join(self.get_target_dir(generated_source), f)) return libs @lru_cache(maxsize=None) def get_custom_target_provided_libraries(self, target): libs = [] for t in target.get_generated_sources(): if not isinstance(t, build.CustomTarget): continue l = self.get_custom_target_provided_by_generated_source(t) libs = libs + l return libs def is_unity(self, target): optval = self.get_option_for_target('unity', target) if optval == 'on' or (optval == 'subprojects' and target.subproject != ''): return True return False def get_custom_target_sources(self, target): ''' Custom target sources can be of various object types; strings, File, BuildTarget, even other CustomTargets. Returns the path to them relative to the build root directory. ''' srcs = [] for i in target.get_sources(): if hasattr(i, 'held_object'): i = i.held_object if isinstance(i, str): fname = [os.path.join(self.build_to_src, target.subdir, i)] elif isinstance(i, build.BuildTarget): fname = [self.get_target_filename(i)] elif isinstance(i, (build.CustomTarget, build.CustomTargetIndex)): fname = [os.path.join(self.get_target_dir(i), p) for p in i.get_outputs()] elif isinstance(i, build.GeneratedList): fname = [os.path.join(self.get_target_private_dir(target), p) for p in i.get_outputs()] elif isinstance(i, build.ExtractedObjects): fname = [os.path.join(self.get_target_private_dir(i.target), p) for p in i.get_outputs(self)] else: fname = [i.rel_to_builddir(self.build_to_src)] if target.absolute_paths: fname = [os.path.join(self.environment.get_build_dir(), f) for f in fname] srcs += fname return srcs def get_custom_target_depend_files(self, target, absolute_paths=False): deps = [] for i in target.depend_files: if isinstance(i, mesonlib.File): if absolute_paths: deps.append(i.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir())) else: deps.append(i.rel_to_builddir(self.build_to_src)) else: if absolute_paths: deps.append(os.path.join(self.environment.get_source_dir(), target.subdir, i)) else: deps.append(os.path.join(self.build_to_src, target.subdir, i)) return deps def eval_custom_target_command(self, target, absolute_outputs=False): # We want the outputs to be absolute only when using the VS backend # XXX: Maybe allow the vs backend to use relative paths too? source_root = self.build_to_src build_root = '.' outdir = self.get_target_dir(target) if absolute_outputs: source_root = self.environment.get_source_dir() build_root = self.environment.get_build_dir() outdir = os.path.join(self.environment.get_build_dir(), outdir) outputs = [] for i in target.get_outputs(): outputs.append(os.path.join(outdir, i)) inputs = self.get_custom_target_sources(target) # Evaluate the command list cmd = [] for i in target.command: if isinstance(i, build.Executable): cmd += self.exe_object_to_cmd_array(i) continue elif isinstance(i, build.CustomTarget): # GIR scanner will attempt to execute this binary but # it assumes that it is in path, so always give it a full path. tmp = i.get_outputs()[0] i = os.path.join(self.get_target_dir(i), tmp) elif isinstance(i, mesonlib.File): i = i.rel_to_builddir(self.build_to_src) if target.absolute_paths: i = os.path.join(self.environment.get_build_dir(), i) # FIXME: str types are blindly added ignoring 'target.absolute_paths' # because we can't know if they refer to a file or just a string elif not isinstance(i, str): err_msg = 'Argument {0} is of unknown type {1}' raise RuntimeError(err_msg.format(str(i), str(type(i)))) elif '@SOURCE_ROOT@' in i: i = i.replace('@SOURCE_ROOT@', source_root) elif '@BUILD_ROOT@' in i: i = i.replace('@BUILD_ROOT@', build_root) elif '@DEPFILE@' in i: if target.depfile is None: msg = 'Custom target {!r} has @DEPFILE@ but no depfile ' \ 'keyword argument.'.format(target.name) raise MesonException(msg) dfilename = os.path.join(outdir, target.depfile) i = i.replace('@DEPFILE@', dfilename) elif '@PRIVATE_DIR@' in i: if target.absolute_paths: pdir = self.get_target_private_dir_abs(target) else: pdir = self.get_target_private_dir(target) i = i.replace('@PRIVATE_DIR@', pdir) elif '@PRIVATE_OUTDIR_' in i: match = re.search(r'@PRIVATE_OUTDIR_(ABS_)?([^/\s*]*)@', i) if not match: msg = 'Custom target {!r} has an invalid argument {!r}' \ ''.format(target.name, i) raise MesonException(msg) source = match.group(0) if match.group(1) is None and not target.absolute_paths: lead_dir = '' else: lead_dir = self.environment.get_build_dir() i = i.replace(source, os.path.join(lead_dir, outdir)) cmd.append(i) # Substitute the rest of the template strings values = mesonlib.get_filenames_templates_dict(inputs, outputs) cmd = mesonlib.substitute_values(cmd, values) # This should not be necessary but removing it breaks # building GStreamer on Windows. The underlying issue # is problems with quoting backslashes on Windows # which is the seventh circle of hell. The downside is # that this breaks custom targets whose command lines # have backslashes. If you try to fix this be sure to # check that it does not break GST. # # The bug causes file paths such as c:\foo to get escaped # into c:\\foo. # # Unfortunately we have not been able to come up with an # isolated test case for this so unless you manage to come up # with one, the only way is to test the building with Gst's # setup. Note this in your MR or ping us and we will get it # fixed. # # https://github.com/mesonbuild/meson/pull/737 cmd = [i.replace('\\', '/') for i in cmd] return inputs, outputs, cmd def run_postconf_scripts(self): env = {'MESON_SOURCE_ROOT': self.environment.get_source_dir(), 'MESON_BUILD_ROOT': self.environment.get_build_dir(), 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in self.environment.get_build_command() + ['introspect']]), } child_env = os.environ.copy() child_env.update(env) for s in self.build.postconf_scripts: cmd = s['exe'] + s['args'] subprocess.check_call(cmd, env=child_env) def create_install_data(self): strip_bin = self.environment.binaries.host.lookup_entry('strip') if strip_bin is None: if self.environment.is_cross_build(): mlog.warning('Cross file does not specify strip binary, result will not be stripped.') else: # TODO go through all candidates, like others strip_bin = [self.environment.default_strip[0]] d = InstallData(self.environment.get_source_dir(), self.environment.get_build_dir(), self.environment.get_prefix(), strip_bin, self.environment.coredata.get_builtin_option('install_umask'), self.environment.get_build_command() + ['introspect']) self.generate_depmf_install(d) self.generate_target_install(d) self.generate_header_install(d) self.generate_man_install(d) self.generate_data_install(d) self.generate_custom_install_script(d) self.generate_subdir_install(d) return d def create_install_data_files(self): install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat') with open(install_data_file, 'wb') as ofile: pickle.dump(self.create_install_data(), ofile) def generate_target_install(self, d): for t in self.build.get_targets().values(): if not t.should_install(): continue outdirs, custom_install_dir = t.get_install_dir(self.environment) # Sanity-check the outputs and install_dirs num_outdirs, num_out = len(outdirs), len(t.get_outputs()) if num_outdirs != 1 and num_outdirs != num_out: m = 'Target {!r} has {} outputs: {!r}, but only {} "install_dir"s were found.\n' \ "Pass 'false' for outputs that should not be installed and 'true' for\n" \ 'using the default installation directory for an output.' raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs)) install_mode = t.get_custom_install_mode() # Install the target output(s) if isinstance(t, build.BuildTarget): # In general, stripping static archives is tricky and full of pitfalls. # Wholesale stripping of static archives with a command such as # # strip libfoo.a # # is broken, as GNU's strip will remove *every* symbol in a static # archive. One solution to this nonintuitive behaviour would be # to only strip local/debug symbols. Unfortunately, strip arguments # are not specified by POSIX and therefore not portable. GNU's `-g` # option (i.e. remove debug symbols) is equivalent to Apple's `-S`. # # TODO: Create GNUStrip/AppleStrip/etc. hierarchy for more # fine-grained stripping of static archives. should_strip = not isinstance(t, build.StaticLibrary) and self.get_option_for_target('strip', t) # Install primary build output (library/executable/jar, etc) # Done separately because of strip/aliases/rpath if outdirs[0] is not False: mappings = t.get_link_deps_mapping(d.prefix, self.environment) i = TargetInstallData(self.get_target_filename(t), outdirs[0], t.get_aliases(), should_strip, mappings, t.install_rpath, install_mode) d.targets.append(i) if isinstance(t, (build.SharedLibrary, build.SharedModule, build.Executable)): # On toolchains/platforms that use an import library for # linking (separate from the shared library with all the # code), we need to install that too (dll.a/.lib). if t.get_import_filename(): if custom_install_dir: # If the DLL is installed into a custom directory, # install the import library into the same place so # it doesn't go into a surprising place implib_install_dir = outdirs[0] else: implib_install_dir = self.environment.get_import_lib_dir() # Install the import library; may not exist for shared modules i = TargetInstallData(self.get_target_filename_for_linking(t), implib_install_dir, {}, False, {}, '', install_mode, optional=isinstance(t, build.SharedModule)) d.targets.append(i) if not should_strip and t.get_debug_filename(): debug_file = os.path.join(self.get_target_dir(t), t.get_debug_filename()) i = TargetInstallData(debug_file, outdirs[0], {}, False, {}, '', install_mode, optional=True) d.targets.append(i) # Install secondary outputs. Only used for Vala right now. if num_outdirs > 1: for output, outdir in zip(t.get_outputs()[1:], outdirs[1:]): # User requested that we not install this output if outdir is False: continue f = os.path.join(self.get_target_dir(t), output) i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode) d.targets.append(i) elif isinstance(t, build.CustomTarget): # If only one install_dir is specified, assume that all # outputs will be installed into it. This is for # backwards-compatibility and because it makes sense to # avoid repetition since this is a common use-case. # # To selectively install only some outputs, pass `false` as # the install_dir for the corresponding output by index if num_outdirs == 1 and num_out > 1: for output in t.get_outputs(): f = os.path.join(self.get_target_dir(t), output) i = TargetInstallData(f, outdirs[0], {}, False, {}, None, install_mode, optional=not t.build_by_default) d.targets.append(i) else: for output, outdir in zip(t.get_outputs(), outdirs): # User requested that we not install this output if outdir is False: continue f = os.path.join(self.get_target_dir(t), output) i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode, optional=not t.build_by_default) d.targets.append(i) def generate_custom_install_script(self, d): result = [] srcdir = self.environment.get_source_dir() builddir = self.environment.get_build_dir() for i in self.build.install_scripts: exe = i['exe'] args = i['args'] fixed_args = [] for a in args: a = a.replace('@SOURCE_ROOT@', srcdir) a = a.replace('@BUILD_ROOT@', builddir) fixed_args.append(a) result.append(build.RunScript(exe, fixed_args)) d.install_scripts = result def generate_header_install(self, d): incroot = self.environment.get_includedir() headers = self.build.get_headers() srcdir = self.environment.get_source_dir() builddir = self.environment.get_build_dir() for h in headers: outdir = h.get_custom_install_dir() if outdir is None: outdir = os.path.join(incroot, h.get_install_subdir()) for f in h.get_sources(): if not isinstance(f, File): msg = 'Invalid header type {!r} can\'t be installed' raise MesonException(msg.format(f)) abspath = f.absolute_path(srcdir, builddir) i = [abspath, outdir, h.get_custom_install_mode()] d.headers.append(i) def generate_man_install(self, d): manroot = self.environment.get_mandir() man = self.build.get_man() for m in man: for f in m.get_sources(): num = f.split('.')[-1] subdir = m.get_custom_install_dir() if subdir is None: subdir = os.path.join(manroot, 'man' + num) srcabs = f.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) dstabs = os.path.join(subdir, os.path.basename(f.fname)) i = [srcabs, dstabs, m.get_custom_install_mode()] d.man.append(i) def generate_data_install(self, d): data = self.build.get_data() srcdir = self.environment.get_source_dir() builddir = self.environment.get_build_dir() for de in data: assert(isinstance(de, build.Data)) subdir = de.install_dir if not subdir: subdir = os.path.join(self.environment.get_datadir(), self.interpreter.build.project_name) for src_file, dst_name in zip(de.sources, de.rename): assert(isinstance(src_file, mesonlib.File)) dst_abs = os.path.join(subdir, dst_name) i = [src_file.absolute_path(srcdir, builddir), dst_abs, de.install_mode] d.data.append(i) def generate_subdir_install(self, d): for sd in self.build.get_install_subdirs(): src_dir = os.path.join(self.environment.get_source_dir(), sd.source_subdir, sd.installable_subdir).rstrip('/') dst_dir = os.path.join(self.environment.get_prefix(), sd.install_dir) if not sd.strip_directory: dst_dir = os.path.join(dst_dir, os.path.basename(src_dir)) d.install_subdirs.append([src_dir, dst_dir, sd.install_mode, sd.exclude]) def get_introspection_data(self, target_id, target): ''' Returns a list of source dicts with the following format for a given target: [ { "language": "", "compiler": ["result", "of", "comp.get_exelist()"], "parameters": ["list", "of", "compiler", "parameters], "sources": ["list", "of", "all", "", "source", "files"], "generated_sources": ["list", "of", "generated", "source", "files"] } ] This is a limited fallback / reference implementation. The backend should override this method. ''' if isinstance(target, (build.CustomTarget, build.BuildTarget)): source_list_raw = target.sources + target.extra_files source_list = [] for j in source_list_raw: if isinstance(j, mesonlib.File): source_list += [j.absolute_path(self.source_dir, self.build_dir)] elif isinstance(j, str): source_list += [os.path.join(self.source_dir, j)] source_list = list(map(lambda x: os.path.normpath(x), source_list)) compiler = [] if isinstance(target, build.CustomTarget): tmp_compiler = target.command if not isinstance(compiler, list): tmp_compiler = [compiler] for j in tmp_compiler: if isinstance(j, mesonlib.File): compiler += [j.absolute_path(self.source_dir, self.build_dir)] elif isinstance(j, str): compiler += [j] elif isinstance(j, (build.BuildTarget, build.CustomTarget)): compiler += j.get_outputs() else: raise RuntimeError('Type "{}" is not supported in get_introspection_data. This is a bug'.format(type(j).__name__)) return [{ 'language': 'unknown', 'compiler': compiler, 'parameters': [], 'sources': source_list, 'generated_sources': [] }] return [] meson-0.53.2/mesonbuild/backend/ninjabackend.py0000644000175000017500000042471213612313307023036 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import typing as T import os import re import pickle import subprocess from collections import OrderedDict import itertools from pathlib import PurePath, Path from functools import lru_cache from . import backends from .. import modules from .. import environment, mesonlib from .. import build from .. import mlog from .. import dependencies from .. import compilers from ..compilers import (Compiler, CompilerArgs, CCompiler, FortranCompiler, PGICCompiler, VisualStudioLikeCompiler) from ..linkers import ArLinker from ..mesonlib import ( File, LibType, MachineChoice, MesonException, OrderedSet, PerMachine, ProgressBar, quote_arg ) from ..mesonlib import get_compiler_for_source, has_path_sep from .backends import CleanTrees from ..build import InvalidArguments FORTRAN_INCLUDE_PAT = r"^\s*#?include\s*['\"](\w+\.\w+)['\"]" FORTRAN_MODULE_PAT = r"^\s*\bmodule\b\s+(\w+)\s*(?:!+.*)*$" FORTRAN_SUBMOD_PAT = r"^\s*\bsubmodule\b\s*\((\w+:?\w+)\)\s*(\w+)" FORTRAN_USE_PAT = r"^\s*use,?\s*(?:non_intrinsic)?\s*(?:::)?\s*(\w+)" if mesonlib.is_windows(): # FIXME: can't use quote_arg on Windows just yet; there are a number of existing workarounds # throughout the codebase that cumulatively make the current code work (see, e.g. Backend.escape_extra_args # and NinjaBuildElement.write below) and need to be properly untangled before attempting this quote_func = lambda s: '"{}"'.format(s) execute_wrapper = ['cmd', '/c'] rmfile_prefix = ['del', '/f', '/s', '/q', '{}', '&&'] else: quote_func = quote_arg execute_wrapper = [] rmfile_prefix = ['rm', '-f', '{}', '&&'] def ninja_quote(text, is_build_line=False): if is_build_line: qcs = ('$', ' ', ':') else: qcs = ('$', ' ') for char in qcs: text = text.replace(char, '$' + char) if '\n' in text: errmsg = '''Ninja does not support newlines in rules. The content was: %s Please report this error with a test case to the Meson bug tracker.''' % text raise MesonException(errmsg) return text class NinjaComment: def __init__(self, comment): self.comment = comment def write(self, outfile): for l in self.comment.split('\n'): outfile.write('# ') outfile.write(l) outfile.write('\n') outfile.write('\n') class NinjaRule: def __init__(self, rule, command, args, description, rspable = False, deps = None, depfile = None, extra = None): self.name = rule self.command = command # includes args which never go into a rspfile self.args = args # args which will go into a rspfile, if used self.description = description self.deps = deps # depstyle 'gcc' or 'msvc' self.depfile = depfile self.extra = extra self.rspable = rspable # if a rspfile can be used self.refcount = 0 def write(self, outfile): if not self.refcount: return outfile.write('rule %s\n' % self.name) if self.rspable: outfile.write(' command = %s @$out.rsp\n' % ' '.join(self.command)) outfile.write(' rspfile = $out.rsp\n') outfile.write(' rspfile_content = %s\n' % ' '.join(self.args)) else: outfile.write(' command = %s\n' % ' '.join(self.command + self.args)) if self.deps: outfile.write(' deps = %s\n' % self.deps) if self.depfile: outfile.write(' depfile = %s\n' % self.depfile) outfile.write(' description = %s\n' % self.description) if self.extra: for l in self.extra.split('\n'): outfile.write(' ') outfile.write(l) outfile.write('\n') outfile.write('\n') class NinjaBuildElement: def __init__(self, all_outputs, outfilenames, rule, infilenames): if isinstance(outfilenames, str): self.outfilenames = [outfilenames] else: self.outfilenames = outfilenames assert(isinstance(rule, str)) self.rule = rule if isinstance(infilenames, str): self.infilenames = [infilenames] else: self.infilenames = infilenames self.deps = OrderedSet() self.orderdeps = OrderedSet() self.elems = [] self.all_outputs = all_outputs def add_dep(self, dep): if isinstance(dep, list): self.deps.update(dep) else: self.deps.add(dep) def add_orderdep(self, dep): if isinstance(dep, list): self.orderdeps.update(dep) else: self.orderdeps.add(dep) def add_item(self, name, elems): if isinstance(elems, str): elems = [elems] self.elems.append((name, elems)) def write(self, outfile): self.check_outputs() line = 'build %s: %s %s' % (' '.join([ninja_quote(i, True) for i in self.outfilenames]), self.rule, ' '.join([ninja_quote(i, True) for i in self.infilenames])) if len(self.deps) > 0: line += ' | ' + ' '.join([ninja_quote(x, True) for x in self.deps]) if len(self.orderdeps) > 0: line += ' || ' + ' '.join([ninja_quote(x, True) for x in self.orderdeps]) line += '\n' # This is the only way I could find to make this work on all # platforms including Windows command shell. Slash is a dir separator # on Windows, too, so all characters are unambiguous and, more importantly, # do not require quoting, unless explicitly specified, which is necessary for # the csc compiler. line = line.replace('\\', '/') outfile.write(line) # ninja variables whose value should remain unquoted. The value of these # ninja variables (or variables we use them in) is interpreted directly # by ninja (e.g. the value of the depfile variable is a pathname that # ninja will read from, etc.), so it must not be shell quoted. raw_names = {'DEPFILE', 'DESC', 'pool', 'description', 'targetdep'} for e in self.elems: (name, elems) = e should_quote = name not in raw_names line = ' %s = ' % name newelems = [] for i in elems: if not should_quote or i == '&&': # Hackety hack hack quoter = ninja_quote else: quoter = lambda x: ninja_quote(quote_func(x)) i = i.replace('\\', '\\\\') if quote_func('') == '""': i = i.replace('"', '\\"') newelems.append(quoter(i)) line += ' '.join(newelems) line += '\n' outfile.write(line) outfile.write('\n') def check_outputs(self): for n in self.outfilenames: if n in self.all_outputs: raise MesonException('Multiple producers for Ninja target "%s". Please rename your targets.' % n) self.all_outputs[n] = True class NinjaBackend(backends.Backend): def __init__(self, build): super().__init__(build) self.name = 'ninja' self.ninja_filename = 'build.ninja' self.fortran_deps = {} self.all_outputs = {} self.introspection_data = {} self.created_llvm_ir_rule = PerMachine(False, False) def create_target_alias(self, to_target): # We need to use aliases for targets that might be used as directory # names to workaround a Ninja bug that breaks `ninja -t clean`. # This is used for 'reserved' targets such as 'test', 'install', # 'benchmark', etc, and also for RunTargets. # https://github.com/mesonbuild/meson/issues/1644 if not to_target.startswith('meson-'): m = 'Invalid usage of create_target_alias with {!r}' raise AssertionError(m.format(to_target)) from_target = to_target[len('meson-'):] elem = NinjaBuildElement(self.all_outputs, from_target, 'phony', to_target) self.add_build(elem) def detect_vs_dep_prefix(self, tempfilename): '''VS writes its dependency in a locale dependent format. Detect the search prefix to use.''' # TODO don't hard-code host for compiler in self.environment.coredata.compilers.host.values(): # Have to detect the dependency format # IFort on windows is MSVC like, but doesn't have /showincludes if isinstance(compiler, FortranCompiler): continue if isinstance(compiler, PGICCompiler) and mesonlib.is_windows(): # for the purpose of this function, PGI doesn't act enough like MSVC return open(tempfilename, 'a', encoding='utf-8') if isinstance(compiler, VisualStudioLikeCompiler): break else: # None of our compilers are MSVC, we're done. return open(tempfilename, 'a', encoding='utf-8') filename = os.path.join(self.environment.get_scratch_dir(), 'incdetect.c') with open(filename, 'w') as f: f.write('''#include int dummy; ''') # The output of cl dependency information is language # and locale dependent. Any attempt at converting it to # Python strings leads to failure. We _must_ do this detection # in raw byte mode and write the result in raw bytes. pc = subprocess.Popen(compiler.get_exelist() + ['/showIncludes', '/c', 'incdetect.c'], cwd=self.environment.get_scratch_dir(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = pc.communicate() # We want to match 'Note: including file: ' in the line # 'Note: including file: d:\MyDir\include\stdio.h', however # different locales have different messages with a different # number of colons. Match up to the the drive name 'd:\'. matchre = re.compile(rb"^(.*\s)[a-zA-Z]:\\.*stdio.h$") def detect_prefix(out): for line in re.split(rb'\r?\n', out): match = matchre.match(line) if match: with open(tempfilename, 'ab') as binfile: binfile.write(b'msvc_deps_prefix = ' + match.group(1) + b'\n') return open(tempfilename, 'a', encoding='utf-8') return None # Some cl wrappers (e.g. Squish Coco) output dependency info # to stderr rather than stdout result = detect_prefix(stdout) or detect_prefix(stderr) if result: return result raise MesonException('Could not determine vs dep dependency prefix string.') def generate(self, interp): self.interpreter = interp ninja = environment.detect_ninja_command_and_version(log=True) if ninja is None: raise MesonException('Could not detect Ninja v1.5 or newer') (self.ninja_command, self.ninja_version) = ninja outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename) tempfilename = outfilename + '~' with open(tempfilename, 'w', encoding='utf-8') as outfile: outfile.write('# This is the build file for project "%s"\n' % self.build.get_project()) outfile.write('# It is autogenerated by the Meson build system.\n') outfile.write('# Do not edit by hand.\n\n') outfile.write('ninja_required_version = 1.5.1\n\n') num_pools = self.environment.coredata.backend_options['backend_max_links'].value if num_pools > 0: outfile.write('''pool link_pool depth = %d ''' % num_pools) with self.detect_vs_dep_prefix(tempfilename) as outfile: self.generate_rules() self.build_elements = [] self.generate_phony() self.add_build_comment(NinjaComment('Build rules for targets')) for t in ProgressBar(self.build.get_targets().values(), desc='Generating targets'): self.generate_target(t) self.add_build_comment(NinjaComment('Test rules')) self.generate_tests() self.add_build_comment(NinjaComment('Install rules')) self.generate_install() self.generate_dist() if 'b_coverage' in self.environment.coredata.base_options and \ self.environment.coredata.base_options['b_coverage'].value: self.add_build_comment(NinjaComment('Coverage rules')) self.generate_coverage_rules() self.add_build_comment(NinjaComment('Suffix')) self.generate_utils() self.generate_ending() self.write_rules(outfile) self.write_builds(outfile) default = 'default all\n\n' outfile.write(default) # Only overwrite the old build file after the new one has been # fully created. os.replace(tempfilename, outfilename) mlog.cmd_ci_include(outfilename) # For CI debugging self.generate_compdb() # http://clang.llvm.org/docs/JSONCompilationDatabase.html def generate_compdb(self): rules = [] for for_machine in MachineChoice: for lang in self.environment.coredata.compilers[for_machine]: rules += [self.get_compiler_rule_name(lang, for_machine)] rules += [self.get_pch_rule_name(lang, for_machine)] compdb_options = ['-x'] if mesonlib.version_compare(self.ninja_version, '>=1.9') else [] ninja_compdb = [self.ninja_command, '-t', 'compdb'] + compdb_options + rules builddir = self.environment.get_build_dir() try: jsondb = subprocess.check_output(ninja_compdb, cwd=builddir) with open(os.path.join(builddir, 'compile_commands.json'), 'wb') as f: f.write(jsondb) except Exception: mlog.warning('Could not create compilation database.') # Get all generated headers. Any source file might need them so # we need to add an order dependency to them. def get_generated_headers(self, target): if hasattr(target, 'cached_generated_headers'): return target.cached_generated_headers header_deps = [] # XXX: Why don't we add deps to CustomTarget headers here? for genlist in target.get_generated_sources(): if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): continue for src in genlist.get_outputs(): if self.environment.is_header(src): header_deps.append(self.get_target_generated_dir(target, genlist, src)) if 'vala' in target.compilers and not isinstance(target, build.Executable): vala_header = File.from_built_file(self.get_target_dir(target), target.vala_header) header_deps.append(vala_header) # Recurse and find generated headers for dep in itertools.chain(target.link_targets, target.link_whole_targets): if isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): header_deps += self.get_generated_headers(dep) target.cached_generated_headers = header_deps return header_deps def get_target_generated_sources(self, target): """ Returns a dictionary with the keys being the path to the file (relative to the build directory) of that type and the value being the GeneratorList or CustomTarget that generated it. """ srcs = OrderedDict() for gensrc in target.get_generated_sources(): for s in gensrc.get_outputs(): f = self.get_target_generated_dir(target, gensrc, s) srcs[f] = s return srcs def get_target_sources(self, target): srcs = OrderedDict() for s in target.get_sources(): # BuildTarget sources are always mesonlib.File files which are # either in the source root, or generated with configure_file and # in the build root if not isinstance(s, File): raise InvalidArguments('All sources in target {!r} must be of type mesonlib.File'.format(s)) f = s.rel_to_builddir(self.build_to_src) srcs[f] = s return srcs # Languages that can mix with C or C++ but don't support unity builds yet # because the syntax we use for unity builds is specific to C/++/ObjC/++. # Assembly files cannot be unitified and neither can LLVM IR files langs_cant_unity = ('d', 'fortran') def get_target_source_can_unity(self, target, source): if isinstance(source, File): source = source.fname if self.environment.is_llvm_ir(source) or \ self.environment.is_assembly(source): return False suffix = os.path.splitext(source)[1][1:] for lang in self.langs_cant_unity: if lang not in target.compilers: continue if suffix in target.compilers[lang].file_suffixes: return False return True def create_target_source_introspection(self, target: build.Target, comp: compilers.Compiler, parameters, sources, generated_sources): ''' Adds the source file introspection information for a language of a target Internal introspection storage formart: self.introspection_data = { '': { : { 'language: 'lang', 'compiler': ['comp', 'exe', 'list'], 'parameters': ['UNIQUE', 'parameter', 'list'], 'sources': [], 'generated_sources': [], } } } ''' tid = target.get_id() lang = comp.get_language() tgt = self.introspection_data[tid] # Find an existing entry or create a new one id_hash = (lang, tuple(parameters)) src_block = tgt.get(id_hash, None) if src_block is None: # Convert parameters if isinstance(parameters, CompilerArgs): parameters = parameters.to_native(copy=True) parameters = comp.compute_parameters_with_absolute_paths(parameters, self.build_dir) # The new entry src_block = { 'language': lang, 'compiler': comp.get_exelist(), 'parameters': parameters, 'sources': [], 'generated_sources': [], } tgt[id_hash] = src_block # Make source files absolute sources = [x.absolute_path(self.source_dir, self.build_dir) if isinstance(x, File) else os.path.normpath(os.path.join(self.build_dir, x)) for x in sources] generated_sources = [x.absolute_path(self.source_dir, self.build_dir) if isinstance(x, File) else os.path.normpath(os.path.join(self.build_dir, x)) for x in generated_sources] # Add the source files src_block['sources'] += sources src_block['generated_sources'] += generated_sources def is_rust_target(self, target): if len(target.sources) > 0: first_file = target.sources[0] if first_file.fname.endswith('.rs'): return True return False def generate_target(self, target): if isinstance(target, build.CustomTarget): self.generate_custom_target(target) if isinstance(target, build.RunTarget): self.generate_run_target(target) name = target.get_id() if name in self.processed_targets: return self.processed_targets[name] = True # Initialize an empty introspection source list self.introspection_data[name] = {} # Generate rules for all dependency targets self.process_target_dependencies(target) # If target uses a language that cannot link to C objects, # just generate for that language and return. if isinstance(target, build.Jar): self.generate_jar_target(target) return if self.is_rust_target(target): self.generate_rust_target(target) return if 'cs' in target.compilers: self.generate_cs_target(target) return if 'swift' in target.compilers: self.generate_swift_target(target) return # Now we handle the following languages: # ObjC++, ObjC, C++, C, D, Fortran, Vala # target_sources: # Pre-existing target C/C++ sources to be built; dict of full path to # source relative to build root and the original File object. # generated_sources: # GeneratedList and CustomTarget sources to be built; dict of the full # path to source relative to build root and the generating target/list # vala_generated_sources: # Array of sources generated by valac that have to be compiled if 'vala' in target.compilers: # Sources consumed by valac are filtered out. These only contain # C/C++ sources, objects, generated libs, and unknown sources now. target_sources, generated_sources, \ vala_generated_sources = self.generate_vala_compile(target) else: target_sources = self.get_target_sources(target) generated_sources = self.get_target_generated_sources(target) vala_generated_sources = [] self.scan_fortran_module_outputs(target) # Generate rules for GeneratedLists self.generate_generator_list_rules(target) # Generate rules for building the remaining source files in this target outname = self.get_target_filename(target) obj_list = [] is_unity = self.is_unity(target) header_deps = [] unity_src = [] unity_deps = [] # Generated sources that must be built before compiling a Unity target. header_deps += self.get_generated_headers(target) if is_unity: # Warn about incompatible sources if a unity build is enabled langs = set(target.compilers.keys()) langs_cant = langs.intersection(self.langs_cant_unity) if langs_cant: langs_are = langs = ', '.join(langs_cant).upper() langs_are += ' are' if len(langs_cant) > 1 else ' is' msg = '{} not supported in Unity builds yet, so {} ' \ 'sources in the {!r} target will be compiled normally' \ ''.format(langs_are, langs, target.name) mlog.log(mlog.red('FIXME'), msg) # Get a list of all generated headers that will be needed while building # this target's sources (generated sources and pre-existing sources). # This will be set as dependencies of all the target's sources. At the # same time, also deal with generated sources that need to be compiled. generated_source_files = [] for rel_src in generated_sources.keys(): dirpart, fnamepart = os.path.split(rel_src) raw_src = File(True, dirpart, fnamepart) if self.environment.is_source(rel_src) and not self.environment.is_header(rel_src): if is_unity and self.get_target_source_can_unity(target, rel_src): unity_deps.append(raw_src) abs_src = os.path.join(self.environment.get_build_dir(), rel_src) unity_src.append(abs_src) else: generated_source_files.append(raw_src) elif self.environment.is_object(rel_src): obj_list.append(rel_src) elif self.environment.is_library(rel_src): pass else: # Assume anything not specifically a source file is a header. This is because # people generate files with weird suffixes (.inc, .fh) that they then include # in their source files. header_deps.append(raw_src) # These are the generated source files that need to be built for use by # this target. We create the Ninja build file elements for this here # because we need `header_deps` to be fully generated in the above loop. for src in generated_source_files: if self.environment.is_llvm_ir(src): o = self.generate_llvm_ir_compile(target, src) else: o = self.generate_single_compile(target, src, True, header_deps=header_deps) obj_list.append(o) use_pch = self.environment.coredata.base_options.get('b_pch', False) if use_pch and target.has_pch(): pch_objects = self.generate_pch(target, header_deps=header_deps) else: pch_objects = [] # Generate compilation targets for C sources generated from Vala # sources. This can be extended to other $LANG->C compilers later if # necessary. This needs to be separate for at least Vala vala_generated_source_files = [] for src in vala_generated_sources: dirpart, fnamepart = os.path.split(src) raw_src = File(True, dirpart, fnamepart) if is_unity: unity_src.append(os.path.join(self.environment.get_build_dir(), src)) header_deps.append(raw_src) else: # Generated targets are ordered deps because the must exist # before the sources compiling them are used. After the first # compile we get precise dependency info from dep files. # This should work in all cases. If it does not, then just # move them from orderdeps to proper deps. if self.environment.is_header(src): header_deps.append(raw_src) else: # We gather all these and generate compile rules below # after `header_deps` (above) is fully generated vala_generated_source_files.append(raw_src) for src in vala_generated_source_files: # Passing 'vala' here signifies that we want the compile # arguments to be specialized for C code generated by # valac. For instance, no warnings should be emitted. obj_list.append(self.generate_single_compile(target, src, 'vala', [], header_deps)) # Generate compile targets for all the pre-existing sources for this target for src in target_sources.values(): if not self.environment.is_header(src): if self.environment.is_llvm_ir(src): obj_list.append(self.generate_llvm_ir_compile(target, src)) elif is_unity and self.get_target_source_can_unity(target, src): abs_src = os.path.join(self.environment.get_build_dir(), src.rel_to_builddir(self.build_to_src)) unity_src.append(abs_src) else: obj_list.append(self.generate_single_compile(target, src, False, [], header_deps)) obj_list += self.flatten_object_list(target) if is_unity: for src in self.generate_unity_files(target, unity_src): obj_list.append(self.generate_single_compile(target, src, True, unity_deps + header_deps)) linker, stdlib_args = self.determine_linker_and_stdlib_args(target) elem = self.generate_link(target, outname, obj_list, linker, pch_objects, stdlib_args=stdlib_args) self.generate_shlib_aliases(target, self.get_target_dir(target)) self.add_build(elem) def process_target_dependencies(self, target): for t in target.get_dependencies(): if t.get_id() not in self.processed_targets: self.generate_target(t) def custom_target_generator_inputs(self, target): for s in target.sources: if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, build.GeneratedList): self.generate_genlist_for_target(s, target) def unwrap_dep_list(self, target): deps = [] for i in target.get_dependencies(): # FIXME, should not grab element at zero but rather expand all. if isinstance(i, list): i = i[0] # Add a dependency on all the outputs of this target for output in i.get_outputs(): deps.append(os.path.join(self.get_target_dir(i), output)) return deps def generate_custom_target(self, target): self.custom_target_generator_inputs(target) (srcs, ofilenames, cmd) = self.eval_custom_target_command(target) deps = self.unwrap_dep_list(target) deps += self.get_custom_target_depend_files(target) desc = 'Generating {0} with a {1} command.' if target.build_always_stale: deps.append('PHONY') if target.depfile is None: rulename = 'CUSTOM_COMMAND' else: rulename = 'CUSTOM_COMMAND_DEP' elem = NinjaBuildElement(self.all_outputs, ofilenames, rulename, srcs) elem.add_dep(deps) for d in target.extra_depends: # Add a dependency on all the outputs of this target for output in d.get_outputs(): elem.add_dep(os.path.join(self.get_target_dir(d), output)) meson_exe_cmd = self.as_meson_exe_cmdline(target.name, target.command[0], cmd[1:], for_machine=target.for_machine, extra_bdeps=target.get_transitive_build_target_deps(), capture=ofilenames[0] if target.capture else None) if meson_exe_cmd: cmd = meson_exe_cmd cmd_type = 'meson_exe.py custom' else: cmd_type = 'custom' if target.depfile is not None: depfile = target.get_dep_outname(elem.infilenames) rel_dfile = os.path.join(self.get_target_dir(target), depfile) abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) os.makedirs(abs_pdir, exist_ok=True) elem.add_item('DEPFILE', rel_dfile) if target.console: elem.add_item('pool', 'console') cmd = self.replace_paths(target, cmd) elem.add_item('COMMAND', cmd) elem.add_item('description', desc.format(target.name, cmd_type)) self.add_build(elem) self.processed_targets[target.get_id()] = True def build_run_target_name(self, target): if target.subproject != '': subproject_prefix = '{}@@'.format(target.subproject) else: subproject_prefix = '' return '{}{}'.format(subproject_prefix, target.name) def generate_run_target(self, target): cmd = self.environment.get_build_command() + ['--internal', 'commandrunner'] deps = self.unwrap_dep_list(target) arg_strings = [] for i in target.args: if isinstance(i, str): arg_strings.append(i) elif isinstance(i, (build.BuildTarget, build.CustomTarget)): relfname = self.get_target_filename(i) arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname)) deps.append(relfname) elif isinstance(i, mesonlib.File): relfname = i.rel_to_builddir(self.build_to_src) arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname)) else: raise AssertionError('Unreachable code in generate_run_target: ' + str(i)) cmd += [self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir] + self.environment.get_build_command() texe = target.command try: texe = texe.held_object except AttributeError: pass if isinstance(texe, build.Executable): abs_exe = os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe)) deps.append(self.get_target_filename(texe)) if self.environment.is_cross_build(): exe_wrap = self.environment.get_exe_wrapper() if exe_wrap: if not exe_wrap.found(): msg = 'The exe_wrapper {!r} defined in the cross file is ' \ 'needed by run target {!r}, but was not found. ' \ 'Please check the command and/or add it to PATH.' raise MesonException(msg.format(exe_wrap.name, target.name)) cmd += exe_wrap.get_command() cmd.append(abs_exe) elif isinstance(texe, dependencies.ExternalProgram): cmd += texe.get_command() elif isinstance(texe, build.CustomTarget): deps.append(self.get_target_filename(texe)) cmd += [os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe))] elif isinstance(texe, mesonlib.File): cmd.append(texe.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir())) else: cmd.append(target.command) cmd += arg_strings if texe: target_name = 'meson-{}'.format(self.build_run_target_name(target)) elem = NinjaBuildElement(self.all_outputs, target_name, 'CUSTOM_COMMAND', []) elem.add_item('COMMAND', cmd) elem.add_item('description', 'Running external command %s.' % target.name) elem.add_item('pool', 'console') # Alias that runs the target defined above with the name the user specified self.create_target_alias(target_name) else: target_name = self.build_run_target_name(target) elem = NinjaBuildElement(self.all_outputs, target_name, 'phony', []) elem.add_dep(deps) self.add_build(elem) self.processed_targets[target.get_id()] = True def generate_coverage_command(self, elem, outputs): elem.add_item('COMMAND', self.environment.get_build_command() + ['--internal', 'coverage'] + outputs + [self.environment.get_source_dir(), os.path.join(self.environment.get_source_dir(), self.build.get_subproject_dir()), self.environment.get_build_dir(), self.environment.get_log_dir()]) def generate_coverage_rules(self): e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, []) e.add_item('description', 'Generates coverage reports.') self.add_build(e) # Alias that runs the target defined above self.create_target_alias('meson-coverage') self.generate_coverage_legacy_rules() def generate_coverage_legacy_rules(self): e = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--xml']) e.add_item('description', 'Generates XML coverage report.') self.add_build(e) # Alias that runs the target defined above self.create_target_alias('meson-coverage-xml') e = NinjaBuildElement(self.all_outputs, 'meson-coverage-text', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--text']) e.add_item('description', 'Generates text coverage report.') self.add_build(e) # Alias that runs the target defined above self.create_target_alias('meson-coverage-text') e = NinjaBuildElement(self.all_outputs, 'meson-coverage-html', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--html']) e.add_item('description', 'Generates HTML coverage report.') self.add_build(e) # Alias that runs the target defined above self.create_target_alias('meson-coverage-html') def generate_install(self): self.create_install_data_files() elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY') elem.add_dep('all') elem.add_item('DESC', 'Installing files.') elem.add_item('COMMAND', self.environment.get_build_command() + ['install', '--no-rebuild']) elem.add_item('pool', 'console') self.add_build(elem) # Alias that runs the target defined above self.create_target_alias('meson-install') def generate_tests(self): self.serialize_tests() cmd = self.environment.get_build_command(True) + ['test', '--no-rebuild'] if not self.environment.coredata.get_builtin_option('stdsplit'): cmd += ['--no-stdsplit'] if self.environment.coredata.get_builtin_option('errorlogs'): cmd += ['--print-errorlogs'] elem = NinjaBuildElement(self.all_outputs, 'meson-test', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running all tests.') elem.add_item('pool', 'console') self.add_build(elem) # Alias that runs the above-defined meson-test target self.create_target_alias('meson-test') # And then benchmarks. cmd = self.environment.get_build_command(True) + [ 'test', '--benchmark', '--logbase', 'benchmarklog', '--num-processes=1', '--no-rebuild'] elem = NinjaBuildElement(self.all_outputs, 'meson-benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running benchmark suite.') elem.add_item('pool', 'console') self.add_build(elem) # Alias that runs the above-defined meson-benchmark target self.create_target_alias('meson-benchmark') def generate_rules(self): self.rules = [] self.ruledict = {} self.add_rule_comment(NinjaComment('Rules for compiling.')) self.generate_compile_rules() self.add_rule_comment(NinjaComment('Rules for linking.')) self.generate_static_link_rules() self.generate_dynamic_link_rules() self.add_rule_comment(NinjaComment('Other rules')) # Ninja errors out if you have deps = gcc but no depfile, so we must # have two rules for custom commands. self.add_rule(NinjaRule('CUSTOM_COMMAND', ['$COMMAND'], [], '$DESC', extra='restat = 1')) self.add_rule(NinjaRule('CUSTOM_COMMAND_DEP', ['$COMMAND'], [], '$DESC', deps='gcc', depfile='$DEPFILE', extra='restat = 1')) c = [ninja_quote(quote_func(x)) for x in self.environment.get_build_command()] + \ ['--internal', 'regenerate', ninja_quote(quote_func(self.environment.get_source_dir())), ninja_quote(quote_func(self.environment.get_build_dir()))] self.add_rule(NinjaRule('REGENERATE_BUILD', c + ['--backend', 'ninja'], [], 'Regenerating build files.', extra='generator = 1')) def add_rule_comment(self, comment): self.rules.append(comment) def add_build_comment(self, comment): self.build_elements.append(comment) def add_rule(self, rule): self.rules.append(rule) self.ruledict[rule.name] = rule def add_build(self, build): self.build_elements.append(build) # increment rule refcount if build.rule != 'phony': self.ruledict[build.rule].refcount += 1 def write_rules(self, outfile): for r in self.rules: r.write(outfile) def write_builds(self, outfile): for b in ProgressBar(self.build_elements, desc='Writing build.ninja'): b.write(outfile) def generate_phony(self): self.add_build_comment(NinjaComment('Phony build target, always out of date')) elem = NinjaBuildElement(self.all_outputs, 'PHONY', 'phony', '') self.add_build(elem) def generate_jar_target(self, target): fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() class_list = [] compiler = target.compilers['java'] c = 'c' m = 'm' e = '' f = 'f' main_class = target.get_main_class() if main_class != '': e = 'e' # Add possible java generated files to src list generated_sources = self.get_target_generated_sources(target) gen_src_list = [] for rel_src in generated_sources.keys(): dirpart, fnamepart = os.path.split(rel_src) raw_src = File(True, dirpart, fnamepart) if rel_src.endswith('.java'): gen_src_list.append(raw_src) compile_args = self.determine_single_java_compile_args(target, compiler) for src in src_list + gen_src_list: plain_class_path = self.generate_single_java_compile(src, target, compiler, compile_args) class_list.append(plain_class_path) class_dep_list = [os.path.join(self.get_target_private_dir(target), i) for i in class_list] manifest_path = os.path.join(self.get_target_private_dir(target), 'META-INF', 'MANIFEST.MF') manifest_fullpath = os.path.join(self.environment.get_build_dir(), manifest_path) os.makedirs(os.path.dirname(manifest_fullpath), exist_ok=True) with open(manifest_fullpath, 'w') as manifest: if any(target.link_targets): manifest.write('Class-Path: ') cp_paths = [os.path.join(self.get_target_dir(l), l.get_filename()) for l in target.link_targets] manifest.write(' '.join(cp_paths)) manifest.write('\n') jar_rule = 'java_LINKER' commands = [c + m + e + f] commands.append(manifest_path) if e != '': commands.append(main_class) commands.append(self.get_target_filename(target)) # Java compilation can produce an arbitrary number of output # class files for a single source file. Thus tell jar to just # grab everything in the final package. commands += ['-C', self.get_target_private_dir(target), '.'] elem = NinjaBuildElement(self.all_outputs, outname_rel, jar_rule, []) elem.add_dep(class_dep_list) elem.add_item('ARGS', commands) self.add_build(elem) # Create introspection information self.create_target_source_introspection(target, compiler, compile_args, src_list, gen_src_list) def generate_cs_resource_tasks(self, target): args = [] deps = [] for r in target.resources: rel_sourcefile = os.path.join(self.build_to_src, target.subdir, r) if r.endswith('.resources'): a = '-resource:' + rel_sourcefile elif r.endswith('.txt') or r.endswith('.resx'): ofilebase = os.path.splitext(os.path.basename(r))[0] + '.resources' ofilename = os.path.join(self.get_target_private_dir(target), ofilebase) elem = NinjaBuildElement(self.all_outputs, ofilename, "CUSTOM_COMMAND", rel_sourcefile) elem.add_item('COMMAND', ['resgen', rel_sourcefile, ofilename]) elem.add_item('DESC', 'Compiling resource %s.' % rel_sourcefile) self.add_build(elem) deps.append(ofilename) a = '-resource:' + ofilename else: raise InvalidArguments('Unknown resource file %s.' % r) args.append(a) return args, deps def generate_cs_target(self, target): buildtype = self.get_option_for_target('buildtype', target) fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() compiler = target.compilers['cs'] rel_srcs = [os.path.normpath(s.rel_to_builddir(self.build_to_src)) for s in src_list] deps = [] commands = CompilerArgs(compiler, target.extra_args.get('cs', [])) commands += compiler.get_buildtype_args(buildtype) commands += compiler.get_optimization_args(self.get_option_for_target('optimization', target)) commands += compiler.get_debug_args(self.get_option_for_target('debug', target)) if isinstance(target, build.Executable): commands.append('-target:exe') elif isinstance(target, build.SharedLibrary): commands.append('-target:library') else: raise MesonException('Unknown C# target type.') (resource_args, resource_deps) = self.generate_cs_resource_tasks(target) commands += resource_args deps += resource_deps commands += compiler.get_output_args(outname_rel) for l in target.link_targets: lname = os.path.join(self.get_target_dir(l), l.get_filename()) commands += compiler.get_link_args(lname) deps.append(lname) if '-g' in commands: outputs = [outname_rel, outname_rel + '.mdb'] else: outputs = [outname_rel] generated_sources = self.get_target_generated_sources(target) generated_rel_srcs = [] for rel_src in generated_sources.keys(): if rel_src.lower().endswith('.cs'): generated_rel_srcs.append(os.path.normpath(rel_src)) deps.append(os.path.normpath(rel_src)) for dep in target.get_external_deps(): commands.extend_direct(dep.get_link_args()) commands += self.build.get_project_args(compiler, target.subproject, target.for_machine) commands += self.build.get_global_args(compiler, target.for_machine) elem = NinjaBuildElement(self.all_outputs, outputs, self.get_compiler_rule_name('cs', target.for_machine), rel_srcs + generated_rel_srcs) elem.add_dep(deps) elem.add_item('ARGS', commands) self.add_build(elem) self.generate_generator_list_rules(target) self.create_target_source_introspection(target, compiler, commands, rel_srcs, generated_rel_srcs) def determine_single_java_compile_args(self, target, compiler): args = [] args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target)) args += self.build.get_global_args(compiler, target.for_machine) args += self.build.get_project_args(compiler, target.subproject, target.for_machine) args += target.get_java_args() args += compiler.get_output_args(self.get_target_private_dir(target)) args += target.get_classpath_args() curdir = target.get_subdir() sourcepath = os.path.join(self.build_to_src, curdir) + os.pathsep sourcepath += os.path.normpath(curdir) + os.pathsep for i in target.include_dirs: for idir in i.get_incdirs(): sourcepath += os.path.join(self.build_to_src, i.curdir, idir) + os.pathsep args += ['-sourcepath', sourcepath] return args def generate_single_java_compile(self, src, target, compiler, args): deps = [os.path.join(self.get_target_dir(l), l.get_filename()) for l in target.link_targets] generated_sources = self.get_target_generated_sources(target) for rel_src in generated_sources.keys(): if rel_src.endswith('.java'): deps.append(rel_src) rel_src = src.rel_to_builddir(self.build_to_src) plain_class_path = src.fname[:-4] + 'class' rel_obj = os.path.join(self.get_target_private_dir(target), plain_class_path) element = NinjaBuildElement(self.all_outputs, rel_obj, self.compiler_to_rule_name(compiler), rel_src) element.add_dep(deps) element.add_item('ARGS', args) self.add_build(element) return plain_class_path def generate_java_link(self): rule = 'java_LINKER' command = ['jar', '$ARGS'] description = 'Creating JAR $out.' self.add_rule(NinjaRule(rule, command, [], description)) def determine_dep_vapis(self, target): """ Peek into the sources of BuildTargets we're linking with, and if any of them was built with Vala, assume that it also generated a .vapi file of the same name as the BuildTarget and return the path to it relative to the build directory. """ result = OrderedSet() for dep in itertools.chain(target.link_targets, target.link_whole_targets): if not dep.is_linkable_target(): continue for i in dep.sources: if hasattr(i, 'fname'): i = i.fname if i.endswith('vala'): vapiname = dep.vala_vapi fullname = os.path.join(self.get_target_dir(dep), vapiname) result.add(fullname) break return list(result) def split_vala_sources(self, t): """ Splits the target's sources into .vala, .gs, .vapi, and other sources. Handles both pre-existing and generated sources. Returns a tuple (vala, vapi, others) each of which is a dictionary with the keys being the path to the file (relative to the build directory) and the value being the object that generated or represents the file. """ vala = OrderedDict() vapi = OrderedDict() others = OrderedDict() othersgen = OrderedDict() # Split pre-existing sources for s in t.get_sources(): # BuildTarget sources are always mesonlib.File files which are # either in the source root, or generated with configure_file and # in the build root if not isinstance(s, File): msg = 'All sources in target {!r} must be of type ' \ 'mesonlib.File, not {!r}'.format(t, s) raise InvalidArguments(msg) f = s.rel_to_builddir(self.build_to_src) if s.endswith(('.vala', '.gs')): srctype = vala elif s.endswith('.vapi'): srctype = vapi else: srctype = others srctype[f] = s # Split generated sources for gensrc in t.get_generated_sources(): for s in gensrc.get_outputs(): f = self.get_target_generated_dir(t, gensrc, s) if s.endswith(('.vala', '.gs')): srctype = vala elif s.endswith('.vapi'): srctype = vapi # Generated non-Vala (C/C++) sources. Won't be used for # generating the Vala compile rule below. else: srctype = othersgen # Duplicate outputs are disastrous if f in srctype and srctype[f] is not gensrc: msg = 'Duplicate output {0!r} from {1!r} {2!r}; ' \ 'conflicts with {0!r} from {4!r} {3!r}' \ ''.format(f, type(gensrc).__name__, gensrc.name, srctype[f].name, type(srctype[f]).__name__) raise InvalidArguments(msg) # Store 'somefile.vala': GeneratedList (or CustomTarget) srctype[f] = gensrc return vala, vapi, (others, othersgen) def generate_vala_compile(self, target): """Vala is compiled into C. Set up all necessary build steps here.""" (vala_src, vapi_src, other_src) = self.split_vala_sources(target) extra_dep_files = [] if not vala_src: msg = 'Vala library {!r} has no Vala or Genie source files.' raise InvalidArguments(msg.format(target.name)) valac = target.compilers['vala'] c_out_dir = self.get_target_private_dir(target) # C files generated by valac vala_c_src = [] # Files generated by valac valac_outputs = [] # All sources that are passed to valac on the commandline all_files = list(vapi_src.keys()) # Passed as --basedir srcbasedir = os.path.join(self.build_to_src, target.get_subdir()) for (vala_file, gensrc) in vala_src.items(): all_files.append(vala_file) # Figure out where the Vala compiler will write the compiled C file # # If the Vala file is in a subdir of the build dir (in our case # because it was generated/built by something else), and is also # a subdir of --basedir (because the builddir is in the source # tree, and the target subdir is the source root), the subdir # components from the source root till the private builddir will be # duplicated inside the private builddir. Otherwise, just the # basename will be used. # # If the Vala file is outside the build directory, the paths from # the --basedir till the subdir will be duplicated inside the # private builddir. if isinstance(gensrc, (build.CustomTarget, build.GeneratedList)) or gensrc.is_built: vala_c_file = os.path.splitext(os.path.basename(vala_file))[0] + '.c' # Check if the vala file is in a subdir of --basedir abs_srcbasedir = os.path.join(self.environment.get_source_dir(), target.get_subdir()) abs_vala_file = os.path.join(self.environment.get_build_dir(), vala_file) if PurePath(os.path.commonpath((abs_srcbasedir, abs_vala_file))) == PurePath(abs_srcbasedir): vala_c_subdir = PurePath(abs_vala_file).parent.relative_to(abs_srcbasedir) vala_c_file = os.path.join(str(vala_c_subdir), vala_c_file) else: path_to_target = os.path.join(self.build_to_src, target.get_subdir()) if vala_file.startswith(path_to_target): vala_c_file = os.path.splitext(os.path.relpath(vala_file, path_to_target))[0] + '.c' else: vala_c_file = os.path.splitext(os.path.basename(vala_file))[0] + '.c' # All this will be placed inside the c_out_dir vala_c_file = os.path.join(c_out_dir, vala_c_file) vala_c_src.append(vala_c_file) valac_outputs.append(vala_c_file) args = self.generate_basic_compiler_args(target, valac) args += valac.get_colorout_args(self.environment.coredata.base_options.get('b_colorout').value) # Tell Valac to output everything in our private directory. Sadly this # means it will also preserve the directory components of Vala sources # found inside the build tree (generated sources). args += ['--directory', c_out_dir] args += ['--basedir', srcbasedir] if target.is_linkable_target(): # Library name args += ['--library', target.name] # Outputted header hname = os.path.join(self.get_target_dir(target), target.vala_header) args += ['--header', hname] if self.is_unity(target): # Without this the declarations will get duplicated in the .c # files and cause a build failure when all of them are # #include-d in one .c file. # https://github.com/mesonbuild/meson/issues/1969 args += ['--use-header'] valac_outputs.append(hname) # Outputted vapi file vapiname = os.path.join(self.get_target_dir(target), target.vala_vapi) # Force valac to write the vapi and gir files in the target build dir. # Without this, it will write it inside c_out_dir args += ['--vapi', os.path.join('..', target.vala_vapi)] valac_outputs.append(vapiname) target.outputs += [target.vala_header, target.vala_vapi] # Install header and vapi to default locations if user requests this if len(target.install_dir) > 1 and target.install_dir[1] is True: target.install_dir[1] = self.environment.get_includedir() if len(target.install_dir) > 2 and target.install_dir[2] is True: target.install_dir[2] = os.path.join(self.environment.get_datadir(), 'vala', 'vapi') # Generate GIR if requested if isinstance(target.vala_gir, str): girname = os.path.join(self.get_target_dir(target), target.vala_gir) args += ['--gir', os.path.join('..', target.vala_gir)] valac_outputs.append(girname) target.outputs.append(target.vala_gir) # Install GIR to default location if requested by user if len(target.install_dir) > 3 and target.install_dir[3] is True: target.install_dir[3] = os.path.join(self.environment.get_datadir(), 'gir-1.0') # Detect gresources and add --gresources arguments for each for gensrc in other_src[1].values(): if isinstance(gensrc, modules.GResourceTarget): gres_xml, = self.get_custom_target_sources(gensrc) args += ['--gresources=' + gres_xml] extra_args = [] for a in target.extra_args.get('vala', []): if isinstance(a, File): relname = a.rel_to_builddir(self.build_to_src) extra_dep_files.append(relname) extra_args.append(relname) else: extra_args.append(a) dependency_vapis = self.determine_dep_vapis(target) extra_dep_files += dependency_vapis args += extra_args element = NinjaBuildElement(self.all_outputs, valac_outputs, self.compiler_to_rule_name(valac), all_files + dependency_vapis) element.add_item('ARGS', args) element.add_dep(extra_dep_files) self.add_build(element) self.create_target_source_introspection(target, valac, args, all_files, []) return other_src[0], other_src[1], vala_c_src def generate_rust_target(self, target): rustc = target.compilers['rust'] # Rust compiler takes only the main file as input and # figures out what other files are needed via import # statements and magic. main_rust_file = None for i in target.get_sources(): if not rustc.can_compile(i): raise InvalidArguments('Rust target %s contains a non-rust source file.' % target.get_basename()) if main_rust_file is None: main_rust_file = i.rel_to_builddir(self.build_to_src) if main_rust_file is None: raise RuntimeError('A Rust target has no Rust sources. This is weird. Also a bug. Please report') target_name = os.path.join(target.subdir, target.get_filename()) args = ['--crate-type'] if isinstance(target, build.Executable): cratetype = 'bin' elif hasattr(target, 'rust_crate_type'): cratetype = target.rust_crate_type elif isinstance(target, build.SharedLibrary): cratetype = 'dylib' elif isinstance(target, build.StaticLibrary): cratetype = 'rlib' else: raise InvalidArguments('Unknown target type for rustc.') args.append(cratetype) # If we're dynamically linking, add those arguments # # Rust is super annoying, calling -C link-arg foo does not work, it has # to be -C link-arg=foo if cratetype in {'bin', 'dylib'}: for a in rustc.linker.get_always_args(): args += ['-C', 'link-arg={}'.format(a)] args += ['--crate-name', target.name] args += rustc.get_buildtype_args(self.get_option_for_target('buildtype', target)) args += rustc.get_debug_args(self.get_option_for_target('debug', target)) args += rustc.get_optimization_args(self.get_option_for_target('optimization', target)) args += self.build.get_global_args(rustc, target.for_machine) args += self.build.get_project_args(rustc, target.subproject, target.for_machine) depfile = os.path.join(target.subdir, target.name + '.d') args += ['--emit', 'dep-info={}'.format(depfile), '--emit', 'link'] args += target.get_extra_args('rust') args += ['-o', os.path.join(target.subdir, target.get_filename())] orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets] linkdirs = OrderedDict() for d in target.link_targets: linkdirs[d.subdir] = True # specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust # dependency, so that collisions with libraries in rustc's # sysroot don't cause ambiguity args += ['--extern', '{}={}'.format(d.name, os.path.join(d.subdir, d.filename))] for d in linkdirs.keys(): if d == '': d = '.' args += ['-L', d] has_shared_deps = False for dep in target.get_dependencies(): if isinstance(dep, build.SharedLibrary): has_shared_deps = True if isinstance(target, build.SharedLibrary) or has_shared_deps: # add prefer-dynamic if any of the Rust libraries we link # against are dynamic, otherwise we'll end up with # multiple implementations of crates args += ['-C', 'prefer-dynamic'] # build the usual rpath arguments as well... # Set runtime-paths so we can run executables without needing to set # LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows. if has_path_sep(target.name): # Target names really should not have slashes in them, but # unfortunately we did not check for that and some downstream projects # now have them. Once slashes are forbidden, remove this bit. target_slashname_workaround_dir = os.path.join(os.path.dirname(target.name), self.get_target_dir(target)) else: target_slashname_workaround_dir = self.get_target_dir(target) rpath_args = rustc.build_rpath_args(self.environment, self.environment.get_build_dir(), target_slashname_workaround_dir, self.determine_rpath_dirs(target), target.build_rpath, target.install_rpath) # ... but then add rustc's sysroot to account for rustup # installations for rpath_arg in rpath_args: args += ['-C', 'link-arg=' + rpath_arg + ':' + os.path.join(rustc.get_sysroot(), 'lib')] compiler_name = self.get_compiler_rule_name('rust', target.for_machine) element = NinjaBuildElement(self.all_outputs, target_name, compiler_name, main_rust_file) if len(orderdeps) > 0: element.add_orderdep(orderdeps) element.add_item('ARGS', args) element.add_item('targetdep', depfile) element.add_item('cratetype', cratetype) self.add_build(element) if isinstance(target, build.SharedLibrary): self.generate_shsym(target) self.create_target_source_introspection(target, rustc, args, [main_rust_file], []) @staticmethod def get_rule_suffix(for_machine: MachineChoice) -> str: return PerMachine('_FOR_BUILD', '')[for_machine] @classmethod def get_compiler_rule_name(cls, lang: str, for_machine: MachineChoice) -> str: return '%s_COMPILER%s' % (lang, cls.get_rule_suffix(for_machine)) @classmethod def get_pch_rule_name(cls, lang: str, for_machine: MachineChoice) -> str: return '%s_PCH%s' % (lang, cls.get_rule_suffix(for_machine)) @classmethod def compiler_to_rule_name(cls, compiler: Compiler) -> str: return cls.get_compiler_rule_name(compiler.get_language(), compiler.for_machine) @classmethod def compiler_to_pch_rule_name(cls, compiler: Compiler) -> str: return cls.get_pch_rule_name(compiler.get_language(), compiler.for_machine) def swift_module_file_name(self, target): return os.path.join(self.get_target_private_dir(target), self.target_swift_modulename(target) + '.swiftmodule') def target_swift_modulename(self, target): return target.name def is_swift_target(self, target): for s in target.sources: if s.endswith('swift'): return True return False def determine_swift_dep_modules(self, target): result = [] for l in target.link_targets: if self.is_swift_target(l): result.append(self.swift_module_file_name(l)) return result def determine_swift_dep_dirs(self, target): result = [] for l in target.link_targets: result.append(self.get_target_private_dir_abs(l)) return result def get_swift_link_deps(self, target): result = [] for l in target.link_targets: result.append(self.get_target_filename(l)) return result def split_swift_generated_sources(self, target): all_srcs = self.get_target_generated_sources(target) srcs = [] others = [] for i in all_srcs: if i.endswith('.swift'): srcs.append(i) else: others.append(i) return srcs, others def generate_swift_target(self, target): module_name = self.target_swift_modulename(target) swiftc = target.compilers['swift'] abssrc = [] relsrc = [] abs_headers = [] header_imports = [] for i in target.get_sources(): if swiftc.can_compile(i): rels = i.rel_to_builddir(self.build_to_src) abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), rels)) relsrc.append(rels) abssrc.append(abss) elif self.environment.is_header(i): relh = i.rel_to_builddir(self.build_to_src) absh = os.path.normpath(os.path.join(self.environment.get_build_dir(), relh)) abs_headers.append(absh) header_imports += swiftc.get_header_import_args(absh) else: raise InvalidArguments('Swift target %s contains a non-swift source file.' % target.get_basename()) os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True) compile_args = swiftc.get_compile_only_args() compile_args += swiftc.get_optimization_args(self.get_option_for_target('optimization', target)) compile_args += swiftc.get_debug_args(self.get_option_for_target('debug', target)) compile_args += swiftc.get_module_args(module_name) compile_args += self.build.get_project_args(swiftc, target.subproject, target.for_machine) compile_args += self.build.get_global_args(swiftc, target.for_machine) for i in reversed(target.get_include_dirs()): basedir = i.get_curdir() for d in i.get_incdirs(): if d not in ('', '.'): expdir = os.path.join(basedir, d) else: expdir = basedir srctreedir = os.path.normpath(os.path.join(self.environment.get_build_dir(), self.build_to_src, expdir)) sargs = swiftc.get_include_args(srctreedir) compile_args += sargs link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))) link_args += self.build.get_project_link_args(swiftc, target.subproject, target.for_machine) link_args += self.build.get_global_link_args(swiftc, target.for_machine) rundir = self.get_target_private_dir(target) out_module_name = self.swift_module_file_name(target) in_module_files = self.determine_swift_dep_modules(target) abs_module_dirs = self.determine_swift_dep_dirs(target) module_includes = [] for x in abs_module_dirs: module_includes += swiftc.get_include_args(x) link_deps = self.get_swift_link_deps(target) abs_link_deps = [os.path.join(self.environment.get_build_dir(), x) for x in link_deps] for d in target.link_targets: reldir = self.get_target_dir(d) if reldir == '': reldir = '.' link_args += ['-L', os.path.normpath(os.path.join(self.environment.get_build_dir(), reldir))] (rel_generated, _) = self.split_swift_generated_sources(target) abs_generated = [os.path.join(self.environment.get_build_dir(), x) for x in rel_generated] # We need absolute paths because swiftc needs to be invoked in a subdir # and this is the easiest way about it. objects = [] # Relative to swift invocation dir rel_objects = [] # Relative to build.ninja for i in abssrc + abs_generated: base = os.path.basename(i) oname = os.path.splitext(base)[0] + '.o' objects.append(oname) rel_objects.append(os.path.join(self.get_target_private_dir(target), oname)) rulename = self.get_compiler_rule_name('swift', target.for_machine) # Swiftc does not seem to be able to emit objects and module files in one go. elem = NinjaBuildElement(self.all_outputs, rel_objects, rulename, abssrc) elem.add_dep(in_module_files + rel_generated) elem.add_dep(abs_headers) elem.add_item('ARGS', compile_args + header_imports + abs_generated + module_includes) elem.add_item('RUNDIR', rundir) self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, out_module_name, self.get_compiler_rule_name('swift', target.for_machine), abssrc) elem.add_dep(in_module_files + rel_generated) elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args()) elem.add_item('RUNDIR', rundir) self.add_build(elem) if isinstance(target, build.StaticLibrary): elem = self.generate_link(target, self.get_target_filename(target), rel_objects, self.build.static_linker[target.for_machine]) self.add_build(elem) elif isinstance(target, build.Executable): elem = NinjaBuildElement(self.all_outputs, self.get_target_filename(target), rulename, []) elem.add_dep(rel_objects) elem.add_dep(link_deps) elem.add_item('ARGS', link_args + swiftc.get_std_exe_link_args() + objects + abs_link_deps) elem.add_item('RUNDIR', rundir) self.add_build(elem) else: raise MesonException('Swift supports only executable and static library targets.') # Introspection information self.create_target_source_introspection(target, swiftc, compile_args + header_imports + module_includes, relsrc, rel_generated) def generate_static_link_rules(self): num_pools = self.environment.coredata.backend_options['backend_max_links'].value if 'java' in self.environment.coredata.compilers.host: self.generate_java_link() for for_machine in MachineChoice: static_linker = self.build.static_linker[for_machine] if static_linker is None: return rule = 'STATIC_LINKER%s' % self.get_rule_suffix(for_machine) cmdlist = [] args = ['$in'] # FIXME: Must normalize file names with pathlib.Path before writing # them out to fix this properly on Windows. See: # https://github.com/mesonbuild/meson/issues/1517 # https://github.com/mesonbuild/meson/issues/1526 if isinstance(static_linker, ArLinker) and not mesonlib.is_windows(): # `ar` has no options to overwrite archives. It always appends, # which is never what we want. Delete an existing library first if # it exists. https://github.com/mesonbuild/meson/issues/1355 cmdlist = execute_wrapper + [c.format('$out') for c in rmfile_prefix] cmdlist += static_linker.get_exelist() cmdlist += ['$LINK_ARGS'] cmdlist += static_linker.get_output_args('$out') description = 'Linking static target $out.' if num_pools > 0: pool = 'pool = link_pool' else: pool = None self.add_rule(NinjaRule(rule, cmdlist, args, description, rspable=static_linker.can_linker_accept_rsp(), extra=pool)) def generate_dynamic_link_rules(self): num_pools = self.environment.coredata.backend_options['backend_max_links'].value for for_machine in MachineChoice: complist = self.environment.coredata.compilers[for_machine] for langname, compiler in complist.items(): if langname == 'java' \ or langname == 'vala' \ or langname == 'rust' \ or langname == 'cs': continue rule = '%s_LINKER%s' % (langname, self.get_rule_suffix(for_machine)) command = compiler.get_linker_exelist() args = ['$ARGS'] + compiler.get_linker_output_args('$out') + ['$in', '$LINK_ARGS'] description = 'Linking target $out.' if num_pools > 0: pool = 'pool = link_pool' else: pool = None self.add_rule(NinjaRule(rule, command, args, description, rspable=compiler.can_linker_accept_rsp(), extra=pool)) args = [ninja_quote(quote_func(x)) for x in self.environment.get_build_command()] + \ ['--internal', 'symbolextractor', '$in', '$out'] symrule = 'SHSYM' symcmd = args + ['$CROSS'] syndesc = 'Generating symbol file $out.' synstat = 'restat = 1' self.add_rule(NinjaRule(symrule, symcmd, [], syndesc, extra=synstat)) def generate_java_compile_rule(self, compiler): rule = self.compiler_to_rule_name(compiler) invoc = [ninja_quote(i) for i in compiler.get_exelist()] command = invoc + ['$ARGS', '$in'] description = 'Compiling Java object $in.' self.add_rule(NinjaRule(rule, command, [], description)) def generate_cs_compile_rule(self, compiler): rule = self.compiler_to_rule_name(compiler) invoc = [ninja_quote(i) for i in compiler.get_exelist()] command = invoc args = ['$ARGS', '$in'] description = 'Compiling C Sharp target $out.' self.add_rule(NinjaRule(rule, command, args, description, rspable=mesonlib.is_windows())) def generate_vala_compile_rules(self, compiler): rule = self.compiler_to_rule_name(compiler) invoc = [ninja_quote(i) for i in compiler.get_exelist()] command = invoc + ['$ARGS', '$in'] description = 'Compiling Vala source $in.' self.add_rule(NinjaRule(rule, command, [], description, extra='restat = 1')) def generate_rust_compile_rules(self, compiler): rule = self.compiler_to_rule_name(compiler) invoc = [ninja_quote(i) for i in compiler.get_exelist()] command = invoc + ['$ARGS', '$in'] description = 'Compiling Rust source $in.' depfile = '$targetdep' depstyle = 'gcc' self.add_rule(NinjaRule(rule, command, [], description, deps=depstyle, depfile=depfile)) def generate_swift_compile_rules(self, compiler): rule = self.compiler_to_rule_name(compiler) full_exe = [ninja_quote(x) for x in self.environment.get_build_command()] + [ '--internal', 'dirchanger', '$RUNDIR', ] invoc = full_exe + [ninja_quote(i) for i in compiler.get_exelist()] command = invoc + ['$ARGS', '$in'] description = 'Compiling Swift source $in.' self.add_rule(NinjaRule(rule, command, [], description)) def generate_fortran_dep_hack(self, crstr): rule = 'FORTRAN_DEP_HACK%s' % (crstr) if mesonlib.is_windows(): cmd = ['cmd', '/C'] else: cmd = ['true'] self.add_rule_comment(NinjaComment('''Workaround for these issues: https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.add_rule(NinjaRule(rule, cmd, [], 'Dep hack', extra='restat = 1')) def generate_llvm_ir_compile_rule(self, compiler): if self.created_llvm_ir_rule[compiler.for_machine]: return rule = self.get_compiler_rule_name('llvm_ir', compiler.for_machine) command = [ninja_quote(i) for i in compiler.get_exelist()] args = ['$ARGS'] + compiler.get_output_args('$out') + compiler.get_compile_only_args() + ['$in'] description = 'Compiling LLVM IR object $in.' self.add_rule(NinjaRule(rule, command, args, description, rspable=compiler.can_linker_accept_rsp())) self.created_llvm_ir_rule[compiler.for_machine] = True def generate_compile_rule_for(self, langname, compiler): if langname == 'java': if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_java_compile_rule(compiler) return if langname == 'cs': if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_cs_compile_rule(compiler) return if langname == 'vala': self.generate_vala_compile_rules(compiler) return if langname == 'rust': self.generate_rust_compile_rules(compiler) return if langname == 'swift': if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_swift_compile_rules(compiler) return crstr = self.get_rule_suffix(compiler.for_machine) if langname == 'fortran': self.generate_fortran_dep_hack(crstr) rule = self.get_compiler_rule_name(langname, compiler.for_machine) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') quoted_depargs = [] for d in depargs: if d != '$out' and d != '$in': d = quote_func(d) quoted_depargs.append(d) command = [ninja_quote(i) for i in compiler.get_exelist()] args = ['$ARGS'] + quoted_depargs + compiler.get_output_args('$out') + compiler.get_compile_only_args() + ['$in'] description = 'Compiling %s object $out.' % compiler.get_display_language() if isinstance(compiler, VisualStudioLikeCompiler): deps = 'msvc' depfile = None else: deps = 'gcc' depfile = '$DEPFILE' self.add_rule(NinjaRule(rule, command, args, description, rspable=compiler.can_linker_accept_rsp(), deps=deps, depfile=depfile)) def generate_pch_rule_for(self, langname, compiler): if langname != 'c' and langname != 'cpp': return rule = self.compiler_to_pch_rule_name(compiler) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') quoted_depargs = [] for d in depargs: if d != '$out' and d != '$in': d = quote_func(d) quoted_depargs.append(d) if isinstance(compiler, VisualStudioLikeCompiler): output = [] else: output = compiler.get_output_args('$out') command = compiler.get_exelist() + ['$ARGS'] + quoted_depargs + output + compiler.get_compile_only_args() + ['$in'] description = 'Precompiling header $in.' if isinstance(compiler, VisualStudioLikeCompiler): deps = 'msvc' depfile = None else: deps = 'gcc' depfile = '$DEPFILE' self.add_rule(NinjaRule(rule, command, [], description, deps=deps, depfile=depfile)) def generate_compile_rules(self): for for_machine in MachineChoice: clist = self.environment.coredata.compilers[for_machine] for langname, compiler in clist.items(): if compiler.get_id() == 'clang': self.generate_llvm_ir_compile_rule(compiler) self.generate_compile_rule_for(langname, compiler) self.generate_pch_rule_for(langname, compiler) def generate_generator_list_rules(self, target): # CustomTargets have already written their rules and # CustomTargetIndexes don't actually get generated, so write rules for # GeneratedLists here for genlist in target.get_generated_sources(): if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): continue self.generate_genlist_for_target(genlist, target) def replace_paths(self, target, args, override_subdir=None): if override_subdir: source_target_dir = os.path.join(self.build_to_src, override_subdir) else: source_target_dir = self.get_target_source_dir(target) relout = self.get_target_private_dir(target) args = [x.replace("@SOURCE_DIR@", self.build_to_src).replace("@BUILD_DIR@", relout) for x in args] args = [x.replace("@CURRENT_SOURCE_DIR@", source_target_dir) for x in args] args = [x.replace("@SOURCE_ROOT@", self.build_to_src).replace("@BUILD_ROOT@", '.') for x in args] args = [x.replace('\\', '/') for x in args] return args def generate_genlist_for_target(self, genlist, target): generator = genlist.get_generator() subdir = genlist.subdir exe = generator.get_exe() exe_arr = self.exe_object_to_cmd_array(exe) infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() extra_dependencies = self.get_custom_target_depend_files(genlist) for i in range(len(infilelist)): curfile = infilelist[i] if len(generator.outputs) == 1: sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i]) else: sole_output = '{}'.format(curfile) infilename = curfile.rel_to_builddir(self.build_to_src) base_args = generator.get_arglist(infilename) outfiles = genlist.get_outputs_for(curfile) outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles] if generator.depfile is None: rulename = 'CUSTOM_COMMAND' args = base_args else: rulename = 'CUSTOM_COMMAND_DEP' depfilename = generator.get_dep_outname(infilename) depfile = os.path.join(self.get_target_private_dir(target), depfilename) args = [x.replace('@DEPFILE@', depfile) for x in base_args] args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output) for x in args] args = self.replace_outputs(args, self.get_target_private_dir(target), outfilelist) # We have consumed output files, so drop them from the list of remaining outputs. if len(generator.outputs) > 1: outfilelist = outfilelist[len(generator.outputs):] args = self.replace_paths(target, args, override_subdir=subdir) cmdlist = exe_arr + self.replace_extra_args(args, genlist) meson_exe_cmd = self.as_meson_exe_cmdline('generator ' + cmdlist[0], cmdlist[0], cmdlist[1:], capture=outfiles[0] if generator.capture else None) if meson_exe_cmd: cmdlist = meson_exe_cmd abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) os.makedirs(abs_pdir, exist_ok=True) elem = NinjaBuildElement(self.all_outputs, outfiles, rulename, infilename) elem.add_dep([self.get_target_filename(x) for x in generator.depends]) if generator.depfile is not None: elem.add_item('DEPFILE', depfile) if len(extra_dependencies) > 0: elem.add_dep(extra_dependencies) if len(generator.outputs) == 1: elem.add_item('DESC', 'Generating {!r}.'.format(sole_output)) else: # since there are multiple outputs, we log the source that caused the rebuild elem.add_item('DESC', 'Generating source from {!r}.'.format(sole_output)) if isinstance(exe, build.BuildTarget): elem.add_dep(self.get_target_filename(exe)) elem.add_item('COMMAND', cmdlist) self.add_build(elem) def scan_fortran_module_outputs(self, target): """ Find all module and submodule made available in a Fortran code file. """ compiler = None # TODO other compilers for lang, c in self.environment.coredata.compilers.host.items(): if lang == 'fortran': compiler = c break if compiler is None: self.fortran_deps[target.get_basename()] = {} return modre = re.compile(FORTRAN_MODULE_PAT, re.IGNORECASE) submodre = re.compile(FORTRAN_SUBMOD_PAT, re.IGNORECASE) module_files = {} submodule_files = {} for s in target.get_sources(): # FIXME, does not work for Fortran sources generated by # custom_target() and generator() as those are run after # the configuration (configure_file() is OK) if not compiler.can_compile(s): continue filename = s.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) # Fortran keywords must be ASCII. with open(filename, encoding='ascii', errors='ignore') as f: for line in f: modmatch = modre.match(line) if modmatch is not None: modname = modmatch.group(1).lower() if modname in module_files: raise InvalidArguments( 'Namespace collision: module %s defined in ' 'two files %s and %s.' % (modname, module_files[modname], s)) module_files[modname] = s else: submodmatch = submodre.match(line) if submodmatch is not None: # '_' is arbitrarily used to distinguish submod from mod. parents = submodmatch.group(1).lower().split(':') submodname = parents[0] + '_' + submodmatch.group(2).lower() if submodname in submodule_files: raise InvalidArguments( 'Namespace collision: submodule %s defined in ' 'two files %s and %s.' % (submodname, submodule_files[submodname], s)) submodule_files[submodname] = s self.fortran_deps[target.get_basename()] = {**module_files, **submodule_files} def get_fortran_deps(self, compiler: FortranCompiler, src: Path, target) -> T.List[str]: """ Find all module and submodule needed by a Fortran target """ dirname = Path(self.get_target_private_dir(target)) tdeps = self.fortran_deps[target.get_basename()] srcdir = Path(self.source_dir) mod_files = _scan_fortran_file_deps(src, srcdir, dirname, tdeps, compiler) return mod_files def get_cross_stdlib_args(self, target, compiler): if self.environment.machines.matches_build_machine(target.for_machine): return [] if not self.environment.properties.host.has_stdlib(compiler.language): return [] return compiler.get_no_stdinc_args() def get_compile_debugfile_args(self, compiler, target, objfile): # The way MSVC uses PDB files is documented exactly nowhere so # the following is what we have been able to decipher via # reverse engineering. # # Each object file gets the path of its PDB file written # inside it. This can be either the final PDB (for, say, # foo.exe) or an object pdb (for foo.obj). If the former, then # each compilation step locks the pdb file for writing, which # is a bottleneck and object files from one target can not be # used in a different target. The latter seems to be the # sensible one (and what Unix does) but there is a catch. If # you try to use precompiled headers MSVC will error out # because both source and pch pdbs go in the same file and # they must be the same. # # This means: # # - pch files must be compiled anew for every object file (negating # the entire point of having them in the first place) # - when using pch, output must go to the target pdb # # Since both of these are broken in some way, use the one that # works for each target. This unfortunately means that you # can't combine pch and object extraction in a single target. # # PDB files also lead to filename collisions. A target foo.exe # has a corresponding foo.pdb. A shared library foo.dll _also_ # has pdb file called foo.pdb. So will a static library # foo.lib, which clobbers both foo.pdb _and_ the dll file's # export library called foo.lib (by default, currently we name # them libfoo.a to avoidt this issue). You can give the files # unique names such as foo_exe.pdb but VC also generates a # bunch of other files which take their names from the target # basename (i.e. "foo") and stomp on each other. # # CMake solves this problem by doing two things. First of all # static libraries do not generate pdb files at # all. Presumably you don't need them and VC is smart enough # to look up the original data when linking (speculation, not # tested). The second solution is that you can only have # target named "foo" as an exe, shared lib _or_ static # lib. This makes filename collisions not happen. The downside # is that you can't have an executable foo that uses a shared # library libfoo.so, which is a common idiom on Unix. # # If you feel that the above is completely wrong and all of # this is actually doable, please send patches. if target.has_pch(): tfilename = self.get_target_filename_abs(target) return compiler.get_compile_debugfile_args(tfilename, pch=True) else: return compiler.get_compile_debugfile_args(objfile, pch=False) def get_link_debugfile_args(self, linker, target, outname): return linker.get_link_debugfile_args(outname) def generate_llvm_ir_compile(self, target, src): compiler = get_compiler_for_source(target.compilers.values(), src) commands = CompilerArgs(compiler) # Compiler args for compiling this target commands += compilers.get_base_compile_args(self.environment.coredata.base_options, compiler) if isinstance(src, File): if src.is_built: src_filename = os.path.join(src.subdir, src.fname) else: src_filename = src.fname elif os.path.isabs(src): src_filename = os.path.basename(src) else: src_filename = src obj_basename = src_filename.replace('/', '_').replace('\\', '_') rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename) rel_obj += '.' + self.environment.machines[target.for_machine].get_object_suffix() commands += self.get_compile_debugfile_args(compiler, target, rel_obj) if isinstance(src, File) and src.is_built: rel_src = src.fname elif isinstance(src, File): rel_src = src.rel_to_builddir(self.build_to_src) else: raise InvalidArguments('Invalid source type: {!r}'.format(src)) # Write the Ninja build command compiler_name = self.get_compiler_rule_name('llvm_ir', compiler.for_machine) element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src) # Convert from GCC-style link argument naming to the naming used by the # current compiler. commands = commands.to_native() element.add_item('ARGS', commands) self.add_build(element) return rel_obj def get_source_dir_include_args(self, target, compiler): curdir = target.get_subdir() tmppath = os.path.normpath(os.path.join(self.build_to_src, curdir)) return compiler.get_include_args(tmppath, False) def get_build_dir_include_args(self, target, compiler): curdir = target.get_subdir() if curdir == '': curdir = '.' return compiler.get_include_args(curdir, False) def get_custom_target_dir_include_args(self, target, compiler): custom_target_include_dirs = [] for i in target.get_generated_sources(): # Generator output goes into the target private dir which is # already in the include paths list. Only custom targets have their # own target build dir. if not isinstance(i, (build.CustomTarget, build.CustomTargetIndex)): continue idir = self.get_target_dir(i) if not idir: idir = '.' if idir not in custom_target_include_dirs: custom_target_include_dirs.append(idir) incs = [] for i in custom_target_include_dirs: incs += compiler.get_include_args(i, False) return incs @lru_cache(maxsize=None) def generate_inc_dir(self, compiler, d, basedir, is_system): # Avoid superfluous '/.' at the end of paths when d is '.' if d not in ('', '.'): expdir = os.path.join(basedir, d) else: expdir = basedir srctreedir = os.path.join(self.build_to_src, expdir) sargs = compiler.get_include_args(srctreedir, is_system) # There may be include dirs where a build directory has not been # created for some source dir. For example if someone does this: # # inc = include_directories('foo/bar/baz') # # But never subdir()s into the actual dir. if os.path.isdir(os.path.join(self.environment.get_build_dir(), expdir)): bargs = compiler.get_include_args(expdir, is_system) else: bargs = [] return (sargs, bargs) @lru_cache(maxsize=None) def _generate_single_compile(self, target, compiler, is_generated=False): base_proxy = self.get_base_options_for_target(target) # Create an empty commands list, and start adding arguments from # various sources in the order in which they must override each other commands = CompilerArgs(compiler) # Start with symbol visibility. commands += compiler.gnu_symbol_visibility_args(target.gnu_symbol_visibility) # Add compiler args for compiling this target derived from 'base' build # options passed on the command-line, in default_options, etc. # These have the lowest priority. commands += compilers.get_base_compile_args(base_proxy, compiler) # The code generated by valac is usually crap and has tons of unused # variables and such, so disable warnings for Vala C sources. no_warn_args = (is_generated == 'vala') # Add compiler args and include paths from several sources; defaults, # build options, external dependencies, etc. commands += self.generate_basic_compiler_args(target, compiler, no_warn_args) # Add custom target dirs as includes automatically, but before # target-specific include directories. # XXX: Not sure if anyone actually uses this? It can cause problems in # situations which increase the likelihood for a header name collision, # such as in subprojects. commands += self.get_custom_target_dir_include_args(target, compiler) # Add include dirs from the `include_directories:` kwarg on the target # and from `include_directories:` of internal deps of the target. # # Target include dirs should override internal deps include dirs. # This is handled in BuildTarget.process_kwargs() # # Include dirs from internal deps should override include dirs from # external deps and must maintain the order in which they are specified. # Hence, we must reverse the list so that the order is preserved. for i in reversed(target.get_include_dirs()): basedir = i.get_curdir() # We should iterate include dirs in reversed orders because # -Ipath will add to begin of array. And without reverse # flags will be added in reversed order. for d in reversed(i.get_incdirs()): # Add source subdir first so that the build subdir overrides it (compile_obj, includeargs) = self.generate_inc_dir(compiler, d, basedir, i.is_system) commands += compile_obj commands += includeargs for d in i.get_extra_build_dirs(): commands += compiler.get_include_args(d, i.is_system) # Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these # near the end since these are supposed to override everything else. commands += self.escape_extra_args(compiler, target.get_extra_args(compiler.get_language())) # D specific additional flags if compiler.language == 'd': commands += compiler.get_feature_args(target.d_features, self.build_to_src) # Add source dir and build dir. Project-specific and target-specific # include paths must override per-target compile args, include paths # from external dependencies, internal dependencies, and from # per-target `include_directories:` # # We prefer headers in the build dir over the source dir since, for # instance, the user might have an srcdir == builddir Autotools build # in their source tree. Many projects that are moving to Meson have # both Meson and Autotools in parallel as part of the transition. if target.implicit_include_directories: commands += self.get_source_dir_include_args(target, compiler) if target.implicit_include_directories: commands += self.get_build_dir_include_args(target, compiler) # Finally add the private dir for the target to the include path. This # must override everything else and must be the final path added. commands += compiler.get_include_args(self.get_target_private_dir(target), False) return commands def generate_single_compile(self, target, src, is_generated=False, header_deps=None, order_deps=None): """ Compiles C/C++, ObjC/ObjC++, Fortran, and D sources """ header_deps = header_deps if header_deps is not None else [] order_deps = order_deps if order_deps is not None else [] if isinstance(src, str) and src.endswith('.h'): raise AssertionError('BUG: sources should not contain headers {!r}'.format(src)) compiler = get_compiler_for_source(target.compilers.values(), src) commands = self._generate_single_compile(target, compiler, is_generated) commands = CompilerArgs(commands.compiler, commands) # Create introspection information if is_generated is False: self.create_target_source_introspection(target, compiler, commands, [src], []) else: self.create_target_source_introspection(target, compiler, commands, [], [src]) build_dir = self.environment.get_build_dir() if isinstance(src, File): rel_src = src.rel_to_builddir(self.build_to_src) if os.path.isabs(rel_src): # Source files may not be from the source directory if they originate in source-only libraries, # so we can't assert that the absolute path is anywhere in particular. if src.is_built: assert rel_src.startswith(build_dir) rel_src = rel_src[len(build_dir) + 1:] elif is_generated: raise AssertionError('BUG: broken generated source file handling for {!r}'.format(src)) else: raise InvalidArguments('Invalid source type: {!r}'.format(src)) obj_basename = self.object_filename_from_source(target, src) rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename) dep_file = compiler.depfile_for_object(rel_obj) # Add MSVC debug file generation compile flags: /Fd /FS commands += self.get_compile_debugfile_args(compiler, target, rel_obj) # PCH handling if self.environment.coredata.base_options.get('b_pch', False): commands += self.get_pch_include_args(compiler, target) pchlist = target.get_pch(compiler.language) else: pchlist = [] if not pchlist: pch_dep = [] elif compiler.id == 'intel': pch_dep = [] else: arr = [] i = os.path.join(self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0])) arr.append(i) pch_dep = arr compiler_name = self.compiler_to_rule_name(compiler) extra_deps = [] if compiler.get_language() == 'fortran': # Can't read source file to scan for deps if it's generated later # at build-time. Skip scanning for deps, and just set the module # outdir argument instead. # https://github.com/mesonbuild/meson/issues/1348 if not is_generated: abs_src = Path(build_dir) / rel_src extra_deps += self.get_fortran_deps(compiler, abs_src, target) # Dependency hack. Remove once multiple outputs in Ninja is fixed: # https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 for modname, srcfile in self.fortran_deps[target.get_basename()].items(): modfile = os.path.join(self.get_target_private_dir(target), compiler.module_name_to_filename(modname)) if srcfile == src: crstr = self.get_rule_suffix(target.for_machine) depelem = NinjaBuildElement(self.all_outputs, modfile, 'FORTRAN_DEP_HACK' + crstr, rel_obj) self.add_build(depelem) commands += compiler.get_module_outdir_args(self.get_target_private_dir(target)) element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src) self.add_header_deps(target, element, header_deps) for d in extra_deps: element.add_dep(d) for d in order_deps: if isinstance(d, File): d = d.rel_to_builddir(self.build_to_src) elif not self.has_dir_part(d): d = os.path.join(self.get_target_private_dir(target), d) element.add_orderdep(d) element.add_dep(pch_dep) # Convert from GCC-style link argument naming to the naming used by the # current compiler. commands = commands.to_native() for i in self.get_fortran_orderdeps(target, compiler): element.add_orderdep(i) element.add_item('DEPFILE', dep_file) element.add_item('ARGS', commands) self.add_build(element) return rel_obj def add_header_deps(self, target, ninja_element, header_deps): for d in header_deps: if isinstance(d, File): d = d.rel_to_builddir(self.build_to_src) elif not self.has_dir_part(d): d = os.path.join(self.get_target_private_dir(target), d) ninja_element.add_dep(d) def has_dir_part(self, fname): # FIXME FIXME: The usage of this is a terrible and unreliable hack if isinstance(fname, File): return fname.subdir != '' return has_path_sep(fname) # Fortran is a bit weird (again). When you link against a library, just compiling a source file # requires the mod files that are output when single files are built. To do this right we would need to # scan all inputs and write out explicit deps for each file. That is stoo slow and too much effort so # instead just have an ordered dependency on the library. This ensures all required mod files are created. # The real deps are then detected via dep file generation from the compiler. This breaks on compilers that # produce incorrect dep files but such is life. def get_fortran_orderdeps(self, target, compiler): if compiler.language != 'fortran': return [] return [os.path.join(self.get_target_dir(lt), lt.get_filename()) for lt in target.link_targets] def generate_msvc_pch_command(self, target, compiler, pch): header = pch[0] pchname = compiler.get_pch_name(header) dst = os.path.join(self.get_target_private_dir(target), pchname) commands = [] commands += self.generate_basic_compiler_args(target, compiler) if len(pch) == 1: # Auto generate PCH. source = self.create_msvc_pch_implementation(target, compiler.get_language(), pch[0]) pch_header_dir = os.path.dirname(os.path.join(self.build_to_src, target.get_source_subdir(), header)) commands += compiler.get_include_args(pch_header_dir, False) else: source = os.path.join(self.build_to_src, target.get_source_subdir(), pch[1]) just_name = os.path.basename(header) (objname, pch_args) = compiler.gen_pch_args(just_name, source, dst) commands += pch_args commands += self._generate_single_compile(target, compiler) commands += self.get_compile_debugfile_args(compiler, target, objname) dep = dst + '.' + compiler.get_depfile_suffix() return commands, dep, dst, [objname], source def generate_gcc_pch_command(self, target, compiler, pch): commands = self._generate_single_compile(target, compiler) if pch.split('.')[-1] == 'h' and compiler.language == 'cpp': # Explicitly compile pch headers as C++. If Clang is invoked in C++ mode, it actually warns if # this option is not set, and for gcc it also makes sense to use it. commands += ['-x', 'c++-header'] dst = os.path.join(self.get_target_private_dir(target), os.path.basename(pch) + '.' + compiler.get_pch_suffix()) dep = dst + '.' + compiler.get_depfile_suffix() return commands, dep, dst, [] # Gcc does not create an object file during pch generation. def generate_pch(self, target, header_deps=None): header_deps = header_deps if header_deps is not None else [] pch_objects = [] for lang in ['c', 'cpp']: pch = target.get_pch(lang) if not pch: continue if not has_path_sep(pch[0]) or not has_path_sep(pch[-1]): msg = 'Precompiled header of {!r} must not be in the same ' \ 'directory as source, please put it in a subdirectory.' \ ''.format(target.get_basename()) raise InvalidArguments(msg) compiler = target.compilers[lang] if isinstance(compiler, VisualStudioLikeCompiler): (commands, dep, dst, objs, src) = self.generate_msvc_pch_command(target, compiler, pch) extradep = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0]) elif compiler.id == 'intel': # Intel generates on target generation continue else: src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0]) (commands, dep, dst, objs) = self.generate_gcc_pch_command(target, compiler, pch[0]) extradep = None pch_objects += objs rulename = self.compiler_to_pch_rule_name(compiler) elem = NinjaBuildElement(self.all_outputs, dst, rulename, src) if extradep is not None: elem.add_dep(extradep) self.add_header_deps(target, elem, header_deps) elem.add_item('ARGS', commands) elem.add_item('DEPFILE', dep) self.add_build(elem) return pch_objects def generate_shsym(self, target): target_name = target.get_filename() target_file = self.get_target_filename(target) targetdir = self.get_target_private_dir(target) symname = os.path.join(targetdir, target_name + '.symbols') elem = NinjaBuildElement(self.all_outputs, symname, 'SHSYM', target_file) if self.environment.is_cross_build(): elem.add_item('CROSS', '--cross-host=' + self.environment.machines[target.for_machine].system) self.add_build(elem) def get_cross_stdlib_link_args(self, target, linker): if isinstance(target, build.StaticLibrary) or \ self.environment.machines.matches_build_machine(target.for_machine): return [] if not self.environment.properties.host.has_stdlib(linker.language): return [] return linker.get_no_stdlib_link_args() def get_target_type_link_args(self, target, linker): commands = [] if isinstance(target, build.Executable): # Currently only used with the Swift compiler to add '-emit-executable' commands += linker.get_std_exe_link_args() # If export_dynamic, add the appropriate linker arguments if target.export_dynamic: commands += linker.gen_export_dynamic_link_args(self.environment) # If implib, and that's significant on this platform (i.e. Windows using either GCC or Visual Studio) if target.import_filename: commands += linker.gen_import_library_args(os.path.join(self.get_target_dir(target), target.import_filename)) if target.pie: commands += linker.get_pie_link_args() elif isinstance(target, build.SharedLibrary): if isinstance(target, build.SharedModule): options = self.environment.coredata.base_options commands += linker.get_std_shared_module_link_args(options) else: commands += linker.get_std_shared_lib_link_args() # All shared libraries are PIC commands += linker.get_pic_args() # Add -Wl,-soname arguments on Linux, -install_name on OS X commands += linker.get_soname_args( self.environment, target.prefix, target.name, target.suffix, target.soversion, target.darwin_versions, isinstance(target, build.SharedModule)) # This is only visited when building for Windows using either GCC or Visual Studio if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'): commands += linker.gen_vs_module_defs_args(target.vs_module_defs.rel_to_builddir(self.build_to_src)) # This is only visited when building for Windows using either GCC or Visual Studio if target.import_filename: commands += linker.gen_import_library_args(os.path.join(self.get_target_dir(target), target.import_filename)) elif isinstance(target, build.StaticLibrary): commands += linker.get_std_link_args() else: raise RuntimeError('Unknown build target type.') return commands def get_target_type_link_args_post_dependencies(self, target, linker): commands = [] if isinstance(target, build.Executable): # If gui_app is significant on this platform, add the appropriate linker arguments. # Unfortunately this can't be done in get_target_type_link_args, because some misguided # libraries (such as SDL2) add -mwindows to their link flags. commands += linker.get_gui_app_args(target.gui_app) return commands def get_link_whole_args(self, linker, target): target_args = self.build_target_link_arguments(linker, target.link_whole_targets) return linker.get_link_whole_for(target_args) if len(target_args) else [] @lru_cache(maxsize=None) def guess_library_absolute_path(self, linker, libname, search_dirs, patterns): for d in search_dirs: for p in patterns: trial = CCompiler._get_trials_from_pattern(p, d, libname) if not trial: continue trial = CCompiler._get_file_from_list(self.environment, trial) if not trial: continue # Return the first result return trial def guess_external_link_dependencies(self, linker, target, commands, internal): # Ideally the linker would generate dependency information that could be used. # But that has 2 problems: # * currently ld can not create dependency information in a way that ninja can use: # https://sourceware.org/bugzilla/show_bug.cgi?id=22843 # * Meson optimizes libraries from the same build using the symbol extractor. # Just letting ninja use ld generated dependencies would undo this optimization. search_dirs = OrderedSet() libs = OrderedSet() absolute_libs = [] build_dir = self.environment.get_build_dir() # the following loop sometimes consumes two items from command in one pass it = iter(linker.native_args_to_unix(commands)) for item in it: if item in internal and not item.startswith('-'): continue if item.startswith('-L'): if len(item) > 2: path = item[2:] else: try: path = next(it) except StopIteration: mlog.warning("Generated linker command has -L argument without following path") break if not os.path.isabs(path): path = os.path.join(build_dir, path) search_dirs.add(path) elif item.startswith('-l'): if len(item) > 2: lib = item[2:] else: try: lib = next(it) except StopIteration: mlog.warning("Generated linker command has '-l' argument without following library name") break libs.add(lib) elif os.path.isabs(item) and self.environment.is_library(item) and os.path.isfile(item): absolute_libs.append(item) guessed_dependencies = [] # TODO The get_library_naming requirement currently excludes link targets that use d or fortran as their main linker if hasattr(linker, 'get_library_naming'): search_dirs = tuple(search_dirs) + tuple(linker.get_library_dirs(self.environment)) static_patterns = linker.get_library_naming(self.environment, LibType.STATIC, strict=True) shared_patterns = linker.get_library_naming(self.environment, LibType.SHARED, strict=True) for libname in libs: # be conservative and record most likely shared and static resolution, because we don't know exactly # which one the linker will prefer staticlibs = self.guess_library_absolute_path(linker, libname, search_dirs, static_patterns) sharedlibs = self.guess_library_absolute_path(linker, libname, search_dirs, shared_patterns) if staticlibs: guessed_dependencies.append(staticlibs.resolve().as_posix()) if sharedlibs: guessed_dependencies.append(sharedlibs.resolve().as_posix()) return guessed_dependencies + absolute_libs def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdlib_args=None): extra_args = extra_args if extra_args is not None else [] stdlib_args = stdlib_args if stdlib_args is not None else [] if isinstance(target, build.StaticLibrary): linker_base = 'STATIC' else: linker_base = linker.get_language() # Fixme. if isinstance(target, build.SharedLibrary): self.generate_shsym(target) crstr = self.get_rule_suffix(target.for_machine) linker_rule = linker_base + '_LINKER' + crstr # Create an empty commands list, and start adding link arguments from # various sources in the order in which they must override each other # starting from hard-coded defaults followed by build options and so on. # # Once all the linker options have been passed, we will start passing # libraries and library paths from internal and external sources. commands = CompilerArgs(linker) # First, the trivial ones that are impossible to override. # # Add linker args for linking this target derived from 'base' build # options passed on the command-line, in default_options, etc. # These have the lowest priority. if isinstance(target, build.StaticLibrary): commands += linker.get_base_link_args(self.get_base_options_for_target(target)) else: commands += compilers.get_base_link_args(self.get_base_options_for_target(target), linker, isinstance(target, build.SharedModule)) # Add -nostdlib if needed; can't be overridden commands += self.get_cross_stdlib_link_args(target, linker) # Add things like /NOLOGO; usually can't be overridden commands += linker.get_linker_always_args() # Add buildtype linker args: optimization level, etc. commands += linker.get_buildtype_linker_args(self.get_option_for_target('buildtype', target)) # Add /DEBUG and the pdb filename when using MSVC if self.get_option_for_target('debug', target): commands += self.get_link_debugfile_args(linker, target, outname) # Add link args specific to this BuildTarget type, such as soname args, # PIC, import library generation, etc. commands += self.get_target_type_link_args(target, linker) # Archives that are copied wholesale in the result. Must be before any # other link targets so missing symbols from whole archives are found in those. if not isinstance(target, build.StaticLibrary): commands += self.get_link_whole_args(linker, target) if not isinstance(target, build.StaticLibrary): # Add link args added using add_project_link_arguments() commands += self.build.get_project_link_args(linker, target.subproject, target.for_machine) # Add link args added using add_global_link_arguments() # These override per-project link arguments commands += self.build.get_global_link_args(linker, target.for_machine) # Link args added from the env: LDFLAGS. We want these to override # all the defaults but not the per-target link args. commands += self.environment.coredata.get_external_link_args(target.for_machine, linker.get_language()) # Now we will add libraries and library paths from various sources # Add link args to link to all internal libraries (link_with:) and # internal dependencies needed by this target. if linker_base == 'STATIC': # Link arguments of static libraries are not put in the command # line of the library. They are instead appended to the command # line where the static library is used. dependencies = [] else: dependencies = target.get_dependencies() internal = self.build_target_link_arguments(linker, dependencies) commands += internal # Only non-static built targets need link args and link dependencies if not isinstance(target, build.StaticLibrary): # For 'automagic' deps: Boost and GTest. Also dependency('threads'). # pkg-config puts the thread flags itself via `Cflags:` commands += linker.get_target_link_args(target) # External deps must be last because target link libraries may depend on them. for dep in target.get_external_deps(): # Extend without reordering or de-dup to preserve `-L -l` sets # https://github.com/mesonbuild/meson/issues/1718 commands.extend_preserving_lflags(linker.get_dependency_link_args(dep)) for d in target.get_dependencies(): if isinstance(d, build.StaticLibrary): for dep in d.get_external_deps(): commands.extend_preserving_lflags(linker.get_dependency_link_args(dep)) # Add link args specific to this BuildTarget type that must not be overridden by dependencies commands += self.get_target_type_link_args_post_dependencies(target, linker) # Add link args for c_* or cpp_* build options. Currently this only # adds c_winlibs and cpp_winlibs when building for Windows. This needs # to be after all internal and external libraries so that unresolved # symbols from those can be found here. This is needed when the # *_winlibs that we want to link to are static mingw64 libraries. commands += linker.get_option_link_args(self.environment.coredata.compiler_options[target.for_machine]) dep_targets = [] dep_targets.extend(self.guess_external_link_dependencies(linker, target, commands, internal)) # Set runtime-paths so we can run executables without needing to set # LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows. if has_path_sep(target.name): # Target names really should not have slashes in them, but # unfortunately we did not check for that and some downstream projects # now have them. Once slashes are forbidden, remove this bit. target_slashname_workaround_dir = os.path.join( os.path.dirname(target.name), self.get_target_dir(target)) else: target_slashname_workaround_dir = self.get_target_dir(target) commands += linker.build_rpath_args(self.environment, self.environment.get_build_dir(), target_slashname_workaround_dir, self.determine_rpath_dirs(target), target.build_rpath, target.install_rpath) # Add libraries generated by custom targets custom_target_libraries = self.get_custom_target_provided_libraries(target) commands += extra_args commands += custom_target_libraries commands += stdlib_args # Standard library arguments go last, because they never depend on anything. # Convert from GCC-style link argument naming to the naming used by the # current compiler. commands = commands.to_native() dep_targets.extend([self.get_dependency_filename(t) for t in dependencies]) dep_targets.extend([self.get_dependency_filename(t) for t in target.link_depends]) elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list) elem.add_dep(dep_targets + custom_target_libraries) elem.add_item('LINK_ARGS', commands) return elem def get_dependency_filename(self, t): if isinstance(t, build.SharedLibrary): return os.path.join(self.get_target_private_dir(t), t.get_filename() + '.symbols') elif isinstance(t, mesonlib.File): if t.is_built: return t.relative_name() else: return t.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) return self.get_target_filename(t) def generate_shlib_aliases(self, target, outdir): aliases = target.get_aliases() for alias, to in aliases.items(): aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias) try: os.remove(aliasfile) except Exception: pass try: os.symlink(to, aliasfile) except NotImplementedError: mlog.debug("Library versioning disabled because symlinks are not supported.") except OSError: mlog.debug("Library versioning disabled because we do not have symlink creation privileges.") def generate_custom_target_clean(self, trees): e = NinjaBuildElement(self.all_outputs, 'meson-clean-ctlist', 'CUSTOM_COMMAND', 'PHONY') d = CleanTrees(self.environment.get_build_dir(), trees) d_file = os.path.join(self.environment.get_scratch_dir(), 'cleantrees.dat') e.add_item('COMMAND', self.environment.get_build_command() + ['--internal', 'cleantrees', d_file]) e.add_item('description', 'Cleaning custom target directories.') self.add_build(e) # Alias that runs the target defined above self.create_target_alias('meson-clean-ctlist') # Write out the data file passed to the script with open(d_file, 'wb') as ofile: pickle.dump(d, ofile) return 'clean-ctlist' def generate_gcov_clean(self): gcno_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcno', 'CUSTOM_COMMAND', 'PHONY') script_root = self.environment.get_script_dir() clean_script = os.path.join(script_root, 'delwithsuffix.py') gcno_elem.add_item('COMMAND', mesonlib.python_command + [clean_script, '.', 'gcno']) gcno_elem.add_item('description', 'Deleting gcno files.') self.add_build(gcno_elem) # Alias that runs the target defined above self.create_target_alias('meson-clean-gcno') gcda_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcda', 'CUSTOM_COMMAND', 'PHONY') script_root = self.environment.get_script_dir() clean_script = os.path.join(script_root, 'delwithsuffix.py') gcda_elem.add_item('COMMAND', mesonlib.python_command + [clean_script, '.', 'gcda']) gcda_elem.add_item('description', 'Deleting gcda files.') self.add_build(gcda_elem) # Alias that runs the target defined above self.create_target_alias('meson-clean-gcda') def get_user_option_args(self): cmds = [] for (k, v) in self.environment.coredata.user_options.items(): cmds.append('-D' + k + '=' + (v.value if isinstance(v.value, str) else str(v.value).lower())) # The order of these arguments must be the same between runs of Meson # to ensure reproducible output. The order we pass them shouldn't # affect behavior in any other way. return sorted(cmds) def generate_dist(self): elem = NinjaBuildElement(self.all_outputs, 'meson-dist', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('DESC', 'Creating source packages') elem.add_item('COMMAND', self.environment.get_build_command() + ['dist']) elem.add_item('pool', 'console') self.add_build(elem) # Alias that runs the target defined above self.create_target_alias('meson-dist') def generate_scanbuild(self): if not environment.detect_scanbuild(): return if ('', 'scan-build') in self.build.run_target_names: return cmd = self.environment.get_build_command() + \ ['--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir] + \ self.environment.get_build_command() + self.get_user_option_args() elem = NinjaBuildElement(self.all_outputs, 'meson-scan-build', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) # Alias that runs the target defined above self.create_target_alias('meson-scan-build') def generate_clangtool(self, name): target_name = 'clang-' + name if not os.path.exists(os.path.join(self.environment.source_dir, '.clang-' + name)) and \ not os.path.exists(os.path.join(self.environment.source_dir, '_clang-' + name)): return if target_name in self.all_outputs: return if ('', target_name) in self.build.run_target_names: return cmd = self.environment.get_build_command() + \ ['--internal', 'clang' + name, self.environment.source_dir, self.environment.build_dir] elem = NinjaBuildElement(self.all_outputs, 'meson-' + target_name, 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) self.create_target_alias('meson-' + target_name) def generate_clangformat(self): if not environment.detect_clangformat(): return self.generate_clangtool('format') def generate_clangtidy(self): import shutil if not shutil.which('clang-tidy'): return self.generate_clangtool('tidy') def generate_tags(self, tool, target_name): import shutil if not shutil.which(tool): return if ('', target_name) in self.build.run_target_names: return if target_name in self.all_outputs: return cmd = self.environment.get_build_command() + \ ['--internal', 'tags', tool, self.environment.source_dir] elem = NinjaBuildElement(self.all_outputs, 'meson-' + target_name, 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) # Alias that runs the target defined above self.create_target_alias('meson-' + target_name) # For things like scan-build and other helper tools we might have. def generate_utils(self): self.generate_scanbuild() self.generate_clangformat() self.generate_clangtidy() self.generate_tags('etags', 'TAGS') self.generate_tags('ctags', 'ctags') self.generate_tags('cscope', 'cscope') cmd = self.environment.get_build_command() + ['--internal', 'uninstall'] elem = NinjaBuildElement(self.all_outputs, 'meson-uninstall', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) # Alias that runs the target defined above self.create_target_alias('meson-uninstall') def generate_ending(self): targetlist = [] for t in self.get_build_by_default_targets().values(): # Add the first output of each target to the 'all' target so that # they are all built targetlist.append(os.path.join(self.get_target_dir(t), t.get_outputs()[0])) elem = NinjaBuildElement(self.all_outputs, 'all', 'phony', targetlist) self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', [self.ninja_command, '-t', 'clean']) elem.add_item('description', 'Cleaning.') # Alias that runs the above-defined meson-clean target self.create_target_alias('meson-clean') # If we have custom targets in this project, add all their outputs to # the list that is passed to the `cleantrees.py` script. The script # will manually delete all custom_target outputs that are directories # instead of files. This is needed because on platforms other than # Windows, Ninja only deletes directories while cleaning if they are # empty. https://github.com/mesonbuild/meson/issues/1220 ctlist = [] for t in self.build.get_targets().values(): if isinstance(t, build.CustomTarget): # Create a list of all custom target outputs for o in t.get_outputs(): ctlist.append(os.path.join(self.get_target_dir(t), o)) if ctlist: elem.add_dep(self.generate_custom_target_clean(ctlist)) if 'b_coverage' in self.environment.coredata.base_options and \ self.environment.coredata.base_options['b_coverage'].value: self.generate_gcov_clean() elem.add_dep('clean-gcda') elem.add_dep('clean-gcno') self.add_build(elem) deps = self.get_regen_filelist() elem = NinjaBuildElement(self.all_outputs, 'build.ninja', 'REGENERATE_BUILD', deps) elem.add_item('pool', 'console') self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, 'reconfigure', 'REGENERATE_BUILD', 'PHONY') elem.add_item('pool', 'console') self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '') self.add_build(elem) def get_introspection_data(self, target_id, target): if target_id not in self.introspection_data or len(self.introspection_data[target_id]) == 0: return super().get_introspection_data(target_id, target) result = [] for i in self.introspection_data[target_id].values(): result += [i] return result def load(build_dir): filename = os.path.join(build_dir, 'meson-private', 'install.dat') with open(filename, 'rb') as f: obj = pickle.load(f) return obj def _scan_fortran_file_deps(src: Path, srcdir: Path, dirname: Path, tdeps, compiler) -> T.List[str]: """ scan a Fortran file for dependencies. Needs to be distinct from target to allow for recursion induced by `include` statements.er It makes a number of assumptions, including * `use`, `module`, `submodule` name is not on a continuation line Regex ----- * `incre` works for `#include "foo.f90"` and `include "foo.f90"` * `usere` works for legacy and Fortran 2003 `use` statements * `submodre` is for Fortran >= 2008 `submodule` """ incre = re.compile(FORTRAN_INCLUDE_PAT, re.IGNORECASE) usere = re.compile(FORTRAN_USE_PAT, re.IGNORECASE) submodre = re.compile(FORTRAN_SUBMOD_PAT, re.IGNORECASE) mod_files = [] src = Path(src) with src.open(encoding='ascii', errors='ignore') as f: for line in f: # included files incmatch = incre.match(line) if incmatch is not None: incfile = srcdir / incmatch.group(1) if incfile.suffix.lower()[1:] in compiler.file_suffixes: mod_files.extend(_scan_fortran_file_deps(incfile, srcdir, dirname, tdeps, compiler)) # modules usematch = usere.match(line) if usematch is not None: usename = usematch.group(1).lower() if usename == 'intrinsic': # this keeps the regex simpler continue if usename not in tdeps: # The module is not provided by any source file. This # is due to: # a) missing file/typo/etc # b) using a module provided by the compiler, such as # OpenMP # There's no easy way to tell which is which (that I # know of) so just ignore this and go on. Ideally we # would print a warning message to the user but this is # a common occurrence, which would lead to lots of # distracting noise. continue srcfile = srcdir / tdeps[usename].fname # type: Path if not srcfile.is_file(): if srcfile.name != src.name: # generated source file pass else: # subproject continue elif srcfile.samefile(src): # self-reference continue mod_name = compiler.module_name_to_filename(usename) mod_files.append(str(dirname / mod_name)) else: # submodules submodmatch = submodre.match(line) if submodmatch is not None: parents = submodmatch.group(1).lower().split(':') assert len(parents) in (1, 2), ( 'submodule ancestry must be specified as' ' ancestor:parent but Meson found {}'.format(parents)) ancestor_child = '_'.join(parents) if ancestor_child not in tdeps: raise MesonException("submodule {} relies on ancestor module {} that was not found.".format(submodmatch.group(2).lower(), ancestor_child.split('_')[0])) submodsrcfile = srcdir / tdeps[ancestor_child].fname # type: Path if not submodsrcfile.is_file(): if submodsrcfile.name != src.name: # generated source file pass else: # subproject continue elif submodsrcfile.samefile(src): # self-reference continue mod_name = compiler.module_name_to_filename(ancestor_child) mod_files.append(str(dirname / mod_name)) return mod_files meson-0.53.2/mesonbuild/backend/vs2010backend.py0000644000175000017500000023437713612313307022700 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import copy import os import pickle import xml.dom.minidom import xml.etree.ElementTree as ET import uuid from pathlib import Path, PurePath from . import backends from .. import build from .. import dependencies from .. import mlog from .. import compilers from ..compilers import CompilerArgs from ..mesonlib import ( MesonException, File, python_command, replace_if_different ) from ..environment import Environment, build_filename def autodetect_vs_version(build): vs_version = os.getenv('VisualStudioVersion', None) vs_install_dir = os.getenv('VSINSTALLDIR', None) if not vs_install_dir: raise MesonException('Could not detect Visual Studio: Environment variable VSINSTALLDIR is not set!\n' 'Are you running meson from the Visual Studio Developer Command Prompt?') # VisualStudioVersion is set since Visual Studio 12.0, but sometimes # vcvarsall.bat doesn't set it, so also use VSINSTALLDIR if vs_version == '14.0' or 'Visual Studio 14' in vs_install_dir: from mesonbuild.backend.vs2015backend import Vs2015Backend return Vs2015Backend(build) if vs_version == '15.0' or 'Visual Studio 17' in vs_install_dir or \ 'Visual Studio\\2017' in vs_install_dir: from mesonbuild.backend.vs2017backend import Vs2017Backend return Vs2017Backend(build) if vs_version == '16.0' or 'Visual Studio 19' in vs_install_dir or \ 'Visual Studio\\2019' in vs_install_dir: from mesonbuild.backend.vs2019backend import Vs2019Backend return Vs2019Backend(build) if 'Visual Studio 10.0' in vs_install_dir: return Vs2010Backend(build) raise MesonException('Could not detect Visual Studio using VisualStudioVersion: {!r} or VSINSTALLDIR: {!r}!\n' 'Please specify the exact backend to use.'.format(vs_version, vs_install_dir)) def split_o_flags_args(args): """ Splits any /O args and returns them. Does not take care of flags overriding previous ones. Skips non-O flag arguments. ['/Ox', '/Ob1'] returns ['/Ox', '/Ob1'] ['/Oxj', '/MP'] returns ['/Ox', '/Oj'] """ o_flags = [] for arg in args: if not arg.startswith('/O'): continue flags = list(arg[2:]) # Assume that this one can't be clumped with the others since it takes # an argument itself if 'b' in flags: o_flags.append(arg) else: o_flags += ['/O' + f for f in flags] return o_flags def generate_guid_from_path(path, path_type): return str(uuid.uuid5(uuid.NAMESPACE_URL, 'meson-vs-' + path_type + ':' + str(path))).upper() class RegenInfo: def __init__(self, source_dir, build_dir, depfiles): self.source_dir = source_dir self.build_dir = build_dir self.depfiles = depfiles class Vs2010Backend(backends.Backend): def __init__(self, build): super().__init__(build) self.name = 'vs2010' self.project_file_version = '10.0.30319.1' self.platform_toolset = None self.vs_version = '2010' self.windows_target_platform_version = None self.subdirs = {} self.handled_target_deps = {} def generate_custom_generator_commands(self, target, parent_node): generator_output_files = [] custom_target_include_dirs = [] custom_target_output_files = [] target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)) down = self.target_to_build_root(target) for genlist in target.get_generated_sources(): if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): for i in genlist.get_outputs(): # Path to the generated source from the current vcxproj dir via the build root ipath = os.path.join(down, self.get_target_dir(genlist), i) custom_target_output_files.append(ipath) idir = self.relpath(self.get_target_dir(genlist), self.get_target_dir(target)) if idir not in custom_target_include_dirs: custom_target_include_dirs.append(idir) else: generator = genlist.get_generator() exe = generator.get_exe() infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() source_dir = os.path.join(down, self.build_to_src, genlist.subdir) exe_arr = self.exe_object_to_cmd_array(exe) idgroup = ET.SubElement(parent_node, 'ItemGroup') for i in range(len(infilelist)): if len(infilelist) == len(outfilelist): sole_output = os.path.join(target_private_dir, outfilelist[i]) else: sole_output = '' curfile = infilelist[i] infilename = os.path.join(down, curfile.rel_to_builddir(self.build_to_src)) deps = self.get_custom_target_depend_files(genlist, True) base_args = generator.get_arglist(infilename) outfiles_rel = genlist.get_outputs_for(curfile) outfiles = [os.path.join(target_private_dir, of) for of in outfiles_rel] generator_output_files += outfiles args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output) for x in base_args] args = self.replace_outputs(args, target_private_dir, outfiles_rel) args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()) .replace("@BUILD_DIR@", target_private_dir) for x in args] args = [x.replace("@CURRENT_SOURCE_DIR@", source_dir) for x in args] args = [x.replace("@SOURCE_ROOT@", self.environment.get_source_dir()) .replace("@BUILD_ROOT@", self.environment.get_build_dir()) for x in args] args = [x.replace('\\', '/') for x in args] cmd = exe_arr + self.replace_extra_args(args, genlist) # Always use a wrapper because MSBuild eats random characters when # there are many arguments. tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) cmd = self.as_meson_exe_cmdline( 'generator ' + cmd[0], cmd[0], cmd[1:], workdir=tdir_abs, capture=outfiles[0] if generator.capture else None, force_serialize=True ) deps = cmd[-1:] + deps abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) os.makedirs(abs_pdir, exist_ok=True) cbs = ET.SubElement(idgroup, 'CustomBuild', Include=infilename) ET.SubElement(cbs, 'Command').text = ' '.join(self.quote_arguments(cmd)) ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles) ET.SubElement(cbs, 'AdditionalInputs').text = ';'.join(deps) return generator_output_files, custom_target_output_files, custom_target_include_dirs def generate(self, interp): self.interpreter = interp target_machine = self.interpreter.builtin['target_machine'].cpu_family_method(None, None) if target_machine.endswith('64'): # amd64 or x86_64 self.platform = 'x64' elif target_machine == 'x86': # x86 self.platform = 'Win32' elif 'arm' in target_machine.lower(): self.platform = 'ARM' else: raise MesonException('Unsupported Visual Studio platform: ' + target_machine) self.buildtype = self.environment.coredata.get_builtin_option('buildtype') sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln') projlist = self.generate_projects() self.gen_testproj('RUN_TESTS', os.path.join(self.environment.get_build_dir(), 'RUN_TESTS.vcxproj')) self.gen_installproj('RUN_INSTALL', os.path.join(self.environment.get_build_dir(), 'RUN_INSTALL.vcxproj')) self.gen_regenproj('REGEN', os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj')) self.generate_solution(sln_filename, projlist) self.generate_regen_info() Vs2010Backend.touch_regen_timestamp(self.environment.get_build_dir()) @staticmethod def get_regen_stampfile(build_dir): return os.path.join(os.path.join(build_dir, Environment.private_dir), 'regen.stamp') @staticmethod def touch_regen_timestamp(build_dir): with open(Vs2010Backend.get_regen_stampfile(build_dir), 'w'): pass def generate_regen_info(self): deps = self.get_regen_filelist() regeninfo = RegenInfo(self.environment.get_source_dir(), self.environment.get_build_dir(), deps) filename = os.path.join(self.environment.get_scratch_dir(), 'regeninfo.dump') with open(filename, 'wb') as f: pickle.dump(regeninfo, f) def get_vcvars_command(self): has_arch_values = 'VSCMD_ARG_TGT_ARCH' in os.environ and 'VSCMD_ARG_HOST_ARCH' in os.environ # Use vcvarsall.bat if we found it. if 'VCINSTALLDIR' in os.environ: vs_version = os.environ['VisualStudioVersion'] \ if 'VisualStudioVersion' in os.environ else None relative_path = 'Auxiliary\\Build\\' if vs_version >= '15.0' else '' script_path = os.environ['VCINSTALLDIR'] + relative_path + 'vcvarsall.bat' if os.path.exists(script_path): if has_arch_values: target_arch = os.environ['VSCMD_ARG_TGT_ARCH'] host_arch = os.environ['VSCMD_ARG_HOST_ARCH'] else: target_arch = os.environ.get('Platform', 'x86') host_arch = target_arch arch = host_arch + '_' + target_arch if host_arch != target_arch else target_arch return '"%s" %s' % (script_path, arch) # Otherwise try the VS2017 Developer Command Prompt. if 'VS150COMNTOOLS' in os.environ and has_arch_values: script_path = os.environ['VS150COMNTOOLS'] + 'VsDevCmd.bat' if os.path.exists(script_path): return '"%s" -arch=%s -host_arch=%s' % \ (script_path, os.environ['VSCMD_ARG_TGT_ARCH'], os.environ['VSCMD_ARG_HOST_ARCH']) return '' def get_obj_target_deps(self, obj_list): result = {} for o in obj_list: if isinstance(o, build.ExtractedObjects): result[o.target.get_id()] = o.target return result.items() def get_target_deps(self, t, recursive=False): all_deps = {} for target in t.values(): if isinstance(target, build.CustomTarget): for d in target.get_target_dependencies(): all_deps[d.get_id()] = d elif isinstance(target, build.RunTarget): for d in [target.command] + target.args: if isinstance(d, (build.BuildTarget, build.CustomTarget)): all_deps[d.get_id()] = d elif isinstance(target, build.BuildTarget): for ldep in target.link_targets: if isinstance(ldep, build.CustomTargetIndex): all_deps[ldep.get_id()] = ldep.target else: all_deps[ldep.get_id()] = ldep for ldep in target.link_whole_targets: if isinstance(ldep, build.CustomTargetIndex): all_deps[ldep.get_id()] = ldep.target else: all_deps[ldep.get_id()] = ldep for obj_id, objdep in self.get_obj_target_deps(target.objects): all_deps[obj_id] = objdep for gendep in target.get_generated_sources(): if isinstance(gendep, build.CustomTarget): all_deps[gendep.get_id()] = gendep elif isinstance(gendep, build.CustomTargetIndex): all_deps[gendep.target.get_id()] = gendep.target else: gen_exe = gendep.generator.get_exe() if isinstance(gen_exe, build.Executable): all_deps[gen_exe.get_id()] = gen_exe else: raise MesonException('Unknown target type for target %s' % target) if not t or not recursive: return all_deps ret = self.get_target_deps(all_deps, recursive) ret.update(all_deps) return ret def generate_solution_dirs(self, ofile, parents): prj_templ = 'Project("{%s}") = "%s", "%s", "{%s}"\n' iterpaths = reversed(parents) # Skip first path next(iterpaths) for path in iterpaths: if path not in self.subdirs: basename = path.name identifier = generate_guid_from_path(path, 'subdir') # top-level directories have None as their parent_dir parent_dir = path.parent parent_identifier = self.subdirs[parent_dir][0] \ if parent_dir != PurePath('.') else None self.subdirs[path] = (identifier, parent_identifier) prj_line = prj_templ % ( self.environment.coredata.lang_guids['directory'], basename, basename, self.subdirs[path][0]) ofile.write(prj_line) ofile.write('EndProject\n') def generate_solution(self, sln_filename, projlist): default_projlist = self.get_build_by_default_targets() sln_filename_tmp = sln_filename + '~' with open(sln_filename_tmp, 'w', encoding='utf-8') as ofile: ofile.write('Microsoft Visual Studio Solution File, Format ' 'Version 11.00\n') ofile.write('# Visual Studio ' + self.vs_version + '\n') prj_templ = 'Project("{%s}") = "%s", "%s", "{%s}"\n' for prj in projlist: coredata = self.environment.coredata if coredata.get_builtin_option('layout') == 'mirror': self.generate_solution_dirs(ofile, prj[1].parents) target = self.build.targets[prj[0]] lang = 'default' if hasattr(target, 'compilers') and target.compilers: for lang_out in target.compilers.keys(): lang = lang_out break prj_line = prj_templ % ( self.environment.coredata.lang_guids[lang], prj[0], prj[1], prj[2]) ofile.write(prj_line) target_dict = {target.get_id(): target} # Get recursive deps recursive_deps = self.get_target_deps( target_dict, recursive=True) ofile.write('EndProject\n') for dep, target in recursive_deps.items(): if prj[0] in default_projlist: default_projlist[dep] = target test_line = prj_templ % (self.environment.coredata.lang_guids['default'], 'RUN_TESTS', 'RUN_TESTS.vcxproj', self.environment.coredata.test_guid) ofile.write(test_line) ofile.write('EndProject\n') regen_line = prj_templ % (self.environment.coredata.lang_guids['default'], 'REGEN', 'REGEN.vcxproj', self.environment.coredata.regen_guid) ofile.write(regen_line) ofile.write('EndProject\n') install_line = prj_templ % (self.environment.coredata.lang_guids['default'], 'RUN_INSTALL', 'RUN_INSTALL.vcxproj', self.environment.coredata.install_guid) ofile.write(install_line) ofile.write('EndProject\n') ofile.write('Global\n') ofile.write('\tGlobalSection(SolutionConfigurationPlatforms) = ' 'preSolution\n') ofile.write('\t\t%s|%s = %s|%s\n' % (self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\tEndGlobalSection\n') ofile.write('\tGlobalSection(ProjectConfigurationPlatforms) = ' 'postSolution\n') ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (self.environment.coredata.regen_guid, self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\t\t{%s}.%s|%s.Build.0 = %s|%s\n' % (self.environment.coredata.regen_guid, self.buildtype, self.platform, self.buildtype, self.platform)) # Create the solution configuration for p in projlist: # Add to the list of projects in this solution ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (p[2], self.buildtype, self.platform, self.buildtype, self.platform)) if p[0] in default_projlist and \ not isinstance(self.build.targets[p[0]], build.RunTarget): # Add to the list of projects to be built ofile.write('\t\t{%s}.%s|%s.Build.0 = %s|%s\n' % (p[2], self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (self.environment.coredata.test_guid, self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (self.environment.coredata.install_guid, self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\tEndGlobalSection\n') ofile.write('\tGlobalSection(SolutionProperties) = preSolution\n') ofile.write('\t\tHideSolutionNode = FALSE\n') ofile.write('\tEndGlobalSection\n') if self.subdirs: ofile.write('\tGlobalSection(NestedProjects) = ' 'preSolution\n') for p in projlist: if p[1].parent != PurePath('.'): ofile.write("\t\t{%s} = {%s}\n" % (p[2], self.subdirs[p[1].parent][0])) for subdir in self.subdirs.values(): if subdir[1]: ofile.write("\t\t{%s} = {%s}\n" % (subdir[0], subdir[1])) ofile.write('\tEndGlobalSection\n') ofile.write('EndGlobal\n') replace_if_different(sln_filename, sln_filename_tmp) def generate_projects(self): startup_project = self.environment.coredata.backend_options['backend_startup_project'].value projlist = [] startup_idx = 0 for (i, (name, target)) in enumerate(self.build.targets.items()): if startup_project and startup_project == target.get_basename(): startup_idx = i outdir = Path( self.environment.get_build_dir(), self.get_target_dir(target) ) outdir.mkdir(exist_ok=True, parents=True) fname = name + '.vcxproj' target_dir = PurePath(self.get_target_dir(target)) relname = target_dir / fname projfile_path = outdir / fname proj_uuid = self.environment.coredata.target_guids[name] self.gen_vcxproj(target, str(projfile_path), proj_uuid) projlist.append((name, relname, proj_uuid)) # Put the startup project first in the project list if startup_idx: projlist = [projlist[startup_idx]] + projlist[0:startup_idx] + projlist[startup_idx + 1:-1] return projlist def split_sources(self, srclist): sources = [] headers = [] objects = [] languages = [] for i in srclist: if self.environment.is_header(i): headers.append(i) elif self.environment.is_object(i): objects.append(i) elif self.environment.is_source(i): sources.append(i) lang = self.lang_from_source_file(i) if lang not in languages: languages.append(lang) elif self.environment.is_library(i): pass else: # Everything that is not an object or source file is considered a header. headers.append(i) return sources, headers, objects, languages def target_to_build_root(self, target): if self.get_target_dir(target) == '': return '' directories = os.path.normpath(self.get_target_dir(target)).split(os.sep) return os.sep.join(['..'] * len(directories)) def quote_arguments(self, arr): return ['"%s"' % i for i in arr] def add_project_reference(self, root, include, projid, link_outputs=False): ig = ET.SubElement(root, 'ItemGroup') pref = ET.SubElement(ig, 'ProjectReference', Include=include) ET.SubElement(pref, 'Project').text = '{%s}' % projid if not link_outputs: # Do not link in generated .lib files from dependencies automatically. # We only use the dependencies for ordering and link in the generated # objects and .lib files manually. ET.SubElement(pref, 'LinkLibraryDependencies').text = 'false' def add_target_deps(self, root, target): target_dict = {target.get_id(): target} for dep in self.get_target_deps(target_dict).values(): if dep.get_id() in self.handled_target_deps[target.get_id()]: # This dependency was already handled manually. continue relpath = self.get_target_dir_relative_to(dep, target) vcxproj = os.path.join(relpath, dep.get_id() + '.vcxproj') tid = self.environment.coredata.target_guids[dep.get_id()] self.add_project_reference(root, vcxproj, tid) def create_basic_crap(self, target, guid): project_name = target.name root = ET.Element('Project', {'DefaultTargets': "Build", 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = '{%s}' % guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.Default.props') type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType') ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' ET.SubElement(type_config, 'UseOfMfc').text = 'false' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.props') direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = target.get_id() + '\\' tname = ET.SubElement(direlem, 'TargetName') tname.text = target.name return root def gen_run_target_vcxproj(self, target, ofname, guid): root = self.create_basic_crap(target, guid) if not target.command: # FIXME: This is an alias target that doesn't run any command, there # is probably a better way than running a this dummy command. cmd_raw = python_command + ['-c', 'exit'] else: cmd_raw = [target.command] + target.args cmd = python_command + \ [os.path.join(self.environment.get_script_dir(), 'commandrunner.py'), self.environment.get_source_dir(), self.environment.get_build_dir(), self.get_target_dir(target)] + self.environment.get_build_command() for i in cmd_raw: if isinstance(i, build.BuildTarget): cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i))) elif isinstance(i, dependencies.ExternalProgram): cmd += i.get_command() elif isinstance(i, File): relfname = i.rel_to_builddir(self.build_to_src) cmd.append(os.path.join(self.environment.get_build_dir(), relfname)) elif isinstance(i, str): # Escape embedded quotes, because we quote the entire argument below. cmd.append(i.replace('"', '\\"')) else: cmd.append(i) cmd_templ = '''"%s" ''' * len(cmd) self.add_custom_build(root, 'run_target', cmd_templ % tuple(cmd)) ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets') self.add_regen_dependency(root) self.add_target_deps(root, target) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) def gen_custom_target_vcxproj(self, target, ofname, guid): root = self.create_basic_crap(target, guid) # We need to always use absolute paths because our invocation is always # from the target dir, not the build root. target.absolute_paths = True (srcs, ofilenames, cmd) = self.eval_custom_target_command(target, True) depend_files = self.get_custom_target_depend_files(target, True) # Always use a wrapper because MSBuild eats random characters when # there are many arguments. tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) extra_bdeps = target.get_transitive_build_target_deps() wrapper_cmd = self.as_meson_exe_cmdline(target.name, target.command[0], cmd[1:], # All targets run from the target dir workdir=tdir_abs, extra_bdeps=extra_bdeps, capture=ofilenames[0] if target.capture else None, force_serialize=True) if target.build_always_stale: # Use a nonexistent file to always consider the target out-of-date. ofilenames += [self.nonexistent_file(os.path.join(self.environment.get_scratch_dir(), 'outofdate.file'))] self.add_custom_build(root, 'custom_target', ' '.join(self.quote_arguments(wrapper_cmd)), deps=wrapper_cmd[-1:] + srcs + depend_files, outputs=ofilenames) ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets') self.generate_custom_generator_commands(target, root) self.add_regen_dependency(root) self.add_target_deps(root, target) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) @classmethod def lang_from_source_file(cls, src): ext = src.split('.')[-1] if ext in compilers.c_suffixes: return 'c' if ext in compilers.cpp_suffixes: return 'cpp' raise MesonException('Could not guess language from source file %s.' % src) def add_pch(self, pch_sources, lang, inc_cl): if len(pch_sources) <= 1: # We only need per file precompiled headers if we have more than 1 language. return self.use_pch(pch_sources, lang, inc_cl) def create_pch(self, pch_sources, lang, inc_cl): pch = ET.SubElement(inc_cl, 'PrecompiledHeader') pch.text = 'Create' self.add_pch_files(pch_sources, lang, inc_cl) def use_pch(self, pch_sources, lang, inc_cl): header = self.add_pch_files(pch_sources, lang, inc_cl) pch_include = ET.SubElement(inc_cl, 'ForcedIncludeFiles') pch_include.text = header + ';%(ForcedIncludeFiles)' def add_pch_files(self, pch_sources, lang, inc_cl): header = os.path.basename(pch_sources[lang][0]) pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') # When USING PCHs, MSVC will not do the regular include # directory lookup, but simply use a string match to find the # PCH to use. That means the #include directive must match the # pch_file.text used during PCH CREATION verbatim. # When CREATING a PCH, MSVC will do the include directory # lookup to find the actual PCH header to use. Thus, the PCH # header must either be in the include_directories of the target # or be in the same directory as the PCH implementation. pch_file.text = header pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % lang return header def is_argument_with_msbuild_xml_entry(self, entry): # Remove arguments that have a top level XML entry so # they are not used twice. # FIXME add args as needed. return entry[1:].startswith('M') def add_additional_options(self, lang, parent_node, file_args): args = [] for arg in file_args[lang].to_native(): if self.is_argument_with_msbuild_xml_entry(arg): continue if arg == '%(AdditionalOptions)': args.append(arg) else: args.append(self.escape_additional_option(arg)) ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(args) def add_preprocessor_defines(self, lang, parent_node, file_defines): defines = [] for define in file_defines[lang]: if define == '%(PreprocessorDefinitions)': defines.append(define) else: defines.append(self.escape_preprocessor_define(define)) ET.SubElement(parent_node, "PreprocessorDefinitions").text = ';'.join(defines) def add_include_dirs(self, lang, parent_node, file_inc_dirs): dirs = file_inc_dirs[lang] ET.SubElement(parent_node, "AdditionalIncludeDirectories").text = ';'.join(dirs) @staticmethod def has_objects(objects, additional_objects, generated_objects): # Ignore generated objects, those are automatically used by MSBuild because they are part of # the CustomBuild Outputs. return len(objects) + len(additional_objects) > 0 @staticmethod def add_generated_objects(node, generated_objects): # Do not add generated objects to project file. Those are automatically used by MSBuild, because # they are part of the CustomBuild Outputs. return @staticmethod def escape_preprocessor_define(define): # See: https://msdn.microsoft.com/en-us/library/bb383819.aspx table = str.maketrans({'%': '%25', '$': '%24', '@': '%40', "'": '%27', ';': '%3B', '?': '%3F', '*': '%2A', # We need to escape backslash because it'll be un-escaped by # Windows during process creation when it parses the arguments # Basically, this converts `\` to `\\`. '\\': '\\\\'}) return define.translate(table) @staticmethod def escape_additional_option(option): # See: https://msdn.microsoft.com/en-us/library/bb383819.aspx table = str.maketrans({'%': '%25', '$': '%24', '@': '%40', "'": '%27', ';': '%3B', '?': '%3F', '*': '%2A', ' ': '%20'}) option = option.translate(table) # Since we're surrounding the option with ", if it ends in \ that will # escape the " when the process arguments are parsed and the starting # " will not terminate. So we escape it if that's the case. I'm not # kidding, this is how escaping works for process args on Windows. if option.endswith('\\'): option += '\\' return '"{}"'.format(option) @staticmethod def split_link_args(args): """ Split a list of link arguments into three lists: * library search paths * library filenames (or paths) * other link arguments """ lpaths = [] libs = [] other = [] for arg in args: if arg.startswith('/LIBPATH:'): lpath = arg[9:] # De-dup library search paths by removing older entries when # a new one is found. This is necessary because unlike other # search paths such as the include path, the library is # searched for in the newest (right-most) search path first. if lpath in lpaths: lpaths.remove(lpath) lpaths.append(lpath) elif arg.startswith(('/', '-')): other.append(arg) # It's ok if we miss libraries with non-standard extensions here. # They will go into the general link arguments. elif arg.endswith('.lib') or arg.endswith('.a'): # De-dup if arg not in libs: libs.append(arg) else: other.append(arg) return lpaths, libs, other def _get_cl_compiler(self, target): for lang, c in target.compilers.items(): if lang in ('c', 'cpp'): return c # No source files, only objects, but we still need a compiler, so # return a found compiler if len(target.objects) > 0: for lang, c in self.environment.coredata.compilers[target.for_machine].items(): if lang in ('c', 'cpp'): return c raise MesonException('Could not find a C or C++ compiler. MSVC can only build C/C++ projects.') def _prettyprint_vcxproj_xml(self, tree, ofname): ofname_tmp = ofname + '~' tree.write(ofname_tmp, encoding='utf-8', xml_declaration=True) # ElementTree can not do prettyprinting so do it manually doc = xml.dom.minidom.parse(ofname_tmp) with open(ofname_tmp, 'w', encoding='utf-8') as of: of.write(doc.toprettyxml()) replace_if_different(ofname, ofname_tmp) def gen_vcxproj(self, target, ofname, guid): mlog.debug('Generating vcxproj %s.' % target.name) entrypoint = 'WinMainCRTStartup' subsystem = 'Windows' self.handled_target_deps[target.get_id()] = [] if isinstance(target, build.Executable): conftype = 'Application' if not target.gui_app: subsystem = 'Console' entrypoint = 'mainCRTStartup' elif isinstance(target, build.StaticLibrary): conftype = 'StaticLibrary' elif isinstance(target, build.SharedLibrary): conftype = 'DynamicLibrary' entrypoint = '_DllMainCrtStartup' elif isinstance(target, build.CustomTarget): return self.gen_custom_target_vcxproj(target, ofname, guid) elif isinstance(target, build.RunTarget): return self.gen_run_target_vcxproj(target, ofname, guid) else: raise MesonException('Unknown target type for %s' % target.get_basename()) # Prefix to use to access the build root from the vcxproj dir down = self.target_to_build_root(target) # Prefix to use to access the source tree's root from the vcxproj dir proj_to_src_root = os.path.join(down, self.build_to_src) # Prefix to use to access the source tree's subdir from the vcxproj dir proj_to_src_dir = os.path.join(proj_to_src_root, self.get_target_dir(target)) (sources, headers, objects, languages) = self.split_sources(target.sources) if self.is_unity(target): sources = self.generate_unity_files(target, sources) compiler = self._get_cl_compiler(target) buildtype_args = compiler.get_buildtype_args(self.buildtype) buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype) vscrt_type = self.environment.coredata.base_options['b_vscrt'] project_name = target.name target_name = target.name root = ET.Element('Project', {'DefaultTargets': "Build", 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform # Globals globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = '{%s}' % guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' ns = ET.SubElement(globalgroup, 'RootNamespace') ns.text = target_name p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.Default.props') # Start configuration type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType').text = conftype ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset # FIXME: Meson's LTO support needs to be integrated here ET.SubElement(type_config, 'WholeProgramOptimization').text = 'false' # Let VS auto-set the RTC level ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'Default' # Incremental linking increases code size if '/INCREMENTAL:NO' in buildtype_link_args: ET.SubElement(type_config, 'LinkIncremental').text = 'false' # Build information compiles = ET.SubElement(root, 'ItemDefinitionGroup') clconf = ET.SubElement(compiles, 'ClCompile') # CRT type; debug or release if vscrt_type.value == 'from_buildtype': if self.buildtype == 'debug' or self.buildtype == 'debugoptimized': ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL' else: ET.SubElement(type_config, 'UseDebugLibraries').text = 'false' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreaded' elif vscrt_type.value == 'mdd': ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL' elif vscrt_type.value == 'mt': # FIXME, wrong ET.SubElement(type_config, 'UseDebugLibraries').text = 'false' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreaded' elif vscrt_type.value == 'mtd': # FIXME, wrong ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDebug' else: ET.SubElement(type_config, 'UseDebugLibraries').text = 'false' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDLL' # Debug format if '/ZI' in buildtype_args: ET.SubElement(type_config, 'DebugInformationFormat').text = 'EditAndContinue' elif '/Zi' in buildtype_args: ET.SubElement(type_config, 'DebugInformationFormat').text = 'ProgramDatabase' elif '/Z7' in buildtype_args: ET.SubElement(type_config, 'DebugInformationFormat').text = 'OldStyle' # Runtime checks if '/RTC1' in buildtype_args: ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'EnableFastChecks' elif '/RTCu' in buildtype_args: ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'UninitializedLocalUsageCheck' elif '/RTCs' in buildtype_args: ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'StackFrameRuntimeCheck' # End configuration ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.props') generated_files, custom_target_output_files, generated_files_include_dirs = self.generate_custom_generator_commands(target, root) (gen_src, gen_hdrs, gen_objs, gen_langs) = self.split_sources(generated_files) (custom_src, custom_hdrs, custom_objs, custom_langs) = self.split_sources(custom_target_output_files) gen_src += custom_src gen_hdrs += custom_hdrs gen_langs += custom_langs # Project information direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = target.get_id() + '\\' tfilename = os.path.splitext(target.get_filename()) ET.SubElement(direlem, 'TargetName').text = tfilename[0] ET.SubElement(direlem, 'TargetExt').text = tfilename[1] # Arguments, include dirs, defines for all files in the current target target_args = [] target_defines = [] target_inc_dirs = [] # Arguments, include dirs, defines passed to individual files in # a target; perhaps because the args are language-specific # # file_args is also later split out into defines and include_dirs in # case someone passed those in there file_args = dict((lang, CompilerArgs(comp)) for lang, comp in target.compilers.items()) file_defines = dict((lang, []) for lang in target.compilers) file_inc_dirs = dict((lang, []) for lang in target.compilers) # The order in which these compile args are added must match # generate_single_compile() and generate_basic_compiler_args() for l, comp in target.compilers.items(): if l in file_args: file_args[l] += compilers.get_base_compile_args(self.get_base_options_for_target(target), comp) file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options[target.for_machine]) # Add compile args added using add_project_arguments() for l, args in self.build.projects_args[target.for_machine].get(target.subproject, {}).items(): if l in file_args: file_args[l] += args # Add compile args added using add_global_arguments() # These override per-project arguments for l, args in self.build.global_args[target.for_machine].items(): if l in file_args: file_args[l] += args # Compile args added from the env or cross file: CFLAGS/CXXFLAGS, etc. We want these # to override all the defaults, but not the per-target compile args. for key, opt in self.environment.coredata.compiler_options[target.for_machine].items(): l, suffix = key.split('_', 1) if suffix == 'args' and l in file_args: file_args[l] += opt.value for args in file_args.values(): # This is where Visual Studio will insert target_args, target_defines, # etc, which are added later from external deps (see below). args += ['%(AdditionalOptions)', '%(PreprocessorDefinitions)', '%(AdditionalIncludeDirectories)'] # Add custom target dirs as includes automatically, but before # target-specific include dirs. See _generate_single_compile() in # the ninja backend for caveats. args += ['-I' + arg for arg in generated_files_include_dirs] # Add include dirs from the `include_directories:` kwarg on the target # and from `include_directories:` of internal deps of the target. # # Target include dirs should override internal deps include dirs. # This is handled in BuildTarget.process_kwargs() # # Include dirs from internal deps should override include dirs from # external deps and must maintain the order in which they are # specified. Hence, we must reverse so that the order is preserved. # # These are per-target, but we still add them as per-file because we # need them to be looked in first. for d in reversed(target.get_include_dirs()): # reversed is used to keep order of includes for i in reversed(d.get_incdirs()): curdir = os.path.join(d.get_curdir(), i) args.append('-I' + self.relpath(curdir, target.subdir)) # build dir args.append('-I' + os.path.join(proj_to_src_root, curdir)) # src dir for i in d.get_extra_build_dirs(): curdir = os.path.join(d.get_curdir(), i) args.append('-I' + self.relpath(curdir, target.subdir)) # build dir # Add per-target compile args, f.ex, `c_args : ['/DFOO']`. We set these # near the end since these are supposed to override everything else. for l, args in target.extra_args.items(): if l in file_args: file_args[l] += args # The highest priority includes. In order of directory search: # target private dir, target build dir, target source dir for args in file_args.values(): t_inc_dirs = [self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))] if target.implicit_include_directories: t_inc_dirs += ['.'] if target.implicit_include_directories: t_inc_dirs += [proj_to_src_dir] args += ['-I' + arg for arg in t_inc_dirs] # Split preprocessor defines and include directories out of the list of # all extra arguments. The rest go into %(AdditionalOptions). for l, args in file_args.items(): for arg in args[:]: if arg.startswith(('-D', '/D')) or arg == '%(PreprocessorDefinitions)': file_args[l].remove(arg) # Don't escape the marker if arg == '%(PreprocessorDefinitions)': define = arg else: define = arg[2:] # De-dup if define in file_defines[l]: file_defines[l].remove(define) file_defines[l].append(define) elif arg.startswith(('-I', '/I')) or arg == '%(AdditionalIncludeDirectories)': file_args[l].remove(arg) # Don't escape the marker if arg == '%(AdditionalIncludeDirectories)': inc_dir = arg else: inc_dir = arg[2:] # De-dup if inc_dir not in file_inc_dirs[l]: file_inc_dirs[l].append(inc_dir) # Split compile args needed to find external dependencies # Link args are added while generating the link command for d in reversed(target.get_external_deps()): # Cflags required by external deps might have UNIX-specific flags, # so filter them out if needed if isinstance(d, dependencies.OpenMPDependency): d_compile_args = compiler.openmp_flags() else: d_compile_args = compiler.unix_args_to_native(d.get_compile_args()) for arg in d_compile_args: if arg.startswith(('-D', '/D')): define = arg[2:] # De-dup if define in target_defines: target_defines.remove(define) target_defines.append(define) elif arg.startswith(('-I', '/I')): inc_dir = arg[2:] # De-dup if inc_dir not in target_inc_dirs: target_inc_dirs.append(inc_dir) else: target_args.append(arg) languages += gen_langs if len(target_args) > 0: target_args.append('%(AdditionalOptions)') ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(target_args) target_inc_dirs.append('%(AdditionalIncludeDirectories)') ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(target_inc_dirs) target_defines.append('%(PreprocessorDefinitions)') ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(target_defines) ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true' # Warning level warning_level = self.get_option_for_target('warning_level', target) ET.SubElement(clconf, 'WarningLevel').text = 'Level' + str(1 + int(warning_level)) if self.get_option_for_target('werror', target): ET.SubElement(clconf, 'TreatWarningAsError').text = 'true' # Optimization flags o_flags = split_o_flags_args(buildtype_args) if '/Ox' in o_flags: ET.SubElement(clconf, 'Optimization').text = 'Full' elif '/O2' in o_flags: ET.SubElement(clconf, 'Optimization').text = 'MaxSpeed' elif '/O1' in o_flags: ET.SubElement(clconf, 'Optimization').text = 'MinSpace' elif '/Od' in o_flags: ET.SubElement(clconf, 'Optimization').text = 'Disabled' if '/Oi' in o_flags: ET.SubElement(clconf, 'IntrinsicFunctions').text = 'true' if '/Ob1' in o_flags: ET.SubElement(clconf, 'InlineFunctionExpansion').text = 'OnlyExplicitInline' elif '/Ob2' in o_flags: ET.SubElement(clconf, 'InlineFunctionExpansion').text = 'AnySuitable' # Size-preserving flags if '/Os' in o_flags: ET.SubElement(clconf, 'FavorSizeOrSpeed').text = 'Size' else: ET.SubElement(clconf, 'FavorSizeOrSpeed').text = 'Speed' # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default pch_sources = {} if self.environment.coredata.base_options.get('b_pch', False): pch_node = ET.SubElement(clconf, 'PrecompiledHeader') for lang in ['c', 'cpp']: pch = target.get_pch(lang) if not pch: continue pch_node.text = 'Use' if compiler.id == 'msvc': if len(pch) == 1: # Auto generate PCH. src = os.path.join(down, self.create_msvc_pch_implementation(target, lang, pch[0])) pch_header_dir = os.path.dirname(os.path.join(proj_to_src_dir, pch[0])) else: src = os.path.join(proj_to_src_dir, pch[1]) pch_header_dir = None pch_sources[lang] = [pch[0], src, lang, pch_header_dir] else: # I don't know whether its relevant but let's handle other compilers # used with a vs backend pch_sources[lang] = [pch[0], None, lang, None] if len(pch_sources) == 1: # If there is only 1 language with precompiled headers, we can use it for the entire project, which # is cleaner than specifying it for each source file. self.use_pch(pch_sources, list(pch_sources)[0], clconf) resourcecompile = ET.SubElement(compiles, 'ResourceCompile') ET.SubElement(resourcecompile, 'PreprocessorDefinitions') # Linker options link = ET.SubElement(compiles, 'Link') extra_link_args = CompilerArgs(compiler) # FIXME: Can these buildtype linker args be added as tags in the # vcxproj file (similar to buildtype compiler args) instead of in # AdditionalOptions? extra_link_args += compiler.get_buildtype_linker_args(self.buildtype) # Generate Debug info if self.buildtype.startswith('debug'): self.generate_debug_information(link) if not isinstance(target, build.StaticLibrary): if isinstance(target, build.SharedModule): options = self.environment.coredata.base_options extra_link_args += compiler.get_std_shared_module_link_args(options) # Add link args added using add_project_link_arguments() extra_link_args += self.build.get_project_link_args(compiler, target.subproject, target.for_machine) # Add link args added using add_global_link_arguments() # These override per-project link arguments extra_link_args += self.build.get_global_link_args(compiler, target.for_machine) # Link args added from the env: LDFLAGS, or the cross file. We want # these to override all the defaults but not the per-target link # args. extra_link_args += self.environment.coredata.get_external_link_args(target.for_machine, compiler.get_language()) # Only non-static built targets need link args and link dependencies extra_link_args += target.link_args # External deps must be last because target link libraries may depend on them. for dep in target.get_external_deps(): # Extend without reordering or de-dup to preserve `-L -l` sets # https://github.com/mesonbuild/meson/issues/1718 if isinstance(dep, dependencies.OpenMPDependency): extra_link_args.extend_direct(compiler.openmp_flags()) else: extra_link_args.extend_direct(dep.get_link_args()) for d in target.get_dependencies(): if isinstance(d, build.StaticLibrary): for dep in d.get_external_deps(): if isinstance(dep, dependencies.OpenMPDependency): extra_link_args.extend_direct(compiler.openmp_flags()) else: extra_link_args.extend_direct(dep.get_link_args()) # Add link args for c_* or cpp_* build options. Currently this only # adds c_winlibs and cpp_winlibs when building for Windows. This needs # to be after all internal and external libraries so that unresolved # symbols from those can be found here. This is needed when the # *_winlibs that we want to link to are static mingw64 libraries. extra_link_args += compiler.get_option_link_args(self.environment.coredata.compiler_options[compiler.for_machine]) (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args.to_native()) # Add more libraries to be linked if needed for t in target.get_dependencies(): if isinstance(t, build.CustomTargetIndex): # We don't need the actual project here, just the library name lobj = t else: lobj = self.build.targets[t.get_id()] linkname = os.path.join(down, self.get_target_filename_for_linking(lobj)) if t in target.link_whole_targets: # /WHOLEARCHIVE:foo must go into AdditionalOptions extra_link_args += compiler.get_link_whole_for(linkname) # To force Visual Studio to build this project even though it # has no sources, we include a reference to the vcxproj file # that builds this target. Technically we should add this only # if the current target has no sources, but it doesn't hurt to # have 'extra' references. trelpath = self.get_target_dir_relative_to(t, target) tvcxproj = os.path.join(trelpath, t.get_id() + '.vcxproj') tid = self.environment.coredata.target_guids[t.get_id()] self.add_project_reference(root, tvcxproj, tid, link_outputs=True) # Mark the dependency as already handled to not have # multiple references to the same target. self.handled_target_deps[target.get_id()].append(t.get_id()) else: # Other libraries go into AdditionalDependencies if linkname not in additional_links: additional_links.append(linkname) for lib in self.get_custom_target_provided_libraries(target): additional_links.append(self.relpath(lib, self.get_target_dir(target))) additional_objects = [] for o in self.flatten_object_list(target, down): assert(isinstance(o, str)) additional_objects.append(o) for o in custom_objs: additional_objects.append(o) if len(extra_link_args) > 0: extra_link_args.append('%(AdditionalOptions)') ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args) if len(additional_libpaths) > 0: additional_libpaths.insert(0, '%(AdditionalLibraryDirectories)') ET.SubElement(link, 'AdditionalLibraryDirectories').text = ';'.join(additional_libpaths) if len(additional_links) > 0: additional_links.append('%(AdditionalDependencies)') ET.SubElement(link, 'AdditionalDependencies').text = ';'.join(additional_links) ofile = ET.SubElement(link, 'OutputFile') ofile.text = '$(OutDir)%s' % target.get_filename() subsys = ET.SubElement(link, 'SubSystem') subsys.text = subsystem if (isinstance(target, build.SharedLibrary) or isinstance(target, build.Executable)) and target.get_import_filename(): # DLLs built with MSVC always have an import library except when # they're data-only DLLs, but we don't support those yet. ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename() if isinstance(target, build.SharedLibrary): # Add module definitions file, if provided if target.vs_module_defs: relpath = os.path.join(down, target.vs_module_defs.rel_to_builddir(self.build_to_src)) ET.SubElement(link, 'ModuleDefinitionFile').text = relpath if '/ZI' in buildtype_args or '/Zi' in buildtype_args: pdb = ET.SubElement(link, 'ProgramDataBaseFileName') pdb.text = '$(OutDir}%s.pdb' % target_name if isinstance(target, build.Executable): ET.SubElement(link, 'EntryPointSymbol').text = entrypoint targetmachine = ET.SubElement(link, 'TargetMachine') targetplatform = self.platform.lower() if targetplatform == 'win32': targetmachine.text = 'MachineX86' elif targetplatform == 'x64': targetmachine.text = 'MachineX64' elif targetplatform == 'arm': targetmachine.text = 'MachineARM' else: raise MesonException('Unsupported Visual Studio target machine: ' + targetplatform) # /nologo ET.SubElement(link, 'SuppressStartupBanner').text = 'true' # /release ET.SubElement(link, 'SetChecksum').text = 'true' meson_file_group = ET.SubElement(root, 'ItemGroup') ET.SubElement(meson_file_group, 'None', Include=os.path.join(proj_to_src_dir, build_filename)) # Visual Studio can't load projects that present duplicated items. Filter them out # by keeping track of already added paths. def path_normalize_add(path, lis): normalized = os.path.normcase(os.path.normpath(path)) if normalized not in lis: lis.append(normalized) return True else: return False previous_includes = [] if len(headers) + len(gen_hdrs) + len(target.extra_files) + len(pch_sources) > 0: inc_hdrs = ET.SubElement(root, 'ItemGroup') for h in headers: relpath = os.path.join(down, h.rel_to_builddir(self.build_to_src)) if path_normalize_add(relpath, previous_includes): ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath) for h in gen_hdrs: if path_normalize_add(h, previous_includes): ET.SubElement(inc_hdrs, 'CLInclude', Include=h) for h in target.extra_files: relpath = os.path.join(down, h.rel_to_builddir(self.build_to_src)) if path_normalize_add(relpath, previous_includes): ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath) for lang in pch_sources: h = pch_sources[lang][0] path = os.path.join(proj_to_src_dir, h) if path_normalize_add(path, previous_includes): ET.SubElement(inc_hdrs, 'CLInclude', Include=path) previous_sources = [] if len(sources) + len(gen_src) + len(pch_sources) > 0: inc_src = ET.SubElement(root, 'ItemGroup') for s in sources: relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src)) if path_normalize_add(relpath, previous_sources): inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) lang = Vs2010Backend.lang_from_source_file(s) self.add_pch(pch_sources, lang, inc_cl) self.add_additional_options(lang, inc_cl, file_args) self.add_preprocessor_defines(lang, inc_cl, file_defines) self.add_include_dirs(lang, inc_cl, file_inc_dirs) ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + self.object_filename_from_source(target, s) for s in gen_src: if path_normalize_add(s, previous_sources): inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=s) lang = Vs2010Backend.lang_from_source_file(s) self.add_pch(pch_sources, lang, inc_cl) self.add_additional_options(lang, inc_cl, file_args) self.add_preprocessor_defines(lang, inc_cl, file_defines) self.add_include_dirs(lang, inc_cl, file_inc_dirs) for lang in pch_sources: impl = pch_sources[lang][1] if impl and path_normalize_add(impl, previous_sources): inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=impl) self.create_pch(pch_sources, lang, inc_cl) self.add_additional_options(lang, inc_cl, file_args) self.add_preprocessor_defines(lang, inc_cl, file_defines) pch_header_dir = pch_sources[lang][3] if pch_header_dir: inc_dirs = copy.deepcopy(file_inc_dirs) inc_dirs[lang] = [pch_header_dir] + inc_dirs[lang] else: inc_dirs = file_inc_dirs self.add_include_dirs(lang, inc_cl, inc_dirs) previous_objects = [] if self.has_objects(objects, additional_objects, gen_objs): inc_objs = ET.SubElement(root, 'ItemGroup') for s in objects: relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src)) if path_normalize_add(relpath, previous_objects): ET.SubElement(inc_objs, 'Object', Include=relpath) for s in additional_objects: if path_normalize_add(s, previous_objects): ET.SubElement(inc_objs, 'Object', Include=s) self.add_generated_objects(inc_objs, gen_objs) ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets') self.add_regen_dependency(root) self.add_target_deps(root, target) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) def gen_regenproj(self, project_name, ofname): root = ET.Element('Project', {'DefaultTargets': 'Build', 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = '{%s}' % self.environment.coredata.regen_guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.Default.props') type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType').text = "Utility" ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' ET.SubElement(type_config, 'UseOfMfc').text = 'false' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.props') direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = 'regen-temp\\' tname = ET.SubElement(direlem, 'TargetName') tname.text = project_name action = ET.SubElement(root, 'ItemDefinitionGroup') midl = ET.SubElement(action, 'Midl') ET.SubElement(midl, "AdditionalIncludeDirectories").text = '%(AdditionalIncludeDirectories)' ET.SubElement(midl, "OutputDirectory").text = '$(IntDir)' ET.SubElement(midl, 'HeaderFileName').text = '%(Filename).h' ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb' ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c' ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c' regen_command = self.environment.get_build_command() + ['--internal', 'regencheck'] cmd_templ = '''call %s > NUL "%s" "%s"''' regen_command = cmd_templ % \ (self.get_vcvars_command(), '" "'.join(regen_command), self.environment.get_scratch_dir()) self.add_custom_build(root, 'regen', regen_command, deps=self.get_regen_filelist(), outputs=[Vs2010Backend.get_regen_stampfile(self.environment.get_build_dir())], msg='Checking whether solution needs to be regenerated.') ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets') ET.SubElement(root, 'ImportGroup', Label='ExtensionTargets') self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) def gen_testproj(self, target_name, ofname): project_name = target_name root = ET.Element('Project', {'DefaultTargets': "Build", 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = '{%s}' % self.environment.coredata.test_guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.Default.props') type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType') ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' ET.SubElement(type_config, 'UseOfMfc').text = 'false' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.props') direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = 'test-temp\\' tname = ET.SubElement(direlem, 'TargetName') tname.text = target_name action = ET.SubElement(root, 'ItemDefinitionGroup') midl = ET.SubElement(action, 'Midl') ET.SubElement(midl, "AdditionalIncludeDirectories").text = '%(AdditionalIncludeDirectories)' ET.SubElement(midl, "OutputDirectory").text = '$(IntDir)' ET.SubElement(midl, 'HeaderFileName').text = '%(Filename).h' ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb' ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c' ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c' # FIXME: No benchmarks? test_command = self.environment.get_build_command() + ['test', '--no-rebuild'] if not self.environment.coredata.get_builtin_option('stdsplit'): test_command += ['--no-stdsplit'] if self.environment.coredata.get_builtin_option('errorlogs'): test_command += ['--print-errorlogs'] self.serialize_tests() self.add_custom_build(root, 'run_tests', '"%s"' % ('" "'.join(test_command))) ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets') self.add_regen_dependency(root) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) def gen_installproj(self, target_name, ofname): self.create_install_data_files() project_name = target_name root = ET.Element('Project', {'DefaultTargets': "Build", 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = '{%s}' % self.environment.coredata.install_guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.Default.props') type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType') ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' ET.SubElement(type_config, 'UseOfMfc').text = 'false' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.props') direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = 'install-temp\\' tname = ET.SubElement(direlem, 'TargetName') tname.text = target_name action = ET.SubElement(root, 'ItemDefinitionGroup') midl = ET.SubElement(action, 'Midl') ET.SubElement(midl, "AdditionalIncludeDirectories").text = '%(AdditionalIncludeDirectories)' ET.SubElement(midl, "OutputDirectory").text = '$(IntDir)' ET.SubElement(midl, 'HeaderFileName').text = '%(Filename).h' ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb' ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c' ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c' install_command = self.environment.get_build_command() + ['install', '--no-rebuild'] self.add_custom_build(root, 'run_install', '"%s"' % ('" "'.join(install_command))) ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets') self.add_regen_dependency(root) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) def add_custom_build(self, node, rulename, command, deps=None, outputs=None, msg=None): igroup = ET.SubElement(node, 'ItemGroup') rulefile = os.path.join(self.environment.get_scratch_dir(), rulename + '.rule') if not os.path.exists(rulefile): with open(rulefile, 'w', encoding='utf-8') as f: f.write("# Meson regen file.") custombuild = ET.SubElement(igroup, 'CustomBuild', Include=rulefile) if msg: message = ET.SubElement(custombuild, 'Message') message.text = msg cmd_templ = '''setlocal %s if %%errorlevel%% neq 0 goto :cmEnd :cmEnd endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone :cmErrorLevel exit /b %%1 :cmDone if %%errorlevel%% neq 0 goto :VCEnd''' ET.SubElement(custombuild, 'Command').text = cmd_templ % command if not outputs: # Use a nonexistent file to always consider the target out-of-date. outputs = [self.nonexistent_file(os.path.join(self.environment.get_scratch_dir(), 'outofdate.file'))] ET.SubElement(custombuild, 'Outputs').text = ';'.join(outputs) if deps: ET.SubElement(custombuild, 'AdditionalInputs').text = ';'.join(deps) @staticmethod def nonexistent_file(prefix): i = 0 file = prefix while os.path.exists(file): file = '%s%d' % (prefix, i) return file def generate_debug_information(self, link): # valid values for vs2015 is 'false', 'true', 'DebugFastLink' ET.SubElement(link, 'GenerateDebugInformation').text = 'true' def add_regen_dependency(self, root): regen_vcxproj = os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj') self.add_project_reference(root, regen_vcxproj, self.environment.coredata.regen_guid) meson-0.53.2/mesonbuild/backend/vs2015backend.py0000644000175000017500000000276513531533273022705 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from .vs2010backend import Vs2010Backend from ..mesonlib import MesonException class Vs2015Backend(Vs2010Backend): def __init__(self, build): super().__init__(build) self.name = 'vs2015' self.vs_version = '2015' if self.environment is not None: # TODO: we assume host == build comps = self.environment.coredata.compilers.host if comps and all(c.id == 'intel-cl' for c in comps.values()): c = list(comps.values())[0] if c.version.startswith('19'): self.platform_toolset = 'Intel C++ Compiler 19.0' else: # We don't have support for versions older than 2019 right now. raise MesonException('There is currently no support for ICL before 19, patches welcome.') if self.platform_toolset is None: self.platform_toolset = 'v140' meson-0.53.2/mesonbuild/backend/vs2017backend.py0000644000175000017500000000417313531533273022702 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import xml.etree.ElementTree as ET from .vs2010backend import Vs2010Backend from ..mesonlib import MesonException class Vs2017Backend(Vs2010Backend): def __init__(self, build): super().__init__(build) self.name = 'vs2017' self.vs_version = '2017' # We assume that host == build if self.environment is not None: comps = self.environment.coredata.compilers.host if comps: if comps and all(c.id == 'clang-cl' for c in comps.values()): self.platform_toolset = 'llvm' elif comps and all(c.id == 'intel-cl' for c in comps.values()): c = list(comps.values())[0] if c.version.startswith('19'): self.platform_toolset = 'Intel C++ Compiler 19.0' else: # We don't have support for versions older than 2019 right now. raise MesonException('There is currently no support for ICL before 19, patches welcome.') if self.platform_toolset is None: self.platform_toolset = 'v141' # WindowsSDKVersion should be set by command prompt. sdk_version = os.environ.get('WindowsSDKVersion', None) if sdk_version: self.windows_target_platform_version = sdk_version.rstrip('\\') def generate_debug_information(self, link): # valid values for vs2017 is 'false', 'true', 'DebugFastLink', 'DebugFull' ET.SubElement(link, 'GenerateDebugInformation').text = 'DebugFull' meson-0.53.2/mesonbuild/backend/vs2019backend.py0000644000175000017500000000356413531533273022707 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import xml.etree.ElementTree as ET from .vs2010backend import Vs2010Backend class Vs2019Backend(Vs2010Backend): def __init__(self, build): super().__init__(build) self.name = 'vs2019' if self.environment is not None: comps = self.environment.coredata.compilers.host if comps and all(c.id == 'clang-cl' for c in comps.values()): self.platform_toolset = 'llvm' elif comps and all(c.id == 'intel-cl' for c in comps.values()): c = list(comps.values())[0] if c.version.startswith('19'): self.platform_toolset = 'Intel C++ Compiler 19.0' # We don't have support for versions older than 2019 right now. if not self.platform_toolset: self.platform_toolset = 'v142' self.vs_version = '2019' # WindowsSDKVersion should be set by command prompt. sdk_version = os.environ.get('WindowsSDKVersion', None) if sdk_version: self.windows_target_platform_version = sdk_version.rstrip('\\') def generate_debug_information(self, link): # valid values for vs2019 is 'false', 'true', 'DebugFastLink', 'DebugFull' ET.SubElement(link, 'GenerateDebugInformation').text = 'DebugFull' meson-0.53.2/mesonbuild/backend/xcodebackend.py0000644000175000017500000012723213571777336023062 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from . import backends from .. import build from .. import dependencies from .. import mesonlib from .. import mlog import uuid, os, operator from ..mesonlib import MesonException class XCodeBackend(backends.Backend): def __init__(self, build): super().__init__(build) self.name = 'xcode' self.project_uid = self.environment.coredata.lang_guids['default'].replace('-', '')[:24] self.project_conflist = self.gen_id() self.indent = '\t' # Recent versions of Xcode uses tabs self.indent_level = 0 self.xcodetypemap = {'c': 'sourcecode.c.c', 'a': 'archive.ar', 'cc': 'sourcecode.cpp.cpp', 'cxx': 'sourcecode.cpp.cpp', 'cpp': 'sourcecode.cpp.cpp', 'c++': 'sourcecode.cpp.cpp', 'm': 'sourcecode.c.objc', 'mm': 'sourcecode.cpp.objcpp', 'h': 'sourcecode.c.h', 'hpp': 'sourcecode.cpp.h', 'hxx': 'sourcecode.cpp.h', 'hh': 'sourcecode.cpp.hh', 'inc': 'sourcecode.c.h', 'dylib': 'compiled.mach-o.dylib', 'o': 'compiled.mach-o.objfile', 's': 'sourcecode.asm', 'asm': 'sourcecode.asm', } self.maingroup_id = self.gen_id() self.all_id = self.gen_id() self.all_buildconf_id = self.gen_id() self.buildtypes = ['debug'] self.test_id = self.gen_id() self.test_command_id = self.gen_id() self.test_buildconf_id = self.gen_id() def gen_id(self): return str(uuid.uuid4()).upper().replace('-', '')[:24] def get_target_dir(self, target): dirname = os.path.join(target.get_subdir(), self.environment.coredata.get_builtin_option('buildtype')) os.makedirs(os.path.join(self.environment.get_build_dir(), dirname), exist_ok=True) return dirname def target_to_build_root(self, target): if self.get_target_dir(target) == '': return '' directories = os.path.normpath(self.get_target_dir(target)).split(os.sep) return os.sep.join(['..'] * len(directories)) def write_line(self, text): self.ofile.write(self.indent * self.indent_level + text) if not text.endswith('\n'): self.ofile.write('\n') def generate(self, interp): self.interpreter = interp test_data = self.serialize_tests()[0] self.generate_filemap() self.generate_buildmap() self.generate_buildstylemap() self.generate_build_phase_map() self.generate_build_configuration_map() self.generate_build_configurationlist_map() self.generate_project_configurations_map() self.generate_buildall_configurations_map() self.generate_test_configurations_map() self.generate_native_target_map() self.generate_native_frameworks_map() self.generate_source_phase_map() self.generate_target_dependency_map() self.generate_pbxdep_map() self.generate_containerproxy_map() self.proj_dir = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.xcodeproj') os.makedirs(self.proj_dir, exist_ok=True) self.proj_file = os.path.join(self.proj_dir, 'project.pbxproj') with open(self.proj_file, 'w') as self.ofile: self.generate_prefix() self.generate_pbx_aggregate_target() self.generate_pbx_build_file() self.generate_pbx_build_style() self.generate_pbx_container_item_proxy() self.generate_pbx_file_reference() self.generate_pbx_frameworks_buildphase() self.generate_pbx_group() self.generate_pbx_native_target() self.generate_pbx_project() self.generate_pbx_shell_build_phase(test_data) self.generate_pbx_sources_build_phase() self.generate_pbx_target_dependency() self.generate_xc_build_configuration() self.generate_xc_configurationList() self.generate_suffix() def get_xcodetype(self, fname): xcodetype = self.xcodetypemap.get(fname.split('.')[-1].lower()) if not xcodetype: xcodetype = 'sourcecode.unknown' mlog.warning('Unknown file type "%s" fallbacking to "%s". Xcode project might be malformed.' % (fname, xcodetype)) return xcodetype def generate_filemap(self): self.filemap = {} # Key is source file relative to src root. self.target_filemap = {} for name, t in self.build.targets.items(): for s in t.sources: if isinstance(s, mesonlib.File): s = os.path.join(s.subdir, s.fname) self.filemap[s] = self.gen_id() for o in t.objects: if isinstance(o, str): o = os.path.join(t.subdir, o) self.filemap[o] = self.gen_id() self.target_filemap[name] = self.gen_id() def generate_buildmap(self): self.buildmap = {} for t in self.build.targets.values(): for s in t.sources: s = os.path.join(s.subdir, s.fname) self.buildmap[s] = self.gen_id() for o in t.objects: o = os.path.join(t.subdir, o) if isinstance(o, str): self.buildmap[o] = self.gen_id() def generate_buildstylemap(self): self.buildstylemap = {'debug': self.gen_id()} def generate_build_phase_map(self): for tname, t in self.build.targets.items(): # generate id for our own target-name t.buildphasemap = {} t.buildphasemap[tname] = self.gen_id() # each target can have it's own Frameworks/Sources/..., generate id's for those t.buildphasemap['Frameworks'] = self.gen_id() t.buildphasemap['Resources'] = self.gen_id() t.buildphasemap['Sources'] = self.gen_id() def generate_build_configuration_map(self): self.buildconfmap = {} for t in self.build.targets: bconfs = {'debug': self.gen_id()} self.buildconfmap[t] = bconfs def generate_project_configurations_map(self): self.project_configurations = {'debug': self.gen_id()} def generate_buildall_configurations_map(self): self.buildall_configurations = {'debug': self.gen_id()} def generate_test_configurations_map(self): self.test_configurations = {'debug': self.gen_id()} def generate_build_configurationlist_map(self): self.buildconflistmap = {} for t in self.build.targets: self.buildconflistmap[t] = self.gen_id() def generate_native_target_map(self): self.native_targets = {} for t in self.build.targets: self.native_targets[t] = self.gen_id() def generate_native_frameworks_map(self): self.native_frameworks = {} self.native_frameworks_fileref = {} for t in self.build.targets.values(): for dep in t.get_external_deps(): if isinstance(dep, dependencies.AppleFrameworks): for f in dep.frameworks: self.native_frameworks[f] = self.gen_id() self.native_frameworks_fileref[f] = self.gen_id() def generate_target_dependency_map(self): self.target_dependency_map = {} for tname, t in self.build.targets.items(): for target in t.link_targets: self.target_dependency_map[(tname, target.get_basename())] = self.gen_id() def generate_pbxdep_map(self): self.pbx_dep_map = {} for t in self.build.targets: self.pbx_dep_map[t] = self.gen_id() def generate_containerproxy_map(self): self.containerproxy_map = {} for t in self.build.targets: self.containerproxy_map[t] = self.gen_id() def generate_source_phase_map(self): self.source_phase = {} for t in self.build.targets: self.source_phase[t] = self.gen_id() def generate_pbx_aggregate_target(self): target_dependencies = list(map(lambda t: self.pbx_dep_map[t], self.build.targets)) aggregated_targets = [] aggregated_targets.append((self.all_id, 'ALL_BUILD', self.all_buildconf_id, [], target_dependencies)) aggregated_targets.append((self.test_id, 'RUN_TESTS', self.test_buildconf_id, [self.test_command_id], [])) # Sort objects by ID before writing sorted_aggregated_targets = sorted(aggregated_targets, key=operator.itemgetter(0)) self.ofile.write('\n/* Begin PBXAggregateTarget section */\n') for t in sorted_aggregated_targets: name = t[1] buildconf_id = t[2] build_phases = t[3] dependencies = t[4] self.write_line('%s /* %s */ = {' % (t[0], name)) self.indent_level += 1 self.write_line('isa = PBXAggregateTarget;') self.write_line('buildConfigurationList = %s /* Build configuration list for PBXAggregateTarget "%s" */;' % (buildconf_id, name)) self.write_line('buildPhases = (') self.indent_level += 1 for bp in build_phases: self.write_line('%s /* ShellScript */,' % bp) self.indent_level -= 1 self.write_line(');') self.write_line('dependencies = (') self.indent_level += 1 for td in dependencies: self.write_line('%s /* PBXTargetDependency */,' % td) self.indent_level -= 1 self.write_line(');') self.write_line('name = %s;' % name) self.write_line('productName = %s;' % name) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXAggregateTarget section */\n') def generate_pbx_build_file(self): self.ofile.write('\n/* Begin PBXBuildFile section */\n') templ = '%s /* %s */ = { isa = PBXBuildFile; fileRef = %s /* %s */; settings = { COMPILER_FLAGS = "%s"; }; };\n' otempl = '%s /* %s */ = { isa = PBXBuildFile; fileRef = %s /* %s */;};\n' for t in self.build.targets.values(): for dep in t.get_external_deps(): if isinstance(dep, dependencies.AppleFrameworks): for f in dep.frameworks: self.write_line('%s /* %s.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = %s /* %s.framework */; };\n' % (self.native_frameworks[f], f, self.native_frameworks_fileref[f], f)) for s in t.sources: if isinstance(s, mesonlib.File): s = s.fname if isinstance(s, str): s = os.path.join(t.subdir, s) idval = self.buildmap[s] fullpath = os.path.join(self.environment.get_source_dir(), s) fileref = self.filemap[s] fullpath2 = fullpath compiler_args = '' self.write_line(templ % (idval, fullpath, fileref, fullpath2, compiler_args)) for o in t.objects: o = os.path.join(t.subdir, o) idval = self.buildmap[o] fileref = self.filemap[o] fullpath = os.path.join(self.environment.get_source_dir(), o) fullpath2 = fullpath self.write_line(otempl % (idval, fullpath, fileref, fullpath2)) self.ofile.write('/* End PBXBuildFile section */\n') def generate_pbx_build_style(self): # FIXME: Xcode 9 and later does not uses PBXBuildStyle and it gets removed. Maybe we can remove this part. self.ofile.write('\n/* Begin PBXBuildStyle section */\n') for name, idval in self.buildstylemap.items(): self.write_line('%s /* %s */ = {\n' % (idval, name)) self.indent_level += 1 self.write_line('isa = PBXBuildStyle;\n') self.write_line('buildSettings = {\n') self.indent_level += 1 self.write_line('COPY_PHASE_STRIP = NO;\n') self.indent_level -= 1 self.write_line('};\n') self.write_line('name = "%s";\n' % name) self.indent_level -= 1 self.write_line('};\n') self.ofile.write('/* End PBXBuildStyle section */\n') def generate_pbx_container_item_proxy(self): self.ofile.write('\n/* Begin PBXContainerItemProxy section */\n') for t in self.build.targets: self.write_line('%s /* PBXContainerItemProxy */ = {' % self.containerproxy_map[t]) self.indent_level += 1 self.write_line('isa = PBXContainerItemProxy;') self.write_line('containerPortal = %s /* Project object */;' % self.project_uid) self.write_line('proxyType = 1;') self.write_line('remoteGlobalIDString = %s;' % self.native_targets[t]) self.write_line('remoteInfo = "%s";' % t) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXContainerItemProxy section */\n') def generate_pbx_file_reference(self): self.ofile.write('\n/* Begin PBXFileReference section */\n') for t in self.build.targets.values(): for dep in t.get_external_deps(): if isinstance(dep, dependencies.AppleFrameworks): for f in dep.frameworks: self.write_line('%s /* %s.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = %s.framework; path = System/Library/Frameworks/%s.framework; sourceTree = SDKROOT; };\n' % (self.native_frameworks_fileref[f], f, f, f)) src_templ = '%s /* %s */ = { isa = PBXFileReference; explicitFileType = "%s"; fileEncoding = 4; name = "%s"; path = "%s"; sourceTree = SOURCE_ROOT; };\n' for fname, idval in self.filemap.items(): fullpath = os.path.join(self.environment.get_source_dir(), fname) xcodetype = self.get_xcodetype(fname) name = os.path.basename(fname) path = fname self.write_line(src_templ % (idval, fullpath, xcodetype, name, path)) target_templ = '%s /* %s */ = { isa = PBXFileReference; explicitFileType = "%s"; path = %s; refType = %d; sourceTree = BUILT_PRODUCTS_DIR; };\n' for tname, idval in self.target_filemap.items(): t = self.build.targets[tname] fname = t.get_filename() reftype = 0 if isinstance(t, build.Executable): typestr = 'compiled.mach-o.executable' path = fname elif isinstance(t, build.SharedLibrary): typestr = self.get_xcodetype('dummy.dylib') path = fname else: typestr = self.get_xcodetype(fname) path = '"%s"' % t.get_filename() self.write_line(target_templ % (idval, tname, typestr, path, reftype)) self.ofile.write('/* End PBXFileReference section */\n') def generate_pbx_frameworks_buildphase(self): for t in self.build.targets.values(): self.ofile.write('\n/* Begin PBXFrameworksBuildPhase section */\n') self.write_line('%s /* %s */ = {\n' % (t.buildphasemap['Frameworks'], 'Frameworks')) self.indent_level += 1 self.write_line('isa = PBXFrameworksBuildPhase;\n') self.write_line('buildActionMask = %s;\n' % (2147483647)) self.write_line('files = (\n') self.indent_level += 1 for dep in t.get_external_deps(): if isinstance(dep, dependencies.AppleFrameworks): for f in dep.frameworks: self.write_line('%s /* %s.framework in Frameworks */,\n' % (self.native_frameworks[f], f)) self.indent_level -= 1 self.write_line(');\n') self.write_line('runOnlyForDeploymentPostprocessing = 0;\n') self.indent_level -= 1 self.write_line('};\n') self.ofile.write('/* End PBXFrameworksBuildPhase section */\n') def generate_pbx_group(self): groupmap = {} target_src_map = {} for t in self.build.targets: groupmap[t] = self.gen_id() target_src_map[t] = self.gen_id() self.ofile.write('\n/* Begin PBXGroup section */\n') sources_id = self.gen_id() resources_id = self.gen_id() products_id = self.gen_id() frameworks_id = self.gen_id() self.write_line('%s = {' % self.maingroup_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 self.write_line('%s /* Sources */,' % sources_id) self.write_line('%s /* Resources */,' % resources_id) self.write_line('%s /* Products */,' % products_id) self.write_line('%s /* Frameworks */,' % frameworks_id) self.indent_level -= 1 self.write_line(');') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') # Sources self.write_line('%s /* Sources */ = {' % sources_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 for t in self.build.targets: self.write_line('%s /* %s */,' % (groupmap[t], t)) self.indent_level -= 1 self.write_line(');') self.write_line('name = Sources;') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') self.write_line('%s /* Resources */ = {' % resources_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.write_line(');') self.write_line('name = Resources;') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') self.write_line('%s /* Frameworks */ = {' % frameworks_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') # write frameworks self.indent_level += 1 for t in self.build.targets.values(): for dep in t.get_external_deps(): if isinstance(dep, dependencies.AppleFrameworks): for f in dep.frameworks: self.write_line('%s /* %s.framework */,\n' % (self.native_frameworks_fileref[f], f)) self.indent_level -= 1 self.write_line(');') self.write_line('name = Frameworks;') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') # Targets for t in self.build.targets: self.write_line('%s /* %s */ = {' % (groupmap[t], t)) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 self.write_line('%s /* Source files */,' % target_src_map[t]) self.indent_level -= 1 self.write_line(');') self.write_line('name = "%s";' % t) self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') self.write_line('%s /* Source files */ = {' % target_src_map[t]) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 for s in self.build.targets[t].sources: s = os.path.join(s.subdir, s.fname) if isinstance(s, str): self.write_line('%s /* %s */,' % (self.filemap[s], s)) for o in self.build.targets[t].objects: o = os.path.join(self.build.targets[t].subdir, o) self.write_line('%s /* %s */,' % (self.filemap[o], o)) self.indent_level -= 1 self.write_line(');') self.write_line('name = "Source files";') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') # And finally products self.write_line('%s /* Products */ = {' % products_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 for t in self.build.targets: self.write_line('%s /* %s */,' % (self.target_filemap[t], t)) self.indent_level -= 1 self.write_line(');') self.write_line('name = Products;') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXGroup section */\n') def generate_pbx_native_target(self): self.ofile.write('\n/* Begin PBXNativeTarget section */\n') for tname, idval in self.native_targets.items(): t = self.build.targets[tname] self.write_line('%s /* %s */ = {' % (idval, tname)) self.indent_level += 1 self.write_line('isa = PBXNativeTarget;') self.write_line('buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;' % (self.buildconflistmap[tname], tname)) self.write_line('buildPhases = (') self.indent_level += 1 for bpname, bpval in t.buildphasemap.items(): self.write_line('%s /* %s yyy */,' % (bpval, bpname)) self.indent_level -= 1 self.write_line(');') self.write_line('buildRules = (') self.write_line(');') self.write_line('dependencies = (') self.indent_level += 1 for lt in self.build.targets[tname].link_targets: # NOT DOCUMENTED, may need to make different links # to same target have different targetdependency item. idval = self.pbx_dep_map[lt.get_id()] self.write_line('%s /* PBXTargetDependency */,' % idval) self.indent_level -= 1 self.write_line(");") self.write_line('name = "%s";' % tname) self.write_line('productName = "%s";' % tname) self.write_line('productReference = %s /* %s */;' % (self.target_filemap[tname], tname)) if isinstance(t, build.Executable): typestr = 'com.apple.product-type.tool' elif isinstance(t, build.StaticLibrary): typestr = 'com.apple.product-type.library.static' elif isinstance(t, build.SharedLibrary): typestr = 'com.apple.product-type.library.dynamic' else: raise MesonException('Unknown target type for %s' % tname) self.write_line('productType = "%s";' % typestr) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXNativeTarget section */\n') def generate_pbx_project(self): self.ofile.write('\n/* Begin PBXProject section */\n') self.write_line('%s /* Project object */ = {' % self.project_uid) self.indent_level += 1 self.write_line('isa = PBXProject;') self.write_line('attributes = {') self.indent_level += 1 self.write_line('BuildIndependentTargetsInParallel = YES;') self.indent_level -= 1 self.write_line('};') conftempl = 'buildConfigurationList = %s /* Build configuration list for PBXProject "%s" */;' self.write_line(conftempl % (self.project_conflist, self.build.project_name)) self.write_line('buildSettings = {') self.write_line('};') self.write_line('buildStyles = (') self.indent_level += 1 for name, idval in self.buildstylemap.items(): self.write_line('%s /* %s */,' % (idval, name)) self.indent_level -= 1 self.write_line(');') self.write_line('compatibilityVersion = "Xcode 3.2";') self.write_line('hasScannedForEncodings = 0;') self.write_line('mainGroup = %s;' % self.maingroup_id) self.write_line('projectDirPath = "%s";' % self.build_to_src) self.write_line('projectRoot = "";') self.write_line('targets = (') self.indent_level += 1 self.write_line('%s /* ALL_BUILD */,' % self.all_id) self.write_line('%s /* RUN_TESTS */,' % self.test_id) for t in self.build.targets: self.write_line('%s /* %s */,' % (self.native_targets[t], t)) self.indent_level -= 1 self.write_line(');') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXProject section */\n') def generate_pbx_shell_build_phase(self, test_data): self.ofile.write('\n/* Begin PBXShellScriptBuildPhase section */\n') self.write_line('%s /* ShellScript */ = {' % self.test_command_id) self.indent_level += 1 self.write_line('isa = PBXShellScriptBuildPhase;') self.write_line('buildActionMask = 2147483647;') self.write_line('files = (') self.write_line(');') self.write_line('inputPaths = (') self.write_line(');') self.write_line('outputPaths = (') self.write_line(');') self.write_line('runOnlyForDeploymentPostprocessing = 0;') self.write_line('shellPath = /bin/sh;') cmd = mesonlib.meson_command + ['test', test_data, '-C', self.environment.get_build_dir()] cmdstr = ' '.join(["'%s'" % i for i in cmd]) self.write_line('shellScript = "%s";' % cmdstr) self.write_line('showEnvVarsInLog = 0;') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXShellScriptBuildPhase section */\n') def generate_pbx_sources_build_phase(self): self.ofile.write('\n/* Begin PBXSourcesBuildPhase section */\n') for name in self.source_phase.keys(): t = self.build.targets[name] self.write_line('%s /* Sources */ = {' % (t.buildphasemap[name])) self.indent_level += 1 self.write_line('isa = PBXSourcesBuildPhase;') self.write_line('buildActionMask = 2147483647;') self.write_line('files = (') self.indent_level += 1 for s in self.build.targets[name].sources: s = os.path.join(s.subdir, s.fname) if not self.environment.is_header(s): self.write_line('%s /* %s */,' % (self.buildmap[s], os.path.join(self.environment.get_source_dir(), s))) self.indent_level -= 1 self.write_line(');') self.write_line('runOnlyForDeploymentPostprocessing = 0;') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXSourcesBuildPhase section */\n') def generate_pbx_target_dependency(self): targets = [] for t in self.build.targets: idval = self.pbx_dep_map[t] # VERIFY: is this correct? targets.append((idval, self.native_targets[t], t, self.containerproxy_map[t])) # Sort object by ID sorted_targets = sorted(targets, key=operator.itemgetter(0)) self.ofile.write('\n/* Begin PBXTargetDependency section */\n') for t in sorted_targets: self.write_line('%s /* PBXTargetDependency */ = {' % t[0]) self.indent_level += 1 self.write_line('isa = PBXTargetDependency;') self.write_line('target = %s /* %s */;' % (t[1], t[2])) self.write_line('targetProxy = %s /* PBXContainerItemProxy */;' % t[3]) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXTargetDependency section */\n') def generate_xc_build_configuration(self): self.ofile.write('\n/* Begin XCBuildConfiguration section */\n') # First the setup for the toplevel project. for buildtype in self.buildtypes: self.write_line('%s /* %s */ = {' % (self.project_configurations[buildtype], buildtype)) self.indent_level += 1 self.write_line('isa = XCBuildConfiguration;') self.write_line('buildSettings = {') self.indent_level += 1 self.write_line('ARCHS = "$(ARCHS_STANDARD_64_BIT)";') self.write_line('ONLY_ACTIVE_ARCH = YES;') self.write_line('SDKROOT = "macosx";') self.write_line('SYMROOT = "%s/build";' % self.environment.get_build_dir()) self.indent_level -= 1 self.write_line('};') self.write_line('name = "%s";' % buildtype) self.indent_level -= 1 self.write_line('};') # Then the all target. for buildtype in self.buildtypes: self.write_line('%s /* %s */ = {' % (self.buildall_configurations[buildtype], buildtype)) self.indent_level += 1 self.write_line('isa = XCBuildConfiguration;') self.write_line('buildSettings = {') self.indent_level += 1 self.write_line('COMBINE_HIDPI_IMAGES = YES;') self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = NO;') self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;') self.write_line('GCC_OPTIMIZATION_LEVEL = 0;') self.write_line('GCC_PREPROCESSOR_DEFINITIONS = "";') self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;') self.write_line('INSTALL_PATH = "";') self.write_line('OTHER_CFLAGS = " ";') self.write_line('OTHER_LDFLAGS = " ";') self.write_line('OTHER_REZFLAGS = "";') self.write_line('PRODUCT_NAME = ALL_BUILD;') self.write_line('SECTORDER_FLAGS = "";') self.write_line('SYMROOT = "%s";' % self.environment.get_build_dir()) self.write_line('USE_HEADERMAP = NO;') self.write_build_setting_line('WARNING_CFLAGS', ['-Wmost', '-Wno-four-char-constants', '-Wno-unknown-pragmas']) self.indent_level -= 1 self.write_line('};') self.write_line('name = "%s";' % buildtype) self.indent_level -= 1 self.write_line('};') # Then the test target. for buildtype in self.buildtypes: self.write_line('%s /* %s */ = {' % (self.test_configurations[buildtype], buildtype)) self.indent_level += 1 self.write_line('isa = XCBuildConfiguration;') self.write_line('buildSettings = {') self.indent_level += 1 self.write_line('COMBINE_HIDPI_IMAGES = YES;') self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = NO;') self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;') self.write_line('GCC_OPTIMIZATION_LEVEL = 0;') self.write_line('GCC_PREPROCESSOR_DEFINITIONS = "";') self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;') self.write_line('INSTALL_PATH = "";') self.write_line('OTHER_CFLAGS = " ";') self.write_line('OTHER_LDFLAGS = " ";') self.write_line('OTHER_REZFLAGS = "";') self.write_line('PRODUCT_NAME = RUN_TESTS;') self.write_line('SECTORDER_FLAGS = "";') self.write_line('SYMROOT = "%s";' % self.environment.get_build_dir()) self.write_line('USE_HEADERMAP = NO;') self.write_build_setting_line('WARNING_CFLAGS', ['-Wmost', '-Wno-four-char-constants', '-Wno-unknown-pragmas']) self.indent_level -= 1 self.write_line('};') self.write_line('name = "%s";' % buildtype) self.indent_level -= 1 self.write_line('};') # Now finally targets. langnamemap = {'c': 'C', 'cpp': 'CPLUSPLUS', 'objc': 'OBJC', 'objcpp': 'OBJCPLUSPLUS'} for target_name, target in self.build.targets.items(): for buildtype in self.buildtypes: dep_libs = [] links_dylib = False headerdirs = [] for d in target.include_dirs: for sd in d.incdirs: cd = os.path.join(d.curdir, sd) headerdirs.append(os.path.join(self.environment.get_source_dir(), cd)) headerdirs.append(os.path.join(self.environment.get_build_dir(), cd)) for l in target.link_targets: abs_path = os.path.join(self.environment.get_build_dir(), l.subdir, buildtype, l.get_filename()) dep_libs.append("'%s'" % abs_path) if isinstance(l, build.SharedLibrary): links_dylib = True if links_dylib: dep_libs = ['-Wl,-search_paths_first', '-Wl,-headerpad_max_install_names'] + dep_libs dylib_version = None if isinstance(target, build.SharedLibrary): ldargs = ['-dynamiclib', '-Wl,-headerpad_max_install_names'] + dep_libs install_path = os.path.join(self.environment.get_build_dir(), target.subdir, buildtype) dylib_version = target.soversion else: ldargs = dep_libs install_path = '' if dylib_version is not None: product_name = target.get_basename() + '.' + dylib_version else: product_name = target.get_basename() ldargs += target.link_args for dep in target.get_external_deps(): ldargs += dep.get_link_args() ldstr = ' '.join(ldargs) valid = self.buildconfmap[target_name][buildtype] langargs = {} for lang in self.environment.coredata.compilers[target.for_machine]: if lang not in langnamemap: continue # Add compile args added using add_project_arguments() pargs = self.build.projects_args[target.for_machine].get(target.subproject, {}).get(lang, []) # Add compile args added using add_global_arguments() # These override per-project arguments gargs = self.build.global_args[target.for_machine].get(lang, []) targs = target.get_extra_args(lang) args = pargs + gargs + targs if args: langargs[langnamemap[lang]] = args symroot = os.path.join(self.environment.get_build_dir(), target.subdir) self.write_line('%s /* %s */ = {' % (valid, buildtype)) self.indent_level += 1 self.write_line('isa = XCBuildConfiguration;') self.write_line('buildSettings = {') self.indent_level += 1 self.write_line('COMBINE_HIDPI_IMAGES = YES;') if dylib_version is not None: self.write_line('DYLIB_CURRENT_VERSION = "%s";' % dylib_version) self.write_line('EXECUTABLE_PREFIX = "%s";' % target.prefix) if target.suffix == '': suffix = '' else: suffix = '.' + target.suffix self.write_line('EXECUTABLE_SUFFIX = "%s";' % suffix) self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = YES;') self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;') self.write_line('GCC_OPTIMIZATION_LEVEL = 0;') if target.has_pch: # Xcode uses GCC_PREFIX_HEADER which only allows one file per target/executable. Precompiling various header files and # applying a particular pch to each source file will require custom scripts (as a build phase) and build flags per each # file. Since Xcode itself already discourages precompiled headers in favor of modules we don't try much harder here. pchs = target.get_pch('c') + target.get_pch('cpp') + target.get_pch('objc') + target.get_pch('objcpp') # Make sure to use headers (other backends require implementation files like *.c *.cpp, etc; these should not be used here) pchs = [pch for pch in pchs if pch.endswith('.h') or pch.endswith('.hh') or pch.endswith('hpp')] if pchs: if len(pchs) > 1: mlog.warning('Unsupported Xcode configuration: More than 1 precompiled header found "%s". Target "%s" might not compile correctly.' % (str(pchs), target.name)) relative_pch_path = os.path.join(target.get_subdir(), pchs[0]) # Path relative to target so it can be used with "$(PROJECT_DIR)" self.write_line('GCC_PRECOMPILE_PREFIX_HEADER = YES;') self.write_line('GCC_PREFIX_HEADER = "$(PROJECT_DIR)/%s";' % relative_pch_path) self.write_line('GCC_PREPROCESSOR_DEFINITIONS = "";') self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;') if headerdirs: quotedh = ','.join(['"\\"%s\\""' % i for i in headerdirs]) self.write_line('HEADER_SEARCH_PATHS=(%s);' % quotedh) self.write_line('INSTALL_PATH = "%s";' % install_path) self.write_line('LIBRARY_SEARCH_PATHS = "";') if isinstance(target, build.SharedLibrary): self.write_line('LIBRARY_STYLE = DYNAMIC;') for langname, args in langargs.items(): self.write_build_setting_line('OTHER_%sFLAGS' % langname, args) self.write_line('OTHER_LDFLAGS = "%s";' % ldstr) self.write_line('OTHER_REZFLAGS = "";') self.write_line('PRODUCT_NAME = %s;' % product_name) self.write_line('SECTORDER_FLAGS = "";') self.write_line('SYMROOT = "%s";' % symroot) self.write_build_setting_line('SYSTEM_HEADER_SEARCH_PATHS', [self.environment.get_build_dir()]) self.write_line('USE_HEADERMAP = NO;') self.write_build_setting_line('WARNING_CFLAGS', ['-Wmost', '-Wno-four-char-constants', '-Wno-unknown-pragmas']) self.indent_level -= 1 self.write_line('};') self.write_line('name = %s;' % buildtype) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End XCBuildConfiguration section */\n') def generate_xc_configurationList(self): # FIXME: sort items self.ofile.write('\n/* Begin XCConfigurationList section */\n') self.write_line('%s /* Build configuration list for PBXProject "%s" */ = {' % (self.project_conflist, self.build.project_name)) self.indent_level += 1 self.write_line('isa = XCConfigurationList;') self.write_line('buildConfigurations = (') self.indent_level += 1 for buildtype in self.buildtypes: self.write_line('%s /* %s */,' % (self.project_configurations[buildtype], buildtype)) self.indent_level -= 1 self.write_line(');') self.write_line('defaultConfigurationIsVisible = 0;') self.write_line('defaultConfigurationName = debug;') self.indent_level -= 1 self.write_line('};') # Now the all target self.write_line('%s /* Build configuration list for PBXAggregateTarget "ALL_BUILD" */ = {' % self.all_buildconf_id) self.indent_level += 1 self.write_line('isa = XCConfigurationList;') self.write_line('buildConfigurations = (') self.indent_level += 1 for buildtype in self.buildtypes: self.write_line('%s /* %s */,' % (self.buildall_configurations[buildtype], buildtype)) self.indent_level -= 1 self.write_line(');') self.write_line('defaultConfigurationIsVisible = 0;') self.write_line('defaultConfigurationName = debug;') self.indent_level -= 1 self.write_line('};') # Test target self.write_line('%s /* Build configuration list for PBXAggregateTarget "ALL_BUILD" */ = {' % self.test_buildconf_id) self.indent_level += 1 self.write_line('isa = XCConfigurationList;') self.write_line('buildConfigurations = (') self.indent_level += 1 for buildtype in self.buildtypes: self.write_line('%s /* %s */,' % (self.test_configurations[buildtype], buildtype)) self.indent_level -= 1 self.write_line(');') self.write_line('defaultConfigurationIsVisible = 0;') self.write_line('defaultConfigurationName = debug;') self.indent_level -= 1 self.write_line('};') for target_name in self.build.targets: listid = self.buildconflistmap[target_name] self.write_line('%s /* Build configuration list for PBXNativeTarget "%s" */ = {' % (listid, target_name)) self.indent_level += 1 self.write_line('isa = XCConfigurationList;') self.write_line('buildConfigurations = (') self.indent_level += 1 typestr = 'debug' idval = self.buildconfmap[target_name][typestr] self.write_line('%s /* %s */,' % (idval, typestr)) self.indent_level -= 1 self.write_line(');') self.write_line('defaultConfigurationIsVisible = 0;') self.write_line('defaultConfigurationName = %s;' % typestr) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End XCConfigurationList section */\n') def write_build_setting_line(self, flag_name, flag_values, explicit=False): if flag_values: if len(flag_values) == 1: value = flag_values[0] if (' ' in value): # If path contains spaces surround it with double colon self.write_line('%s = "\\"%s\\"";' % (flag_name, value)) else: self.write_line('%s = "%s";' % (flag_name, value)) else: self.write_line('%s = (' % flag_name) self.indent_level += 1 for value in flag_values: if (' ' in value): # If path contains spaces surround it with double colon self.write_line('"\\"%s\\"",' % value) else: self.write_line('"%s",' % value) self.indent_level -= 1 self.write_line(');') else: if explicit: self.write_line('%s = "";' % flag_name) def generate_prefix(self): self.ofile.write('// !$*UTF8*$!\n{\n') self.indent_level += 1 self.write_line('archiveVersion = 1;\n') self.write_line('classes = {\n') self.write_line('};\n') self.write_line('objectVersion = 46;\n') self.write_line('objects = {\n') self.indent_level += 1 def generate_suffix(self): self.indent_level -= 1 self.write_line('};\n') self.write_line('rootObject = ' + self.project_uid + ' /* Project object */;') self.indent_level -= 1 self.write_line('}\n') meson-0.53.2/mesonbuild/build.py0000644000175000017500000032433513612411367020144 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import copy, os, re from collections import OrderedDict import itertools, pathlib import hashlib import pickle from functools import lru_cache import typing as T from . import environment from . import dependencies from . import mlog from .mesonlib import ( File, MesonException, MachineChoice, PerMachine, OrderedSet, listify, extract_as_list, typeslistify, stringlistify, classify_unity_sources, get_filenames_templates_dict, substitute_values, has_path_sep, ) from .compilers import Compiler, is_object, clink_langs, sort_clink, lang_suffixes from .linkers import StaticLinker from .interpreterbase import FeatureNew pch_kwargs = set(['c_pch', 'cpp_pch']) lang_arg_kwargs = set([ 'c_args', 'cpp_args', 'cuda_args', 'd_args', 'd_import_dirs', 'd_unittest', 'd_module_versions', 'd_debug', 'fortran_args', 'java_args', 'objc_args', 'objcpp_args', 'rust_args', 'vala_args', 'cs_args', ]) vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi']) rust_kwargs = set(['rust_crate_type']) cs_kwargs = set(['resources', 'cs_args']) buildtarget_kwargs = set([ 'build_by_default', 'build_rpath', 'dependencies', 'extra_files', 'gui_app', 'link_with', 'link_whole', 'link_args', 'link_depends', 'implicit_include_directories', 'include_directories', 'install', 'install_rpath', 'install_dir', 'install_mode', 'name_prefix', 'name_suffix', 'native', 'objects', 'override_options', 'sources', 'gnu_symbol_visibility', ]) known_build_target_kwargs = ( buildtarget_kwargs | lang_arg_kwargs | pch_kwargs | vala_kwargs | rust_kwargs | cs_kwargs) known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'link_language', 'pie'} known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions'} known_shmod_kwargs = known_build_target_kwargs | {'vs_module_defs'} known_stlib_kwargs = known_build_target_kwargs | {'pic'} known_jar_kwargs = known_exe_kwargs | {'main_class'} @lru_cache(maxsize=None) def get_target_macos_dylib_install_name(ld) -> str: name = ['@rpath/', ld.prefix, ld.name] if ld.soversion is not None: name.append('.' + ld.soversion) name.append('.dylib') return ''.join(name) class InvalidArguments(MesonException): pass class Build: """A class that holds the status of one build including all dependencies and so on. """ def __init__(self, environment: environment.Environment): self.project_name = 'name of master project' self.project_version = None self.environment = environment self.projects = {} self.targets = OrderedDict() self.run_target_names = set() # type: T.Set[T.Tuple[str, str]] self.global_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]] self.projects_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]] self.global_link_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]] self.projects_link_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]] self.tests = [] self.benchmarks = [] self.headers = [] self.man = [] self.data = [] self.static_linker = PerMachine(None, None) # type: PerMachine[StaticLinker] self.subprojects = {} self.subproject_dir = '' self.install_scripts = [] self.postconf_scripts = [] self.dist_scripts = [] self.install_dirs = [] self.dep_manifest_name = None self.dep_manifest = {} self.stdlibs = PerMachine({}, {}) self.test_setups = {} # type: T.Dict[str, TestSetup] self.test_setup_default_name = None self.find_overrides = {} self.searched_programs = set() # The list of all programs that have been searched for. def copy(self): other = Build(self.environment) for k, v in self.__dict__.items(): if isinstance(v, (list, dict, set, OrderedDict)): other.__dict__[k] = v.copy() else: other.__dict__[k] = v return other def merge(self, other): for k, v in other.__dict__.items(): self.__dict__[k] = v def ensure_static_linker(self, compiler): if self.static_linker[compiler.for_machine] is None and compiler.needs_static_linker(): self.static_linker[compiler.for_machine] = self.environment.detect_static_linker(compiler) def get_project(self): return self.projects[''] def get_subproject_dir(self): return self.subproject_dir def get_targets(self): return self.targets def get_tests(self): return self.tests def get_benchmarks(self): return self.benchmarks def get_headers(self): return self.headers def get_man(self): return self.man def get_data(self): return self.data def get_install_subdirs(self): return self.install_dirs def get_global_args(self, compiler, for_machine): d = self.global_args[for_machine] return d.get(compiler.get_language(), []) def get_project_args(self, compiler, project, for_machine): d = self.projects_args[for_machine] args = d.get(project) if not args: return [] return args.get(compiler.get_language(), []) def get_global_link_args(self, compiler, for_machine): d = self.global_link_args[for_machine] return d.get(compiler.get_language(), []) def get_project_link_args(self, compiler, project, for_machine): d = self.projects_link_args[for_machine] link_args = d.get(project) if not link_args: return [] return link_args.get(compiler.get_language(), []) class IncludeDirs: def __init__(self, curdir, dirs, is_system, extra_build_dirs=None): self.curdir = curdir self.incdirs = dirs self.is_system = is_system # Interpreter has validated that all given directories # actually exist. if extra_build_dirs is None: self.extra_build_dirs = [] else: self.extra_build_dirs = extra_build_dirs def __repr__(self): r = '<{} {}/{}>' return r.format(self.__class__.__name__, self.curdir, self.incdirs) def get_curdir(self): return self.curdir def get_incdirs(self): return self.incdirs def get_extra_build_dirs(self): return self.extra_build_dirs class ExtractedObjects: ''' Holds a list of sources for which the objects must be extracted ''' def __init__(self, target, srclist=None, genlist=None, objlist=None, recursive=True): self.target = target self.recursive = recursive self.srclist = srclist if srclist is not None else [] self.genlist = genlist if genlist is not None else [] self.objlist = objlist if objlist is not None else [] if self.target.is_unity: self.check_unity_compatible() def __repr__(self): r = '<{0} {1!r}: {2}>' return r.format(self.__class__.__name__, self.target.name, self.srclist) def classify_all_sources(self, sources, generated_sources): # Merge sources and generated sources sources = list(sources) for gensrc in generated_sources: for s in gensrc.get_outputs(): # We cannot know the path where this source will be generated, # but all we need here is the file extension to determine the # compiler. sources.append(s) # Filter out headers and all non-source files sources = [s for s in sources if environment.is_source(s) and not environment.is_header(s)] return classify_unity_sources(self.target.compilers.values(), sources) def check_unity_compatible(self): # Figure out if the extracted object list is compatible with a Unity # build. When we're doing a Unified build, we go through the sources, # and create a single source file from each subset of the sources that # can be compiled with a specific compiler. Then we create one object # from each unified source file. So for each compiler we can either # extra all its sources or none. cmpsrcs = self.classify_all_sources(self.target.sources, self.target.generated) extracted_cmpsrcs = self.classify_all_sources(self.srclist, self.genlist) for comp, srcs in extracted_cmpsrcs.items(): if set(srcs) != set(cmpsrcs[comp]): raise MesonException('Single object files can not be extracted ' 'in Unity builds. You can only extract all ' 'the object files for each compiler at once.') def get_outputs(self, backend): # TODO: Consider if we need to handle genlist here return [ backend.object_filename_from_source(self.target, source) for source in self.srclist ] class EnvironmentVariables: def __init__(self): self.envvars = [] # The set of all env vars we have operations for. Only used for self.has_name() self.varnames = set() def __repr__(self): repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.envvars) def add_var(self, method, name, args, kwargs): self.varnames.add(name) self.envvars.append((method, name, args, kwargs)) def has_name(self, name): return name in self.varnames def get_value(self, values, kwargs): separator = kwargs.get('separator', os.pathsep) value = '' for var in values: value += separator + var return separator, value.strip(separator) def set(self, env, name, values, kwargs): return self.get_value(values, kwargs)[1] def append(self, env, name, values, kwargs): sep, value = self.get_value(values, kwargs) if name in env: return env[name] + sep + value return value def prepend(self, env, name, values, kwargs): sep, value = self.get_value(values, kwargs) if name in env: return value + sep + env[name] return value def get_env(self, full_env: T.Dict[str, str]) -> T.Dict[str, str]: env = full_env.copy() for method, name, values, kwargs in self.envvars: env[name] = method(full_env, name, values, kwargs) return env class Target: def __init__(self, name, subdir, subproject, build_by_default, for_machine: MachineChoice): if has_path_sep(name): # Fix failing test 53 when this becomes an error. mlog.warning('''Target "%s" has a path separator in its name. This is not supported, it can cause unexpected failures and will become a hard error in the future.''' % name) self.name = name self.subdir = subdir self.subproject = subproject self.build_by_default = build_by_default self.for_machine = for_machine self.install = False self.build_always_stale = False self.option_overrides = {} 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: T.Any) -> T.Union[bool, type(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: T.Any) -> T.Union[bool, type(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: T.Any) -> T.Union[bool, type(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: T.Any) -> T.Union[bool, type(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) outdirs = self.get_custom_install_dir() if outdirs[0] is not None and outdirs[0] != default_install_dir and outdirs[0] is not True: # Either the value is set to a non-default value, or is set to # False (which means we want this specific output out of many # outputs to not be installed). custom_install_dir = True else: custom_install_dir = False outdirs[0] = default_install_dir return outdirs, custom_install_dir def get_basename(self): return self.name def get_subdir(self): return self.subdir def get_typename(self): return self.typename @staticmethod def _get_id_hash(target_id): # We don't really need cryptographic security here. # Small-digest hash function with unlikely collision is good enough. h = hashlib.sha256() h.update(target_id.encode(encoding='utf-8', errors='replace')) # This ID should be case-insensitive and should work in Visual Studio, # e.g. it should not start with leading '-'. return h.hexdigest()[:7] @staticmethod def construct_id_from_path(subdir, name, type_suffix): """Construct target ID from subdir, name and type suffix. This helper function is made public mostly for tests.""" # This ID must also be a valid file name on all OSs. # It should also avoid shell metacharacters for obvious # reasons. '@' is not used as often as '_' in source code names. # In case of collisions consider using checksums. # FIXME replace with assert when slash in names is prohibited name_part = name.replace('/', '@').replace('\\', '@') assert not has_path_sep(type_suffix) my_id = name_part + type_suffix if subdir: subdir_part = Target._get_id_hash(subdir) # preserve myid for better debuggability return subdir_part + '@@' + my_id return my_id def get_id(self): return self.construct_id_from_path( self.subdir, self.name, self.type_suffix()) 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): raise InvalidArguments('build_by_default must be a boolean value.') elif kwargs.get('install', False): # For backward compatibility, if build_by_default is not explicitly # set, use the value of 'install' if it's enabled. self.build_by_default = True self.option_overrides = self.parse_overrides(kwargs) def parse_overrides(self, kwargs) -> dict: result = {} overrides = stringlistify(kwargs.get('override_options', [])) for o in overrides: if '=' not in o: raise InvalidArguments('Overrides must be of form "key=value"') k, v = o.split('=', 1) k = k.strip() v = v.strip() result[k] = v return result def is_linkable_target(self) -> bool: return False class BuildTarget(Target): known_kwargs = known_build_target_kwargs def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs): super().__init__(name, subdir, subproject, True, for_machine) unity_opt = environment.coredata.get_builtin_option('unity') self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '') self.environment = environment self.sources = [] self.compilers = OrderedDict() # type: OrderedDict[str, Compiler] self.objects = [] self.external_deps = [] self.include_dirs = [] self.link_language = kwargs.get('link_language') self.link_targets = [] self.link_whole_targets = [] self.link_depends = [] self.name_prefix_set = False self.name_suffix_set = False self.filename = 'no_name' # The list of all files outputted by this target. Useful in cases such # as Vala which generates .vapi and .h besides the compiled output. self.outputs = [self.filename] self.need_install = False self.pch = {} self.extra_args = {} self.generated = [] self.extra_files = [] self.d_features = {} self.pic = False self.pie = False # Sources can be: # 1. Pre-existing source files in the source tree # 2. Pre-existing sources generated by configure_file in the build tree # 3. Sources files generated by another target or a Generator self.process_sourcelist(sources) # Objects can be: # 1. Pre-existing objects provided by the user with the `objects:` kwarg # 2. Compiled objects created by and extracted from another target self.process_objectlist(objects) self.process_kwargs(kwargs, environment) self.check_unknown_kwargs(kwargs) self.process_compilers() if not any([self.sources, self.generated, self.objects, self.link_whole]): raise InvalidArguments('Build target %s has no sources.' % name) self.process_compilers_late() self.validate_sources() self.validate_install(environment) self.check_module_linking() def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.filename) def validate_install(self, environment): if self.for_machine is MachineChoice.BUILD and self.need_install: if environment.is_cross_build(): raise InvalidArguments('Tried to install a target for the build machine in a cross build.') else: mlog.warning('Installing target build for the build machine. This will fail in a cross build.') def check_unknown_kwargs(self, kwargs): # Override this method in derived classes that have more # keywords. self.check_unknown_kwargs_int(kwargs, self.known_kwargs) def check_unknown_kwargs_int(self, kwargs, known_kwargs): unknowns = [] for k in kwargs: if k not in known_kwargs: unknowns.append(k) if len(unknowns) > 0: mlog.warning('Unknown keyword argument(s) in target %s: %s.' % (self.name, ', '.join(unknowns))) def process_objectlist(self, objects): assert(isinstance(objects, list)) for s in objects: if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, (str, File, ExtractedObjects)): self.objects.append(s) elif isinstance(s, (GeneratedList, CustomTarget)): msg = 'Generated files are not allowed in the \'objects\' kwarg ' + \ 'for target {!r}.\nIt is meant only for '.format(self.name) + \ 'pre-built object files that are shipped with the\nsource ' + \ 'tree. Try adding it in the list of sources.' raise InvalidArguments(msg) else: msg = 'Bad object of type {!r} in target {!r}.'.format(type(s).__name__, self.name) raise InvalidArguments(msg) def process_sourcelist(self, sources): sources = listify(sources) added_sources = {} # If the same source is defined multiple times, use it only once. for s in sources: # Holder unpacking. Ugly. if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, File): if s not in added_sources: self.sources.append(s) added_sources[s] = True elif isinstance(s, (GeneratedList, CustomTarget, CustomTargetIndex)): self.generated.append(s) else: msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name) raise InvalidArguments(msg) @staticmethod def can_compile_remove_sources(compiler, sources): removed = False for s in sources[:]: if compiler.can_compile(s): sources.remove(s) removed = True return removed def process_compilers_late(self): """Processes additional compilers after kwargs have been evaluated. This can add extra compilers that might be required by keyword arguments, such as link_with or dependencies. It will also try to guess which compiler to use if one hasn't been selected already. """ # Populate list of compilers compilers = self.environment.coredata.compilers[self.for_machine] # did user override clink_langs for this target? link_langs = [self.link_language] if self.link_language else clink_langs # If this library is linked against another library we need to consider # the languages of those libraries as well. if self.link_targets or self.link_whole_targets: extra = set() for t in itertools.chain(self.link_targets, self.link_whole_targets): if isinstance(t, CustomTarget) or isinstance(t, CustomTargetIndex): continue # We can't know anything about these. for name, compiler in t.compilers.items(): if name in link_langs: extra.add((name, compiler)) for name, compiler in sorted(extra, key=lambda p: sort_clink(p[0])): self.compilers[name] = compiler if not self.compilers: # No source files or parent targets, target consists of only object # files of unknown origin. Just add the first clink compiler # that we have and hope that it can link these objects for lang in link_langs: if lang in compilers: self.compilers[lang] = compilers[lang] break def process_compilers(self): ''' Populate self.compilers, which is the list of compilers that this target will use for compiling all its sources. We also add compilers that were used by extracted objects to simplify dynamic linker determination. ''' if not self.sources and not self.generated and not self.objects: return # Populate list of compilers compilers = self.environment.coredata.compilers[self.for_machine] # Pre-existing sources sources = list(self.sources) # All generated sources for gensrc in self.generated: for s in gensrc.get_outputs(): # Generated objects can't be compiled, so don't use them for # compiler detection. If our target only has generated objects, # we will fall back to using the first c-like compiler we find, # which is what we need. if not is_object(s): sources.append(s) for d in self.external_deps: if hasattr(d, 'held_object'): d = d.held_object for s in d.sources: if isinstance(s, (str, File)): sources.append(s) # Sources that were used to create our extracted objects for o in self.objects: if not isinstance(o, ExtractedObjects): continue for s in o.srclist: # Don't add Vala sources since that will pull in the Vala # compiler even though we will never use it since we are # dealing with compiled C code. if not s.endswith(lang_suffixes['vala']): sources.append(s) if sources: # For each source, try to add one compiler that can compile it. # It's ok if no compilers can do so, because users are expected to # be able to add arbitrary non-source files to the sources list. for s in sources: for lang, compiler in compilers.items(): if compiler.can_compile(s): if lang not in self.compilers: self.compilers[lang] = compiler break # Re-sort according to clink_langs self.compilers = OrderedDict(sorted(self.compilers.items(), key=lambda t: sort_clink(t[0]))) # If all our sources are Vala, our target also needs the C compiler but # it won't get added above. if 'vala' in self.compilers and 'c' not in self.compilers: self.compilers['c'] = compilers['c'] def validate_sources(self): if not self.sources: return for lang in ('cs', 'java'): if lang in self.compilers: check_sources = list(self.sources) compiler = self.compilers[lang] if not self.can_compile_remove_sources(compiler, check_sources): m = 'No {} sources found in target {!r}'.format(lang, self.name) raise InvalidArguments(m) if check_sources: m = '{0} targets can only contain {0} files:\n'.format(lang.capitalize()) m += '\n'.join([repr(c) for c in check_sources]) raise InvalidArguments(m) # CSharp and Java targets can't contain any other file types assert(len(self.compilers) == 1) return def process_link_depends(self, sources, environment): """Process the link_depends keyword argument. This is designed to handle strings, Files, and the output of Custom Targets. Notably it doesn't handle generator() returned objects, since adding them as a link depends would inherently cause them to be generated twice, since the output needs to be passed to the ld_args and link_depends. """ sources = listify(sources) for s in sources: if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, File): self.link_depends.append(s) elif isinstance(s, str): self.link_depends.append( File.from_source_file(environment.source_dir, self.subdir, s)) elif hasattr(s, 'get_outputs'): self.link_depends.extend( [File.from_built_file(s.subdir, p) for p in s.get_outputs()]) else: raise InvalidArguments( 'Link_depends arguments must be strings, Files, ' 'or a Custom Target, or lists thereof.') def get_original_kwargs(self): return self.kwargs def unpack_holder(self, d): d = listify(d) newd = [] for i in d: if isinstance(i, list): i = self.unpack_holder(i) elif hasattr(i, 'held_object'): i = i.held_object for t in ['dependencies', 'link_with', 'include_directories', 'sources']: if hasattr(i, t): setattr(i, t, self.unpack_holder(getattr(i, t))) newd.append(i) return newd def copy_kwargs(self, kwargs): self.kwargs = copy.copy(kwargs) # This sucks quite badly. Arguments # are holders but they can't be pickled # so unpack those known. for k, v in self.kwargs.items(): if isinstance(v, list): self.kwargs[k] = self.unpack_holder(v) if hasattr(v, 'held_object'): self.kwargs[k] = v.held_object for t in ['dependencies', 'link_with', 'include_directories', 'sources']: if t in self.kwargs: self.kwargs[t] = self.unpack_holder(self.kwargs[t]) def extract_objects(self, srclist): obj_src = [] for src in srclist: if isinstance(src, str): src = File(False, self.subdir, src) elif isinstance(src, File): FeatureNew('File argument for extract_objects', '0.50.0').use(self.subproject) else: raise MesonException('Object extraction arguments must be strings or Files.') # FIXME: It could be a generated source if src not in self.sources: raise MesonException('Tried to extract unknown source %s.' % src) obj_src.append(src) return ExtractedObjects(self, obj_src) def extract_all_objects(self, recursive=True): return ExtractedObjects(self, self.sources, self.generated, self.objects, recursive) def get_all_link_deps(self): return self.get_transitive_link_deps() @lru_cache(maxsize=None) def get_transitive_link_deps(self): result = [] for i in self.link_targets: result += i.get_all_link_deps() return result def get_link_deps_mapping(self, prefix, environment): return self.get_transitive_link_deps_mapping(prefix, environment) @lru_cache(maxsize=None) def get_transitive_link_deps_mapping(self, prefix, environment): result = {} for i in self.link_targets: mapping = i.get_link_deps_mapping(prefix, environment) #we are merging two dictionaries, while keeping the earlier one dominant result_tmp = mapping.copy() result_tmp.update(result) result = result_tmp return result @lru_cache(maxsize=None) def get_link_dep_subdirs(self): result = OrderedSet() for i in self.link_targets: result.add(i.get_subdir()) result.update(i.get_link_dep_subdirs()) return result def get_default_install_dir(self, environment): return environment.get_libdir() def get_custom_install_dir(self): return self.install_dir def get_custom_install_mode(self): return self.install_mode def process_kwargs(self, kwargs, environment): self.process_kwargs_base(kwargs) self.copy_kwargs(kwargs) kwargs.get('modules', []) self.need_install = kwargs.get('install', self.need_install) llist = extract_as_list(kwargs, 'link_with') for linktarget in llist: # Sorry for this hack. Keyword targets are kept in holders # in kwargs. Unpack here without looking at the exact type. if hasattr(linktarget, "held_object"): linktarget = linktarget.held_object if isinstance(linktarget, dependencies.ExternalLibrary): raise MesonException('''An external library was used in link_with keyword argument, which is reserved for libraries built as part of this project. External libraries must be passed using the dependencies keyword argument instead, because they are conceptually "external dependencies", just like those detected with the dependency() function.''') self.link(linktarget) lwhole = extract_as_list(kwargs, 'link_whole') for linktarget in lwhole: self.link_whole(linktarget) c_pchlist, cpp_pchlist, clist, cpplist, cudalist, cslist, valalist, objclist, objcpplist, fortranlist, rustlist \ = extract_as_list(kwargs, 'c_pch', 'cpp_pch', 'c_args', 'cpp_args', 'cuda_args', 'cs_args', 'vala_args', 'objc_args', 'objcpp_args', 'fortran_args', 'rust_args') self.add_pch('c', c_pchlist) self.add_pch('cpp', cpp_pchlist) compiler_args = {'c': clist, 'cpp': cpplist, 'cuda': cudalist, 'cs': cslist, 'vala': valalist, 'objc': objclist, 'objcpp': objcpplist, 'fortran': fortranlist, 'rust': rustlist } for key, value in compiler_args.items(): self.add_compiler_args(key, value) if not isinstance(self, Executable) or 'export_dynamic' in kwargs: self.vala_header = kwargs.get('vala_header', self.name + '.h') self.vala_vapi = kwargs.get('vala_vapi', self.name + '.vapi') self.vala_gir = kwargs.get('vala_gir', None) dlist = stringlistify(kwargs.get('d_args', [])) self.add_compiler_args('d', dlist) dfeatures = dict() dfeature_unittest = kwargs.get('d_unittest', False) if dfeature_unittest: dfeatures['unittest'] = dfeature_unittest dfeature_versions = kwargs.get('d_module_versions', []) if dfeature_versions: dfeatures['versions'] = dfeature_versions dfeature_debug = kwargs.get('d_debug', []) if dfeature_debug: dfeatures['debug'] = dfeature_debug if 'd_import_dirs' in kwargs: dfeature_import_dirs = extract_as_list(kwargs, 'd_import_dirs', unholder=True) for d in dfeature_import_dirs: if not isinstance(d, IncludeDirs): raise InvalidArguments('Arguments to d_import_dirs must be include_directories.') dfeatures['import_dirs'] = dfeature_import_dirs if dfeatures: self.d_features = dfeatures self.link_args = extract_as_list(kwargs, 'link_args') for i in self.link_args: if not isinstance(i, str): raise InvalidArguments('Link_args arguments must be strings.') for l in self.link_args: if '-Wl,-rpath' in l or l.startswith('-rpath'): mlog.warning('''Please do not define rpath with a linker argument, use install_rpath or build_rpath properties instead. This will become a hard error in a future Meson release.''') self.process_link_depends(kwargs.get('link_depends', []), environment) # Target-specific include dirs must be added BEFORE include dirs from # internal deps (added inside self.add_deps()) to override them. inclist = extract_as_list(kwargs, 'include_directories') self.add_include_dirs(inclist) # Add dependencies (which also have include_directories) deplist = extract_as_list(kwargs, 'dependencies') self.add_deps(deplist) # If an item in this list is False, the output corresponding to # the list index of that item will not be installed self.install_dir = typeslistify(kwargs.get('install_dir', [None]), (str, bool)) self.install_mode = kwargs.get('install_mode', None) main_class = kwargs.get('main_class', '') if not isinstance(main_class, str): raise InvalidArguments('Main class must be a string') self.main_class = main_class if isinstance(self, Executable): self.gui_app = kwargs.get('gui_app', False) if not isinstance(self.gui_app, bool): raise InvalidArguments('Argument gui_app must be boolean.') elif 'gui_app' in kwargs: raise InvalidArguments('Argument gui_app can only be used on executables.') extra_files = extract_as_list(kwargs, 'extra_files') for i in extra_files: assert(isinstance(i, File)) trial = os.path.join(environment.get_source_dir(), i.subdir, i.fname) if not(os.path.isfile(trial)): raise InvalidArguments('Tried to add non-existing extra file %s.' % i) self.extra_files = extra_files self.install_rpath = kwargs.get('install_rpath', '') if not isinstance(self.install_rpath, str): raise InvalidArguments('Install_rpath is not a string.') self.build_rpath = kwargs.get('build_rpath', '') if not isinstance(self.build_rpath, str): raise InvalidArguments('Build_rpath is not a string.') resources = extract_as_list(kwargs, 'resources') for r in resources: if not isinstance(r, str): raise InvalidArguments('Resource argument is not a string.') trial = os.path.join(environment.get_source_dir(), self.subdir, r) if not os.path.isfile(trial): raise InvalidArguments('Tried to add non-existing resource %s.' % r) self.resources = resources if 'name_prefix' in kwargs: name_prefix = kwargs['name_prefix'] if isinstance(name_prefix, list): if name_prefix: raise InvalidArguments('name_prefix array must be empty to signify null.') elif not isinstance(name_prefix, str): raise InvalidArguments('name_prefix must be a string.') self.prefix = name_prefix self.name_prefix_set = True if 'name_suffix' in kwargs: name_suffix = kwargs['name_suffix'] if isinstance(name_suffix, list): if name_suffix: raise InvalidArguments('name_suffix array must be empty to signify null.') else: if not isinstance(name_suffix, str): raise InvalidArguments('name_suffix must be a string.') if name_suffix == '': raise InvalidArguments('name_suffix should not be an empty string. ' 'If you want meson to use the default behaviour ' 'for each platform pass `[]` (empty array)') self.suffix = name_suffix self.name_suffix_set = True if isinstance(self, StaticLibrary): # You can't disable PIC on OS X. The compiler ignores -fno-PIC. # PIC is always on for Windows (all code is position-independent # since library loading is done differently) m = self.environment.machines[self.for_machine] if m.is_darwin() or m.is_windows(): self.pic = True else: self.pic = self._extract_pic_pie(kwargs, 'pic') if isinstance(self, Executable): # Executables must be PIE on Android if self.environment.machines[self.for_machine].is_android(): self.pie = True else: self.pie = self._extract_pic_pie(kwargs, 'pie') self.implicit_include_directories = kwargs.get('implicit_include_directories', True) if not isinstance(self.implicit_include_directories, bool): raise InvalidArguments('Implicit_include_directories must be a boolean.') self.gnu_symbol_visibility = kwargs.get('gnu_symbol_visibility', '') if not isinstance(self.gnu_symbol_visibility, str): raise InvalidArguments('GNU symbol visibility must be a string.') if self.gnu_symbol_visibility != '': permitted = ['default', 'internal', 'hidden', 'protected', 'inlineshidden'] if self.gnu_symbol_visibility not in permitted: raise InvalidArguments('GNU symbol visibility arg %s not one of: %s', self.symbol_visibility, ', '.join(permitted)) def _extract_pic_pie(self, kwargs, arg): # Check if we have -fPIC, -fpic, -fPIE, or -fpie in cflags all_flags = self.extra_args['c'] + self.extra_args['cpp'] if '-f' + arg.lower() in all_flags or '-f' + arg.upper() in all_flags: mlog.warning("Use the '{}' kwarg instead of passing '{}' manually to {!r}".format(arg, '-f' + arg, self.name)) return True val = kwargs.get(arg, False) if not isinstance(val, bool): raise InvalidArguments('Argument {} to {!r} must be boolean'.format(arg, self.name)) return val def get_filename(self): return self.filename def get_outputs(self): return self.outputs def get_extra_args(self, language): return self.extra_args.get(language, []) def get_dependencies(self, exclude=None, for_pkgconfig=False): transitive_deps = [] if exclude is None: exclude = [] for t in itertools.chain(self.link_targets, self.link_whole_targets): if t in transitive_deps or t in exclude: continue # When generating `Libs:` and `Libs.private:` lists in pkg-config # files we don't want to include static libraries that we link_whole # or are uninstalled (they're implicitly promoted to link_whole). # But we still need to include their transitive dependencies, # a static library we link_whole would itself link to a shared # library or an installed static library. if not for_pkgconfig or (not t.is_internal() and t not in self.link_whole_targets): transitive_deps.append(t) if isinstance(t, StaticLibrary): transitive_deps += t.get_dependencies(transitive_deps + exclude, for_pkgconfig) return transitive_deps def get_source_subdir(self): return self.subdir def get_sources(self): return self.sources def get_objects(self): return self.objects def get_generated_sources(self): return self.generated def should_install(self): return self.need_install def has_pch(self): return len(self.pch) > 0 def get_pch(self, language): try: return self.pch[language] except KeyError: return[] def get_include_dirs(self): return self.include_dirs def add_deps(self, deps): deps = listify(deps) for dep in deps: if hasattr(dep, 'held_object'): dep = dep.held_object if isinstance(dep, dependencies.InternalDependency): # Those parts that are internal. self.process_sourcelist(dep.sources) self.add_include_dirs(dep.include_directories, dep.get_include_type()) for l in dep.libraries: self.link(l) for l in dep.whole_libraries: self.link_whole(l) if dep.get_compile_args() or dep.get_link_args(): # Those parts that are external. extpart = dependencies.InternalDependency('undefined', [], dep.get_compile_args(), dep.get_link_args(), [], [], [], []) self.external_deps.append(extpart) # Deps of deps. self.add_deps(dep.ext_deps) elif isinstance(dep, dependencies.Dependency): if dep not in self.external_deps: self.external_deps.append(dep) self.process_sourcelist(dep.get_sources()) self.add_deps(dep.ext_deps) elif isinstance(dep, BuildTarget): raise InvalidArguments('''Tried to use a build target as a dependency. You probably should put it in link_with instead.''') else: # This is a bit of a hack. We do not want Build to know anything # about the interpreter so we can't import it and use isinstance. # This should be reliable enough. if hasattr(dep, 'project_args_frozen') or hasattr(dep, 'global_args_frozen'): raise InvalidArguments('Tried to use subproject object as a dependency.\n' 'You probably wanted to use a dependency declared in it instead.\n' 'Access it by calling get_variable() on the subproject object.') raise InvalidArguments('Argument is of an unacceptable type {!r}.\nMust be ' 'either an external dependency (returned by find_library() or ' 'dependency()) or an internal dependency (returned by ' 'declare_dependency()).'.format(type(dep).__name__)) def get_external_deps(self): return self.external_deps def is_internal(self): return isinstance(self, StaticLibrary) and not self.need_install def link(self, target): for t in listify(target, unholder=True): if isinstance(self, StaticLibrary) and self.need_install and t.is_internal(): # When we're a static library and we link_with to an # internal/convenience library, promote to link_whole. return self.link_whole(t) if not isinstance(t, (Target, CustomTargetIndex)): raise InvalidArguments('{!r} is not a target.'.format(t)) if not t.is_linkable_target(): raise InvalidArguments('Link target {!r} is not linkable.'.format(t)) if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic: msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name) 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 {} and {} in target {!r}'.format(self.for_machine, t.for_machine, self.name) if self.environment.is_cross_build(): raise InvalidArguments(msg + ' This is not possible in a cross build.') else: mlog.warning(msg + ' This will fail in cross build.') self.link_targets.append(t) def link_whole(self, target): for t in listify(target, unholder=True): if isinstance(t, (CustomTarget, CustomTargetIndex)): if not t.is_linkable_target(): raise InvalidArguments('Custom target {!r} is not linkable.'.format(t)) if not t.get_filename().endswith('.a'): raise InvalidArguments('Can only link_whole custom targets that are .a archives.') if isinstance(self, StaticLibrary): # FIXME: We could extract the .a archive to get object files raise InvalidArguments('Cannot link_whole a custom target into a static library') elif not isinstance(t, StaticLibrary): raise InvalidArguments('{!r} is not a static library.'.format(t)) elif isinstance(self, SharedLibrary) and not t.pic: msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name) 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 {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: mlog.warning(msg + ' This will fail in cross build.') if isinstance(self, StaticLibrary): # When we're a static library and we link_whole: to another static # library, we need to add that target's objects to ourselves. self.objects += t.extract_all_objects_recurse() self.link_whole_targets.append(t) def extract_all_objects_recurse(self): objs = [self.extract_all_objects()] for t in self.link_targets: if t.is_internal(): objs += t.extract_all_objects_recurse() return objs def add_pch(self, language, pchlist): if not pchlist: return elif len(pchlist) == 1: if not environment.is_header(pchlist[0]): raise InvalidArguments('PCH argument %s is not a header.' % pchlist[0]) elif len(pchlist) == 2: if environment.is_header(pchlist[0]): if not environment.is_source(pchlist[1]): raise InvalidArguments('PCH definition must contain one header and at most one source.') elif environment.is_source(pchlist[0]): if not environment.is_header(pchlist[1]): raise InvalidArguments('PCH definition must contain one header and at most one source.') pchlist = [pchlist[1], pchlist[0]] else: raise InvalidArguments('PCH argument %s is of unknown type.' % pchlist[0]) if (os.path.dirname(pchlist[0]) != os.path.dirname(pchlist[1])): raise InvalidArguments('PCH files must be stored in the same folder.') mlog.warning('PCH source files are deprecated, only a single header file should be used.') elif len(pchlist) > 2: raise InvalidArguments('PCH definition may have a maximum of 2 files.') for f in pchlist: if not isinstance(f, str): raise MesonException('PCH arguments must be strings.') if not os.path.isfile(os.path.join(self.environment.source_dir, self.subdir, f)): raise MesonException('File %s does not exist.' % f) self.pch[language] = pchlist def add_include_dirs(self, args, set_is_system: T.Optional[str] = None): ids = [] for a in args: # FIXME same hack, forcibly unpack from holder. if hasattr(a, 'held_object'): a = a.held_object if not isinstance(a, IncludeDirs): raise InvalidArguments('Include directory to be added is not an include directory object.') ids.append(a) if set_is_system is None: set_is_system = 'preserve' if set_is_system != 'preserve': is_system = set_is_system == 'system' ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), is_system, x.get_extra_build_dirs()) for x in ids] self.include_dirs += ids def add_compiler_args(self, language, args): args = listify(args) for a in args: if not isinstance(a, (str, File)): raise InvalidArguments('A non-string passed to compiler args.') if language in self.extra_args: self.extra_args[language] += args else: self.extra_args[language] = args def get_aliases(self): return {} def get_langs_used_by_deps(self) -> T.List[str]: ''' Sometimes you want to link to a C++ library that exports C API, which means the linker must link in the C++ stdlib, and we must use a C++ compiler for linking. The same is also applicable for objc/objc++, etc, so we can keep using clink_langs for the priority order. See: https://github.com/mesonbuild/meson/issues/1653 ''' langs = [] # User specified link_language of target (for multi-language targets) if self.link_language: return [self.link_language] # Check if any of the external libraries were written in this language for dep in self.external_deps: if dep.language is None: continue if dep.language not in langs: langs.append(dep.language) # Check if any of the internal libraries this target links to were # written in this language for link_target in itertools.chain(self.link_targets, self.link_whole_targets): if isinstance(link_target, (CustomTarget, CustomTargetIndex)): continue for language in link_target.compilers: if language not in langs: langs.append(language) return langs def get_clink_dynamic_linker_and_stdlibs(self): ''' We use the order of languages in `clink_langs` to determine which linker to use in case the target has sources compiled with multiple compilers. All languages other than those in this list have their own linker. Note that Vala outputs C code, so Vala sources can use any linker that can link compiled C. We don't actually need to add an exception for Vala here because of that. ''' # Populate list of all compilers, not just those being used to compile # sources in this target all_compilers = self.environment.coredata.compilers[self.for_machine] # Languages used by dependencies dep_langs = self.get_langs_used_by_deps() # Pick a compiler based on the language priority-order for l in clink_langs: if l in self.compilers or l in dep_langs: try: linker = all_compilers[l] except KeyError: raise MesonException( 'Could not get a dynamic linker for build target {!r}. ' 'Requires a linker for language "{}", but that is not ' 'a project language.'.format(self.name, l)) stdlib_args = [] added_languages = set() for dl in itertools.chain(self.compilers, dep_langs): if dl != linker.language: stdlib_args += all_compilers[dl].language_stdlib_only_link_flags() added_languages.add(dl) return linker, stdlib_args m = 'Could not get a dynamic linker for build target {!r}' raise AssertionError(m.format(self.name)) def get_using_rustc(self): if len(self.sources) > 0 and self.sources[0].fname.endswith('.rs'): return True def get_using_msvc(self): ''' Check if the dynamic linker is MSVC. Used by Executable, StaticLibrary, and SharedLibrary for deciding when to use MSVC-specific file naming and debug filenames. If at least some code is built with MSVC and the final library is linked with MSVC, we can be sure that some debug info will be generated. We only check the dynamic linker here because the static linker is guaranteed to be of the same type. Interesting cases: 1. The Vala compiler outputs C code to be compiled by whatever C compiler we're using, so all objects will still be created by the MSVC compiler. 2. If the target contains only objects, process_compilers guesses and picks the first compiler that smells right. ''' linker, _ = self.get_clink_dynamic_linker_and_stdlibs() # Mixing many languages with MSVC is not supported yet so ignore stdlibs. if linker and linker.get_id() in {'msvc', 'clang-cl', 'intel-cl', 'llvm', 'dmd', 'nvcc'}: return True return False def check_module_linking(self): ''' Warn if shared modules are linked with target: (link_with) #2865 ''' for link_target in self.link_targets: if isinstance(link_target, SharedModule): if self.environment.machines[self.for_machine].is_darwin(): raise MesonException('''target links against shared modules. This is not permitted on OSX''') else: mlog.warning('''target links against shared modules. This is not recommended as it is not supported on some platforms''') return class Generator: def __init__(self, args, kwargs): if len(args) != 1: raise InvalidArguments('Generator requires exactly one positional argument: the executable') exe = args[0] if hasattr(exe, 'held_object'): exe = exe.held_object if not isinstance(exe, (Executable, dependencies.ExternalProgram)): raise InvalidArguments('First generator argument must be an executable.') self.exe = exe self.depfile = None self.capture = False self.depends = [] self.process_kwargs(kwargs) def __repr__(self): repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.exe) def get_exe(self): return self.exe def process_kwargs(self, kwargs): if 'arguments' not in kwargs: raise InvalidArguments('Generator must have "arguments" keyword argument.') args = kwargs['arguments'] if isinstance(args, str): args = [args] if not isinstance(args, list): raise InvalidArguments('"Arguments" keyword argument must be a string or a list of strings.') for a in args: if not isinstance(a, str): raise InvalidArguments('A non-string object in "arguments" keyword argument.') self.arglist = args if 'output' not in kwargs: raise InvalidArguments('Generator must have "output" keyword argument.') outputs = listify(kwargs['output']) for rule in outputs: if not isinstance(rule, str): raise InvalidArguments('"output" may only contain strings.') if '@BASENAME@' not in rule and '@PLAINNAME@' not in rule: raise InvalidArguments('Every element of "output" must contain @BASENAME@ or @PLAINNAME@.') if has_path_sep(rule): raise InvalidArguments('"outputs" must not contain a directory separator.') if len(outputs) > 1: for o in outputs: if '@OUTPUT@' in o: raise InvalidArguments('Tried to use @OUTPUT@ in a rule with more than one output.') self.outputs = outputs if 'depfile' in kwargs: depfile = kwargs['depfile'] if not isinstance(depfile, str): raise InvalidArguments('Depfile must be a string.') if os.path.basename(depfile) != depfile: raise InvalidArguments('Depfile must be a plain filename without a subdirectory.') self.depfile = depfile if 'capture' in kwargs: capture = kwargs['capture'] if not isinstance(capture, bool): raise InvalidArguments('Capture must be boolean.') self.capture = capture if 'depends' in kwargs: depends = listify(kwargs['depends'], unholder=True) for d in depends: if not isinstance(d, BuildTarget): raise InvalidArguments('Depends entries must be build targets.') self.depends.append(d) def get_base_outnames(self, inname): plainname = os.path.basename(inname) basename = os.path.splitext(plainname)[0] bases = [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.outputs] return bases def get_dep_outname(self, inname): if self.depfile is None: raise InvalidArguments('Tried to get dep name for rule that does not have dependency file defined.') plainname = os.path.basename(inname) basename = os.path.splitext(plainname)[0] return self.depfile.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) def get_arglist(self, inname): plainname = os.path.basename(inname) basename = os.path.splitext(plainname)[0] return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.arglist] def is_parent_path(self, parent, trial): relpath = pathlib.PurePath(trial).relative_to(parent) return relpath.parts[0] != '..' # For subdirs we can only go "down". def process_files(self, name, files, state, preserve_path_from=None, extra_args=None): output = GeneratedList(self, state.subdir, preserve_path_from, extra_args=extra_args if extra_args is not None else []) for f in files: if isinstance(f, str): f = File.from_source_file(state.environment.source_dir, state.subdir, f) elif not isinstance(f, File): raise InvalidArguments('{} arguments must be strings or files not {!r}.'.format(name, f)) if preserve_path_from: abs_f = f.absolute_path(state.environment.source_dir, state.environment.build_dir) if not self.is_parent_path(preserve_path_from, abs_f): raise InvalidArguments('When using preserve_path_from, all input files must be in a subdirectory of the given dir.') output.add_file(f, state) return output class GeneratedList: def __init__(self, generator, subdir, preserve_path_from=None, extra_args=None): if hasattr(generator, 'held_object'): generator = generator.held_object self.generator = generator self.name = self.generator.exe self.subdir = subdir self.infilelist = [] self.outfilelist = [] self.outmap = {} self.extra_depends = [] self.depend_files = [] self.preserve_path_from = preserve_path_from self.extra_args = extra_args if extra_args is not None else [] if isinstance(generator.exe, dependencies.ExternalProgram): if not generator.exe.found(): raise InvalidArguments('Tried to use not-found external program as generator') path = generator.exe.get_path() if os.path.isabs(path): # Can only add a dependency on an external program which we # know the absolute path of self.depend_files.append(File.from_absolute_file(path)) def add_preserved_path_segment(self, infile, outfiles, state): result = [] in_abs = infile.absolute_path(state.environment.source_dir, state.environment.build_dir) assert(os.path.isabs(self.preserve_path_from)) rel = os.path.relpath(in_abs, self.preserve_path_from) path_segment = os.path.dirname(rel) for of in outfiles: result.append(os.path.join(path_segment, of)) return result def add_file(self, newfile, state): self.infilelist.append(newfile) outfiles = self.generator.get_base_outnames(newfile.fname) if self.preserve_path_from: outfiles = self.add_preserved_path_segment(newfile, outfiles, state) self.outfilelist += outfiles self.outmap[newfile] = outfiles def get_inputs(self): return self.infilelist def get_outputs(self): return self.outfilelist def get_outputs_for(self, filename): return self.outmap[filename] def get_generator(self): return self.generator def get_extra_args(self): return self.extra_args class Executable(BuildTarget): known_kwargs = known_exe_kwargs def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs): self.typename = 'executable' if 'pie' not in kwargs and 'b_pie' in environment.coredata.base_options: kwargs['pie'] = environment.coredata.base_options['b_pie'].value super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) # Unless overridden, executables have no suffix or prefix. Except on # Windows and with C#/Mono executables where the suffix is 'exe' if not hasattr(self, 'prefix'): self.prefix = '' if not hasattr(self, 'suffix'): machine = environment.machines[for_machine] # Executable for Windows or C#/Mono if machine.is_windows() or machine.is_cygwin() or 'cs' in self.compilers: self.suffix = 'exe' elif machine.system.startswith('wasm') or machine.system == 'emscripten': self.suffix = 'js' elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('arm') or 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('arm')): self.suffix = 'axf' elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('ccrx') or 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('ccrx')): self.suffix = 'abs' else: self.suffix = environment.machines[for_machine].get_exe_suffix() self.filename = self.name if self.suffix: self.filename += '.' + self.suffix self.outputs = [self.filename] # The import library this target will generate self.import_filename = None # The import library that Visual Studio would generate (and accept) self.vs_import_filename = None # The import library that GCC would generate (and prefer) self.gcc_import_filename = None # The debugging information file this target will generate self.debug_filename = None # Check for export_dynamic self.export_dynamic = False if kwargs.get('export_dynamic'): if not isinstance(kwargs['export_dynamic'], bool): raise InvalidArguments('"export_dynamic" keyword argument must be a boolean') self.export_dynamic = True if kwargs.get('implib'): self.export_dynamic = True if self.export_dynamic and kwargs.get('implib') is False: raise InvalidArguments('"implib" keyword argument must not be false for if "export_dynamic" is true') m = environment.machines[for_machine] # If using export_dynamic, set the import library name if self.export_dynamic: implib_basename = self.name + '.exe' if not isinstance(kwargs.get('implib', False), bool): implib_basename = kwargs['implib'] if m.is_windows() or m.is_cygwin(): self.vs_import_filename = '{0}.lib'.format(implib_basename) self.gcc_import_filename = 'lib{0}.a'.format(implib_basename) if self.get_using_msvc(): self.import_filename = self.vs_import_filename else: self.import_filename = self.gcc_import_filename if m.is_windows() and ('cs' in self.compilers or self.get_using_rustc() or self.get_using_msvc()): self.debug_filename = self.name + '.pdb' # Only linkwithable if using export_dynamic self.is_linkwithable = self.export_dynamic def get_default_install_dir(self, environment): return environment.get_bindir() def description(self): '''Human friendly description of the executable''' return self.name def type_suffix(self): return "@exe" def get_import_filename(self): """ The name of the import library that will be outputted by the compiler Returns None if there is no import library required for this platform """ return self.import_filename def get_import_filenameslist(self): if self.import_filename: return [self.vs_import_filename, self.gcc_import_filename] return [] def get_debug_filename(self): """ The name of debuginfo file that will be created by the compiler Returns None if the build won't create any debuginfo file """ return self.debug_filename def is_linkable_target(self): return self.is_linkwithable class StaticLibrary(BuildTarget): known_kwargs = known_stlib_kwargs def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs): self.typename = 'static library' if 'pic' not in kwargs and 'b_staticpic' in environment.coredata.base_options: kwargs['pic'] = environment.coredata.base_options['b_staticpic'].value super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) if 'cs' in self.compilers: raise InvalidArguments('Static libraries not supported for C#.') if 'rust' in self.compilers: # If no crate type is specified, or it's the generic lib type, use rlib if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'lib': mlog.debug('Defaulting Rust static library target crate type to rlib') self.rust_crate_type = 'rlib' # Don't let configuration proceed with a non-static crate type elif self.rust_crate_type not in ['rlib', 'staticlib']: raise InvalidArguments('Crate type "{0}" invalid for static libraries; must be "rlib" or "staticlib"'.format(self.rust_crate_type)) # By default a static library is named libfoo.a even on Windows because # MSVC does not have a consistent convention for what static libraries # are called. The MSVC CRT uses libfoo.lib syntax but nothing else uses # it and GCC only looks for static libraries called foo.lib and # libfoo.a. However, we cannot use foo.lib because that's the same as # the import library. Using libfoo.a is ok because people using MSVC # always pass the library filename while linking anyway. if not hasattr(self, 'prefix'): self.prefix = 'lib' if not hasattr(self, 'suffix'): if 'rust' in self.compilers: if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'rlib': # default Rust static library suffix self.suffix = 'rlib' elif self.rust_crate_type == 'staticlib': self.suffix = 'a' else: self.suffix = 'a' self.filename = self.prefix + self.name + '.' + self.suffix self.outputs = [self.filename] def get_link_deps_mapping(self, prefix, environment): return {} def get_default_install_dir(self, environment): return environment.get_static_lib_dir() def type_suffix(self): return "@sta" def process_kwargs(self, kwargs, environment): super().process_kwargs(kwargs, environment) if 'rust_crate_type' in kwargs: rust_crate_type = kwargs['rust_crate_type'] if isinstance(rust_crate_type, str): self.rust_crate_type = rust_crate_type else: raise InvalidArguments('Invalid rust_crate_type "{0}": must be a string.'.format(rust_crate_type)) def is_linkable_target(self): return True class SharedLibrary(BuildTarget): known_kwargs = known_shlib_kwargs def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs): self.typename = 'shared library' self.soversion = None self.ltversion = None # Max length 2, first element is compatibility_version, second is current_version self.darwin_versions = [] self.vs_module_defs = None # The import library this target will generate self.import_filename = None # The import library that Visual Studio would generate (and accept) self.vs_import_filename = None # The import library that GCC would generate (and prefer) self.gcc_import_filename = None # The debugging information file this target will generate self.debug_filename = None super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) if 'rust' in self.compilers: # If no crate type is specified, or it's the generic lib type, use dylib if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'lib': mlog.debug('Defaulting Rust dynamic library target crate type to "dylib"') self.rust_crate_type = 'dylib' # Don't let configuration proceed with a non-dynamic crate type elif self.rust_crate_type not in ['dylib', 'cdylib']: raise InvalidArguments('Crate type "{0}" invalid for dynamic libraries; must be "dylib" or "cdylib"'.format(self.rust_crate_type)) if not hasattr(self, 'prefix'): self.prefix = None if not hasattr(self, 'suffix'): self.suffix = None self.basic_filename_tpl = '{0.prefix}{0.name}.{0.suffix}' self.determine_filenames(environment) def get_link_deps_mapping(self, prefix, environment): result = {} mappings = self.get_transitive_link_deps_mapping(prefix, environment) old = get_target_macos_dylib_install_name(self) if old not in mappings: fname = self.get_filename() outdirs, _ = self.get_install_dir(self.environment) new = os.path.join(prefix, outdirs[0], fname) result.update({old: new}) mappings.update(result) return mappings def get_default_install_dir(self, environment): return environment.get_shared_lib_dir() def determine_filenames(self, env): """ See https://github.com/mesonbuild/meson/pull/417 for details. First we determine the filename template (self.filename_tpl), then we set the output filename (self.filename). The template is needed while creating aliases (self.get_aliases), which are needed while generating .so shared libraries for Linux. Besides this, there's also the import library name, which is only used on Windows since on that platform the linker uses a separate library called the "import library" during linking instead of the shared library (DLL). The toolchain will output an import library in one of two formats: GCC or Visual Studio. When we're building with Visual Studio, the import library that will be generated by the toolchain is self.vs_import_filename, and with MinGW/GCC, it's self.gcc_import_filename. self.import_filename will always contain the import library name this target will generate. """ prefix = '' suffix = '' create_debug_file = False self.filename_tpl = self.basic_filename_tpl # NOTE: manual prefix/suffix override is currently only tested for C/C++ # C# and Mono if 'cs' in self.compilers: prefix = '' suffix = 'dll' self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' create_debug_file = True # C, C++, Swift, Vala # Only Windows uses a separate import library for linking # For all other targets/platforms import_filename stays None elif env.machines[self.for_machine].is_windows(): suffix = 'dll' self.vs_import_filename = '{0}{1}.lib'.format(self.prefix if self.prefix is not None else '', self.name) self.gcc_import_filename = '{0}{1}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name) if self.get_using_rustc(): # Shared library is of the form foo.dll prefix = '' # Import library is called foo.dll.lib self.import_filename = '{0}.dll.lib'.format(self.name) create_debug_file = True elif self.get_using_msvc(): # Shared library is of the form foo.dll prefix = '' # Import library is called foo.lib self.import_filename = self.vs_import_filename create_debug_file = True # Assume GCC-compatible naming else: # Shared library is of the form libfoo.dll prefix = 'lib' # Import library is called libfoo.dll.a self.import_filename = self.gcc_import_filename # Shared library has the soversion if it is defined if self.soversion: self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}' else: self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' elif env.machines[self.for_machine].is_cygwin(): suffix = 'dll' self.gcc_import_filename = '{0}{1}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name) # Shared library is of the form cygfoo.dll # (ld --dll-search-prefix=cyg is the default) prefix = 'cyg' # Import library is called libfoo.dll.a self.import_filename = self.gcc_import_filename if self.soversion: self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}' else: self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' elif env.machines[self.for_machine].is_darwin(): prefix = 'lib' suffix = 'dylib' # On macOS, the filename can only contain the major version if self.soversion: # libfoo.X.dylib self.filename_tpl = '{0.prefix}{0.name}.{0.soversion}.{0.suffix}' else: # libfoo.dylib self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' elif env.machines[self.for_machine].is_android(): prefix = 'lib' suffix = 'so' # Android doesn't support shared_library versioning self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' else: prefix = 'lib' suffix = 'so' if self.ltversion: # libfoo.so.X[.Y[.Z]] (.Y and .Z are optional) self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.ltversion}' elif self.soversion: # libfoo.so.X self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.soversion}' else: # No versioning, libfoo.so self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' if self.prefix is None: self.prefix = prefix if self.suffix is None: self.suffix = suffix self.filename = self.filename_tpl.format(self) self.outputs = [self.filename] if create_debug_file: self.debug_filename = os.path.splitext(self.filename)[0] + '.pdb' @staticmethod def _validate_darwin_versions(darwin_versions): try: if isinstance(darwin_versions, int): darwin_versions = str(darwin_versions) if isinstance(darwin_versions, str): darwin_versions = 2 * [darwin_versions] if not isinstance(darwin_versions, list): raise InvalidArguments('Shared library darwin_versions: must be a string, integer,' 'or a list, not {!r}'.format(darwin_versions)) if len(darwin_versions) > 2: raise InvalidArguments('Shared library darwin_versions: list must contain 2 or fewer elements') if len(darwin_versions) == 1: darwin_versions = 2 * darwin_versions for i, v in enumerate(darwin_versions[:]): if isinstance(v, int): v = str(v) if not isinstance(v, str): raise InvalidArguments('Shared library darwin_versions: list elements ' 'must be strings or integers, not {!r}'.format(v)) if not re.fullmatch(r'[0-9]+(\.[0-9]+){0,2}', v): raise InvalidArguments('Shared library darwin_versions: must be X.Y.Z where ' 'X, Y, Z are numbers, and Y and Z are optional') parts = v.split('.') if len(parts) in (1, 2, 3) and int(parts[0]) > 65535: raise InvalidArguments('Shared library darwin_versions: must be X.Y.Z ' 'where X is [0, 65535] and Y, Z are optional') if len(parts) in (2, 3) and int(parts[1]) > 255: raise InvalidArguments('Shared library darwin_versions: must be X.Y.Z ' 'where Y is [0, 255] and Y, Z are optional') if len(parts) == 3 and int(parts[2]) > 255: raise InvalidArguments('Shared library darwin_versions: must be X.Y.Z ' 'where Z is [0, 255] and Y, Z are optional') darwin_versions[i] = v except ValueError: raise InvalidArguments('Shared library darwin_versions: value is invalid') return darwin_versions def process_kwargs(self, kwargs, environment): super().process_kwargs(kwargs, environment) if not self.environment.machines[self.for_machine].is_android(): supports_versioning = True else: supports_versioning = False if supports_versioning: # Shared library version if 'version' in kwargs: self.ltversion = kwargs['version'] if not isinstance(self.ltversion, str): raise InvalidArguments('Shared library version needs to be a string, not ' + type(self.ltversion).__name__) if not re.fullmatch(r'[0-9]+(\.[0-9]+){0,2}', self.ltversion): raise InvalidArguments('Invalid Shared library version "{0}". Must be of the form X.Y.Z where all three are numbers. Y and Z are optional.'.format(self.ltversion)) # Try to extract/deduce the soversion if 'soversion' in kwargs: self.soversion = kwargs['soversion'] if isinstance(self.soversion, int): self.soversion = str(self.soversion) if not isinstance(self.soversion, str): raise InvalidArguments('Shared library soversion is not a string or integer.') elif self.ltversion: # library version is defined, get the soversion from that # We replicate what Autotools does here and take the first # number of the version by default. self.soversion = self.ltversion.split('.')[0] # macOS, iOS and tvOS dylib compatibility_version and current_version if 'darwin_versions' in kwargs: self.darwin_versions = self._validate_darwin_versions(kwargs['darwin_versions']) elif self.soversion: # If unspecified, pick the soversion self.darwin_versions = 2 * [self.soversion] # Visual Studio module-definitions file if 'vs_module_defs' in kwargs: path = kwargs['vs_module_defs'] if hasattr(path, 'held_object'): path = path.held_object if isinstance(path, str): if os.path.isabs(path): self.vs_module_defs = File.from_absolute_file(path) else: self.vs_module_defs = File.from_source_file(environment.source_dir, self.subdir, path) self.link_depends.append(self.vs_module_defs) elif isinstance(path, File): # When passing a generated file. self.vs_module_defs = path self.link_depends.append(path) elif hasattr(path, 'get_filename'): # When passing output of a Custom Target path = File.from_built_file(path.subdir, path.get_filename()) self.vs_module_defs = path self.link_depends.append(path) else: raise InvalidArguments( 'Shared library vs_module_defs must be either a string, ' 'a file object or a Custom Target') if 'rust_crate_type' in kwargs: rust_crate_type = kwargs['rust_crate_type'] if isinstance(rust_crate_type, str): self.rust_crate_type = rust_crate_type else: raise InvalidArguments('Invalid rust_crate_type "{0}": must be a string.'.format(rust_crate_type)) def get_import_filename(self): """ The name of the import library that will be outputted by the compiler Returns None if there is no import library required for this platform """ return self.import_filename def get_debug_filename(self): """ The name of debuginfo file that will be created by the compiler Returns None if the build won't create any debuginfo file """ return self.debug_filename def get_import_filenameslist(self): if self.import_filename: return [self.vs_import_filename, self.gcc_import_filename] return [] def get_all_link_deps(self): return [self] + self.get_transitive_link_deps() def get_aliases(self): """ If the versioned library name is libfoo.so.0.100.0, aliases are: * libfoo.so.0 (soversion) -> libfoo.so.0.100.0 * libfoo.so (unversioned; for linking) -> libfoo.so.0 Same for dylib: * libfoo.dylib (unversioned; for linking) -> libfoo.0.dylib """ aliases = {} # Aliases are only useful with .so and .dylib libraries. Also if # there's no self.soversion (no versioning), we don't need aliases. if self.suffix not in ('so', 'dylib') or not self.soversion: return {} # With .so libraries, the minor and micro versions are also in the # filename. If ltversion != soversion we create an soversion alias: # libfoo.so.0 -> libfoo.so.0.100.0 # Where libfoo.so.0.100.0 is the actual library if self.suffix == 'so' and self.ltversion and self.ltversion != self.soversion: alias_tpl = self.filename_tpl.replace('ltversion', 'soversion') ltversion_filename = alias_tpl.format(self) aliases[ltversion_filename] = self.filename # libfoo.so.0/libfoo.0.dylib is the actual library else: ltversion_filename = self.filename # Unversioned alias: # libfoo.so -> libfoo.so.0 # libfoo.dylib -> libfoo.0.dylib aliases[self.basic_filename_tpl.format(self)] = ltversion_filename return aliases def type_suffix(self): return "@sha" def is_linkable_target(self): return True # A shared library that is meant to be used with dlopen rather than linking # into something else. class SharedModule(SharedLibrary): known_kwargs = known_shmod_kwargs def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs): if 'version' in kwargs: raise MesonException('Shared modules must not specify the version kwarg.') if 'soversion' in kwargs: raise MesonException('Shared modules must not specify the soversion kwarg.') super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) self.typename = 'shared module' def get_default_install_dir(self, environment): return environment.get_shared_module_dir() class CustomTarget(Target): known_kwargs = set([ 'input', 'output', 'command', 'capture', 'install', 'install_dir', 'install_mode', 'build_always', 'build_always_stale', 'depends', 'depend_files', 'depfile', 'build_by_default', 'override_options', 'console', ]) def __init__(self, name, subdir, subproject, kwargs, absolute_paths=False, backend=None): self.typename = 'custom' # TODO expose keyword arg to make MachineChoice.HOST configurable super().__init__(name, subdir, subproject, False, MachineChoice.HOST) self.dependencies = [] self.extra_depends = [] self.depend_files = [] # Files that this target depends on but are not on the command line. self.depfile = None self.process_kwargs(kwargs, backend) self.extra_files = [] # Whether to use absolute paths for all files on the commandline self.absolute_paths = absolute_paths unknowns = [] for k in kwargs: if k not in CustomTarget.known_kwargs: unknowns.append(k) if len(unknowns) > 0: mlog.warning('Unknown keyword arguments in target %s: %s' % (self.name, ', '.join(unknowns))) def get_default_install_dir(self, environment): return None def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.command) def get_target_dependencies(self): deps = self.dependencies[:] deps += self.extra_depends for c in self.sources: if hasattr(c, 'held_object'): c = c.held_object if isinstance(c, (BuildTarget, CustomTarget)): deps.append(c) return deps def get_transitive_build_target_deps(self): ''' Recursively fetch the build targets that this custom target depends on, whether through `command:`, `depends:`, or `sources:` The recursion is only performed on custom targets. This is useful for setting PATH on Windows for finding required DLLs. F.ex, if you have a python script that loads a C module that links to other DLLs in your project. ''' bdeps = set() deps = self.get_target_dependencies() for d in deps: if isinstance(d, BuildTarget): bdeps.add(d) elif isinstance(d, CustomTarget): bdeps.update(d.get_transitive_build_target_deps()) return bdeps def flatten_command(self, cmd): cmd = listify(cmd, unholder=True) final_cmd = [] for c in cmd: if isinstance(c, str): final_cmd.append(c) elif isinstance(c, File): self.depend_files.append(c) final_cmd.append(c) elif isinstance(c, dependencies.ExternalProgram): if not c.found(): raise InvalidArguments('Tried to use not-found external program in "command"') path = c.get_path() if os.path.isabs(path): # Can only add a dependency on an external program which we # know the absolute path of self.depend_files.append(File.from_absolute_file(path)) final_cmd += c.get_command() elif isinstance(c, (BuildTarget, CustomTarget)): self.dependencies.append(c) final_cmd.append(c) elif isinstance(c, list): final_cmd += self.flatten_command(c) else: raise InvalidArguments('Argument {!r} in "command" is invalid'.format(c)) return final_cmd def process_kwargs(self, kwargs, backend): 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".') self.outputs = listify(kwargs['output']) # This will substitute values from the input into output and return it. inputs = get_sources_string_names(self.sources, backend) values = get_filenames_templates_dict(inputs, []) for i in self.outputs: if not(isinstance(i, str)): raise InvalidArguments('Output argument not a string.') if i == '': raise InvalidArguments('Output must not be empty.') if i.strip() == '': raise InvalidArguments('Output must not consist only of whitespace.') if has_path_sep(i): raise InvalidArguments('Output {!r} must not contain a path segment.'.format(i)) if '@INPUT@' in i or '@INPUT0@' in i: m = 'Output cannot contain @INPUT@ or @INPUT0@, did you ' \ 'mean @PLAINNAME@ or @BASENAME@?' raise InvalidArguments(m) # We already check this during substitution, but the error message # will be unclear/confusing, so check it here. if len(inputs) != 1 and ('@PLAINNAME@' in i or '@BASENAME@' in i): m = "Output cannot contain @PLAINNAME@ or @BASENAME@ when " \ "there is more than one input (we can't know which to use)" raise InvalidArguments(m) self.outputs = substitute_values(self.outputs, values) self.capture = kwargs.get('capture', False) if self.capture and len(self.outputs) != 1: raise InvalidArguments('Capturing can only output to a single file.') self.console = kwargs.get('console', False) if not isinstance(self.console, bool): raise InvalidArguments('"console" kwarg only accepts booleans') if self.capture and self.console: raise InvalidArguments("Can't both capture output and output to console") if 'command' not in kwargs: raise InvalidArguments('Missing keyword argument "command".') if 'depfile' in kwargs: depfile = kwargs['depfile'] if not isinstance(depfile, str): raise InvalidArguments('Depfile must be a string.') if os.path.basename(depfile) != depfile: raise InvalidArguments('Depfile must be a plain filename without a subdirectory.') self.depfile = depfile self.command = self.flatten_command(kwargs['command']) if self.capture: for c in self.command: if isinstance(c, str) and '@OUTPUT@' in c: raise InvalidArguments('@OUTPUT@ is not allowed when capturing output.') if 'install' in kwargs: self.install = kwargs['install'] if not isinstance(self.install, bool): raise InvalidArguments('"install" must be boolean.') if self.install: if 'install_dir' not in kwargs: raise InvalidArguments('"install_dir" must be specified ' 'when installing a target') if isinstance(kwargs['install_dir'], list): FeatureNew('multiple install_dir for custom_target', '0.40.0').use(self.subproject) # If an item in this list is False, the output corresponding to # the list index of that item will not be installed self.install_dir = typeslistify(kwargs['install_dir'], (str, bool)) self.install_mode = kwargs.get('install_mode', None) else: self.install = False self.install_dir = [None] self.install_mode = None if 'build_always' in kwargs and 'build_always_stale' in kwargs: raise InvalidArguments('build_always and build_always_stale are mutually exclusive. Combine build_by_default and build_always_stale.') elif 'build_always' in kwargs: mlog.deprecation('build_always is deprecated. Combine build_by_default and build_always_stale instead.') if 'build_by_default' not in kwargs: self.build_by_default = kwargs['build_always'] self.build_always_stale = kwargs['build_always'] elif 'build_always_stale' in kwargs: self.build_always_stale = kwargs['build_always_stale'] if not isinstance(self.build_always_stale, bool): raise InvalidArguments('Argument build_always_stale must be a boolean.') extra_deps, depend_files = extract_as_list(kwargs, 'depends', 'depend_files', pop = False) for ed in extra_deps: while hasattr(ed, 'held_object'): ed = ed.held_object if not isinstance(ed, (CustomTarget, BuildTarget)): raise InvalidArguments('Can only depend on toplevel targets: custom_target or build_target (executable or a library) got: %s(%s)' % (type(ed), ed)) self.extra_depends.append(ed) for i in depend_files: if isinstance(i, (File, str)): self.depend_files.append(i) else: mlog.debug(i) raise InvalidArguments('Unknown type {!r} in depend_files.'.format(type(i).__name__)) def get_dependencies(self): return self.dependencies def should_install(self): return self.install def get_custom_install_dir(self): return self.install_dir def get_custom_install_mode(self): return self.install_mode def get_outputs(self): return self.outputs def get_filename(self): return self.outputs[0] def get_sources(self): return self.sources def get_generated_lists(self): genlists = [] for c in self.sources: if hasattr(c, 'held_object'): c = c.held_object if isinstance(c, GeneratedList): genlists.append(c) return genlists def get_generated_sources(self): return self.get_generated_lists() def get_dep_outname(self, infilenames): if self.depfile is None: raise InvalidArguments('Tried to get depfile name for custom_target that does not have depfile defined.') if len(infilenames): plainname = os.path.basename(infilenames[0]) basename = os.path.splitext(plainname)[0] return self.depfile.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) else: if '@BASENAME@' in self.depfile or '@PLAINNAME@' in self.depfile: raise InvalidArguments('Substitution in depfile for custom_target that does not have an input file.') return self.depfile def is_linkable_target(self): if len(self.outputs) != 1: return False suf = os.path.splitext(self.outputs[0])[-1] if suf == '.a' or suf == '.dll' or suf == '.lib' or suf == '.so': return True def get_link_deps_mapping(self, prefix, environment): return {} def get_link_dep_subdirs(self): return OrderedSet() def get_all_link_deps(self): return [] def type_suffix(self): return "@cus" def __getitem__(self, index): return CustomTargetIndex(self, self.outputs[index]) def __setitem__(self, index, value): raise NotImplementedError def __delitem__(self, index): raise NotImplementedError class RunTarget(Target): def __init__(self, name, command, args, dependencies, subdir, subproject): self.typename = 'run' # These don't produce output artifacts super().__init__(name, subdir, subproject, False, MachineChoice.BUILD) self.command = command self.args = args self.dependencies = dependencies 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 def get_generated_sources(self): return [] def get_sources(self): return [] def should_install(self): return False def get_filename(self): return self.name def get_outputs(self): if isinstance(self.name, str): return [self.name] elif isinstance(self.name, list): return self.name else: raise RuntimeError('RunTarget: self.name is neither a list nor a string. This is a bug') def type_suffix(self): return "@run" class AliasTarget(RunTarget): def __init__(self, name, dependencies, subdir, subproject): super().__init__(name, '', [], dependencies, subdir, subproject) class Jar(BuildTarget): known_kwargs = known_jar_kwargs def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs): self.typename = 'jar' super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) for s in self.sources: if not s.endswith('.java'): raise InvalidArguments('Jar source %s is not a java file.' % s) for t in self.link_targets: if not isinstance(t, Jar): raise InvalidArguments('Link target %s is not a jar target.' % t) self.filename = self.name + '.jar' self.outputs = [self.filename] self.java_args = kwargs.get('java_args', []) def get_main_class(self): return self.main_class def type_suffix(self): return "@jar" def get_java_args(self): return self.java_args def validate_install(self, environment): # All jar targets are installable. pass def is_linkable_target(self): return True def get_classpath_args(self): cp_paths = [os.path.join(l.get_subdir(), l.get_filename()) for l in self.link_targets] cp_string = os.pathsep.join(cp_paths) if cp_string: return ['-cp', os.pathsep.join(cp_paths)] return [] class CustomTargetIndex: """A special opaque object returned by indexing a CustomTarget. This object exists in meson, but acts as a proxy in the backends, making targets depend on the CustomTarget it's derived from, but only adding one source file to the sources. """ def __init__(self, target, output): self.typename = 'custom' self.target = target self.output = output self.for_machine = target.for_machine def __repr__(self): return ''.format( self.target, self.target.get_outputs().index(self.output)) def get_outputs(self): return [self.output] def get_subdir(self): return self.target.get_subdir() def get_filename(self): return self.output def get_id(self): return self.target.get_id() def get_all_link_deps(self): return self.target.get_all_link_deps() def get_link_deps_mapping(self, prefix, environment): return self.target.get_link_deps_mapping(prefix, environment) def get_link_dep_subdirs(self): return self.target.get_link_dep_subdirs() def is_linkable_target(self): suf = os.path.splitext(self.output)[-1] if suf == '.a' or suf == '.dll' or suf == '.lib' or suf == '.so': return True class ConfigureFile: def __init__(self, subdir, sourcename, targetname, configuration_data): self.subdir = subdir self.sourcename = sourcename self.targetname = targetname self.configuration_data = configuration_data def __repr__(self): repr_str = "<{0}: {1} -> {2}>" src = os.path.join(self.subdir, self.sourcename) dst = os.path.join(self.subdir, self.targetname) return repr_str.format(self.__class__.__name__, src, dst) def get_configuration_data(self): return self.configuration_data def get_subdir(self): return self.subdir def get_source_name(self): return self.sourcename def get_target_name(self): return self.targetname class ConfigurationData: def __init__(self): super().__init__() self.values = {} def __repr__(self): return repr(self.values) def __contains__(self, value): return value in self.values def get(self, name): return self.values[name] # (val, desc) def keys(self): return self.values.keys() # A bit poorly named, but this represents plain data files to copy # during install. class Data: def __init__(self, sources, install_dir, install_mode=None, rename=None): self.sources = sources self.install_dir = install_dir self.install_mode = install_mode self.sources = listify(self.sources) for s in self.sources: assert(isinstance(s, File)) if rename is None: self.rename = [os.path.basename(f.fname) for f in self.sources] else: self.rename = stringlistify(rename) if len(self.rename) != len(self.sources): raise MesonException('Size of rename argument is different from number of sources') class RunScript(dict): def __init__(self, script, args): super().__init__() assert(isinstance(script, list)) assert(isinstance(args, list)) self['exe'] = script self['args'] = args class TestSetup: def __init__(self, exe_wrapper: T.Optional[T.List[str]], gdb: bool, timeout_multiplier: int, env: EnvironmentVariables): self.exe_wrapper = exe_wrapper self.gdb = gdb self.timeout_multiplier = timeout_multiplier self.env = env def get_sources_string_names(sources, backend): ''' For the specified list of @sources which can be strings, Files, or targets, get all the output basenames. ''' names = [] for s in sources: if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, str): names.append(s) elif isinstance(s, (BuildTarget, CustomTarget, CustomTargetIndex, GeneratedList)): names += s.get_outputs() elif isinstance(s, ExtractedObjects): names += s.get_outputs(backend) elif isinstance(s, File): names.append(s.fname) else: raise AssertionError('Unknown source type: {!r}'.format(s)) return names def load(build_dir: str) -> Build: filename = os.path.join(build_dir, 'meson-private', 'build.dat') load_fail_msg = 'Build data file {!r} is corrupted. Try with a fresh build tree.'.format(filename) nonexisting_fail_msg = 'No such build data file as "{!r}".'.format(filename) try: with open(filename, 'rb') as f: obj = pickle.load(f) except FileNotFoundError: raise MesonException(nonexisting_fail_msg) except (pickle.UnpicklingError, EOFError): raise MesonException(load_fail_msg) except AttributeError: raise MesonException( "Build data file {!r} references functions or classes that don't " "exist. This probably means that it was generated with an old " "version of meson. Try running from the source directory " "meson {} --wipe".format(filename, build_dir)) if not isinstance(obj, Build): raise MesonException(load_fail_msg) return obj def save(obj, filename): with open(filename, 'wb') as f: pickle.dump(obj, f) meson-0.53.2/mesonbuild/cmake/0000755000175000017500000000000013625242354017543 5ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/cmake/__init__.py0000644000175000017500000000234513612411367021656 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. __all__ = [ 'CMakeClient', 'CMakeExecutor', 'CMakeException', 'CMakeFileAPI', 'CMakeInterpreter', 'CMakeTarget', 'CMakeTraceLine', 'CMakeTraceParser', 'parse_generator_expressions', 'language_map', ] from .common import CMakeException from .client import CMakeClient from .executor import CMakeExecutor from .fileapi import CMakeFileAPI from .generator import parse_generator_expressions from .interpreter import CMakeInterpreter, language_map from .traceparser import CMakeTarget, CMakeTraceLine, CMakeTraceParser meson-0.53.2/mesonbuild/cmake/client.py0000644000175000017500000003166313612313307021375 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. from .common import CMakeException, CMakeConfiguration, CMakeBuildFile from .executor import CMakeExecutor from ..environment import Environment from ..mesonlib import MachineChoice from .. import mlog from contextlib import contextmanager from subprocess import Popen, PIPE, TimeoutExpired import typing as T import json import os CMAKE_SERVER_BEGIN_STR = '[== "CMake Server" ==[' CMAKE_SERVER_END_STR = ']== "CMake Server" ==]' CMAKE_MESSAGE_TYPES = { 'error': ['cookie', 'errorMessage'], 'hello': ['supportedProtocolVersions'], 'message': ['cookie', 'message'], 'progress': ['cookie'], 'reply': ['cookie', 'inReplyTo'], 'signal': ['cookie', 'name'], } CMAKE_REPLY_TYPES = { 'handshake': [], 'configure': [], 'compute': [], 'cmakeInputs': ['buildFiles', 'cmakeRootDirectory', 'sourceDirectory'], 'codemodel': ['configurations'] } # Base CMake server message classes class MessageBase: def __init__(self, msg_type: str, cookie: str): self.type = msg_type self.cookie = cookie def to_dict(self) -> dict: return {'type': self.type, 'cookie': self.cookie} def log(self) -> None: mlog.warning('CMake server message of type', mlog.bold(type(self).__name__), 'has no log function') class RequestBase(MessageBase): cookie_counter = 0 def __init__(self, msg_type: str): super().__init__(msg_type, self.gen_cookie()) @staticmethod def gen_cookie(): RequestBase.cookie_counter += 1 return 'meson_{}'.format(RequestBase.cookie_counter) class ReplyBase(MessageBase): def __init__(self, cookie: str, in_reply_to: str): super().__init__('reply', cookie) self.in_reply_to = in_reply_to class SignalBase(MessageBase): def __init__(self, cookie: str, signal_name: str): super().__init__('signal', cookie) self.signal_name = signal_name def log(self) -> None: mlog.log(mlog.bold('CMake signal:'), mlog.yellow(self.signal_name)) # Special Message classes class Error(MessageBase): def __init__(self, cookie: str, message: str): super().__init__('error', cookie) self.message = message def log(self) -> None: mlog.error(mlog.bold('CMake server error:'), mlog.red(self.message)) class Message(MessageBase): def __init__(self, cookie: str, message: str): super().__init__('message', cookie) self.message = message def log(self) -> None: #mlog.log(mlog.bold('CMake:'), self.message) pass class Progress(MessageBase): def __init__(self, cookie: str): super().__init__('progress', cookie) def log(self) -> None: pass class MessageHello(MessageBase): def __init__(self, supported_protocol_versions: T.List[dict]): super().__init__('hello', '') self.supported_protocol_versions = supported_protocol_versions def supports(self, major: int, minor: T.Optional[int] = None) -> bool: for i in self.supported_protocol_versions: if major == i['major']: if minor is None or minor == i['minor']: return True return False # Request classes class RequestHandShake(RequestBase): def __init__(self, src_dir: str, build_dir: str, generator: str, vers_major: int, vers_minor: T.Optional[int] = None): super().__init__('handshake') self.src_dir = src_dir self.build_dir = build_dir self.generator = generator self.vers_major = vers_major self.vers_minor = vers_minor def to_dict(self) -> dict: vers = {'major': self.vers_major} if self.vers_minor is not None: vers['minor'] = self.vers_minor # Old CMake versions (3.7) want '/' even on Windows src_list = os.path.normpath(self.src_dir).split(os.sep) bld_list = os.path.normpath(self.build_dir).split(os.sep) return { **super().to_dict(), 'sourceDirectory': '/'.join(src_list), 'buildDirectory': '/'.join(bld_list), 'generator': self.generator, 'protocolVersion': vers } class RequestConfigure(RequestBase): def __init__(self, args: T.Optional[T.List[str]] = None): super().__init__('configure') self.args = args def to_dict(self) -> dict: res = super().to_dict() if self.args: res['cacheArguments'] = self.args return res class RequestCompute(RequestBase): def __init__(self): super().__init__('compute') class RequestCMakeInputs(RequestBase): def __init__(self): super().__init__('cmakeInputs') class RequestCodeModel(RequestBase): def __init__(self): super().__init__('codemodel') # Reply classes class ReplyHandShake(ReplyBase): def __init__(self, cookie: str): super().__init__(cookie, 'handshake') class ReplyConfigure(ReplyBase): def __init__(self, cookie: str): super().__init__(cookie, 'configure') class ReplyCompute(ReplyBase): def __init__(self, cookie: str): super().__init__(cookie, 'compute') class ReplyCMakeInputs(ReplyBase): def __init__(self, cookie: str, cmake_root: str, src_dir: str, build_files: T.List[CMakeBuildFile]): super().__init__(cookie, 'cmakeInputs') self.cmake_root = cmake_root self.src_dir = src_dir self.build_files = build_files def log(self) -> None: mlog.log('CMake root: ', mlog.bold(self.cmake_root)) mlog.log('Source dir: ', mlog.bold(self.src_dir)) mlog.log('Build files:', mlog.bold(str(len(self.build_files)))) with mlog.nested(): for i in self.build_files: mlog.log(str(i)) class ReplyCodeModel(ReplyBase): def __init__(self, data: dict): super().__init__(data['cookie'], 'codemodel') self.configs = [] for i in data['configurations']: self.configs += [CMakeConfiguration(i)] def log(self) -> None: mlog.log('CMake code mode:') for idx, i in enumerate(self.configs): mlog.log('Configuration {}:'.format(idx)) with mlog.nested(): i.log() # Main client class class CMakeClient: def __init__(self, env: Environment): self.env = env self.proc = None self.type_map = { 'error': lambda data: Error(data['cookie'], data['errorMessage']), 'hello': lambda data: MessageHello(data['supportedProtocolVersions']), 'message': lambda data: Message(data['cookie'], data['message']), 'progress': lambda data: Progress(data['cookie']), 'reply': self.resolve_type_reply, 'signal': lambda data: SignalBase(data['cookie'], data['name']) } self.reply_map = { 'handshake': lambda data: ReplyHandShake(data['cookie']), 'configure': lambda data: ReplyConfigure(data['cookie']), 'compute': lambda data: ReplyCompute(data['cookie']), 'cmakeInputs': self.resolve_reply_cmakeInputs, 'codemodel': lambda data: ReplyCodeModel(data), } def readMessageRaw(self) -> dict: assert(self.proc is not None) rawData = [] begin = False while self.proc.poll() is None: line = self.proc.stdout.readline() if not line: break line = line.decode('utf-8') line = line.strip() if begin and line == CMAKE_SERVER_END_STR: break # End of the message elif begin: rawData += [line] elif line == CMAKE_SERVER_BEGIN_STR: begin = True # Begin of the message if rawData: return json.loads('\n'.join(rawData)) raise CMakeException('Failed to read data from the CMake server') def readMessage(self) -> MessageBase: raw_data = self.readMessageRaw() if 'type' not in raw_data: raise CMakeException('The "type" attribute is missing from the message') msg_type = raw_data['type'] func = self.type_map.get(msg_type, None) if not func: raise CMakeException('Recieved unknown message type "{}"'.format(msg_type)) for i in CMAKE_MESSAGE_TYPES[msg_type]: if i not in raw_data: raise CMakeException('Key "{}" is missing from CMake server message type {}'.format(i, msg_type)) return func(raw_data) def writeMessage(self, msg: MessageBase) -> None: raw_data = '\n{}\n{}\n{}\n'.format(CMAKE_SERVER_BEGIN_STR, json.dumps(msg.to_dict(), indent=2), CMAKE_SERVER_END_STR) self.proc.stdin.write(raw_data.encode('ascii')) self.proc.stdin.flush() def query(self, request: RequestBase) -> MessageBase: self.writeMessage(request) while True: reply = self.readMessage() if reply.cookie == request.cookie and reply.type in ['reply', 'error']: return reply reply.log() def query_checked(self, request: RequestBase, message: str) -> ReplyBase: reply = self.query(request) h = mlog.green('SUCCEEDED') if reply.type == 'reply' else mlog.red('FAILED') mlog.log(message + ':', h) if reply.type != 'reply': reply.log() raise CMakeException('CMake server query failed') return reply def do_handshake(self, src_dir: str, build_dir: str, generator: str, vers_major: int, vers_minor: T.Optional[int] = None) -> None: # CMake prints the hello message on startup msg = self.readMessage() if not isinstance(msg, MessageHello): raise CMakeException('Recieved an unexpected message from the CMake server') request = RequestHandShake(src_dir, build_dir, generator, vers_major, vers_minor) self.query_checked(request, 'CMake server handshake') def resolve_type_reply(self, data: dict) -> ReplyBase: reply_type = data['inReplyTo'] func = self.reply_map.get(reply_type, None) if not func: raise CMakeException('Recieved unknown reply type "{}"'.format(reply_type)) for i in ['cookie'] + CMAKE_REPLY_TYPES[reply_type]: if i not in data: raise CMakeException('Key "{}" is missing from CMake server message type {}'.format(i, type)) return func(data) def resolve_reply_cmakeInputs(self, data: dict) -> ReplyCMakeInputs: files = [] for i in data['buildFiles']: for j in i['sources']: files += [CMakeBuildFile(j, i['isCMake'], i['isTemporary'])] return ReplyCMakeInputs(data['cookie'], data['cmakeRootDirectory'], data['sourceDirectory'], files) @contextmanager def connect(self): self.startup() try: yield finally: self.shutdown() def startup(self) -> None: if self.proc is not None: raise CMakeException('The CMake server was already started') for_machine = MachineChoice.HOST # TODO make parameter cmake_exe = CMakeExecutor(self.env, '>=3.7', for_machine) if not cmake_exe.found(): raise CMakeException('Unable to find CMake') mlog.debug('Starting CMake server with CMake', mlog.bold(' '.join(cmake_exe.get_command())), 'version', mlog.cyan(cmake_exe.version())) self.proc = Popen(cmake_exe.get_command() + ['-E', 'server', '--experimental', '--debug'], stdin=PIPE, stdout=PIPE) def shutdown(self) -> None: if self.proc is None: return mlog.debug('Shutting down the CMake server') # Close the pipes to exit self.proc.stdin.close() self.proc.stdout.close() # Wait for CMake to finish try: self.proc.wait(timeout=2) except TimeoutExpired: # Terminate CMake if there is a timeout # terminate() may throw a platform specific exception if the process has already # terminated. This may be the case if there is a race condition (CMake exited after # the timeout but before the terminate() call). Additionally, this behavior can # also be triggered on cygwin if CMake crashes. # See https://github.com/mesonbuild/meson/pull/4969#issuecomment-499413233 try: self.proc.terminate() except Exception: pass self.proc = None meson-0.53.2/mesonbuild/cmake/common.py0000644000175000017500000001470713612313307021407 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. from ..mesonlib import MesonException from .. import mlog import typing as T class CMakeException(MesonException): pass class CMakeBuildFile: def __init__(self, file: str, is_cmake: bool, is_temp: bool): self.file = file self.is_cmake = is_cmake self.is_temp = is_temp def __repr__(self): return '<{}: {}; cmake={}; temp={}>'.format(self.__class__.__name__, self.file, self.is_cmake, self.is_temp) def _flags_to_list(raw: str) -> T.List[str]: # Convert a raw commandline string into a list of strings res = [] curr = '' escape = False in_string = False for i in raw: if escape: # If the current char is not a quote, the '\' is probably important if i not in ['"', "'"]: curr += '\\' curr += i escape = False elif i == '\\': escape = True elif i in ['"', "'"]: in_string = not in_string elif i in [' ', '\n']: if in_string: curr += i else: res += [curr] curr = '' else: curr += i res += [curr] res = list(filter(lambda x: len(x) > 0, res)) return res class CMakeFileGroup: def __init__(self, data: dict): self.defines = data.get('defines', '') self.flags = _flags_to_list(data.get('compileFlags', '')) self.includes = data.get('includePath', []) self.is_generated = data.get('isGenerated', False) self.language = data.get('language', 'C') self.sources = data.get('sources', []) # Fix the include directories tmp = [] for i in self.includes: if isinstance(i, dict) and 'path' in i: i['isSystem'] = i.get('isSystem', False) tmp += [i] elif isinstance(i, str): tmp += [{'path': i, 'isSystem': False}] self.includes = tmp def log(self) -> None: mlog.log('flags =', mlog.bold(', '.join(self.flags))) mlog.log('defines =', mlog.bold(', '.join(self.defines))) mlog.log('includes =', mlog.bold(', '.join(self.includes))) mlog.log('is_generated =', mlog.bold('true' if self.is_generated else 'false')) mlog.log('language =', mlog.bold(self.language)) mlog.log('sources:') for i in self.sources: with mlog.nested(): mlog.log(i) class CMakeTarget: def __init__(self, data: dict): self.artifacts = data.get('artifacts', []) self.src_dir = data.get('sourceDirectory', '') self.build_dir = data.get('buildDirectory', '') self.name = data.get('name', '') self.full_name = data.get('fullName', '') self.install = data.get('hasInstallRule', False) self.install_paths = list(set(data.get('installPaths', []))) self.link_lang = data.get('linkerLanguage', '') self.link_libraries = _flags_to_list(data.get('linkLibraries', '')) self.link_flags = _flags_to_list(data.get('linkFlags', '')) self.link_lang_flags = _flags_to_list(data.get('linkLanguageFlags', '')) # self.link_path = data.get('linkPath', '') self.type = data.get('type', 'EXECUTABLE') # self.is_generator_provided = data.get('isGeneratorProvided', False) self.files = [] for i in data.get('fileGroups', []): self.files += [CMakeFileGroup(i)] def log(self) -> None: mlog.log('artifacts =', mlog.bold(', '.join(self.artifacts))) mlog.log('src_dir =', mlog.bold(self.src_dir)) mlog.log('build_dir =', mlog.bold(self.build_dir)) mlog.log('name =', mlog.bold(self.name)) mlog.log('full_name =', mlog.bold(self.full_name)) mlog.log('install =', mlog.bold('true' if self.install else 'false')) mlog.log('install_paths =', mlog.bold(', '.join(self.install_paths))) mlog.log('link_lang =', mlog.bold(self.link_lang)) mlog.log('link_libraries =', mlog.bold(', '.join(self.link_libraries))) mlog.log('link_flags =', mlog.bold(', '.join(self.link_flags))) mlog.log('link_lang_flags =', mlog.bold(', '.join(self.link_lang_flags))) # mlog.log('link_path =', mlog.bold(self.link_path)) mlog.log('type =', mlog.bold(self.type)) # mlog.log('is_generator_provided =', mlog.bold('true' if self.is_generator_provided else 'false')) for idx, i in enumerate(self.files): mlog.log('Files {}:'.format(idx)) with mlog.nested(): i.log() class CMakeProject: def __init__(self, data: dict): self.src_dir = data.get('sourceDirectory', '') self.build_dir = data.get('buildDirectory', '') self.name = data.get('name', '') self.targets = [] for i in data.get('targets', []): self.targets += [CMakeTarget(i)] def log(self) -> None: mlog.log('src_dir =', mlog.bold(self.src_dir)) mlog.log('build_dir =', mlog.bold(self.build_dir)) mlog.log('name =', mlog.bold(self.name)) for idx, i in enumerate(self.targets): mlog.log('Target {}:'.format(idx)) with mlog.nested(): i.log() class CMakeConfiguration: def __init__(self, data: dict): self.name = data.get('name', '') self.projects = [] for i in data.get('projects', []): self.projects += [CMakeProject(i)] def log(self) -> None: mlog.log('name =', mlog.bold(self.name)) for idx, i in enumerate(self.projects): mlog.log('Project {}:'.format(idx)) with mlog.nested(): i.log() meson-0.53.2/mesonbuild/cmake/data/0000755000175000017500000000000013625242354020454 5ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/cmake/data/preload.cmake0000644000175000017500000000153313625260316023104 0ustar jpakkanejpakkane00000000000000if(MESON_PS_LOADED) return() endif() set(MESON_PS_LOADED ON) # Dummy macros that have a special meaning in the meson code macro(meson_ps_execute_delayed_calls) endmacro() macro(meson_ps_reload_vars) endmacro() # Helper macro to inspect the current CMake state macro(meson_ps_inspect_vars) set(MESON_PS_CMAKE_CURRENT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") set(MESON_PS_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") meson_ps_execute_delayed_calls() endmacro() # Override some system functions with custom code and forward the args # to the original function macro(add_custom_command) meson_ps_inspect_vars() _add_custom_command(${ARGV}) endmacro() macro(add_custom_target) meson_ps_inspect_vars() _add_custom_target(${ARGV}) endmacro() set(MESON_PS_DELAYED_CALLS add_custom_command;add_custom_target) meson_ps_reload_vars() meson-0.53.2/mesonbuild/cmake/data/run_ctgt.py0000755000175000017500000000420613571777347022677 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import argparse import subprocess import shutil import os import sys commands = [[]] SEPARATOR = ';;;' # Generate CMD parameters parser = argparse.ArgumentParser(description='Wrapper for add_custom_command') parser.add_argument('-d', '--directory', type=str, metavar='D', required=True, help='Working directory to cwd to') parser.add_argument('-o', '--outputs', nargs='+', metavar='O', required=True, help='Expected output files') parser.add_argument('-O', '--original-outputs', nargs='*', metavar='O', default=[], help='Output files expected by CMake') parser.add_argument('commands', nargs=argparse.REMAINDER, help='A "{}" seperated list of commands'.format(SEPARATOR)) # Parse args = parser.parse_args() dummy_target = None if len(args.outputs) == 1 and len(args.original_outputs) == 0: dummy_target = args.outputs[0] elif len(args.outputs) != len(args.original_outputs): print('Length of output list and original output list differ') sys.exit(1) for i in args.commands: if i == SEPARATOR: commands += [[]] continue i = i.replace('"', '') # Remove lefover quotes commands[-1] += [i] # Execute for i in commands: # Skip empty lists if not i: continue try: os.makedirs(args.directory, exist_ok=True) subprocess.run(i, cwd=args.directory, check=True) except subprocess.CalledProcessError: exit(1) if dummy_target: with open(dummy_target, 'a'): os.utime(dummy_target, None) exit(0) # Copy outputs zipped_outputs = zip(args.outputs, args.original_outputs) for expected, generated in zipped_outputs: do_copy = False if not os.path.exists(expected): if not os.path.exists(generated): print('Unable to find generated file. This can cause the build to fail:') print(generated) do_copy = False else: do_copy = True elif os.path.exists(generated): if os.path.getmtime(generated) > os.path.getmtime(expected): do_copy = True if do_copy: if os.path.exists(expected): os.remove(expected) shutil.copyfile(generated, expected) meson-0.53.2/mesonbuild/cmake/executor.py0000644000175000017500000003305513625260316021757 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. import subprocess from pathlib import Path import typing as T import re import os import shutil import ctypes import textwrap from .. import mlog, mesonlib from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice from ..environment import Environment if T.TYPE_CHECKING: from ..dependencies.base import ExternalProgram class CMakeExecutor: # The class's copy of the CMake path. Avoids having to search for it # multiple times in the same Meson invocation. class_cmakebin = PerMachine(None, None) class_cmakevers = PerMachine(None, None) class_cmake_cache = {} def __init__(self, environment: Environment, version: str, for_machine: MachineChoice, silent: bool = False): self.min_version = version self.environment = environment self.for_machine = for_machine self.cmakebin, self.cmakevers = self.find_cmake_binary(self.environment, silent=silent) if self.cmakebin is False: self.cmakebin = None return if not version_compare(self.cmakevers, self.min_version): mlog.warning( 'The version of CMake', mlog.bold(self.cmakebin.get_path()), 'is', mlog.bold(self.cmakevers), 'but version', mlog.bold(self.min_version), 'is required') self.cmakebin = None return def find_cmake_binary(self, environment: Environment, silent: bool = False) -> T.Tuple['ExternalProgram', str]: from ..dependencies.base import ExternalProgram # Create an iterator of options def search(): # Lookup in cross or machine file. potential_cmakepath = environment.binaries[self.for_machine].lookup_entry('cmake') if potential_cmakepath is not None: mlog.debug('CMake binary for %s specified from cross file, native file, or env var as %s.', self.for_machine, potential_cmakepath) yield ExternalProgram.from_entry('cmake', potential_cmakepath) # We never fallback if the user-specified option is no good, so # stop returning options. return mlog.debug('CMake binary missing from cross or native file, or env var undefined.') # Fallback on hard-coded defaults. # TODO prefix this for the cross case instead of ignoring thing. if environment.machines.matches_build_machine(self.for_machine): for potential_cmakepath in environment.default_cmake: mlog.debug('Trying a default CMake fallback at', potential_cmakepath) yield ExternalProgram(potential_cmakepath, silent=True) # Only search for CMake the first time and store the result in the class # definition if CMakeExecutor.class_cmakebin[self.for_machine] is False: mlog.debug('CMake binary for %s is cached as not found' % self.for_machine) elif CMakeExecutor.class_cmakebin[self.for_machine] is not None: mlog.debug('CMake binary for %s is cached.' % self.for_machine) else: assert CMakeExecutor.class_cmakebin[self.for_machine] is None mlog.debug('CMake binary for %s is not cached' % self.for_machine) for potential_cmakebin in search(): mlog.debug('Trying CMake binary {} for machine {} at {}' .format(potential_cmakebin.name, self.for_machine, potential_cmakebin.command)) version_if_ok = self.check_cmake(potential_cmakebin) if not version_if_ok: continue if not silent: mlog.log('Found CMake:', mlog.bold(potential_cmakebin.get_path()), '(%s)' % version_if_ok) CMakeExecutor.class_cmakebin[self.for_machine] = potential_cmakebin CMakeExecutor.class_cmakevers[self.for_machine] = version_if_ok break else: if not silent: mlog.log('Found CMake:', mlog.red('NO')) # Set to False instead of None to signify that we've already # searched for it and not found it CMakeExecutor.class_cmakebin[self.for_machine] = False CMakeExecutor.class_cmakevers[self.for_machine] = None return CMakeExecutor.class_cmakebin[self.for_machine], CMakeExecutor.class_cmakevers[self.for_machine] def check_cmake(self, cmakebin: 'ExternalProgram') -> T.Optional[str]: if not cmakebin.found(): mlog.log('Did not find CMake {!r}'.format(cmakebin.name)) return None try: p, out = Popen_safe(cmakebin.get_command() + ['--version'])[0:2] if p.returncode != 0: mlog.warning('Found CMake {!r} but couldn\'t run it' ''.format(' '.join(cmakebin.get_command()))) return None except FileNotFoundError: mlog.warning('We thought we found CMake {!r} but now it\'s not there. How odd!' ''.format(' '.join(cmakebin.get_command()))) return None except PermissionError: msg = 'Found CMake {!r} but didn\'t have permissions to run it.'.format(' '.join(cmakebin.get_command())) if not mesonlib.is_windows(): msg += '\n\nOn Unix-like systems this is often caused by scripts that are not executable.' mlog.warning(msg) return None cmvers = re.sub(r'\s*cmake version\s*', '', out.split('\n')[0]).strip() return cmvers def _cache_key(self, args: T.List[str], build_dir: str, env): fenv = frozenset(env.items()) if env is not None else None targs = tuple(args) return (self.cmakebin, targs, build_dir, fenv) def _call_real(self, args: T.List[str], build_dir: str, env) -> T.Tuple[int, str, str]: os.makedirs(build_dir, exist_ok=True) cmd = self.cmakebin.get_command() + args ret = subprocess.run(cmd, env=env, cwd=build_dir, close_fds=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False) rc = ret.returncode out = ret.stdout.decode(errors='ignore') err = ret.stderr.decode(errors='ignore') call = ' '.join(cmd) mlog.debug("Called `{}` in {} -> {}".format(call, build_dir, rc)) return rc, out, err def call(self, args: T.List[str], build_dir: str, env=None, disable_cache: bool = False): if env is None: env = os.environ if disable_cache: return self._call_real(args, build_dir, env) # First check if cached, if not call the real cmake function cache = CMakeExecutor.class_cmake_cache key = self._cache_key(args, build_dir, env) if key not in cache: cache[key] = self._call_real(args, build_dir, env) return cache[key] def call_with_fake_build(self, args: T.List[str], build_dir: str, env=None): # First check the cache cache = CMakeExecutor.class_cmake_cache key = self._cache_key(args, build_dir, env) if key in cache: return cache[key] os.makedirs(build_dir, exist_ok=True) # Try to set the correct compiler for C and C++ # This step is required to make try_compile work inside CMake fallback = os.path.realpath(__file__) # A file used as a fallback wehen everything else fails compilers = self.environment.coredata.compilers[MachineChoice.BUILD] def make_abs(exe: str, lang: str) -> str: if os.path.isabs(exe): return exe p = shutil.which(exe) if p is None: mlog.debug('Failed to find a {} compiler for CMake. This might cause CMake to fail.'.format(lang)) p = fallback return p def choose_compiler(lang: str) -> T.Tuple[str, str]: exe_list = [] if lang in compilers: exe_list = compilers[lang].get_exelist() else: try: comp_obj = self.environment.compiler_from_language(lang, MachineChoice.BUILD) if comp_obj is not None: exe_list = comp_obj.get_exelist() except Exception: pass if len(exe_list) == 1: return make_abs(exe_list[0], lang), '' elif len(exe_list) == 2: return make_abs(exe_list[1], lang), make_abs(exe_list[0], lang) else: mlog.debug('Failed to find a {} compiler for CMake. This might cause CMake to fail.'.format(lang)) return fallback, '' c_comp, c_launcher = choose_compiler('c') cxx_comp, cxx_launcher = choose_compiler('cpp') fortran_comp, fortran_launcher = choose_compiler('fortran') # on Windows, choose_compiler returns path with \ as separator - replace by / before writing to CMAKE file c_comp = c_comp.replace('\\', '/') c_launcher = c_launcher.replace('\\', '/') cxx_comp = cxx_comp.replace('\\', '/') cxx_launcher = cxx_launcher.replace('\\', '/') fortran_comp = fortran_comp.replace('\\', '/') fortran_launcher = fortran_launcher.replace('\\', '/') # Reset the CMake cache (Path(build_dir) / 'CMakeCache.txt').write_text('CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1\n') # Fake the compiler files comp_dir = Path(build_dir) / 'CMakeFiles' / self.cmakevers comp_dir.mkdir(parents=True, exist_ok=True) c_comp_file = comp_dir / 'CMakeCCompiler.cmake' cxx_comp_file = comp_dir / 'CMakeCXXCompiler.cmake' fortran_comp_file = comp_dir / 'CMakeFortranCompiler.cmake' if c_comp and not c_comp_file.is_file(): c_comp_file.write_text(textwrap.dedent('''\ # Fake CMake file to skip the boring and slow stuff set(CMAKE_C_COMPILER "{}") # Should be a valid compiler for try_compile, etc. set(CMAKE_C_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) set(CMAKE_C_COMPILER_ID "GNU") # Pretend we have found GCC set(CMAKE_COMPILER_IS_GNUCC 1) set(CMAKE_C_COMPILER_LOADED 1) set(CMAKE_C_COMPILER_WORKS TRUE) set(CMAKE_C_ABI_COMPILED TRUE) set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m) set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) set(CMAKE_SIZEOF_VOID_P "{}") '''.format(c_comp, c_launcher, ctypes.sizeof(ctypes.c_voidp)))) if cxx_comp and not cxx_comp_file.is_file(): cxx_comp_file.write_text(textwrap.dedent('''\ # Fake CMake file to skip the boring and slow stuff set(CMAKE_CXX_COMPILER "{}") # Should be a valid compiler for try_compile, etc. set(CMAKE_CXX_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) set(CMAKE_CXX_COMPILER_ID "GNU") # Pretend we have found GCC set(CMAKE_COMPILER_IS_GNUCXX 1) set(CMAKE_CXX_COMPILER_LOADED 1) set(CMAKE_CXX_COMPILER_WORKS TRUE) set(CMAKE_CXX_ABI_COMPILED TRUE) set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;mm;CPP) set(CMAKE_SIZEOF_VOID_P "{}") '''.format(cxx_comp, cxx_launcher, ctypes.sizeof(ctypes.c_voidp)))) if fortran_comp and not fortran_comp_file.is_file(): fortran_comp_file.write_text(textwrap.dedent('''\ # Fake CMake file to skip the boring and slow stuff set(CMAKE_Fortran_COMPILER "{}") # Should be a valid compiler for try_compile, etc. set(CMAKE_Fortran_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) set(CMAKE_Fortran_COMPILER_ID "GNU") # Pretend we have found GCC set(CMAKE_COMPILER_IS_GNUG77 1) set(CMAKE_Fortran_COMPILER_LOADED 1) set(CMAKE_Fortran_COMPILER_WORKS TRUE) set(CMAKE_Fortran_ABI_COMPILED TRUE) set(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95) set(CMAKE_SIZEOF_VOID_P "{}") '''.format(fortran_comp, fortran_launcher, ctypes.sizeof(ctypes.c_voidp)))) return self.call(args, build_dir, env) def found(self) -> bool: return self.cmakebin is not None def version(self) -> str: return self.cmakevers def executable_path(self) -> str: return self.cmakebin.get_path() def get_command(self): return self.cmakebin.get_command() def machine_choice(self) -> MachineChoice: return self.for_machine meson-0.53.2/mesonbuild/cmake/fileapi.py0000644000175000017500000003063213612313307021523 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from .common import CMakeException, CMakeBuildFile, CMakeConfiguration import typing as T from .. import mlog import os import json import re STRIP_KEYS = ['cmake', 'reply', 'backtrace', 'backtraceGraph', 'version'] class CMakeFileAPI: def __init__(self, build_dir: str): self.build_dir = build_dir self.api_base_dir = os.path.join(self.build_dir, '.cmake', 'api', 'v1') self.request_dir = os.path.join(self.api_base_dir, 'query', 'client-meson') self.reply_dir = os.path.join(self.api_base_dir, 'reply') self.cmake_sources = [] self.cmake_configurations = [] self.kind_resolver_map = { 'codemodel': self._parse_codemodel, 'cmakeFiles': self._parse_cmakeFiles, } def get_cmake_sources(self) -> T.List[CMakeBuildFile]: return self.cmake_sources def get_cmake_configurations(self) -> T.List[CMakeConfiguration]: return self.cmake_configurations def setup_request(self) -> None: os.makedirs(self.request_dir, exist_ok=True) query = { 'requests': [ {'kind': 'codemodel', 'version': {'major': 2, 'minor': 0}}, {'kind': 'cmakeFiles', 'version': {'major': 1, 'minor': 0}}, ] } with open(os.path.join(self.request_dir, 'query.json'), 'w') as fp: json.dump(query, fp, indent=2) def load_reply(self) -> None: if not os.path.isdir(self.reply_dir): raise CMakeException('No response from the CMake file API') files = os.listdir(self.reply_dir) root = None reg_index = re.compile(r'^index-.*\.json$') for i in files: if reg_index.match(i): root = i break if not root: raise CMakeException('Failed to find the CMake file API index') index = self._reply_file_content(root) # Load the root index index = self._strip_data(index) # Avoid loading duplicate files index = self._resolve_references(index) # Load everything index = self._strip_data(index) # Strip unused data (again for loaded files) # Debug output debug_json = os.path.normpath(os.path.join(self.build_dir, '..', 'fileAPI.json')) with open(debug_json, 'w') as fp: json.dump(index, fp, indent=2) mlog.cmd_ci_include(debug_json) # parse the JSON for i in index['objects']: assert(isinstance(i, dict)) assert('kind' in i) assert(i['kind'] in self.kind_resolver_map) self.kind_resolver_map[i['kind']](i) def _parse_codemodel(self, data: dict) -> None: assert('configurations' in data) assert('paths' in data) source_dir = data['paths']['source'] build_dir = data['paths']['build'] # The file API output differs quite a bit from the server # output. It is more flat than the server output and makes # heavy use of references. Here these references are # resolved and the resulting data structure is identical # to the CMake serve output. def helper_parse_dir(dir_entry: dict) -> T.Tuple[str, str]: src_dir = dir_entry.get('source', '.') bld_dir = dir_entry.get('build', '.') src_dir = src_dir if os.path.isabs(src_dir) else os.path.join(source_dir, src_dir) bld_dir = bld_dir if os.path.isabs(bld_dir) else os.path.join(source_dir, bld_dir) src_dir = os.path.normpath(src_dir) bld_dir = os.path.normpath(bld_dir) return src_dir, bld_dir def parse_sources(comp_group: dict, tgt: dict) -> T.Tuple[T.List[str], T.List[str], T.List[int]]: gen = [] src = [] idx = [] src_list_raw = tgt.get('sources', []) for i in comp_group.get('sourceIndexes', []): if i >= len(src_list_raw) or 'path' not in src_list_raw[i]: continue if src_list_raw[i].get('isGenerated', False): gen += [src_list_raw[i]['path']] else: src += [src_list_raw[i]['path']] idx += [i] return src, gen, idx def parse_target(tgt: dict) -> dict: src_dir, bld_dir = helper_parse_dir(cnf.get('paths', {})) # Parse install paths (if present) install_paths = [] if 'install' in tgt: prefix = tgt['install']['prefix']['path'] install_paths = [os.path.join(prefix, x['path']) for x in tgt['install']['destinations']] install_paths = list(set(install_paths)) # On the first look, it looks really nice that the CMake devs have # decided to use arrays for the linker flags. However, this feeling # soon turns into despair when you realize that there only one entry # per type in most cases, and we still have to do manual string splitting. link_flags = [] link_libs = [] for i in tgt.get('link', {}).get('commandFragments', []): if i['role'] == 'flags': link_flags += [i['fragment']] elif i['role'] == 'libraries': link_libs += [i['fragment']] elif i['role'] == 'libraryPath': link_flags += ['-L{}'.format(i['fragment'])] elif i['role'] == 'frameworkPath': link_flags += ['-F{}'.format(i['fragment'])] for i in tgt.get('archive', {}).get('commandFragments', []): if i['role'] == 'flags': link_flags += [i['fragment']] # TODO The `dependencies` entry is new in the file API. # maybe we can make use of that in addition to the # implicit dependency detection tgt_data = { 'artifacts': [x.get('path', '') for x in tgt.get('artifacts', [])], 'sourceDirectory': src_dir, 'buildDirectory': bld_dir, 'name': tgt.get('name', ''), 'fullName': tgt.get('nameOnDisk', ''), 'hasInstallRule': 'install' in tgt, 'installPaths': install_paths, 'linkerLanguage': tgt.get('link', {}).get('language', 'CXX'), 'linkLibraries': ' '.join(link_libs), # See previous comment block why we join the array 'linkFlags': ' '.join(link_flags), # See previous comment block why we join the array 'type': tgt.get('type', 'EXECUTABLE'), 'fileGroups': [], } processed_src_idx = [] for cg in tgt.get('compileGroups', []): # Again, why an array, when there is usually only one element # and arguments are separated with spaces... flags = [] for i in cg.get('compileCommandFragments', []): flags += [i['fragment']] cg_data = { 'defines': [x.get('define', '') for x in cg.get('defines', [])], 'compileFlags': ' '.join(flags), 'language': cg.get('language', 'C'), 'isGenerated': None, # Set later, flag is stored per source file 'sources': [], 'includePath': cg.get('includes', []), } normal_src, generated_src, src_idx = parse_sources(cg, tgt) if normal_src: cg_data = dict(cg_data) cg_data['isGenerated'] = False cg_data['sources'] = normal_src tgt_data['fileGroups'] += [cg_data] if generated_src: cg_data = dict(cg_data) cg_data['isGenerated'] = True cg_data['sources'] = generated_src tgt_data['fileGroups'] += [cg_data] processed_src_idx += src_idx # Object libraries have no compile groups, only source groups. # So we add all the source files to a dummy source group that were # not found in the previous loop normal_src = [] generated_src = [] for idx, src in enumerate(tgt.get('sources', [])): if idx in processed_src_idx: continue if src.get('isGenerated', False): generated_src += [src['path']] else: normal_src += [src['path']] if normal_src: tgt_data['fileGroups'] += [{ 'isGenerated': False, 'sources': normal_src, }] if generated_src: tgt_data['fileGroups'] += [{ 'isGenerated': True, 'sources': generated_src, }] return tgt_data def parse_project(pro: dict) -> dict: # Only look at the first directory specified in directoryIndexes # TODO Figure out what the other indexes are there for p_src_dir = source_dir p_bld_dir = build_dir try: p_src_dir, p_bld_dir = helper_parse_dir(cnf['directories'][pro['directoryIndexes'][0]]) except (IndexError, KeyError): pass pro_data = { 'name': pro.get('name', ''), 'sourceDirectory': p_src_dir, 'buildDirectory': p_bld_dir, 'targets': [], } for ref in pro.get('targetIndexes', []): tgt = {} try: tgt = cnf['targets'][ref] except (IndexError, KeyError): pass pro_data['targets'] += [parse_target(tgt)] return pro_data for cnf in data.get('configurations', []): cnf_data = { 'name': cnf.get('name', ''), 'projects': [], } for pro in cnf.get('projects', []): cnf_data['projects'] += [parse_project(pro)] self.cmake_configurations += [CMakeConfiguration(cnf_data)] def _parse_cmakeFiles(self, data: dict) -> None: assert('inputs' in data) assert('paths' in data) src_dir = data['paths']['source'] for i in data['inputs']: path = i['path'] path = path if os.path.isabs(path) else os.path.join(src_dir, path) self.cmake_sources += [CMakeBuildFile(path, i.get('isCMake', False), i.get('isGenerated', False))] def _strip_data(self, data: T.Any) -> T.Any: if isinstance(data, list): for idx, i in enumerate(data): data[idx] = self._strip_data(i) elif isinstance(data, dict): new = {} for key, val in data.items(): if key not in STRIP_KEYS: new[key] = self._strip_data(val) data = new return data def _resolve_references(self, data: T.Any) -> T.Any: if isinstance(data, list): for idx, i in enumerate(data): data[idx] = self._resolve_references(i) elif isinstance(data, dict): # Check for the "magic" reference entry and insert # it into the root data dict if 'jsonFile' in data: data.update(self._reply_file_content(data['jsonFile'])) for key, val in data.items(): data[key] = self._resolve_references(val) return data def _reply_file_content(self, filename: str) -> dict: real_path = os.path.join(self.reply_dir, filename) if not os.path.exists(real_path): raise CMakeException('File "{}" does not exist'.format(real_path)) with open(real_path, 'r') as fp: return json.load(fp) meson-0.53.2/mesonbuild/cmake/generator.py0000644000175000017500000001006613531533273022105 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from .. import mesonlib def parse_generator_expressions(raw: str) -> str: '''Parse CMake generator expressions Most generator expressions are simply ignored for simplicety, however some are required for some common use cases. ''' out = '' # type: str i = 0 # type: int def equal(arg: str) -> str: col_pos = arg.find(',') if col_pos < 0: return '0' else: return '1' if arg[:col_pos] == arg[col_pos + 1:] else '0' def vers_comp(op: str, arg: str) -> str: col_pos = arg.find(',') if col_pos < 0: return '0' else: return '1' if mesonlib.version_compare(arg[:col_pos], '{}{}'.format(op, arg[col_pos + 1:])) else '0' supported = { # Boolean functions 'BOOL': lambda x: '0' if x.upper() in ['0', 'FALSE', 'OFF', 'N', 'NO', 'IGNORE', 'NOTFOUND'] or x.endswith('-NOTFOUND') else '1', 'AND': lambda x: '1' if all([y == '1' for y in x.split(',')]) else '0', 'OR': lambda x: '1' if any([y == '1' for y in x.split(',')]) else '0', 'NOT': lambda x: '0' if x == '1' else '1', '0': lambda x: '', '1': lambda x: x, # String operations 'STREQUAL': equal, 'EQUAL': equal, 'VERSION_LESS': lambda x: vers_comp('<', x), 'VERSION_GREATER': lambda x: vers_comp('>', x), 'VERSION_EQUAL': lambda x: vers_comp('=', x), 'VERSION_LESS_EQUAL': lambda x: vers_comp('<=', x), 'VERSION_GREATER_EQUAL': lambda x: vers_comp('>=', x), # String modification 'LOWER_CASE': lambda x: x.lower(), 'UPPER_CASE': lambda x: x.upper(), # Always assume the BUILD_INTERFACE is valid. # INSTALL_INTERFACE is always invalid for subprojects and # it should also never appear in CMake config files, used # for dependencies 'INSTALL_INTERFACE': lambda x: '', 'BUILD_INTERFACE': lambda x: x, # Constants 'ANGLE-R': lambda x: '>', 'COMMA': lambda x: ',', 'SEMICOLON': lambda x: ';', } # Recursively evaluate generator expressions def eval_generator_expressions() -> str: nonlocal i i += 2 func = '' # type: str args = '' # type: str res = '' # type: str exp = '' # type: str # Determine the body of the expression while i < len(raw): if raw[i] == '>': # End of the generator expression break elif i < len(raw) - 1 and raw[i] == '$' and raw[i + 1] == '<': # Nested generator expression exp += eval_generator_expressions() else: # Generator expression body exp += raw[i] i += 1 # Split the expression into a function and arguments part col_pos = exp.find(':') if col_pos < 0: func = exp else: func = exp[:col_pos] args = exp[col_pos + 1:] func = func.strip() args = args.strip() # Evaluate the function if func in supported: res = supported[func](args) return res while i < len(raw): if i < len(raw) - 1 and raw[i] == '$' and raw[i + 1] == '<': # Generator expression detected --> try resolving it out += eval_generator_expressions() else: # Normal string, leave unchanged out += raw[i] i += 1 return out meson-0.53.2/mesonbuild/cmake/interpreter.py0000644000175000017500000015434613625260316022473 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. from .common import CMakeException, CMakeTarget from .client import CMakeClient, RequestCMakeInputs, RequestConfigure, RequestCompute, RequestCodeModel from .fileapi import CMakeFileAPI from .executor import CMakeExecutor from .traceparser import CMakeTraceParser, CMakeGeneratorTarget from .. import mlog from ..environment import Environment from ..mesonlib import MachineChoice, version_compare from ..compilers.compilers import lang_suffixes, header_suffixes, obj_suffixes, lib_suffixes, is_header from subprocess import Popen, PIPE from threading import Thread from enum import Enum from functools import lru_cache from pathlib import Path import typing as T import os, re from ..mparser import ( Token, BaseNode, CodeBlockNode, FunctionNode, ArrayNode, ArgumentNode, AssignmentNode, BooleanNode, StringNode, IdNode, IndexNode, MethodNode, NumberNode, ) if T.TYPE_CHECKING: from ..build import Build from ..backend.backends import Backend # Disable all warnings automaticall enabled with --trace and friends # See https://cmake.org/cmake/help/latest/variable/CMAKE_POLICY_WARNING_CMPNNNN.html disable_policy_warnings = [ 'CMP0025', 'CMP0047', 'CMP0056', 'CMP0060', 'CMP0065', 'CMP0066', 'CMP0067', 'CMP0082', 'CMP0089', ] backend_generator_map = { 'ninja': 'Ninja', 'xcode': 'Xcode', 'vs2010': 'Visual Studio 10 2010', 'vs2015': 'Visual Studio 15 2017', 'vs2017': 'Visual Studio 15 2017', 'vs2019': 'Visual Studio 16 2019', } language_map = { 'c': 'C', 'cpp': 'CXX', 'cuda': 'CUDA', 'objc': 'OBJC', 'objcpp': 'OBJCXX', 'cs': 'CSharp', 'java': 'Java', 'fortran': 'Fortran', 'swift': 'Swift', } target_type_map = { 'STATIC_LIBRARY': 'static_library', 'MODULE_LIBRARY': 'shared_module', 'SHARED_LIBRARY': 'shared_library', 'EXECUTABLE': 'executable', 'OBJECT_LIBRARY': 'static_library', 'INTERFACE_LIBRARY': 'header_only' } skip_targets = ['UTILITY'] blacklist_compiler_flags = [ '-Wall', '-Wextra', '-Weverything', '-Werror', '-Wpedantic', '-pedantic', '-w', '/W1', '/W2', '/W3', '/W4', '/Wall', '/WX', '/w', '/O1', '/O2', '/Ob', '/Od', '/Og', '/Oi', '/Os', '/Ot', '/Ox', '/Oy', '/Ob0', '/RTC1', '/RTCc', '/RTCs', '/RTCu', '/Z7', '/Zi', '/ZI', ] blacklist_link_flags = [ '/machine:x64', '/machine:x86', '/machine:arm', '/machine:ebc', '/debug', '/debug:fastlink', '/debug:full', '/debug:none', '/incremental', ] blacklist_clang_cl_link_flags = ['/GR', '/EHsc', '/MDd', '/Zi', '/RTC1'] blacklist_link_libs = [ 'kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'comdlg32.lib', 'advapi32.lib' ] transfer_dependencies_from = ['header_only'] _cmake_name_regex = re.compile(r'[^_a-zA-Z0-9]') def _sanitize_cmake_name(name: str) -> str: name = _cmake_name_regex.sub('_', name) return 'cm_' + name class OutputTargetMap: rm_so_version = re.compile(r'(\.[0-9]+)+$') def __init__(self, build_dir: str): self.tgt_map = {} self.build_dir = build_dir def add(self, tgt: T.Union['ConverterTarget', 'ConverterCustomTarget']) -> None: def assign_keys(keys: T.List[str]) -> None: for i in [x for x in keys if x]: self.tgt_map[i] = tgt keys = [self._target_key(tgt.cmake_name)] if isinstance(tgt, ConverterTarget): keys += [tgt.full_name] keys += [self._rel_artifact_key(x) for x in tgt.artifacts] keys += [self._base_artifact_key(x) for x in tgt.artifacts] if isinstance(tgt, ConverterCustomTarget): keys += [self._rel_generated_file_key(x) for x in tgt.original_outputs] keys += [self._base_generated_file_key(x) for x in tgt.original_outputs] assign_keys(keys) def _return_first_valid_key(self, keys: T.List[str]) -> T.Optional[T.Union['ConverterTarget', 'ConverterCustomTarget']]: for i in keys: if i and i in self.tgt_map: return self.tgt_map[i] return None def target(self, name: str) -> T.Optional[T.Union['ConverterTarget', 'ConverterCustomTarget']]: return self._return_first_valid_key([self._target_key(name)]) def artifact(self, name: str) -> T.Optional[T.Union['ConverterTarget', 'ConverterCustomTarget']]: keys = [] candidates = [name, OutputTargetMap.rm_so_version.sub('', name)] for i in lib_suffixes: if not name.endswith('.' + i): continue new_name = name[:-len(i) - 1] new_name = OutputTargetMap.rm_so_version.sub('', new_name) candidates += ['{}.{}'.format(new_name, i)] for i in candidates: keys += [self._rel_artifact_key(i), os.path.basename(i), self._base_artifact_key(i)] return self._return_first_valid_key(keys) def generated(self, name: str) -> T.Optional[T.Union['ConverterTarget', 'ConverterCustomTarget']]: return self._return_first_valid_key([self._rel_generated_file_key(name), self._base_generated_file_key(name)]) # Utility functions to generate local keys def _rel_path(self, fname: str) -> T.Optional[str]: fname = os.path.normpath(os.path.join(self.build_dir, fname)) if os.path.commonpath([self.build_dir, fname]) != self.build_dir: return None return os.path.relpath(fname, self.build_dir) def _target_key(self, tgt_name: str) -> str: return '__tgt_{}__'.format(tgt_name) def _rel_generated_file_key(self, fname: str) -> T.Optional[str]: path = self._rel_path(fname) return '__relgen_{}__'.format(path) if path else None def _base_generated_file_key(self, fname: str) -> str: return '__gen_{}__'.format(os.path.basename(fname)) def _rel_artifact_key(self, fname: str) -> T.Optional[str]: path = self._rel_path(fname) return '__relart_{}__'.format(path) if path else None def _base_artifact_key(self, fname: str) -> str: return '__art_{}__'.format(os.path.basename(fname)) class ConverterTarget: def __init__(self, target: CMakeTarget, env: Environment): self.env = env self.artifacts = target.artifacts self.src_dir = target.src_dir self.build_dir = target.build_dir self.name = target.name self.cmake_name = target.name self.full_name = target.full_name self.type = target.type self.install = target.install self.install_dir = '' self.link_libraries = target.link_libraries self.link_flags = target.link_flags + target.link_lang_flags self.depends_raw = [] self.depends = [] if target.install_paths: self.install_dir = target.install_paths[0] self.languages = [] self.sources = [] self.generated = [] self.includes = [] self.sys_includes = [] self.link_with = [] self.object_libs = [] self.compile_opts = {} self.public_compile_opts = [] self.pie = False # Project default override options (c_std, cpp_std, etc.) self.override_options = [] # Convert the target name to a valid meson target name self.name = _sanitize_cmake_name(self.name) for i in target.files: # Determine the meson language 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: self.compile_opts[lang] = [] # Add arguments, but avoid duplicates args = i.flags args += ['-D{}'.format(x) for x in i.defines] self.compile_opts[lang] += [x for x in args if x not in self.compile_opts[lang]] # Handle include directories self.includes += [x['path'] for x in i.includes if x not in self.includes and not x['isSystem']] self.sys_includes += [x['path'] for x in i.includes if x not in self.sys_includes and x['isSystem']] # Add sources to the right array if i.is_generated: self.generated += i.sources else: self.sources += i.sources def __repr__(self) -> str: return '<{}: {}>'.format(self.__class__.__name__, self.name) std_regex = re.compile(r'([-]{1,2}std=|/std:v?|[-]{1,2}std:)(.*)') def postprocess(self, output_target_map: OutputTargetMap, root_src_dir: str, subdir: str, install_prefix: str, trace: CMakeTraceParser) -> None: # Detect setting the C and C++ standard for i in ['c', 'cpp']: if i not in self.compile_opts: continue temp = [] for j in self.compile_opts[i]: m = ConverterTarget.std_regex.match(j) if m: self.override_options += ['{}_std={}'.format(i, m.group(2))] elif j in ['-fPIC', '-fpic', '-fPIE', '-fpie']: self.pie = True elif j in blacklist_compiler_flags: pass else: temp += [j] self.compile_opts[i] = temp # Make sure to force enable -fPIC for OBJECT libraries if self.type.upper() == 'OBJECT_LIBRARY': self.pie = True # Use the CMake trace, if required tgt = trace.targets.get(self.cmake_name) if tgt: self.depends_raw = trace.targets[self.cmake_name].depends if self.type.upper() == 'INTERFACE_LIBRARY': props = tgt.properties self.includes += props.get('INTERFACE_INCLUDE_DIRECTORIES', []) self.public_compile_opts += props.get('INTERFACE_COMPILE_DEFINITIONS', []) self.public_compile_opts += props.get('INTERFACE_COMPILE_OPTIONS', []) self.link_flags += props.get('INTERFACE_LINK_OPTIONS', []) # TODO refactor this copy paste from CMakeDependency for future releases reg_is_lib = re.compile(r'^(-l[a-zA-Z0-9_]+|-l?pthread)$') to_process = [self.cmake_name] processed = [] while len(to_process) > 0: curr = to_process.pop(0) if curr in processed or curr not in trace.targets: continue tgt = trace.targets[curr] cfgs = [] cfg = '' otherDeps = [] libraries = [] mlog.debug(tgt) if 'INTERFACE_COMPILE_DEFINITIONS' in tgt.properties: self.public_compile_opts += ['-D' + re.sub('^-D', '', x) for x in tgt.properties['INTERFACE_COMPILE_DEFINITIONS'] if x] if 'INTERFACE_COMPILE_OPTIONS' in tgt.properties: self.public_compile_opts += [x for x in tgt.properties['INTERFACE_COMPILE_OPTIONS'] if x] if 'IMPORTED_CONFIGURATIONS' in tgt.properties: cfgs += [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x] cfg = cfgs[0] if 'CONFIGURATIONS' in tgt.properties: cfgs += [x for x in tgt.properties['CONFIGURATIONS'] if x] cfg = cfgs[0] if 'RELEASE' in cfgs: cfg = 'RELEASE' if 'IMPORTED_IMPLIB_{}'.format(cfg) in tgt.properties: libraries += [x for x in tgt.properties['IMPORTED_IMPLIB_{}'.format(cfg)] if x] elif 'IMPORTED_IMPLIB' in tgt.properties: libraries += [x for x in tgt.properties['IMPORTED_IMPLIB'] if x] elif 'IMPORTED_LOCATION_{}'.format(cfg) in tgt.properties: libraries += [x for x in tgt.properties['IMPORTED_LOCATION_{}'.format(cfg)] if x] elif 'IMPORTED_LOCATION' in tgt.properties: libraries += [x for x in tgt.properties['IMPORTED_LOCATION'] if x] if 'LINK_LIBRARIES' in tgt.properties: otherDeps += [x for x in tgt.properties['LINK_LIBRARIES'] if x] if 'INTERFACE_LINK_LIBRARIES' in tgt.properties: otherDeps += [x for x in tgt.properties['INTERFACE_LINK_LIBRARIES'] if x] if 'IMPORTED_LINK_DEPENDENT_LIBRARIES_{}'.format(cfg) in tgt.properties: otherDeps += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES_{}'.format(cfg)] if x] elif 'IMPORTED_LINK_DEPENDENT_LIBRARIES' in tgt.properties: otherDeps += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES'] if x] for j in otherDeps: if j in trace.targets: to_process += [j] elif reg_is_lib.match(j) or os.path.exists(j): libraries += [j] for j in libraries: if j not in self.link_libraries: self.link_libraries += [j] processed += [curr] elif self.type.upper() not in ['EXECUTABLE', 'OBJECT_LIBRARY']: mlog.warning('CMake: Target', mlog.bold(self.cmake_name), 'not found in CMake trace. This can lead to build errors') temp = [] for i in self.link_libraries: # Let meson handle this arcane magic if ',-rpath,' in i: continue if not os.path.isabs(i): link_with = output_target_map.artifact(i) if link_with: self.link_with += [link_with] continue temp += [i] self.link_libraries = temp # Filter out files that are not supported by the language supported = list(header_suffixes) + list(obj_suffixes) for i in self.languages: supported += list(lang_suffixes[i]) supported = ['.{}'.format(x) for x in supported] self.sources = [x for x in self.sources if any([x.endswith(y) for y in supported])] self.generated = [x for x in self.generated if any([x.endswith(y) for y in supported])] # Make paths relative def rel_path(x: str, is_header: bool, is_generated: bool) -> T.Optional[str]: if not os.path.isabs(x): x = os.path.normpath(os.path.join(self.src_dir, x)) if not os.path.exists(x) and not any([x.endswith(y) for y in obj_suffixes]) and not is_generated: mlog.warning('CMake: path', mlog.bold(x), 'does not exist.') mlog.warning(' --> Ignoring. This can lead to build errors.') return None if ( os.path.isabs(x) and os.path.commonpath([x, self.env.get_source_dir()]) == self.env.get_source_dir() and not ( os.path.commonpath([x, root_src_dir]) == root_src_dir or os.path.commonpath([x, self.env.get_build_dir()]) == self.env.get_build_dir() ) ): mlog.warning('CMake: path', mlog.bold(x), 'is inside the root project but', mlog.bold('not'), 'inside the subproject.') mlog.warning(' --> Ignoring. This can lead to build errors.') return None if os.path.isabs(x) and os.path.commonpath([x, self.env.get_build_dir()]) == self.env.get_build_dir(): if is_header: return os.path.relpath(x, os.path.join(self.env.get_build_dir(), subdir)) else: return os.path.relpath(x, root_src_dir) if os.path.isabs(x) and os.path.commonpath([x, root_src_dir]) == root_src_dir: return os.path.relpath(x, root_src_dir) return x def custom_target(x: str): ctgt = output_target_map.generated(x) if ctgt: assert(isinstance(ctgt, ConverterCustomTarget)) ref = ctgt.get_ref(x) assert(isinstance(ref, CustomTargetReference) and ref.valid()) return ref return x build_dir_rel = os.path.relpath(self.build_dir, os.path.join(self.env.get_build_dir(), subdir)) self.includes = list(set([rel_path(x, True, False) for x in set(self.includes)] + [build_dir_rel])) self.sys_includes = list(set([rel_path(x, True, False) for x in set(self.sys_includes)])) self.sources = [rel_path(x, False, False) for x in self.sources] self.generated = [rel_path(x, False, True) for x in self.generated] # Resolve custom targets self.generated = [custom_target(x) for x in self.generated] # Remove delete entries self.includes = [x for x in self.includes if x is not None] self.sys_includes = [x for x in self.sys_includes if x is not None] self.sources = [x for x in self.sources if x is not None] self.generated = [x for x in self.generated if x is not None] # Make sure '.' is always in the include directories if '.' not in self.includes: self.includes += ['.'] # make install dir relative to the install prefix if self.install_dir and os.path.isabs(self.install_dir): if os.path.commonpath([self.install_dir, install_prefix]) == install_prefix: self.install_dir = os.path.relpath(self.install_dir, install_prefix) # Remove blacklisted options and libs def check_flag(flag: str) -> bool: if flag.lower() in blacklist_link_flags or flag in blacklist_compiler_flags + blacklist_clang_cl_link_flags: return False if flag.startswith('/D'): return False return True self.link_libraries = [x for x in self.link_libraries if x.lower() not in blacklist_link_libs] self.link_flags = [x for x in self.link_flags if check_flag(x)] # Handle explicit CMake add_dependency() calls for i in self.depends_raw: tgt = output_target_map.target(i) if tgt: self.depends.append(tgt) def process_object_libs(self, obj_target_list: T.List['ConverterTarget'], linker_workaround: bool): # Try to detect the object library(s) from the generated input sources temp = [x for x in self.generated if isinstance(x, str)] temp = [os.path.basename(x) for x in temp] temp = [x for x in temp if any([x.endswith('.' + y) for y in obj_suffixes])] temp = [os.path.splitext(x)[0] for x in temp] exts = self._all_source_suffixes() # Temp now stores the source filenames of the object files for i in obj_target_list: source_files = [x for x in i.sources + i.generated if isinstance(x, str)] source_files = [os.path.basename(x) for x in source_files] for j in temp: # On some platforms (specifically looking at you Windows with vs20xy backend) CMake does # not produce object files with the format `foo.cpp.obj`, instead it skipps the language # suffix and just produces object files like `foo.obj`. Thus we have to do our best to # undo this step and guess the correct language suffix of the object file. This is done # by trying all language suffixes meson knows and checking if one of them fits. candidates = [j] # type: T.List[str] if not any([j.endswith('.' + x) for x in exts]): mlog.warning('Object files do not contain source file extensions, thus falling back to guessing them.', once=True) candidates += ['{}.{}'.format(j, x) for x in exts] if any([x in source_files for x in candidates]): if linker_workaround: self._append_objlib_sources(i) else: self.includes += i.includes self.includes = list(set(self.includes)) self.object_libs += [i] break # Filter out object files from the sources self.generated = [x for x in self.generated if not isinstance(x, str) or not any([x.endswith('.' + y) for y in obj_suffixes])] def _append_objlib_sources(self, tgt: 'ConverterTarget') -> None: self.includes += tgt.includes self.sources += tgt.sources self.generated += tgt.generated self.sources = list(set(self.sources)) self.generated = list(set(self.generated)) self.includes = list(set(self.includes)) # Inherit compiler arguments since they may be required for building for lang, opts in tgt.compile_opts.items(): if lang not in self.compile_opts: self.compile_opts[lang] = [] self.compile_opts[lang] += [x for x in opts if x not in self.compile_opts[lang]] @lru_cache(maxsize=None) def _all_source_suffixes(self) -> T.List[str]: suffixes = [] # type: T.List[str] for exts in lang_suffixes.values(): suffixes += [x for x in exts] return suffixes def process_inter_target_dependencies(self): # Move the dependencies from all transfer_dependencies_from to the target to_process = list(self.depends) processed = [] new_deps = [] for i in to_process: processed += [i] if isinstance(i, ConverterTarget) and i.meson_func() in transfer_dependencies_from: to_process += [x for x in i.depends if x not in processed] else: new_deps += [i] self.depends = list(set(new_deps)) def cleanup_dependencies(self): # Clear the dependencies from targets that where moved from if self.meson_func() in transfer_dependencies_from: self.depends = [] def meson_func(self) -> str: return target_type_map.get(self.type.upper()) def log(self) -> None: mlog.log('Target', mlog.bold(self.name), '({})'.format(self.cmake_name)) mlog.log(' -- artifacts: ', mlog.bold(str(self.artifacts))) mlog.log(' -- full_name: ', mlog.bold(self.full_name)) mlog.log(' -- type: ', mlog.bold(self.type)) mlog.log(' -- install: ', mlog.bold('true' if self.install else 'false')) mlog.log(' -- install_dir: ', mlog.bold(self.install_dir)) mlog.log(' -- link_libraries: ', mlog.bold(str(self.link_libraries))) mlog.log(' -- link_with: ', mlog.bold(str(self.link_with))) mlog.log(' -- object_libs: ', mlog.bold(str(self.object_libs))) mlog.log(' -- link_flags: ', mlog.bold(str(self.link_flags))) mlog.log(' -- languages: ', mlog.bold(str(self.languages))) mlog.log(' -- includes: ', mlog.bold(str(self.includes))) mlog.log(' -- sys_includes: ', mlog.bold(str(self.sys_includes))) mlog.log(' -- sources: ', mlog.bold(str(self.sources))) mlog.log(' -- generated: ', mlog.bold(str(self.generated))) mlog.log(' -- pie: ', mlog.bold('true' if self.pie else 'false')) mlog.log(' -- override_opts: ', mlog.bold(str(self.override_options))) mlog.log(' -- depends: ', mlog.bold(str(self.depends))) mlog.log(' -- options:') for key, val in self.compile_opts.items(): mlog.log(' -', key, '=', mlog.bold(str(val))) class CustomTargetReference: def __init__(self, ctgt: 'ConverterCustomTarget', index: int): self.ctgt = ctgt # type: ConverterCustomTarget self.index = index # type: int def __repr__(self) -> str: if self.valid(): return '<{}: {} [{}]>'.format(self.__class__.__name__, self.ctgt.name, self.ctgt.outputs[self.index]) else: return '<{}: INVALID REFERENCE>'.format(self.__class__.__name__) def valid(self) -> bool: return self.ctgt is not None and self.index >= 0 def filename(self) -> str: return self.ctgt.outputs[self.index] class ConverterCustomTarget: tgt_counter = 0 # type: int out_counter = 0 # type: int def __init__(self, target: CMakeGeneratorTarget): assert(target.current_bin_dir is not None) assert(target.current_src_dir is not None) self.name = target.name if not self.name: self.name = 'custom_tgt_{}'.format(ConverterCustomTarget.tgt_counter) ConverterCustomTarget.tgt_counter += 1 self.cmake_name = str(self.name) self.original_outputs = list(target.outputs) self.outputs = [os.path.basename(x) for x in self.original_outputs] self.conflict_map = {} self.command = target.command self.working_dir = target.working_dir self.depends_raw = target.depends self.inputs = [] self.depends = [] self.current_bin_dir = Path(target.current_bin_dir) self.current_src_dir = Path(target.current_src_dir) # Convert the target name to a valid meson target name self.name = _sanitize_cmake_name(self.name) def __repr__(self) -> str: return '<{}: {} {}>'.format(self.__class__.__name__, self.name, self.outputs) def postprocess(self, output_target_map: OutputTargetMap, root_src_dir: str, subdir: str, all_outputs: T.List[str]) -> None: # Default the working directory to ${CMAKE_CURRENT_BINARY_DIR} if not self.working_dir: self.working_dir = self.current_bin_dir.as_posix() # relative paths in the working directory are always relative # to ${CMAKE_CURRENT_BINARY_DIR} if not os.path.isabs(self.working_dir): self.working_dir = (self.current_bin_dir / self.working_dir).as_posix() # Modify the original outputs if they are relative. Again, # relative paths are relative to ${CMAKE_CURRENT_BINARY_DIR} def ensure_absolute(x: Path) -> Path: if x.is_absolute(): return x else: return self.current_bin_dir / x self.original_outputs = [ensure_absolute(Path(x)).as_posix() for x in self.original_outputs] # Ensure that there is no duplicate output in the project so # that meson can handle cases where the same filename is # generated in multiple directories temp_outputs = [] # type: T.List[str] for i in self.outputs: if i in all_outputs: old = str(i) i = 'c{}_{}'.format(ConverterCustomTarget.out_counter, i) ConverterCustomTarget.out_counter += 1 self.conflict_map[old] = i all_outputs += [i] temp_outputs += [i] self.outputs = temp_outputs # Check if the command is a build target commands = [] for i in self.command: assert(isinstance(i, list)) cmd = [] for j in i: if not j: continue target = output_target_map.target(j) cmd += [target] if target else [j] commands += [cmd] self.command = commands # If the custom target does not declare any output, create a dummy # one that can be used as dependency. if not self.outputs: self.outputs = [self.name + '.h'] # Check dependencies and input files root = Path(root_src_dir) for i in self.depends_raw: if not i: continue raw = Path(i) art = output_target_map.artifact(i) tgt = output_target_map.target(i) gen = output_target_map.generated(i) rel_to_root = None try: rel_to_root = raw.relative_to(root) except ValueError: rel_to_root = None # First check for existing files. Only then check for existing # targets, etc. This reduces the chance of misdetecting input files # as outputs from other targets. # See https://github.com/mesonbuild/meson/issues/6632 if not raw.is_absolute() and (self.current_src_dir / raw).exists(): self.inputs += [(self.current_src_dir / raw).relative_to(root).as_posix()] elif raw.is_absolute() and raw.exists() and rel_to_root is not None: self.inputs += [rel_to_root.as_posix()] elif art: self.depends += [art] elif tgt: self.depends += [tgt] elif gen: self.inputs += [gen.get_ref(i)] def process_inter_target_dependencies(self): # Move the dependencies from all transfer_dependencies_from to the target to_process = list(self.depends) processed = [] new_deps = [] for i in to_process: processed += [i] if isinstance(i, ConverterTarget) and i.meson_func() in transfer_dependencies_from: to_process += [x for x in i.depends if x not in processed] else: new_deps += [i] self.depends = list(set(new_deps)) def get_ref(self, fname: str) -> T.Optional[CustomTargetReference]: fname = os.path.basename(fname) try: if fname in self.conflict_map: fname = self.conflict_map[fname] idx = self.outputs.index(fname) return CustomTargetReference(self, idx) except ValueError: return None def log(self) -> None: mlog.log('Custom Target', mlog.bold(self.name)) mlog.log(' -- command: ', mlog.bold(str(self.command))) mlog.log(' -- outputs: ', mlog.bold(str(self.outputs))) mlog.log(' -- conflict_map: ', mlog.bold(str(self.conflict_map))) mlog.log(' -- working_dir: ', mlog.bold(str(self.working_dir))) mlog.log(' -- depends_raw: ', mlog.bold(str(self.depends_raw))) mlog.log(' -- inputs: ', mlog.bold(str(self.inputs))) mlog.log(' -- depends: ', mlog.bold(str(self.depends))) class CMakeAPI(Enum): SERVER = 1 FILE = 2 class CMakeInterpreter: def __init__(self, build: 'Build', subdir: str, src_dir: str, install_prefix: str, env: Environment, backend: 'Backend'): assert(hasattr(backend, 'name')) self.build = build self.subdir = subdir self.src_dir = src_dir self.build_dir_rel = os.path.join(subdir, '__CMake_build') self.build_dir = os.path.join(env.get_build_dir(), self.build_dir_rel) self.install_prefix = install_prefix self.env = env self.backend_name = backend.name self.linkers = set() # type: T.Set[str] self.cmake_api = CMakeAPI.SERVER self.client = CMakeClient(self.env) self.fileapi = CMakeFileAPI(self.build_dir) # Raw CMake results self.bs_files = [] self.codemodel_configs = None self.raw_trace = None # Analysed data self.project_name = '' self.languages = [] self.targets = [] self.custom_targets = [] # type: T.List[ConverterCustomTarget] self.trace = CMakeTraceParser() self.output_target_map = OutputTargetMap(self.build_dir) # Generated meson data self.generated_targets = {} self.internal_name_map = {} def configure(self, extra_cmake_options: T.List[str]) -> None: for_machine = MachineChoice.HOST # TODO make parameter # Find CMake cmake_exe = CMakeExecutor(self.env, '>=3.7', for_machine) if not cmake_exe.found(): raise CMakeException('Unable to find CMake') preload_file = Path(__file__).resolve().parent / 'data' / 'preload.cmake' # Prefere CMAKE_PROJECT_INCLUDE over CMAKE_TOOLCHAIN_FILE if possible, # since CMAKE_PROJECT_INCLUDE was actually designed for code injection. preload_var = 'CMAKE_PROJECT_INCLUDE' if version_compare(cmake_exe.version(), '<3.15'): preload_var = 'CMAKE_TOOLCHAIN_FILE' generator = backend_generator_map[self.backend_name] cmake_args = cmake_exe.get_command() trace_args = ['--trace', '--trace-expand', '--no-warn-unused-cli'] cmcmp_args = ['-DCMAKE_POLICY_WARNING_{}=OFF'.format(x) for x in disable_policy_warnings] pload_args = ['-D{}={}'.format(preload_var, str(preload_file))] if version_compare(cmake_exe.version(), '>=3.14'): self.cmake_api = CMakeAPI.FILE self.fileapi.setup_request() # Map meson compiler to CMake variables for lang, comp in self.env.coredata.compilers[for_machine].items(): if lang not in language_map: continue self.linkers.add(comp.get_linker_id()) cmake_lang = language_map[lang] exelist = comp.get_exelist() if len(exelist) == 1: cmake_args += ['-DCMAKE_{}_COMPILER={}'.format(cmake_lang, exelist[0])] elif len(exelist) == 2: cmake_args += ['-DCMAKE_{}_COMPILER_LAUNCHER={}'.format(cmake_lang, exelist[0]), '-DCMAKE_{}_COMPILER={}'.format(cmake_lang, exelist[1])] if hasattr(comp, 'get_linker_exelist') and comp.get_id() == 'clang-cl': cmake_args += ['-DCMAKE_LINKER={}'.format(comp.get_linker_exelist()[0])] cmake_args += ['-G', generator] cmake_args += ['-DCMAKE_INSTALL_PREFIX={}'.format(self.install_prefix)] cmake_args += extra_cmake_options # Run CMake mlog.log() with mlog.nested(): mlog.log('Configuring the build directory with', mlog.bold('CMake'), 'version', mlog.cyan(cmake_exe.version())) mlog.log(mlog.bold('Running:'), ' '.join(cmake_args)) mlog.log(mlog.bold(' - build directory: '), self.build_dir) mlog.log(mlog.bold(' - source directory: '), self.src_dir) mlog.log(mlog.bold(' - trace args: '), ' '.join(trace_args)) mlog.log(mlog.bold(' - preload file: '), str(preload_file)) mlog.log(mlog.bold(' - disabled policy warnings:'), '[{}]'.format(', '.join(disable_policy_warnings))) mlog.log() os.makedirs(self.build_dir, exist_ok=True) os_env = os.environ.copy() os_env['LC_ALL'] = 'C' final_command = cmake_args + trace_args + cmcmp_args + pload_args + [self.src_dir] proc = Popen(final_command, stdout=PIPE, stderr=PIPE, cwd=self.build_dir, env=os_env) def print_stdout(): while True: line = proc.stdout.readline() if not line: break mlog.log(line.decode('utf-8').strip('\n')) proc.stdout.close() t = Thread(target=print_stdout) t.start() # Read stderr line by line and log non trace lines self.raw_trace = '' tline_start_reg = re.compile(r'^\s*(.*\.(cmake|txt))\(([0-9]+)\):\s*(\w+)\(.*$') inside_multiline_trace = False while True: line = proc.stderr.readline() if not line: break line = line.decode('utf-8') if tline_start_reg.match(line): self.raw_trace += line inside_multiline_trace = not line.endswith(' )\n') elif inside_multiline_trace: self.raw_trace += line else: mlog.warning(line.strip('\n')) proc.stderr.close() proc.wait() t.join() mlog.log() h = mlog.green('SUCCEEDED') if proc.returncode == 0 else mlog.red('FAILED') mlog.log('CMake configuration:', h) if proc.returncode != 0: raise CMakeException('Failed to configure the CMake subproject') def initialise(self, extra_cmake_options: T.List[str]) -> None: # Run configure the old way because doing it # with the server doesn't work for some reason # Additionally, the File API requires a configure anyway self.configure(extra_cmake_options) # Continue with the file API If supported if self.cmake_api is CMakeAPI.FILE: # Parse the result self.fileapi.load_reply() # Load the buildsystem file list cmake_files = self.fileapi.get_cmake_sources() self.bs_files = [x.file for x in cmake_files if not x.is_cmake and not x.is_temp] self.bs_files = [os.path.relpath(x, self.env.get_source_dir()) for x in self.bs_files] self.bs_files = list(set(self.bs_files)) # Load the codemodel configurations self.codemodel_configs = self.fileapi.get_cmake_configurations() return with self.client.connect(): generator = backend_generator_map[self.backend_name] self.client.do_handshake(self.src_dir, self.build_dir, generator, 1) # Do a second configure to initialise the server self.client.query_checked(RequestConfigure(), 'CMake server configure') # Generate the build system files self.client.query_checked(RequestCompute(), 'Generating build system files') # Get CMake build system files bs_reply = self.client.query_checked(RequestCMakeInputs(), 'Querying build system files') # Now get the CMake code model cm_reply = self.client.query_checked(RequestCodeModel(), 'Querying the CMake code model') src_dir = bs_reply.src_dir self.bs_files = [x.file for x in bs_reply.build_files if not x.is_cmake and not x.is_temp] self.bs_files = [os.path.relpath(os.path.join(src_dir, x), self.env.get_source_dir()) for x in self.bs_files] self.bs_files = list(set(self.bs_files)) self.codemodel_configs = cm_reply.configs def analyse(self) -> None: if self.codemodel_configs is None: raise CMakeException('CMakeInterpreter was not initialized') # Clear analyser data self.project_name = '' self.languages = [] self.targets = [] self.custom_targets = [] self.trace = CMakeTraceParser(permissive=True) # Parse the trace self.trace.parse(self.raw_trace) # Find all targets added_target_names = [] # type: T.List[str] for i in self.codemodel_configs: for j in i.projects: if not self.project_name: self.project_name = j.name for k in j.targets: # Avoid duplicate targets from different configurations and known # dummy CMake internal target types if k.type not in skip_targets and k.name not in added_target_names: added_target_names += [k.name] self.targets += [ConverterTarget(k, self.env)] # Add interface targets from trace, if not already present. # This step is required because interface targets were removed from # the CMake file API output. api_target_name_list = [x.name for x in self.targets] for i in self.trace.targets.values(): if i.type != 'INTERFACE' or i.name in api_target_name_list or i.imported: continue dummy = CMakeTarget({ 'name': i.name, 'type': 'INTERFACE_LIBRARY', 'sourceDirectory': self.src_dir, 'buildDirectory': self.build_dir, }) self.targets += [ConverterTarget(dummy, self.env)] for i in self.trace.custom_targets: self.custom_targets += [ConverterCustomTarget(i)] # generate the output_target_map for i in [*self.targets, *self.custom_targets]: self.output_target_map.add(i) # First pass: Basic target cleanup object_libs = [] custom_target_outputs = [] # type: T.List[str] for i in self.custom_targets: i.postprocess(self.output_target_map, self.src_dir, self.subdir, custom_target_outputs) for i in self.targets: i.postprocess(self.output_target_map, self.src_dir, self.subdir, self.install_prefix, self.trace) if i.type == 'OBJECT_LIBRARY': object_libs += [i] self.languages += [x for x in i.languages if x not in self.languages] # Second pass: Detect object library dependencies for i in self.targets: i.process_object_libs(object_libs, self._object_lib_workaround()) # Third pass: Reassign dependencies to avoid some loops for i in self.targets: i.process_inter_target_dependencies() for i in self.custom_targets: i.process_inter_target_dependencies() # Fourth pass: Remove rassigned dependencies for i in self.targets: i.cleanup_dependencies() mlog.log('CMake project', mlog.bold(self.project_name), 'has', mlog.bold(str(len(self.targets) + len(self.custom_targets))), 'build targets.') def pretend_to_be_meson(self) -> CodeBlockNode: if not self.project_name: raise CMakeException('CMakeInterpreter was not analysed') def token(tid: str = 'string', val='') -> Token: return Token(tid, self.subdir, 0, 0, 0, None, val) def string(value: str) -> StringNode: return StringNode(token(val=value)) def id_node(value: str) -> IdNode: return IdNode(token(val=value)) def number(value: int) -> NumberNode: return NumberNode(token(val=value)) def nodeify(value): if isinstance(value, str): return string(value) elif isinstance(value, bool): return BooleanNode(token(), value) elif isinstance(value, int): return number(value) elif isinstance(value, list): return array(value) return value def indexed(node: BaseNode, index: int) -> IndexNode: return IndexNode(node, nodeify(index)) def array(elements) -> ArrayNode: args = ArgumentNode(token()) if not isinstance(elements, list): elements = [args] args.arguments += [nodeify(x) for x in elements if x is not None] return ArrayNode(args, 0, 0, 0, 0) def function(name: str, args=None, kwargs=None) -> FunctionNode: args = [] if args is None else args kwargs = {} if kwargs is None else kwargs args_n = ArgumentNode(token()) if not isinstance(args, list): args = [args] args_n.arguments = [nodeify(x) for x in args if x is not None] args_n.kwargs = {k: nodeify(v) for k, v in kwargs.items() if v is not None} func_n = FunctionNode(self.subdir, 0, 0, 0, 0, name, args_n) return func_n def method(obj: BaseNode, name: str, args=None, kwargs=None) -> MethodNode: args = [] if args is None else args kwargs = {} if kwargs is None else kwargs args_n = ArgumentNode(token()) if not isinstance(args, list): args = [args] args_n.arguments = [nodeify(x) for x in args if x is not None] args_n.kwargs = {k: nodeify(v) for k, v in kwargs.items() if v is not None} return MethodNode(self.subdir, 0, 0, obj, name, args_n) def assign(var_name: str, value: BaseNode) -> AssignmentNode: return AssignmentNode(self.subdir, 0, 0, var_name, value) # Generate the root code block and the project function call root_cb = CodeBlockNode(token()) root_cb.lines += [function('project', [self.project_name] + self.languages)] # Add the run script for custom commands run_script = '{}/data/run_ctgt.py'.format(os.path.dirname(os.path.realpath(__file__))) run_script_var = 'ctgt_run_script' root_cb.lines += [assign(run_script_var, function('find_program', [[run_script]], {'required': True}))] # Add the targets processing = [] processed = {} name_map = {} def extract_tgt(tgt: T.Union[ConverterTarget, ConverterCustomTarget, CustomTargetReference]) -> IdNode: tgt_name = None if isinstance(tgt, (ConverterTarget, ConverterCustomTarget)): tgt_name = tgt.name elif isinstance(tgt, CustomTargetReference): tgt_name = tgt.ctgt.name assert(tgt_name is not None and tgt_name in processed) res_var = processed[tgt_name]['tgt'] return id_node(res_var) if res_var else None def detect_cycle(tgt: T.Union[ConverterTarget, ConverterCustomTarget]) -> None: if tgt.name in processing: raise CMakeException('Cycle in CMake inputs/dependencies detected') processing.append(tgt.name) def resolve_ctgt_ref(ref: CustomTargetReference) -> BaseNode: tgt_var = extract_tgt(ref) if len(ref.ctgt.outputs) == 1: return tgt_var else: return indexed(tgt_var, ref.index) def process_target(tgt: ConverterTarget): detect_cycle(tgt) # First handle inter target dependencies link_with = [] objec_libs = [] # type: T.List[IdNode] sources = [] generated = [] generated_filenames = [] custom_targets = [] dependencies = [] for i in tgt.link_with: assert(isinstance(i, ConverterTarget)) if i.name not in processed: process_target(i) link_with += [extract_tgt(i)] for i in tgt.object_libs: assert(isinstance(i, ConverterTarget)) if i.name not in processed: process_target(i) objec_libs += [extract_tgt(i)] for i in tgt.depends: if not isinstance(i, ConverterCustomTarget): continue if i.name not in processed: process_custom_target(i) dependencies += [extract_tgt(i)] # Generate the source list and handle generated sources for i in tgt.sources + tgt.generated: if isinstance(i, CustomTargetReference): if i.ctgt.name not in processed: process_custom_target(i.ctgt) generated += [resolve_ctgt_ref(i)] generated_filenames += [i.filename()] if i.ctgt not in custom_targets: custom_targets += [i.ctgt] else: sources += [i] # Add all header files from all used custom targets. This # ensures that all custom targets are built before any # sources of the current target are compiled and thus all # header files are present. This step is necessary because # CMake always ensures that a custom target is executed # before another target if at least one output is used. for i in custom_targets: for j in i.outputs: if not is_header(j) or j in generated_filenames: continue generated += [resolve_ctgt_ref(i.get_ref(j))] generated_filenames += [j] # Determine the meson function to use for the build target tgt_func = tgt.meson_func() if not tgt_func: raise CMakeException('Unknown target type "{}"'.format(tgt.type)) # Determine the variable names inc_var = '{}_inc'.format(tgt.name) dir_var = '{}_dir'.format(tgt.name) sys_var = '{}_sys'.format(tgt.name) src_var = '{}_src'.format(tgt.name) dep_var = '{}_dep'.format(tgt.name) tgt_var = tgt.name # Generate target kwargs tgt_kwargs = { 'build_by_default': False, 'link_args': tgt.link_flags + tgt.link_libraries, 'link_with': link_with, 'include_directories': id_node(inc_var), 'install': tgt.install, 'install_dir': tgt.install_dir, 'override_options': tgt.override_options, 'objects': [method(x, 'extract_all_objects') for x in objec_libs], } # Handle compiler args for key, val in tgt.compile_opts.items(): tgt_kwargs['{}_args'.format(key)] = val # Handle -fPCI, etc if tgt_func == 'executable': tgt_kwargs['pie'] = tgt.pie elif tgt_func == 'static_library': tgt_kwargs['pic'] = tgt.pie # declare_dependency kwargs dep_kwargs = { 'link_args': tgt.link_flags + tgt.link_libraries, 'link_with': id_node(tgt_var), 'compile_args': tgt.public_compile_opts, 'include_directories': id_node(inc_var), } if dependencies: generated += dependencies # Generate the function nodes dir_node = assign(dir_var, function('include_directories', tgt.includes)) sys_node = assign(sys_var, function('include_directories', tgt.sys_includes, {'is_system': True})) inc_node = assign(inc_var, array([id_node(dir_var), id_node(sys_var)])) node_list = [dir_node, sys_node, inc_node] if tgt_func == 'header_only': del dep_kwargs['link_with'] dep_node = assign(dep_var, function('declare_dependency', kwargs=dep_kwargs)) node_list += [dep_node] src_var = None tgt_var = None else: src_node = assign(src_var, function('files', sources)) tgt_node = assign(tgt_var, function(tgt_func, [tgt_var, [id_node(src_var)] + generated], tgt_kwargs)) node_list += [src_node, tgt_node] if tgt_func in ['static_library', 'shared_library']: dep_node = assign(dep_var, function('declare_dependency', kwargs=dep_kwargs)) node_list += [dep_node] else: dep_var = None # Add the nodes to the ast root_cb.lines += node_list processed[tgt.name] = {'inc': inc_var, 'src': src_var, 'dep': dep_var, 'tgt': tgt_var, 'func': tgt_func} name_map[tgt.cmake_name] = tgt.name def process_custom_target(tgt: ConverterCustomTarget) -> None: # CMake allows to specify multiple commands in a custom target. # To map this to meson, a helper script is used to execute all # commands in order. This additionally allows setting the working # directory. detect_cycle(tgt) tgt_var = tgt.name # type: str def resolve_source(x: T.Any) -> T.Any: if isinstance(x, ConverterTarget): if x.name not in processed: process_target(x) return extract_tgt(x) if isinstance(x, ConverterCustomTarget): if x.name not in processed: process_custom_target(x) return extract_tgt(x) elif isinstance(x, CustomTargetReference): if x.ctgt.name not in processed: process_custom_target(x.ctgt) return resolve_ctgt_ref(x) else: return x # Generate the command list command = [] command += [id_node(run_script_var)] command += ['-o', '@OUTPUT@'] if tgt.original_outputs: command += ['-O'] + tgt.original_outputs command += ['-d', tgt.working_dir] # Generate the commands. Subcommands are separated by ';;;' for cmd in tgt.command: command += [resolve_source(x) for x in cmd] + [';;;'] tgt_kwargs = { 'input': [resolve_source(x) for x in tgt.inputs], 'output': tgt.outputs, 'command': command, 'depends': [resolve_source(x) for x in tgt.depends], } root_cb.lines += [assign(tgt_var, function('custom_target', [tgt.name], tgt_kwargs))] processed[tgt.name] = {'inc': None, 'src': None, 'dep': None, 'tgt': tgt_var, 'func': 'custom_target'} name_map[tgt.cmake_name] = tgt.name # Now generate the target function calls for i in self.custom_targets: if i.name not in processed: process_custom_target(i) for i in self.targets: if i.name not in processed: process_target(i) self.generated_targets = processed self.internal_name_map = name_map return root_cb def target_info(self, target: str) -> T.Optional[T.Dict[str, str]]: # Try resolving the target name # start by checking if there is a 100% match (excluding the name prefix) prx_tgt = _sanitize_cmake_name(target) if prx_tgt in self.generated_targets: return self.generated_targets[prx_tgt] # check if there exists a name mapping if target in self.internal_name_map: target = self.internal_name_map[target] assert(target in self.generated_targets) return self.generated_targets[target] return None def target_list(self) -> T.List[str]: return list(self.internal_name_map.keys()) def _object_lib_workaround(self) -> bool: return 'link' in self.linkers and self.backend_name.startswith('vs') meson-0.53.2/mesonbuild/cmake/traceparser.py0000644000175000017500000005575413625260316022446 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. from .common import CMakeException from .generator import parse_generator_expressions from .. import mlog import typing as T import re import os class CMakeTraceLine: def __init__(self, file, line, func, args): self.file = file self.line = line self.func = func.lower() self.args = args def __repr__(self): s = 'CMake TRACE: {0}:{1} {2}({3})' return s.format(self.file, self.line, self.func, self.args) class CMakeTarget: def __init__(self, name, target_type, properties=None, imported: bool = False, tline: T.Optional[CMakeTraceLine] = None): if properties is None: properties = {} self.name = name self.type = target_type self.properties = properties self.imported = imported self.tline = tline self.depends = [] self.current_bin_dir = None self.current_src_dir = None def __repr__(self): s = 'CMake TARGET:\n -- name: {}\n -- type: {}\n -- imported: {}\n -- properties: {{\n{} }}\n -- tline: {}' propSTR = '' for i in self.properties: propSTR += " '{}': {}\n".format(i, self.properties[i]) return s.format(self.name, self.type, self.imported, propSTR, self.tline) def strip_properties(self) -> None: # Strip the strings in the properties if not self.properties: return for key, val in self.properties.items(): self.properties[key] = [x.strip() for x in val] class CMakeGeneratorTarget(CMakeTarget): def __init__(self, name): super().__init__(name, 'CUSTOM', {}) self.outputs = [] # type: T.List[str] self.command = [] # type: T.List[T.List[str]] self.working_dir = None # type: T.Optional[str] class CMakeTraceParser: def __init__(self, permissive: bool = False): self.vars = {} # type: T.Dict[str, T.List[str]] self.targets = {} # type: T.Dict[str, CMakeTarget] # T.List of targes that were added with add_custom_command to generate files self.custom_targets = [] # type: T.List[CMakeGeneratorTarget] self.permissive = permissive # type: bool # State for delayed command execution. Delayed command execution is realised # with a custom CMake file that overrides some functions and adds some # introspection information to the trace. self.delayed_commands = [] # type: T.List[str] self.stored_commands = [] # type: T.List[CMakeTraceLine] # All supported functions self.functions = { 'set': self._cmake_set, 'unset': self._cmake_unset, 'add_executable': self._cmake_add_executable, 'add_library': self._cmake_add_library, 'add_custom_command': self._cmake_add_custom_command, 'add_custom_target': self._cmake_add_custom_target, 'set_property': self._cmake_set_property, 'set_target_properties': self._cmake_set_target_properties, 'target_compile_definitions': self._cmake_target_compile_definitions, 'target_compile_options': self._cmake_target_compile_options, 'target_include_directories': self._cmake_target_include_directories, 'target_link_libraries': self._cmake_target_link_libraries, 'target_link_options': self._cmake_target_link_options, 'add_dependencies': self._cmake_add_dependencies, # Special functions defined in the preload script. # These functions do nothing in the CMake code, but have special # meaning here in the trace parser. 'meson_ps_execute_delayed_calls': self._meson_ps_execute_delayed_calls, 'meson_ps_reload_vars': self._meson_ps_reload_vars, } def parse(self, trace: str) -> None: # First parse the trace lexer1 = self._lex_trace(trace) # Primary pass -- parse everything for l in lexer1: # store the function if its execution should be delayed if l.func in self.delayed_commands: self.stored_commands += [l] continue # "Execute" the CMake function if supported fn = self.functions.get(l.func, None) if(fn): fn(l) # Postprocess for tgt in self.targets.values(): tgt.strip_properties() def get_first_cmake_var_of(self, var_list: T.List[str]) -> T.List[str]: # Return the first found CMake variable in list var_list for i in var_list: if i in self.vars: return self.vars[i] return [] def get_cmake_var(self, var: str) -> T.List[str]: # Return the value of the CMake variable var or an empty list if var does not exist if var in self.vars: return self.vars[var] return [] def var_to_str(self, var: str) -> T.Optional[str]: if var in self.vars and self.vars[var]: return self.vars[var][0] return None def var_to_bool(self, var): if var not in self.vars: return False if len(self.vars[var]) < 1: return False if self.vars[var][0].upper() in ['1', 'ON', 'TRUE']: return True return False def _gen_exception(self, function: str, error: str, tline: CMakeTraceLine) -> None: # Generate an exception if the parser is not in permissive mode if self.permissive: mlog.debug('CMake trace warning: {}() {}\n{}'.format(function, error, tline)) return None raise CMakeException('CMake: {}() {}\n{}'.format(function, error, tline)) def _cmake_set(self, tline: CMakeTraceLine) -> None: """Handler for the CMake set() function in all variaties. comes in three flavors: set( [PARENT_SCOPE]) set( CACHE [FORCE]) set(ENV{} ) We don't support the ENV variant, and any uses of it will be ignored silently. the other two variates are supported, with some caveats: - we don't properly handle scoping, so calls to set() inside a function without PARENT_SCOPE set could incorrectly shadow the outer scope. - We don't honor the type of CACHE arguments """ # DOC: https://cmake.org/cmake/help/latest/command/set.html # 1st remove PARENT_SCOPE and CACHE from args args = [] for i in tline.args: if not i or i == 'PARENT_SCOPE': continue # Discard everything after the CACHE keyword if i == 'CACHE': break args.append(i) if len(args) < 1: return self._gen_exception('set', 'requires at least one argument', tline) # Now that we've removed extra arguments all that should be left is the # variable identifier and the value, join the value back together to # ensure spaces in the value are correctly handled. This assumes that # variable names don't have spaces. Please don't do that... identifier = args.pop(0) value = ' '.join(args) if not value: # Same as unset if identifier in self.vars: del self.vars[identifier] else: self.vars[identifier] = value.split(';') def _cmake_unset(self, tline: CMakeTraceLine): # DOC: https://cmake.org/cmake/help/latest/command/unset.html if len(tline.args) < 1: return self._gen_exception('unset', 'requires at least one argument', tline) if tline.args[0] in self.vars: del self.vars[tline.args[0]] def _cmake_add_executable(self, tline: CMakeTraceLine): # DOC: https://cmake.org/cmake/help/latest/command/add_executable.html args = list(tline.args) # Make a working copy # Make sure the exe is imported if 'IMPORTED' not in args: return self._gen_exception('add_executable', 'non imported executables are not supported', tline) args.remove('IMPORTED') if len(args) < 1: return self._gen_exception('add_executable', 'requires at least 1 argument', tline) self.targets[args[0]] = CMakeTarget(args[0], 'EXECUTABLE', {}) def _cmake_add_library(self, tline: CMakeTraceLine): # DOC: https://cmake.org/cmake/help/latest/command/add_library.html args = list(tline.args) # Make a working copy # Make sure the lib is imported if 'INTERFACE' in args: args.remove('INTERFACE') if len(args) < 1: return self._gen_exception('add_library', 'interface library name not specified', tline) self.targets[args[0]] = CMakeTarget(args[0], 'INTERFACE', {}, tline=tline, imported='IMPORTED' in args) elif 'IMPORTED' in args: args.remove('IMPORTED') # Now, only look at the first two arguments (target_name and target_type) and ignore the rest if len(args) < 2: return self._gen_exception('add_library', 'requires at least 2 arguments', tline) self.targets[args[0]] = CMakeTarget(args[0], args[1], {}, tline=tline, imported=True) elif 'ALIAS' in args: args.remove('ALIAS') # Now, only look at the first two arguments (target_name and target_ref) and ignore the rest if len(args) < 2: return self._gen_exception('add_library', 'requires at least 2 arguments', tline) # Simulate the ALIAS with INTERFACE_LINK_LIBRARIES self.targets[args[0]] = CMakeTarget(args[0], 'ALIAS', {'INTERFACE_LINK_LIBRARIES': [args[1]]}, tline=tline) elif 'OBJECT' in args: return self._gen_exception('add_library', 'OBJECT libraries are not supported', tline) else: self.targets[args[0]] = CMakeTarget(args[0], 'NORMAL', {}, tline=tline) def _cmake_add_custom_command(self, tline: CMakeTraceLine, name=None): # DOC: https://cmake.org/cmake/help/latest/command/add_custom_command.html args = list(tline.args) # Make a working copy if not args: return self._gen_exception('add_custom_command', 'requires at least 1 argument', tline) # Skip the second function signature if args[0] == 'TARGET': return self._gen_exception('add_custom_command', 'TARGET syntax is currently not supported', tline) magic_keys = ['OUTPUT', 'COMMAND', 'MAIN_DEPENDENCY', 'DEPENDS', 'BYPRODUCTS', 'IMPLICIT_DEPENDS', 'WORKING_DIRECTORY', 'COMMENT', 'DEPFILE', 'JOB_POOL', 'VERBATIM', 'APPEND', 'USES_TERMINAL', 'COMMAND_EXPAND_LISTS'] target = CMakeGeneratorTarget(name) def handle_output(key: str, target: CMakeGeneratorTarget) -> None: target.outputs += key.split(';') def handle_command(key: str, target: CMakeGeneratorTarget) -> None: if key == 'ARGS': return target.command[-1] += key.split(';') def handle_depends(key: str, target: CMakeGeneratorTarget) -> None: target.depends += key.split(';') def handle_working_dir(key: str, target: CMakeGeneratorTarget) -> None: if target.working_dir is None: target.working_dir = key else: target.working_dir += ' ' target.working_dir += key fn = None for i in args: if i in magic_keys: if i == 'OUTPUT': fn = handle_output elif i == 'DEPENDS': fn = handle_depends elif i == 'WORKING_DIRECTORY': fn = handle_working_dir elif i == 'COMMAND': fn = handle_command target.command += [[]] else: fn = None continue if fn is not None: fn(i, target) target.current_bin_dir = self.var_to_str('MESON_PS_CMAKE_CURRENT_BINARY_DIR') target.current_src_dir = self.var_to_str('MESON_PS_CMAKE_CURRENT_SOURCE_DIR') target.outputs = self._guess_files(target.outputs) target.depends = self._guess_files(target.depends) target.command = [self._guess_files(x) for x in target.command] self.custom_targets += [target] if name: self.targets[name] = target def _cmake_add_custom_target(self, tline: CMakeTraceLine): # DOC: https://cmake.org/cmake/help/latest/command/add_custom_target.html # We only the first parameter (the target name) is interesting if len(tline.args) < 1: return self._gen_exception('add_custom_target', 'requires at least one argument', tline) # It's pretty much the same as a custom command self._cmake_add_custom_command(tline, tline.args[0]) def _cmake_set_property(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/set_property.html args = list(tline.args) # We only care for TARGET properties if args.pop(0) != 'TARGET': return append = False targets = [] while args: curr = args.pop(0) # XXX: APPEND_STRING is specifically *not* supposed to create a # list, is treating them as aliases really okay? if curr == 'APPEND' or curr == 'APPEND_STRING': append = True continue if curr == 'PROPERTY': break targets.append(curr) if not args: return self._gen_exception('set_property', 'faild to parse argument list', tline) if len(args) == 1: # Tries to set property to nothing so nothing has to be done return identifier = args.pop(0) value = ' '.join(args).split(';') if not value: return for i in targets: if i not in self.targets: return self._gen_exception('set_property', 'TARGET {} not found'.format(i), tline) if identifier not in self.targets[i].properties: self.targets[i].properties[identifier] = [] if append: self.targets[i].properties[identifier] += value else: self.targets[i].properties[identifier] = value def _cmake_set_target_properties(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/set_target_properties.html args = list(tline.args) targets = [] while args: curr = args.pop(0) if curr == 'PROPERTIES': break targets.append(curr) # Now we need to try to reconsitute the original quoted format of the # arguments, as a property value could have spaces in it. Unlike # set_property() this is not context free. There are two approaches I # can think of, both have drawbacks: # # 1. Assume that the property will be capitalized ([A-Z_]), this is # convention but cmake doesn't require it. # 2. Maintain a copy of the list here: https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#target-properties # # Neither of these is awesome for obvious reasons. I'm going to try # option 1 first and fall back to 2, as 1 requires less code and less # synchroniztion for cmake changes. arglist = [] # type: T.List[T.Tuple[str, T.List[str]]] name = args.pop(0) values = [] prop_regex = re.compile(r'^[A-Z_]+$') for a in args: if prop_regex.match(a): if values: arglist.append((name, ' '.join(values).split(';'))) name = a values = [] else: values.append(a) if values: arglist.append((name, ' '.join(values).split(';'))) for name, value in arglist: for i in targets: if i not in self.targets: return self._gen_exception('set_target_properties', 'TARGET {} not found'.format(i), tline) self.targets[i].properties[name] = value def _cmake_add_dependencies(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/add_dependencies.html args = list(tline.args) if len(args) < 2: return self._gen_exception('add_dependencies', 'takes at least 2 arguments', tline) target = self.targets.get(args[0]) if not target: return self._gen_exception('add_dependencies', 'target not found', tline) for i in args[1:]: target.depends += i.split(';') def _cmake_target_compile_definitions(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/target_compile_definitions.html self._parse_common_target_options('target_compile_definitions', 'COMPILE_DEFINITIONS', 'INTERFACE_COMPILE_DEFINITIONS', tline) def _cmake_target_compile_options(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/target_compile_options.html self._parse_common_target_options('target_compile_options', 'COMPILE_OPTIONS', 'INTERFACE_COMPILE_OPTIONS', tline) def _cmake_target_include_directories(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/target_include_directories.html self._parse_common_target_options('target_include_directories', 'INCLUDE_DIRECTORIES', 'INTERFACE_INCLUDE_DIRECTORIES', tline, ignore=['SYSTEM', 'BEFORE'], paths=True) def _cmake_target_link_options(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/target_link_options.html self._parse_common_target_options('target_link_options', 'LINK_OPTIONS', 'INTERFACE_LINK_OPTIONS', tline) def _cmake_target_link_libraries(self, tline: CMakeTraceLine) -> None: # DOC: https://cmake.org/cmake/help/latest/command/target_link_libraries.html self._parse_common_target_options('target_link_options', 'LINK_LIBRARIES', 'INTERFACE_LINK_LIBRARIES', tline) def _parse_common_target_options(self, func: str, private_prop: str, interface_prop: str, tline: CMakeTraceLine, ignore: T.Optional[T.List[str]] = None, paths: bool = False): if ignore is None: ignore = ['BEFORE'] args = list(tline.args) if len(args) < 1: return self._gen_exception(func, 'requires at least one argument', tline) target = args[0] if target not in self.targets: return self._gen_exception(func, 'TARGET {} not found'.format(target), tline) interface = [] private = [] mode = 'PUBLIC' for i in args[1:]: if i in ignore: continue if i in ['INTERFACE', 'LINK_INTERFACE_LIBRARIES', 'PUBLIC', 'PRIVATE', 'LINK_PUBLIC', 'LINK_PRIVATE']: mode = i continue if mode in ['INTERFACE', 'LINK_INTERFACE_LIBRARIES', 'PUBLIC', 'LINK_PUBLIC']: interface += [i] if mode in ['PUBLIC', 'PRIVATE', 'LINK_PRIVATE']: private += [i] if paths: interface = self._guess_files(interface) private = self._guess_files(private) interface = [x for x in interface if x] private = [x for x in private if x] for i in [(private_prop, private), (interface_prop, interface)]: if not i[0] in self.targets[target].properties: self.targets[target].properties[i[0]] = [] self.targets[target].properties[i[0]] += i[1] def _meson_ps_execute_delayed_calls(self, tline: CMakeTraceLine) -> None: for l in self.stored_commands: fn = self.functions.get(l.func, None) if(fn): fn(l) # clear the stored commands self.stored_commands = [] def _meson_ps_reload_vars(self, tline: CMakeTraceLine) -> None: self.delayed_commands = self.get_cmake_var('MESON_PS_DELAYED_CALLS') def _lex_trace(self, trace): # The trace format is: '(): ( )\n' reg_tline = re.compile(r'\s*(.*\.(cmake|txt))\(([0-9]+)\):\s*(\w+)\(([\s\S]*?) ?\)\s*\n', re.MULTILINE) reg_other = re.compile(r'[^\n]*\n') loc = 0 while loc < len(trace): mo_file_line = reg_tline.match(trace, loc) if not mo_file_line: skip_match = reg_other.match(trace, loc) if not skip_match: print(trace[loc:]) raise CMakeException('Failed to parse CMake trace') loc = skip_match.end() continue loc = mo_file_line.end() file = mo_file_line.group(1) line = mo_file_line.group(3) func = mo_file_line.group(4) args = mo_file_line.group(5) args = parse_generator_expressions(args) args = args.split(' ') args = list(map(lambda x: x.strip(), args)) yield CMakeTraceLine(file, line, func, args) def _guess_files(self, broken_list: T.List[str]) -> T.List[str]: #Try joining file paths that contain spaces reg_start = re.compile(r'^([A-Za-z]:)?/.*/[^./]+$') reg_end = re.compile(r'^.*\.[a-zA-Z]+$') fixed_list = [] # type: T.List[str] curr_str = None # type: T.Optional[str] for i in broken_list: if curr_str is None: curr_str = i elif os.path.isfile(curr_str): # Abort concatenation if curr_str is an existing file fixed_list += [curr_str] curr_str = i elif not reg_start.match(curr_str): # Abort concatenation if curr_str no longer matches the regex fixed_list += [curr_str] curr_str = i elif reg_end.match(i) or os.path.exists('{} {}'.format(curr_str, i)): # File detected curr_str = '{} {}'.format(curr_str, i) fixed_list += [curr_str] curr_str = None else: curr_str = '{} {}'.format(curr_str, i) if curr_str: fixed_list += [curr_str] return fixed_list meson-0.53.2/mesonbuild/compilers/0000755000175000017500000000000013625242354020460 5ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/compilers/__init__.py0000644000175000017500000001102413571777336022604 0ustar jpakkanejpakkane00000000000000# Copyright 2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Public symbols for compilers sub-package when using 'from . import compilers' __all__ = [ 'Compiler', 'all_languages', 'base_options', 'clib_langs', 'clink_langs', 'c_suffixes', 'cpp_suffixes', 'get_base_compile_args', 'get_base_link_args', 'is_assembly', 'is_header', 'is_library', 'is_llvm_ir', 'is_object', 'is_source', 'lang_suffixes', 'sort_clink', 'AppleClangCCompiler', 'AppleClangCPPCompiler', 'ArmCCompiler', 'ArmCPPCompiler', 'ArmclangCCompiler', 'ArmclangCPPCompiler', 'CCompiler', 'ClangCCompiler', 'ClangCompiler', 'ClangCPPCompiler', 'ClangObjCCompiler', 'ClangObjCPPCompiler', 'ClangClCCompiler', 'ClangClCPPCompiler', 'CompilerArgs', 'CPPCompiler', 'DCompiler', 'DmdDCompiler', 'FortranCompiler', 'G95FortranCompiler', 'GnuCCompiler', 'ElbrusCCompiler', 'EmscriptenCCompiler', 'GnuCompiler', 'GnuCPPCompiler', 'ElbrusCPPCompiler', 'EmscriptenCPPCompiler', 'GnuDCompiler', 'GnuFortranCompiler', 'ElbrusFortranCompiler', 'FlangFortranCompiler', 'GnuObjCCompiler', 'GnuObjCPPCompiler', 'IntelGnuLikeCompiler', 'IntelVisualStudioLikeCompiler', 'IntelCCompiler', 'IntelCPPCompiler', 'IntelClCCompiler', 'IntelClCPPCompiler', 'IntelFortranCompiler', 'IntelClFortranCompiler', 'JavaCompiler', 'LLVMDCompiler', 'MonoCompiler', 'CudaCompiler', 'VisualStudioCsCompiler', 'NAGFortranCompiler', 'ObjCCompiler', 'ObjCPPCompiler', 'Open64FortranCompiler', 'PathScaleFortranCompiler', 'PGICCompiler', 'PGICPPCompiler', 'PGIFortranCompiler', 'RustCompiler', 'CcrxCCompiler', 'CcrxCPPCompiler', 'SunFortranCompiler', 'SwiftCompiler', 'ValaCompiler', 'VisualStudioLikeCompiler', 'VisualStudioCCompiler', 'VisualStudioCPPCompiler', ] # Bring symbols from each module into compilers sub-package namespace from .compilers import ( Compiler, all_languages, base_options, clib_langs, clink_langs, c_suffixes, cpp_suffixes, get_base_compile_args, get_base_link_args, is_header, is_source, is_assembly, is_llvm_ir, is_object, is_library, lang_suffixes, sort_clink, CompilerArgs, ) from .c import ( CCompiler, AppleClangCCompiler, ArmCCompiler, ArmclangCCompiler, ClangCCompiler, ClangClCCompiler, GnuCCompiler, ElbrusCCompiler, EmscriptenCCompiler, IntelCCompiler, IntelClCCompiler, PGICCompiler, CcrxCCompiler, VisualStudioCCompiler, ) from .cpp import ( CPPCompiler, AppleClangCPPCompiler, ArmCPPCompiler, ArmclangCPPCompiler, ClangCPPCompiler, ClangClCPPCompiler, GnuCPPCompiler, ElbrusCPPCompiler, EmscriptenCPPCompiler, IntelCPPCompiler, IntelClCPPCompiler, PGICPPCompiler, CcrxCPPCompiler, VisualStudioCPPCompiler, ) from .cs import MonoCompiler, VisualStudioCsCompiler from .d import ( DCompiler, DmdDCompiler, GnuDCompiler, LLVMDCompiler, ) from .cuda import CudaCompiler from .fortran import ( FortranCompiler, G95FortranCompiler, GnuFortranCompiler, ElbrusFortranCompiler, FlangFortranCompiler, IntelFortranCompiler, IntelClFortranCompiler, NAGFortranCompiler, Open64FortranCompiler, PathScaleFortranCompiler, PGIFortranCompiler, SunFortranCompiler, ) from .java import JavaCompiler from .objc import ( ObjCCompiler, ClangObjCCompiler, GnuObjCCompiler, ) from .objcpp import ( ObjCPPCompiler, ClangObjCPPCompiler, GnuObjCPPCompiler, ) from .rust import RustCompiler from .swift import SwiftCompiler from .vala import ValaCompiler from .mixins.visualstudio import VisualStudioLikeCompiler from .mixins.gnu import GnuCompiler from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler from .mixins.clang import ClangCompiler meson-0.53.2/mesonbuild/compilers/c.py0000644000175000017500000004146113625260316021260 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os.path import typing as T from .. import coredata from ..mesonlib import MachineChoice, MesonException, mlog, version_compare from .c_function_attributes import C_FUNC_ATTRIBUTES from .mixins.clike import CLikeCompiler from .mixins.ccrx import CcrxCompiler from .mixins.arm import ArmCompiler, ArmclangCompiler from .mixins.visualstudio import VisualStudioLikeCompiler from .mixins.gnu import GnuCompiler from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler from .mixins.clang import ClangCompiler from .mixins.elbrus import ElbrusCompiler from .mixins.pgi import PGICompiler from .mixins.islinker import BasicLinkerIsCompilerMixin, LinkerEnvVarsMixin from .mixins.emscripten import EmscriptenMixin from .compilers import ( gnu_winlibs, msvc_winlibs, Compiler, ) if T.TYPE_CHECKING: from ..envconfig import MachineInfo class CCompiler(CLikeCompiler, Compiler): @staticmethod def attribute_check_func(name): try: return C_FUNC_ATTRIBUTES[name] except KeyError: raise MesonException('Unknown function attribute "{}"'.format(name)) language = 'c' def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional[str] = None, **kwargs): # If a child ObjC or CPP class has already set it, don't set it ourselves Compiler.__init__(self, exelist, version, for_machine, info, **kwargs) CLikeCompiler.__init__(self, is_cross, exe_wrapper) def get_no_stdinc_args(self): return ['-nostdinc'] def sanity_check(self, work_dir, environment): code = 'int main(void) { int class=0; return class; }\n' return self.sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code) def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None): fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol} t = '''{prefix} #include <{header}> int main(void) {{ /* If it's not defined as a macro, try to use as a symbol */ #ifndef {symbol} {symbol}; #endif return 0; }}''' return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) class ClangCCompiler(ClangCompiler, CCompiler): _C17_VERSION = '>=6.0.0' _C18_VERSION = '>=8.0.0' def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) ClangCompiler.__init__(self) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): opts = CCompiler.get_options(self) c_stds = ['c89', 'c99', 'c11'] g_stds = ['gnu89', 'gnu99', 'gnu11'] # https://releases.llvm.org/6.0.0/tools/clang/docs/ReleaseNotes.html # https://en.wikipedia.org/wiki/Xcode#Latest_versions if version_compare(self.version, self._C17_VERSION): c_stds += ['c17'] g_stds += ['gnu17'] if version_compare(self.version, self._C18_VERSION): c_stds += ['c18'] g_stds += ['gnu18'] opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none'] + c_stds + g_stds, 'none')}) return opts def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options): return [] class AppleClangCCompiler(ClangCCompiler): """Handle the differences between Apple Clang and Vanilla Clang. Right now this just handles the differences between the versions that new C standards were added. """ _C17_VERSION = '>=10.0.0' _C18_VERSION = '>=11.0.0' class EmscriptenCCompiler(LinkerEnvVarsMixin, EmscriptenMixin, BasicLinkerIsCompilerMixin, ClangCCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs): if not is_cross: raise MesonException('Emscripten compiler can only be used for cross compilation.') ClangCCompiler.__init__(self, exelist=exelist, version=version, for_machine=for_machine, is_cross=is_cross, info=info, exe_wrapper=exe_wrapper, **kwargs) self.id = 'emscripten' class ArmclangCCompiler(ArmclangCompiler, CCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) ArmclangCompiler.__init__(self) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): opts = CCompiler.get_options(self) opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none', 'c90', 'c99', 'c11', 'gnu90', 'gnu99', 'gnu11'], 'none')}) return opts def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options): return [] class GnuCCompiler(GnuCompiler, CCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, defines=None, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) GnuCompiler.__init__(self, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): opts = CCompiler.get_options(self) c_stds = ['c89', 'c99', 'c11'] g_stds = ['gnu89', 'gnu99', 'gnu11'] v = '>=8.0.0' if version_compare(self.version, v): c_stds += ['c17', 'c18'] g_stds += ['gnu17', 'gnu18'] opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none'] + c_stds + g_stds, 'none')}) if self.info.is_windows() or self.info.is_cygwin(): opts.update({ 'c_winlibs': coredata.UserArrayOption('Standard Win libraries to link against', gnu_winlibs), }) return opts def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options): if self.info.is_windows() or self.info.is_cygwin(): return options['c_winlibs'].value[:] return [] def get_pch_use_args(self, pch_dir, header): return ['-fpch-preprocess', '-include', os.path.basename(header)] class PGICCompiler(PGICompiler, CCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) PGICompiler.__init__(self) class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, defines=None, **kwargs): GnuCCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, defines, **kwargs) ElbrusCompiler.__init__(self) # It does support some various ISO standards and c/gnu 90, 9x, 1x in addition to those which GNU CC supports. def get_options(self): opts = CCompiler.get_options(self) opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none', 'c89', 'c90', 'c9x', 'c99', 'c1x', 'c11', 'gnu89', 'gnu90', 'gnu9x', 'gnu99', 'gnu1x', 'gnu11', 'iso9899:2011', 'iso9899:1990', 'iso9899:199409', 'iso9899:1999'], 'none')}) return opts # Elbrus C compiler does not have lchmod, but there is only linker warning, not compiler error. # So we should explicitly fail at this case. def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None): if funcname == 'lchmod': return False, False else: return super().has_function(funcname, prefix, env, extra_args=extra_args, dependencies=dependencies) class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) IntelGnuLikeCompiler.__init__(self) self.lang_header = 'c-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra']} def get_options(self): opts = CCompiler.get_options(self) c_stds = ['c89', 'c99'] g_stds = ['gnu89', 'gnu99'] if version_compare(self.version, '>=16.0.0'): c_stds += ['c11'] opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none'] + c_stds + g_stds, 'none')}) return opts def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value != 'none': args.append('-std=' + std.value) return args class VisualStudioLikeCCompilerMixin: """Shared methods that apply to MSVC-like C compilers.""" def get_options(self): opts = super().get_options() opts.update({'c_winlibs': coredata.UserArrayOption('Windows libs to link against.', msvc_winlibs)}) return opts def get_option_link_args(self, options): return options['c_winlibs'].value[:] class VisualStudioCCompiler(VisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap, target: str, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) VisualStudioLikeCompiler.__init__(self, target) self.id = 'msvc' class ClangClCCompiler(VisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) VisualStudioLikeCompiler.__init__(self, target) self.id = 'clang-cl' class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler): """Intel "ICL" compiler abstraction.""" def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) IntelVisualStudioLikeCompiler.__init__(self, target) def get_options(self): opts = super().get_options() c_stds = ['none', 'c89', 'c99', 'c11'] opts.update({'c_std': coredata.UserComboOption('C language standard to use', c_stds, 'none')}) return opts def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value == 'c89': mlog.warning("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.", once=True) elif std.value != 'none': args.append('/Qstd:' + std.value) return args class ArmCCompiler(ArmCompiler, CCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) ArmCompiler.__init__(self) def get_options(self): opts = CCompiler.get_options(self) opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none', 'c90', 'c99'], 'none')}) return opts def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value != 'none': args.append('--' + std.value) return args class CcrxCCompiler(CcrxCompiler, CCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) CcrxCompiler.__init__(self) # Override CCompiler.get_always_args def get_always_args(self): return ['-nologo'] def get_options(self): opts = CCompiler.get_options(self) opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none', 'c89', 'c99'], 'none')}) return opts def get_no_stdinc_args(self): return [] def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value == 'c89': args.append('-lang=c') elif std.value == 'c99': args.append('-lang=c99') return args def get_compile_only_args(self): return [] def get_no_optimization_args(self): return ['-optimize=0'] def get_output_args(self, target): return ['-output=obj=%s' % target] def get_werror_args(self): return ['-change_message=error'] def get_include_args(self, path, is_system): if path == '': path = '.' return ['-include=' + path] meson-0.53.2/mesonbuild/compilers/c_function_attributes.py0000644000175000017500000001134013531533273025425 0ustar jpakkanejpakkane00000000000000# These functions are based on the following code: # https://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_gcc_func_attribute.m4, # which is licensed under the following terms: # # Copyright (c) 2013 Gabriele Svelto # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. # C_FUNC_ATTRIBUTES = { 'alias': ''' int foo(void) { return 0; } int bar(void) __attribute__((alias("foo")));''', 'aligned': 'int foo(void) __attribute__((aligned(32)));', 'alloc_size': 'void *foo(int a) __attribute__((alloc_size(1)));', 'always_inline': 'inline __attribute__((always_inline)) int foo(void) { return 0; }', 'artificial': 'inline __attribute__((artificial)) int foo(void) { return 0; }', 'cold': 'int foo(void) __attribute__((cold));', 'const': 'int foo(void) __attribute__((const));', 'constructor': 'int foo(void) __attribute__((constructor));', 'constructor_priority': 'int foo( void ) __attribute__((__constructor__(65535/2)));', 'deprecated': 'int foo(void) __attribute__((deprecated("")));', 'destructor': 'int foo(void) __attribute__((destructor));', 'dllexport': '__declspec(dllexport) int foo(void) { return 0; }', 'dllimport': '__declspec(dllimport) int foo(void);', 'error': 'int foo(void) __attribute__((error("")));', 'externally_visible': 'int foo(void) __attribute__((externally_visible));', 'fallthrough': ''' int foo( void ) { switch (0) { case 1: __attribute__((fallthrough)); case 2: break; } return 0; };''', 'flatten': 'int foo(void) __attribute__((flatten));', 'format': 'int foo(const char * p, ...) __attribute__((format(printf, 1, 2)));', 'format_arg': 'char * foo(const char * p) __attribute__((format_arg(1)));', 'gnu_inline': 'inline __attribute__((gnu_inline)) int foo(void) { return 0; }', 'hot': 'int foo(void) __attribute__((hot));', 'ifunc': ('int my_foo(void) { return 0; }' 'static int (*resolve_foo(void))(void) { return my_foo; }' 'int foo(void) __attribute__((ifunc("resolve_foo")));'), 'leaf': '__attribute__((leaf)) int foo(void) { return 0; }', 'malloc': 'int *foo(void) __attribute__((malloc));', 'noclone': 'int foo(void) __attribute__((noclone));', 'noinline': '__attribute__((noinline)) int foo(void) { return 0; }', 'nonnull': 'int foo(char * p) __attribute__((nonnull(1)));', 'noreturn': 'int foo(void) __attribute__((noreturn));', 'nothrow': 'int foo(void) __attribute__((nothrow));', 'optimize': '__attribute__((optimize(3))) int foo(void) { return 0; }', 'packed': 'struct __attribute__((packed)) foo { int bar; };', 'pure': 'int foo(void) __attribute__((pure));', 'returns_nonnull': 'int *foo(void) __attribute__((returns_nonnull));', 'unused': 'int foo(void) __attribute__((unused));', 'used': 'int foo(void) __attribute__((used));', 'visibility': ''' int foo_def(void) __attribute__((visibility("default"))); int foo_hid(void) __attribute__((visibility("hidden"))); int foo_int(void) __attribute__((visibility("internal")));''', 'visibility:default': 'int foo(void) __attribute__((visibility("default")));', 'visibility:hidden': 'int foo(void) __attribute__((visibility("hidden")));', 'visibility:internal': 'int foo(void) __attribute__((visibility("internal")));', 'visibility:protected': 'int foo(void) __attribute__((visibility("protected")));', 'warning': 'int foo(void) __attribute__((warning("")));', 'warn_unused_result': 'int foo(void) __attribute__((warn_unused_result));', 'weak': 'int foo(void) __attribute__((weak));', 'weakref': ''' static int foo(void) { return 0; } static int var(void) __attribute__((weakref("foo")));''', } CXX_FUNC_ATTRIBUTES = { # Alias must be applied to the mangled name in C++ 'alias': ('extern "C" {' 'int foo(void) { return 0; }' '}' 'int bar(void) __attribute__((alias("foo")));' ), 'ifunc': ('extern "C" {' 'int my_foo(void) { return 0; }' 'static int (*resolve_foo(void))(void) { return my_foo; }' '}' 'int foo(void) __attribute__((ifunc("resolve_foo")));'), } meson-0.53.2/mesonbuild/compilers/compilers.py0000644000175000017500000014041413625260316023031 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import contextlib, os.path, re, tempfile import collections.abc import typing as T from ..linkers import StaticLinker, GnuLikeDynamicLinkerMixin, SolarisDynamicLinker from .. import coredata from .. import mlog from .. import mesonlib from ..mesonlib import ( EnvironmentException, MachineChoice, MesonException, Popen_safe, split_args ) from ..envconfig import ( Properties, ) if T.TYPE_CHECKING: from ..coredata import OptionDictType from ..envconfig import MachineInfo from ..environment import Environment from ..linkers import DynamicLinker # noqa: F401 """This file contains the data files of all compilers Meson knows about. To support a new compiler, add its information below. Also add corresponding autodetection code in environment.py.""" header_suffixes = ('h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di') obj_suffixes = ('o', 'obj', 'res') lib_suffixes = ('a', 'lib', 'dll', 'dll.a', 'dylib', 'so') # Mapping of language to suffixes of files that should always be in that language # This means we can't include .h headers here since they could be C, C++, ObjC, etc. lang_suffixes = { 'c': ('c',), 'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx'), 'cuda': ('cu',), # f90, f95, f03, f08 are for free-form fortran ('f90' recommended) # f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended) 'fortran': ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'), 'd': ('d', 'di'), 'objc': ('m',), 'objcpp': ('mm',), 'rust': ('rs',), 'vala': ('vala', 'vapi', 'gs'), 'cs': ('cs',), 'swift': ('swift',), 'java': ('java',), } all_languages = lang_suffixes.keys() cpp_suffixes = lang_suffixes['cpp'] + ('h',) c_suffixes = lang_suffixes['c'] + ('h',) # List of languages that by default consume and output libraries following the # C ABI; these can generally be used interchangebly clib_langs = ('objcpp', 'cpp', 'objc', 'c', 'fortran',) # List of languages that can be linked with C code directly by the linker # used in build.py:process_compilers() and build.py:get_dynamic_linker() clink_langs = ('d', 'cuda') + clib_langs clink_suffixes = () for _l in clink_langs + ('vala',): clink_suffixes += lang_suffixes[_l] clink_suffixes += ('h', 'll', 's') # Languages that should use LDFLAGS arguments when linking. languages_using_ldflags = ('objcpp', 'cpp', 'objc', 'c', 'fortran', 'd', 'cuda') soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$') # Environment variables that each lang uses. cflags_mapping = {'c': 'CFLAGS', 'cpp': 'CXXFLAGS', 'cuda': 'CUFLAGS', 'objc': 'OBJCFLAGS', 'objcpp': 'OBJCXXFLAGS', 'fortran': 'FFLAGS', 'd': 'DFLAGS', 'vala': 'VALAFLAGS', 'rust': 'RUSTFLAGS'} unixy_compiler_internal_libs = ('m', 'c', 'pthread', 'dl', 'rt') # execinfo is a compiler lib on FreeBSD and NetBSD if mesonlib.is_freebsd() or mesonlib.is_netbsd(): unixy_compiler_internal_libs += ('execinfo',) # All these are only for C-linkable languages; see `clink_langs` above. def sort_clink(lang): ''' Sorting function to sort the list of languages according to reversed(compilers.clink_langs) and append the unknown langs in the end. The purpose is to prefer C over C++ for files that can be compiled by both such as assembly, C, etc. Also applies to ObjC, ObjC++, etc. ''' if lang not in clink_langs: return 1 return -clink_langs.index(lang) def is_header(fname): if hasattr(fname, 'fname'): fname = fname.fname suffix = fname.split('.')[-1] return suffix in header_suffixes def is_source(fname): if hasattr(fname, 'fname'): fname = fname.fname suffix = fname.split('.')[-1].lower() return suffix in clink_suffixes def is_assembly(fname): if hasattr(fname, 'fname'): fname = fname.fname return fname.split('.')[-1].lower() == 's' def is_llvm_ir(fname): if hasattr(fname, 'fname'): fname = fname.fname return fname.split('.')[-1] == 'll' def is_object(fname): if hasattr(fname, 'fname'): fname = fname.fname suffix = fname.split('.')[-1] return suffix in obj_suffixes def is_library(fname): if hasattr(fname, 'fname'): fname = fname.fname if soregex.match(fname): return True suffix = fname.split('.')[-1] return suffix in lib_suffixes cuda_buildtype_args = {'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], } java_buildtype_args = {'plain': [], 'debug': ['-g'], 'debugoptimized': ['-g'], 'release': [], 'minsize': [], 'custom': [], } rust_buildtype_args = {'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], 'custom': [], } d_gdc_buildtype_args = {'plain': [], 'debug': [], 'debugoptimized': ['-finline-functions'], 'release': ['-frelease', '-finline-functions'], 'minsize': [], 'custom': [], } d_ldc_buildtype_args = {'plain': [], 'debug': [], 'debugoptimized': ['-enable-inlining', '-Hkeep-all-bodies'], 'release': ['-release', '-enable-inlining', '-Hkeep-all-bodies'], 'minsize': [], 'custom': [], } d_dmd_buildtype_args = {'plain': [], 'debug': [], 'debugoptimized': ['-inline'], 'release': ['-release', '-inline'], 'minsize': [], 'custom': [], } mono_buildtype_args = {'plain': [], 'debug': [], 'debugoptimized': ['-optimize+'], 'release': ['-optimize+'], 'minsize': [], 'custom': [], } swift_buildtype_args = {'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], 'custom': [], } gnu_winlibs = ['-lkernel32', '-luser32', '-lgdi32', '-lwinspool', '-lshell32', '-lole32', '-loleaut32', '-luuid', '-lcomdlg32', '-ladvapi32'] msvc_winlibs = ['kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'comdlg32.lib', 'advapi32.lib'] clike_optimization_args = {'0': [], 'g': [], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-Os'], } cuda_optimization_args = {'0': [], 'g': ['-O0'], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-O3'] } cuda_debug_args = {False: [], True: ['-g']} clike_debug_args = {False: [], True: ['-g']} base_options = {'b_pch': coredata.UserBooleanOption('Use precompiled headers', True), 'b_lto': coredata.UserBooleanOption('Use link time optimization', False), 'b_sanitize': coredata.UserComboOption('Code sanitizer to use', ['none', 'address', 'thread', 'undefined', 'memory', 'address,undefined'], 'none'), 'b_lundef': coredata.UserBooleanOption('Use -Wl,--no-undefined when linking', True), 'b_asneeded': coredata.UserBooleanOption('Use -Wl,--as-needed when linking', True), 'b_pgo': coredata.UserComboOption('Use profile guided optimization', ['off', 'generate', 'use'], 'off'), 'b_coverage': coredata.UserBooleanOption('Enable coverage tracking.', False), 'b_colorout': coredata.UserComboOption('Use colored output', ['auto', 'always', 'never'], 'always'), 'b_ndebug': coredata.UserComboOption('Disable asserts', ['true', 'false', 'if-release'], 'false'), 'b_staticpic': coredata.UserBooleanOption('Build static libraries as position independent', True), 'b_pie': coredata.UserBooleanOption('Build executables as position independent', False), 'b_bitcode': coredata.UserBooleanOption('Generate and embed bitcode (only macOS/iOS/tvOS)', False), 'b_vscrt': coredata.UserComboOption('VS run-time library type to use.', ['none', 'md', 'mdd', 'mt', 'mtd', 'from_buildtype'], 'from_buildtype'), } def option_enabled(boptions, options, option): try: if option not in boptions: return False return options[option].value except KeyError: return False def get_base_compile_args(options, compiler): args = [] try: if options['b_lto'].value: args.extend(compiler.get_lto_compile_args()) except KeyError: pass try: args += compiler.get_colorout_args(options['b_colorout'].value) except KeyError: pass try: args += compiler.sanitizer_compile_args(options['b_sanitize'].value) except KeyError: pass try: pgo_val = options['b_pgo'].value if pgo_val == 'generate': args.extend(compiler.get_profile_generate_args()) elif pgo_val == 'use': args.extend(compiler.get_profile_use_args()) except KeyError: pass try: if options['b_coverage'].value: args += compiler.get_coverage_args() except KeyError: pass try: if (options['b_ndebug'].value == 'true' or (options['b_ndebug'].value == 'if-release' and options['buildtype'].value in {'release', 'plain'})): args += ['-DNDEBUG'] except KeyError: pass # This does not need a try...except if option_enabled(compiler.base_options, options, 'b_bitcode'): args.append('-fembed-bitcode') try: crt_val = options['b_vscrt'].value buildtype = options['buildtype'].value try: args += compiler.get_crt_compile_args(crt_val, buildtype) except AttributeError: pass except KeyError: pass return args def get_base_link_args(options, linker, is_shared_module): args = [] try: if options['b_lto'].value: args.extend(linker.get_lto_link_args()) except KeyError: pass try: args += linker.sanitizer_link_args(options['b_sanitize'].value) except KeyError: pass try: pgo_val = options['b_pgo'].value if pgo_val == 'generate': args.extend(linker.get_profile_generate_args()) elif pgo_val == 'use': args.extend(linker.get_profile_use_args()) except KeyError: pass try: if options['b_coverage'].value: args += linker.get_coverage_link_args() except KeyError: pass as_needed = option_enabled(linker.base_options, options, 'b_asneeded') bitcode = option_enabled(linker.base_options, options, 'b_bitcode') # Shared modules cannot be built with bitcode_bundle because # -bitcode_bundle is incompatible with -undefined and -bundle if bitcode and not is_shared_module: args.extend(linker.bitcode_args()) elif as_needed: # -Wl,-dead_strip_dylibs is incompatible with bitcode args.extend(linker.get_asneeded_args()) # Apple's ld (the only one that supports bitcode) does not like any # -undefined arguments at all, so don't pass these when using bitcode if not bitcode: if (not is_shared_module and option_enabled(linker.base_options, options, 'b_lundef')): args.extend(linker.no_undefined_link_args()) else: args.extend(linker.get_allow_undefined_link_args()) try: crt_val = options['b_vscrt'].value buildtype = options['buildtype'].value try: args += linker.get_crt_link_args(crt_val, buildtype) except AttributeError: pass except KeyError: pass return args class CrossNoRunException(MesonException): pass class RunResult: def __init__(self, compiled, returncode=999, stdout='UNDEFINED', stderr='UNDEFINED'): self.compiled = compiled self.returncode = returncode self.stdout = stdout self.stderr = stderr class CompilerArgs(collections.abc.MutableSequence): ''' 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 .to_native() method to which you must pass an instance of the compiler or the compiler class. New arguments added to this class (either with .append(), .extend(), or +=) are added in a way that ensures that they override previous arguments. For example: >>> a = ['-Lfoo', '-lbar'] >>> a += ['-Lpho', '-lbaz'] >>> print(a) ['-Lpho', '-Lfoo', '-lbar', '-lbaz'] Arguments will also be de-duped if they can be de-duped safely. Note that because of all this, this class is not commutative and does not preserve the order of arguments if it is safe to not. For example: >>> ['-Ifoo', '-Ibar'] + ['-Ifez', '-Ibaz', '-Werror'] ['-Ifez', '-Ibaz', '-Ifoo', '-Ibar', '-Werror'] >>> ['-Ifez', '-Ibaz', '-Werror'] + ['-Ifoo', '-Ibar'] ['-Ifoo', '-Ibar', '-Ifez', '-Ibaz', '-Werror'] ''' # NOTE: currently this class is only for C-like compilers, but it can be # extended to other languages easily. Just move the following to the # compiler class and initialize when self.compiler is set. # Arg prefixes that override by prepending instead of appending prepend_prefixes = ('-I', '-L') # Arg prefixes and args that must be de-duped by returning 2 dedup2_prefixes = ('-I', '-isystem', '-L', '-D', '-U') dedup2_suffixes = () dedup2_args = () # Arg prefixes and args that must be de-duped by returning 1 # # NOTE: not thorough. A list of potential corner cases can be found in # https://github.com/mesonbuild/meson/pull/4593#pullrequestreview-182016038 dedup1_prefixes = ('-l', '-Wl,-l', '-Wl,--export-dynamic') dedup1_suffixes = ('.lib', '.dll', '.so', '.dylib', '.a') # Match a .so of the form path/to/libfoo.so.0.1.0 # Only UNIX shared libraries require this. Others have a fixed extension. dedup1_regex = re.compile(r'([\/\\]|\A)lib.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$') dedup1_args = ('-c', '-S', '-E', '-pipe', '-pthread') # 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) def __init__(self, compiler: T.Union['Compiler', StaticLinker], iterable: T.Optional[T.Iterable[str]] = None): self.compiler = compiler self.__container = list(iterable) if iterable is not None else [] # type: T.List[str] @T.overload # noqa: F811 def __getitem__(self, index: int) -> str: # noqa: F811 pass @T.overload # noqa: F811 def __getitem__(self, index: slice) -> T.List[str]: # noqa: F811 pass def __getitem__(self, index): # noqa: F811 return self.__container[index] @T.overload # noqa: F811 def __setitem__(self, index: int, value: str) -> None: # noqa: F811 pass @T.overload # noqa: F811 def __setitem__(self, index: slice, value: T.List[str]) -> None: # noqa: F811 pass def __setitem__(self, index, value) -> None: # noqa: F811 self.__container[index] = value def __delitem__(self, index: T.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): ''' Returns whether the argument can be safely de-duped. This is dependent on three things: a) Whether an argument can be 'overridden' by a later argument. For example, -DFOO defines FOO and -UFOO undefines FOO. In this case, we can safely remove the previous occurrence and add a new one. The same is true for include paths and library paths with -I and -L. For these we return `2`. See `dedup2_prefixes` and `dedup2_args`. b) Arguments that once specified cannot be undone, such as `-c` or `-pipe`. New instances of these can be completely skipped. For these we return `1`. See `dedup1_prefixes` and `dedup1_args`. c) Whether it matters where or how many times on the command-line a particular argument is present. This can matter for symbol resolution in static or shared libraries, so we cannot de-dup or reorder them. For these we return `0`. This is the default. In addition to these, we handle library arguments specially. With GNU ld, we surround library arguments with -Wl,--start/end-group to recursively search for symbols in the libraries. This is not needed with other linkers. ''' # A standalone argument must never be deduplicated because it is # defined by what comes _after_ it. Thus dedupping this: # -D FOO -D BAR # would yield either # -D FOO BAR # or # FOO -D BAR # both of which are invalid. if arg in cls.dedup2_prefixes: return 0 if arg in cls.dedup2_args or \ arg.startswith(cls.dedup2_prefixes) or \ arg.endswith(cls.dedup2_suffixes): return 2 if arg in cls.dedup1_args or \ arg.startswith(cls.dedup1_prefixes) or \ arg.endswith(cls.dedup1_suffixes) or \ re.search(cls.dedup1_regex, arg): return 1 return 0 @classmethod def _should_prepend(cls, arg): if arg.startswith(cls.prepend_prefixes): return True return False def to_native(self, copy: bool = False) -> T.List[str]: # Check if we need to add --start/end-group for circular dependencies # between static libraries, and for recursively searching for symbols # needed by static libraries that are provided by object files or # shared libraries. if copy: new = self.copy() else: new = self # 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 (isinstance(self.compiler, Compiler) and self.compiler.linker is not None and isinstance(self.compiler.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker))): group_start = -1 group_end = -1 for i, each in enumerate(new): if not each.startswith(('-Wl,-l', '-l')) and not each.endswith('.a') and \ not soregex.match(each): continue group_end = i if group_start < 0: # First occurrence of a library group_start = i if group_start >= 0: # Last occurrence of a library new.insert(group_end + 1, '-Wl,--end-group') new.insert(group_start, '-Wl,--start-group') # 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 = [] # type: T.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 i < (len(new) - 1) and new[i + 1] in default_dirs): bad_idx_list += [i, i + 1] elif each.startswith('-isystem=') and each[9:] in default_dirs: bad_idx_list += [i] elif each.startswith('-isystem') and each[8:] in default_dirs: bad_idx_list += [i] for i in reversed(bad_idx_list): new.pop(i) return self.compiler.unix_args_to_native(new.__container) 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 safely. ''' if os.path.isabs(arg): self.append(arg) else: self.__container.append(arg) def extend_direct(self, iterable: T.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 include search directories is not relevant ''' for elem in iterable: self.append_direct(elem) def extend_preserving_lflags(self, iterable: T.Iterable[str]) -> None: normal_flags = [] lflags = [] for i in iterable: if i not in self.always_dedup_args and (i.startswith('-l') or i.startswith('-L')): lflags.append(i) else: normal_flags.append(i) self.extend(normal_flags) self.extend_direct(lflags) def __add__(self, args: T.Iterable[str]) -> 'CompilerArgs': new = self.copy() new += args return new def __iadd__(self, args: T.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 = [] # type: T.List[str] post = [] # type: T.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 # new occurrence. dedup = self._can_dedup(arg) if dedup == 1: # Argument already exists and adding a new instance is useless if arg in self or arg in pre or arg in post: continue if dedup == 2: # Remove all previous occurrences of the arg and add it anew if arg in self: self.remove(arg) if arg in pre: pre.remove(arg) if arg in post: post.remove(arg) if self._should_prepend(arg): pre.append(arg) else: post.append(arg) # Insert at the beginning self[:0] = pre # Append to the end self.__container += post return self def __radd__(self, args: T.Iterable[str]): new = CompilerArgs(self.compiler, args) new += self return new def __eq__(self, other: T.Any) -> T.Union[bool, type(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 append(self, arg: str) -> None: self.__iadd__([arg]) def extend(self, args: T.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. ignore_libs = () # Libraries that are internal compiler implementations, and must not be # manually searched. internal_libs = () LINKER_PREFIX = None # type: T.Union[None, str, T.List[str]] INVOKES_LINKER = True def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', linker: T.Optional['DynamicLinker'] = None, **kwargs): if isinstance(exelist, str): self.exelist = [exelist] elif isinstance(exelist, list): self.exelist = exelist else: raise TypeError('Unknown argument to Compiler') # In case it's been overridden by a child class already if not hasattr(self, 'file_suffixes'): self.file_suffixes = lang_suffixes[self.language] if not hasattr(self, 'can_compile_suffixes'): self.can_compile_suffixes = set(self.file_suffixes) self.default_suffix = self.file_suffixes[0] self.version = version if 'full_version' in kwargs: self.full_version = kwargs['full_version'] else: self.full_version = None self.for_machine = for_machine self.base_options = [] self.linker = linker self.info = info def __repr__(self): repr_str = "<{0}: v{1} `{2}`>" return repr_str.format(self.__class__.__name__, self.version, ' '.join(self.exelist)) def can_compile(self, src) -> bool: if hasattr(src, 'fname'): src = src.fname suffix = os.path.splitext(src)[1].lower() if suffix and suffix[1:] in self.can_compile_suffixes: return True return False def get_id(self) -> str: return self.id def get_linker_id(self) -> str: # There is not guarantee that we have a dynamic linker instance, as # some languages don't have separate linkers and compilers. In those # cases return the compiler id try: return self.linker.id except AttributeError: return self.id def get_version_string(self) -> str: details = [self.id, self.version] if self.full_version: details += ['"%s"' % (self.full_version)] return '(%s)' % (' '.join(details)) def get_language(self) -> str: return self.language @classmethod def get_display_language(cls) -> str: return cls.language.capitalize() def get_default_suffix(self) -> str: return self.default_suffix def get_define(self, dname, prefix, env, extra_args, dependencies) -> T.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: raise EnvironmentException('%s does not support compute_int ' % self.get_id()) 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) -> T.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) -> T.Tuple[bool, bool]: raise EnvironmentException('%s does not support has_type ' % self.get_id()) def symbols_have_underscore_prefix(self, env) -> bool: raise EnvironmentException('%s does not support symbols_have_underscore_prefix ' % self.get_id()) def get_exelist(self): return self.exelist[:] def get_linker_exelist(self) -> T.List[str]: return self.linker.get_exelist() def get_linker_output_args(self, outputname: str) -> T.List[str]: return self.linker.get_output_args(outputname) def get_builtin_define(self, *args, **kwargs): raise EnvironmentException('%s does not support get_builtin_define.' % self.id) def has_builtin_define(self, *args, **kwargs): raise EnvironmentException('%s does not support has_builtin_define.' % self.id) def get_always_args(self): return [] def can_linker_accept_rsp(self) -> bool: """ Determines whether the linker can accept arguments using the @rsp syntax. """ return self.linker.get_accepts_rsp() def get_linker_always_args(self): return self.linker.get_always_args() def get_linker_lib_prefix(self): return self.linker.get_lib_prefix() def gen_import_library_args(self, implibname): """ Used only on Windows for libraries that need an import library. This currently means C, C++, Fortran. """ return [] def get_linker_args_from_envvars(self) -> T.List[str]: return self.linker.get_args_from_envvars() def get_options(self) -> T.Dict[str, coredata.UserOption]: return {} def get_option_compile_args(self, options): return [] def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: return self.linker.get_option_args(options) def check_header(self, *args, **kwargs) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language()) def has_header(self, *args, **kwargs) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language()) def has_header_symbol(self, *args, **kwargs) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header symbol checks.' % self.get_display_language()) def compiles(self, *args, **kwargs) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support compile checks.' % self.get_display_language()) def links(self, *args, **kwargs) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support link checks.' % self.get_display_language()) def run(self, *args, **kwargs) -> RunResult: raise EnvironmentException('Language %s does not support run checks.' % self.get_display_language()) def sizeof(self, *args, **kwargs) -> int: raise EnvironmentException('Language %s does not support sizeof checks.' % self.get_display_language()) 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) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support function checks.' % self.get_display_language()) @classmethod def unix_args_to_native(cls, args): "Always returns a copy that can be independently mutated" return args[:] @classmethod def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]: "Always returns a copy that can be independently mutated" return args[:] def find_library(self, *args, **kwargs): raise EnvironmentException('Language {} does not support library finding.'.format(self.get_display_language())) def get_library_dirs(self, *args, **kwargs): return () def get_program_dirs(self, *args, **kwargs): return [] def has_multi_arguments(self, args, env) -> T.Tuple[bool, bool]: raise EnvironmentException( 'Language {} does not support has_multi_arguments.'.format( self.get_display_language())) def has_multi_link_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: return self.linker.has_multi_arguments(args, env) def _get_compile_output(self, dirname, mode): # In pre-processor mode, the output is sent to stdout and discarded if mode == 'preprocess': return None # Extension only matters if running results; '.exe' is # guaranteed to be executable on every platform. if mode == 'link': suffix = 'exe' else: suffix = 'obj' return os.path.join(dirname, 'output.' + suffix) def get_compiler_args_for_mode(self, mode): args = [] args += self.get_always_args() if mode == 'compile': args += self.get_compile_only_args() if mode == 'preprocess': args += self.get_preprocess_only_args() return args @contextlib.contextmanager def compile(self, code, extra_args=None, *, mode='link', want_output=False, temp_dir=None): if extra_args is None: extra_args = [] try: with tempfile.TemporaryDirectory(dir=temp_dir) as tmpdirname: if isinstance(code, str): srcname = os.path.join(tmpdirname, 'testfile.' + self.default_suffix) with open(srcname, 'w') as ofile: ofile.write(code) elif isinstance(code, mesonlib.File): srcname = code.fname # Construct the compiler command-line commands = CompilerArgs(self) commands.append(srcname) # Preprocess mode outputs to stdout, so no output args if mode != 'preprocess': output = self._get_compile_output(tmpdirname, mode) commands += self.get_output_args(output) commands.extend(self.get_compiler_args_for_mode(mode)) # extra_args must be last because it could contain '/link' to # pass args to VisualStudio's linker. In that case everything # in the command line after '/link' is given to the linker. commands += extra_args # Generate full command-line with the exelist commands = self.get_exelist() + commands.to_native() mlog.debug('Running compile:') mlog.debug('Working directory: ', tmpdirname) mlog.debug('Command line: ', ' '.join(commands), '\n') mlog.debug('Code:\n', code) os_env = os.environ.copy() os_env['LC_ALL'] = 'C' p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname, env=os_env) mlog.debug('Compiler stdout:\n', p.stdo) mlog.debug('Compiler stderr:\n', p.stde) p.commands = commands p.input_name = srcname if want_output: p.output_name = output p.cached = False # Make sure that the cached attribute always exists yield p except OSError: # On Windows antivirus programs and the like hold on to files so # they can't be deleted. There's not much to do in this case. Also, # catch OSError because the directory is then no longer empty. pass @contextlib.contextmanager def cached_compile(self, code, cdata: coredata.CoreData, *, extra_args=None, mode: str = 'link', temp_dir=None): assert(isinstance(cdata, coredata.CoreData)) # Calculate the key textra_args = tuple(extra_args) if extra_args is not None else None key = (tuple(self.exelist), self.version, code, textra_args, mode) # Check if not cached if key not in cdata.compiler_check_cache: with self.compile(code, extra_args=extra_args, mode=mode, want_output=False, temp_dir=temp_dir) as p: # Remove all attributes except the following # This way the object can be serialized tokeep = ['args', 'commands', 'input_name', 'output_name', 'pid', 'returncode', 'stdo', 'stde', 'text_mode'] todel = [x for x in vars(p).keys() if x not in tokeep] for i in todel: delattr(p, i) p.cached = False cdata.compiler_check_cache[key] = p yield p return # Return cached p = cdata.compiler_check_cache[key] p.cached = True mlog.debug('Using cached compile:') mlog.debug('Cached command line: ', ' '.join(p.commands), '\n') mlog.debug('Code:\n', code) mlog.debug('Cached compiler stdout:\n', p.stdo) mlog.debug('Cached compiler stderr:\n', p.stde) yield p def get_colorout_args(self, colortype): return [] # Some compilers (msvc) write debug info to a separate file. # These args specify where it should be written. def get_compile_debugfile_args(self, rel_obj, **kwargs): return [] def get_link_debugfile_args(self, targetfile: str) -> T.List[str]: return self.linker.get_debugfile_args(targetfile) def get_std_shared_lib_link_args(self) -> T.List[str]: return self.linker.get_std_shared_lib_args() def get_std_shared_module_link_args(self, options: 'OptionDictType') -> T.List[str]: return self.linker.get_std_shared_module_args(options) def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: return self.linker.get_link_whole_for(args) def get_allow_undefined_link_args(self) -> T.List[str]: return self.linker.get_allow_undefined_args() def no_undefined_link_args(self) -> T.List[str]: return self.linker.no_undefined_args() # Compiler arguments needed to enable the given instruction set. # May be [] meaning nothing needed or None meaning the given set # is not supported. def get_instruction_set_args(self, instruction_set): return None def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, install_rpath: str) -> T.List[str]: return self.linker.build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) def thread_flags(self, env): return [] def openmp_flags(self): raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language()) def language_stdlib_only_link_flags(self): return [] def gnu_symbol_visibility_args(self, vistype): return [] def get_gui_app_args(self, value): return [] def has_func_attribute(self, name, env): raise EnvironmentException( 'Language {} does not support function attributes.'.format(self.get_display_language())) def get_pic_args(self): m = 'Language {} does not support position-independent code' raise EnvironmentException(m.format(self.get_display_language())) def get_pie_args(self): m = 'Language {} does not support position-independent executable' raise EnvironmentException(m.format(self.get_display_language())) def get_pie_link_args(self) -> T.List[str]: return self.linker.get_pie_args() def get_argument_syntax(self): """Returns the argument family type. Compilers fall into families if they try to emulate the command line interface of another compiler. For example, clang is in the GCC family since it accepts most of the same arguments as GCC. ICL (ICC on windows) is in the MSVC family since it accepts most of the same arguments as MSVC. """ return 'other' def get_profile_generate_args(self): raise EnvironmentException( '%s does not support get_profile_generate_args ' % self.get_id()) def get_profile_use_args(self): raise EnvironmentException( '%s does not support get_profile_use_args ' % self.get_id()) def get_undefined_link_args(self) -> T.List[str]: return self.linker.get_undefined_link_args() def remove_linkerlike_args(self, args): rm_exact = ('-headerpad_max_install_names',) rm_prefixes = ('-Wl,', '-L',) rm_next = ('-L',) ret = [] iargs = iter(args) for arg in iargs: # Remove this argument if arg in rm_exact: continue # If the argument starts with this, but is not *exactly* this # f.ex., '-L' should match ['-Lfoo'] but not ['-L', 'foo'] if arg.startswith(rm_prefixes) and arg not in rm_prefixes: continue # Ignore this argument and the one after it if arg in rm_next: next(iargs) continue ret.append(arg) return ret def get_lto_compile_args(self) -> T.List[str]: return [] def get_lto_link_args(self) -> T.List[str]: return self.linker.get_lto_args() def sanitizer_compile_args(self, value: str) -> T.List[str]: return [] def sanitizer_link_args(self, value: str) -> T.List[str]: return self.linker.sanitizer_args(value) def get_asneeded_args(self) -> T.List[str]: return self.linker.get_asneeded_args() def bitcode_args(self) -> T.List[str]: return self.linker.bitcode_args() def get_linker_debug_crt_args(self) -> T.List[str]: return self.linker.get_debug_crt_args() def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: 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: T.Tuple[str, str], is_shared_module: bool) -> T.List[str]: return self.linker.get_soname_args( env, prefix, shlib_name, suffix, soversion, darwin_versions, is_shared_module) def get_target_link_args(self, target): return target.link_args def get_dependency_compile_args(self, dep): return dep.get_compile_args() def get_dependency_link_args(self, dep): return dep.get_link_args() @classmethod def use_linker_args(cls, linker: str) -> T.List[str]: """Get a list of arguments to pass to the compiler to set the linker. """ return [] def get_largefile_args(compiler): ''' Enable transparent large-file-support for 32-bit UNIX systems ''' if not (compiler.info.is_windows() or compiler.info.is_darwin()): # Enable large-file support unconditionally on all platforms other # than macOS and Windows. macOS is now 64-bit-only so it doesn't # need anything special, and Windows doesn't have automatic LFS. # You must use the 64-bit counterparts explicitly. # glibc, musl, and uclibc, and all BSD libcs support this. On Android, # support for transparent LFS is available depending on the version of # Bionic: https://github.com/android/platform_bionic#32-bit-abi-bugs # https://code.google.com/p/android/issues/detail?id=64613 # # If this breaks your code, fix it! It's been 20+ years! return ['-D_FILE_OFFSET_BITS=64'] # We don't enable -D_LARGEFILE64_SOURCE since that enables # transitionary features and must be enabled by programs that use # those features explicitly. return [] def get_args_from_envvars(lang: str, use_linker_args: bool) -> T.Tuple[T.List[str], T.List[str]]: """ Returns a tuple of (compile_flags, link_flags) for the specified language from the inherited environment """ def log_var(var, val: T.Optional[str]): if val: mlog.log('Appending {} from environment: {!r}'.format(var, val)) else: mlog.debug('No {} in the environment, not changing global flags.'.format(var)) if lang not in cflags_mapping: return [], [] compile_flags = [] # type: T.List[str] link_flags = [] # type: T.List[str] env_compile_flags = os.environ.get(cflags_mapping[lang]) log_var(cflags_mapping[lang], env_compile_flags) if env_compile_flags is not None: compile_flags += split_args(env_compile_flags) # Link flags (same for all languages) if lang in languages_using_ldflags: # This is duplicated between the linkers, but I'm not sure how else # to handle this env_link_flags = split_args(os.environ.get('LDFLAGS', '')) else: env_link_flags = [] log_var('LDFLAGS', env_link_flags) link_flags += env_link_flags if use_linker_args: # When the compiler is used as a wrapper around the linker (such as # with GCC and Clang), the compile flags can be needed while linking # too. This is also what Autotools does. However, we don't want to do # this when the linker is stand-alone such as with MSVC C/C++, etc. link_flags = compile_flags + link_flags # Pre-processor flags for certain languages if lang in {'c', 'cpp', 'objc', 'objcpp'}: env_preproc_flags = os.environ.get('CPPFLAGS') log_var('CPPFLAGS', env_preproc_flags) if env_preproc_flags is not None: compile_flags += split_args(env_preproc_flags) return compile_flags, link_flags def get_global_options(lang: str, comp: T.Type[Compiler], properties: Properties) -> T.Dict[str, coredata.UserOption]: """Retreive options that apply to all compilers for a given language.""" description = 'Extra arguments passed to the {}'.format(lang) opts = { lang + '_args': coredata.UserArrayOption( description + ' compiler', [], split_args=True, user_input=True, allow_dups=True), lang + '_link_args': coredata.UserArrayOption( description + ' linker', [], split_args=True, user_input=True, allow_dups=True), } if properties.fallback: # Get from env vars. # XXX: True here is a hack compile_args, link_args = get_args_from_envvars(lang, comp.INVOKES_LINKER) else: compile_args = [] link_args = [] for k, o in opts.items(): if k in properties: # Get from configuration files. o.set_value(properties[k]) elif k == lang + '_args': o.set_value(compile_args) elif k == lang + '_link_args': o.set_value(link_args) return opts meson-0.53.2/mesonbuild/compilers/cpp.py0000644000175000017500000006530213625260316021620 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import copy import functools import os.path import typing as T from .. import coredata from .. import mlog from ..mesonlib import MesonException, MachineChoice, version_compare from .compilers import ( gnu_winlibs, msvc_winlibs, Compiler, ) from .c_function_attributes import CXX_FUNC_ATTRIBUTES, C_FUNC_ATTRIBUTES from .mixins.clike import CLikeCompiler from .mixins.ccrx import CcrxCompiler from .mixins.arm import ArmCompiler, ArmclangCompiler from .mixins.visualstudio import VisualStudioLikeCompiler from .mixins.gnu import GnuCompiler from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler from .mixins.clang import ClangCompiler from .mixins.elbrus import ElbrusCompiler from .mixins.pgi import PGICompiler from .mixins.islinker import BasicLinkerIsCompilerMixin, LinkerEnvVarsMixin from .mixins.emscripten import EmscriptenMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo def non_msvc_eh_options(eh, args): if eh == 'none': args.append('-fno-exceptions') elif eh == 's' or eh == 'c': mlog.warning('non-MSVC compilers do not support ' + eh + ' exception handling.' + 'You may want to set eh to \'default\'.') class CPPCompiler(CLikeCompiler, Compiler): @classmethod def attribute_check_func(cls, name): try: return CXX_FUNC_ATTRIBUTES.get(name, C_FUNC_ATTRIBUTES[name]) except KeyError: raise MesonException('Unknown function attribute "{}"'.format(name)) language = 'cpp' def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrap: T.Optional[str] = None, **kwargs): # If a child ObjCPP class has already set it, don't set it ourselves Compiler.__init__(self, exelist, version, for_machine, info, **kwargs) CLikeCompiler.__init__(self, is_cross, exe_wrap) @staticmethod def get_display_language(): return 'C++' def get_no_stdinc_args(self): return ['-nostdinc++'] def sanity_check(self, work_dir, environment): code = 'class breakCCompiler;int main(void) { return 0; }\n' return self.sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code) def get_compiler_check_args(self): # -fpermissive allows non-conforming code to compile which is necessary # for many C++ checks. Particularly, the has_header_symbol check is # too strict without this and always fails. return super().get_compiler_check_args() + ['-fpermissive'] def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None): # Check if it's a C-like symbol found, cached = super().has_header_symbol(hname, symbol, prefix, env, extra_args=extra_args, dependencies=dependencies) if found: return True, cached # Check if it's a class or a template if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol} t = '''{prefix} #include <{header}> using {symbol}; int main(void) {{ return 0; }}''' return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) def _test_cpp_std_arg(self, cpp_std_value): # Test whether the compiler understands a -std=XY argument assert(cpp_std_value.startswith('-std=')) # This test does not use has_multi_arguments() for two reasons: # 1. has_multi_arguments() requires an env argument, which the compiler # object does not have at this point. # 2. even if it did have an env object, that might contain another more # recent -std= argument, which might lead to a cascaded failure. CPP_TEST = 'int i = static_cast(0);' with self.compile(CPP_TEST, extra_args=[cpp_std_value], mode='compile') as p: if p.returncode == 0: mlog.debug('Compiler accepts {}:'.format(cpp_std_value), 'YES') return True else: mlog.debug('Compiler accepts {}:'.format(cpp_std_value), 'NO') return False @functools.lru_cache() def _find_best_cpp_std(self, cpp_std): # The initial version mapping approach to make falling back # from '-std=c++14' to '-std=c++1y' was too brittle. For instance, # Apple's Clang uses a different versioning scheme to upstream LLVM, # making the whole detection logic awfully brittle. Instead, let's # just see if feeding GCC or Clang our '-std=' setting works, and # if not, try the fallback argument. CPP_FALLBACKS = { 'c++11': 'c++0x', 'gnu++11': 'gnu++0x', 'c++14': 'c++1y', 'gnu++14': 'gnu++1y', 'c++17': 'c++1z', 'gnu++17': 'gnu++1z' } # Currently, remapping is only supported for Clang, Elbrus and GCC assert(self.id in frozenset(['clang', 'lcc', 'gcc', 'emscripten'])) if cpp_std not in CPP_FALLBACKS: # 'c++03' and 'c++98' don't have fallback types return '-std=' + cpp_std for i in (cpp_std, CPP_FALLBACKS[cpp_std]): cpp_std_value = '-std=' + i if self._test_cpp_std_arg(cpp_std_value): return cpp_std_value raise MesonException('C++ Compiler does not support -std={}'.format(cpp_std)) class ClangCPPCompiler(ClangCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) ClangCompiler.__init__(self) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): opts = CPPCompiler.get_options(self) opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), 'cpp_rtti': coredata.UserBooleanOption('Enable RTTI', True), 'cpp_std': coredata.UserComboOption('C++ language standard to use', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'], 'none')}) return opts def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) non_msvc_eh_options(options['cpp_eh'].value, args) if not options['cpp_rtti'].value: args.append('-fno-rtti') return args def get_option_link_args(self, options): return [] def language_stdlib_only_link_flags(self): return ['-lstdc++'] class AppleClangCPPCompiler(ClangCPPCompiler): pass class EmscriptenCPPCompiler(LinkerEnvVarsMixin, EmscriptenMixin, BasicLinkerIsCompilerMixin, ClangCPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs): if not is_cross: raise MesonException('Emscripten compiler can only be used for cross compilation.') ClangCPPCompiler.__init__(self, exelist=exelist, version=version, for_machine=for_machine, is_cross=is_cross, info=info, exe_wrapper=exe_wrapper, **kwargs) self.id = 'emscripten' def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) return args class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) ArmclangCompiler.__init__(self) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): opts = CPPCompiler.get_options(self) opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), 'cpp_std': coredata.UserComboOption('C++ language standard to use', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'gnu++98', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17'], 'none')}) return opts def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': args.append('-std=' + std.value) non_msvc_eh_options(options['cpp_eh'].value, args) return args def get_option_link_args(self, options): return [] class GnuCPPCompiler(GnuCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap, defines, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) GnuCompiler.__init__(self, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): opts = CPPCompiler.get_options(self) opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), 'cpp_rtti': coredata.UserBooleanOption('Enable RTTI', True), 'cpp_std': coredata.UserComboOption('C++ language standard to use', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'], 'none'), 'cpp_debugstl': coredata.UserBooleanOption('STL debug mode', False)}) if self.info.is_windows() or self.info.is_cygwin(): opts.update({ 'cpp_winlibs': coredata.UserArrayOption('Standard Win libraries to link against', gnu_winlibs), }) return opts def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) non_msvc_eh_options(options['cpp_eh'].value, args) if not options['cpp_rtti'].value: args.append('-fno-rtti') if options['cpp_debugstl'].value: args.append('-D_GLIBCXX_DEBUG=1') return args def get_option_link_args(self, options): if self.info.is_windows() or self.info.is_cygwin(): return options['cpp_winlibs'].value[:] return [] def get_pch_use_args(self, pch_dir, header): return ['-fpch-preprocess', '-include', os.path.basename(header)] def language_stdlib_only_link_flags(self): return ['-lstdc++'] class PGICPPCompiler(PGICompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) PGICompiler.__init__(self) class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, defines=None, **kwargs): GnuCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, defines, **kwargs) ElbrusCompiler.__init__(self) # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98. def get_options(self): opts = CPPCompiler.get_options(self) opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), 'cpp_std': coredata.UserComboOption('C++ language standard to use', ['none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y', 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y'], 'none'), 'cpp_debugstl': coredata.UserBooleanOption('STL debug mode', False)}) return opts # Elbrus C++ compiler does not have lchmod, but there is only linker warning, not compiler error. # So we should explicitly fail at this case. def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None): if funcname == 'lchmod': return False, False else: return super().has_function(funcname, prefix, env, extra_args=extra_args, dependencies=dependencies) # Elbrus C++ compiler does not support RTTI, so don't check for it. def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) non_msvc_eh_options(options['cpp_eh'].value, args) if options['cpp_debugstl'].value: args.append('-D_GLIBCXX_DEBUG=1') return args class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) IntelGnuLikeCompiler.__init__(self) self.lang_header = 'c++-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', '-Wpch-messages', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra']} def get_options(self): opts = CPPCompiler.get_options(self) # Every Unix compiler under the sun seems to accept -std=c++03, # with the exception of ICC. Instead of preventing the user from # globally requesting C++03, we transparently remap it to C++98 c_stds = ['c++98', 'c++03'] g_stds = ['gnu++98', 'gnu++03'] if version_compare(self.version, '>=15.0.0'): c_stds += ['c++11', 'c++14'] g_stds += ['gnu++11'] if version_compare(self.version, '>=16.0.0'): c_stds += ['c++17'] if version_compare(self.version, '>=17.0.0'): g_stds += ['gnu++14'] opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), 'cpp_rtti': coredata.UserBooleanOption('Enable RTTI', True), 'cpp_std': coredata.UserComboOption('C++ language standard to use', ['none'] + c_stds + g_stds, 'none'), 'cpp_debugstl': coredata.UserBooleanOption('STL debug mode', False)}) return opts def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': remap_cpp03 = { 'c++03': 'c++98', 'gnu++03': 'gnu++98' } args.append('-std=' + remap_cpp03.get(std.value, std.value)) if options['cpp_eh'].value == 'none': args.append('-fno-exceptions') if not options['cpp_rtti'].value: args.append('-fno-rtti') if options['cpp_debugstl'].value: args.append('-D_GLIBCXX_DEBUG=1') return args def get_option_link_args(self, options): return [] class VisualStudioLikeCPPCompilerMixin: """Mixin for C++ specific method overrides in MSVC-like compilers.""" VC_VERSION_MAP = { 'none': (True, None), 'vc++11': (True, 11), 'vc++14': (True, 14), 'vc++17': (True, 17), 'vc++latest': (True, "latest"), 'c++11': (False, 11), 'c++14': (False, 14), 'c++17': (False, 17), 'c++latest': (False, "latest"), } def get_option_link_args(self, options): return options['cpp_winlibs'].value[:] def _get_options_impl(self, opts, cpp_stds: T.List[str]): opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default'), 'cpp_rtti': coredata.UserBooleanOption('Enable RTTI', True), 'cpp_std': coredata.UserComboOption('C++ language standard to use', cpp_stds, 'none'), 'cpp_winlibs': coredata.UserArrayOption('Windows libs to link against.', msvc_winlibs)}) return opts def get_option_compile_args(self, options): args = [] eh = options['cpp_eh'] if eh.value == 'default': args.append('/EHsc') elif eh.value == 'none': args.append('/EHs-c-') else: args.append('/EH' + eh.value) if not options['cpp_rtti'].value: args.append('/GR-') permissive, ver = self.VC_VERSION_MAP[options['cpp_std'].value] if ver is not None: args.append('/std:c++{}'.format(ver)) if not permissive: args.append('/permissive-') return args def get_compiler_check_args(self): # XXX: this is a hack because so much GnuLike stuff is in the base CPPCompiler class. return CLikeCompiler.get_compiler_check_args(self) class CPP11AsCPP14Mixin: """Mixin class for VisualStudio and ClangCl to replace C++11 std with C++14. This is a limitation of Clang and MSVC that ICL doesn't share. """ def get_option_compile_args(self, options): # Note: there is no explicit flag for supporting C++11; we attempt to do the best we can # which means setting the C++ standard version to C++14, in compilers that support it # (i.e., after VS2015U3) # if one is using anything before that point, one cannot set the standard. if options['cpp_std'].value in {'vc++11', 'c++11'}: mlog.warning(self.id, 'does not support C++11;', 'attempting best effort; setting the standard to C++14', once=True) # Don't mutate anything we're going to change, we need to use # deepcopy since we're messing with members, and we can't simply # copy the members because the option proxy doesn't support it. options = copy.deepcopy(options) if options['cpp_std'].value == 'vc++11': options['cpp_std'].value = 'vc++14' else: options['cpp_std'].value = 'c++14' return super().get_option_compile_args(options) class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrap, target, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) VisualStudioLikeCompiler.__init__(self, target) self.base_options = ['b_pch', 'b_vscrt'] # FIXME add lto, pgo and the like self.id = 'msvc' def get_options(self): cpp_stds = ['none', 'c++11', 'vc++11'] # Visual Studio 2015 and later if version_compare(self.version, '>=19'): cpp_stds.extend(['c++14', 'c++latest', 'vc++latest']) # Visual Studio 2017 and later if version_compare(self.version, '>=19.11'): cpp_stds.extend(['vc++14', 'c++17', 'vc++17']) return self._get_options_impl(super().get_options(), cpp_stds) def get_option_compile_args(self, options): if options['cpp_std'].value != 'none' and version_compare(self.version, '<19.00.24210'): mlog.warning('This version of MSVC does not support cpp_std arguments') options = copy.copy(options) options['cpp_std'].value = 'none' args = super().get_option_compile_args(options) if version_compare(self.version, '<19.11'): try: i = args.index('/permissive-') except ValueError: return args del args[i] return args class ClangClCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) VisualStudioLikeCompiler.__init__(self, target) self.id = 'clang-cl' def get_options(self): cpp_stds = ['none', 'c++11', 'vc++11', 'c++14', 'vc++14', 'c++17', 'vc++17', 'c++latest'] return self._get_options_impl(super().get_options(), cpp_stds) class IntelClCPPCompiler(VisualStudioLikeCPPCompilerMixin, IntelVisualStudioLikeCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) IntelVisualStudioLikeCompiler.__init__(self, target) def get_options(self): # This has only been tested with version 19.0, cpp_stds = ['none', 'c++11', 'vc++11', 'c++14', 'vc++14', 'c++17', 'vc++17', 'c++latest'] return self._get_options_impl(super().get_options(), cpp_stds) class ArmCPPCompiler(ArmCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap=None, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) ArmCompiler.__init__(self) def get_options(self): opts = CPPCompiler.get_options(self) opts.update({'cpp_std': coredata.UserComboOption('C++ language standard to use', ['none', 'c++03', 'c++11'], 'none')}) return opts def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value == 'c++11': args.append('--cpp11') elif std.value == 'c++03': args.append('--cpp') return args def get_option_link_args(self, options): return [] def get_compiler_check_args(self): return [] class CcrxCPPCompiler(CcrxCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrap=None, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) CcrxCompiler.__init__(self) # Override CCompiler.get_always_args def get_always_args(self): return ['-nologo', '-lang=cpp'] def get_option_compile_args(self, options): return [] def get_compile_only_args(self): return [] def get_output_args(self, target): return ['-output=obj=%s' % target] def get_option_link_args(self, options): return [] def get_compiler_check_args(self): return [] meson-0.53.2/mesonbuild/compilers/cs.py0000644000175000017500000001167613612313307021443 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os.path, subprocess import typing as T from ..mesonlib import EnvironmentException from .compilers import Compiler, MachineChoice, mono_buildtype_args from .mixins.islinker import BasicLinkerIsCompilerMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo cs_optimization_args = {'0': [], 'g': [], '1': ['-optimize+'], '2': ['-optimize+'], '3': ['-optimize+'], 's': ['-optimize+'], } class CsCompiler(BasicLinkerIsCompilerMixin, Compiler): language = 'cs' def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', comp_id, runner=None): super().__init__(exelist, version, for_machine, info) self.id = comp_id self.is_cross = False self.runner = runner @classmethod def get_display_language(cls): return 'C sharp' def get_always_args(self): return ['/nologo'] def get_linker_always_args(self): return ['/nologo'] def get_output_args(self, fname): return ['-out:' + fname] def get_link_args(self, fname): return ['-r:' + fname] def get_werror_args(self): return ['-warnaserror'] def split_shlib_to_parts(self, fname): return None, fname def get_dependency_gen_args(self, outtarget, outfile): return [] def get_linker_exelist(self): return self.exelist[:] def get_compile_only_args(self): return [] def get_coverage_args(self): return [] def get_std_exe_link_args(self): return [] def get_include_args(self, path): return [] def get_pic_args(self): return [] def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): for idx, i in enumerate(parameter_list): if i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) if i[:5] == '-lib:': parameter_list[idx] = i[:5] + os.path.normpath(os.path.join(build_dir, i[5:])) return parameter_list def name_string(self): return ' '.join(self.exelist) def get_pch_use_args(self, pch_dir, header): return [] def get_pch_name(self, header_name): return '' def sanity_check(self, work_dir, environment): src = 'sanity.cs' obj = 'sanity.exe' source_name = os.path.join(work_dir, src) with open(source_name, 'w') as ofile: ofile.write('''public class Sanity { static public void Main () { } } ''') pc = subprocess.Popen(self.exelist + self.get_always_args() + [src], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('Mono compiler %s can not compile programs.' % self.name_string()) if self.runner: cmdlist = [self.runner, obj] else: cmdlist = [os.path.join(work_dir, obj)] pe = subprocess.Popen(cmdlist, cwd=work_dir) pe.wait() if pe.returncode != 0: raise EnvironmentException('Executables created by Mono compiler %s are not runnable.' % self.name_string()) def needs_static_linker(self): return False def get_buildtype_args(self, buildtype): return mono_buildtype_args[buildtype] def get_debug_args(self, is_debug): return ['-debug'] if is_debug else [] def get_optimization_args(self, optimization_level): return cs_optimization_args[optimization_level] class MonoCompiler(CsCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo'): super().__init__(exelist, version, for_machine, info, 'mono', runner='mono') class VisualStudioCsCompiler(CsCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo'): super().__init__(exelist, version, for_machine, info, 'csc') def get_buildtype_args(self, buildtype): res = mono_buildtype_args[buildtype] if not self.info.is_windows(): tmp = [] for flag in res: if flag == '-debug': flag = '-debug:portable' tmp.append(flag) res = tmp return res meson-0.53.2/mesonbuild/compilers/cuda.py0000644000175000017500000003155213612313307021745 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os.path import typing as T from functools import partial from .. import coredata from .. import mlog from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe, OptionOverrideProxy, is_windows, LibType from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args, cuda_debug_args) if T.TYPE_CHECKING: from ..environment import Environment # noqa: F401 from ..envconfig import MachineInfo class CudaCompiler(Compiler): LINKER_PREFIX = '-Xlinker=' language = 'cuda' _universal_flags = {'compiler': ['-I', '-D', '-U', '-E'], 'linker': ['-l', '-L']} def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper, host_compiler, info: 'MachineInfo', **kwargs): super().__init__(exelist, version, for_machine, info, **kwargs) self.is_cross = is_cross self.exe_wrapper = exe_wrapper self.host_compiler = host_compiler self.base_options = host_compiler.base_options self.id = 'nvcc' self.warn_args = {level: self._to_host_flags(flags) for level, flags in host_compiler.warn_args.items()} @classmethod def _to_host_flags(cls, flags, phase='compiler'): return list(map(partial(cls._to_host_flag, phase=phase), flags)) @classmethod def _to_host_flag(cls, flag, phase): if not flag[0] in ['-', '/'] or flag[:2] in cls._universal_flags[phase]: return flag return '-X{}={}'.format(phase, flag) def needs_static_linker(self): return False def get_always_args(self): return [] def get_no_stdinc_args(self): return [] def thread_link_flags(self, environment): return self._to_host_flags(self.host_compiler.thread_link_flags(environment)) def sanity_check(self, work_dir, environment): mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist)) mlog.debug('Is cross compiler: %s.' % str(self.is_cross)) sname = 'sanitycheckcuda.cu' code = r''' #include #include __global__ void kernel (void) {} int main(void){ struct cudaDeviceProp prop; int count, i; cudaError_t ret = cudaGetDeviceCount(&count); if(ret != cudaSuccess){ fprintf(stderr, "%d\n", (int)ret); }else{ for(i=0;i using {symbol}; int main(void) {{ return 0; }}''' return self.compiles(t.format(**fargs), env, extra_args, dependencies) def get_options(self): opts = super().get_options() opts.update({'cuda_std': coredata.UserComboOption('C++ language standard to use', ['none', 'c++03', 'c++11', 'c++14'], 'none')}) return opts def _to_host_compiler_options(self, options): overrides = {name: opt.value for name, opt in options.copy().items()} return OptionOverrideProxy(overrides, self.host_compiler.get_options()) def get_option_compile_args(self, options): args = [] # On Windows, the version of the C++ standard used by nvcc is dictated by # the combination of CUDA version and MSVC version; the --std= is thus ignored # and attempting to use it will result in a warning: https://stackoverflow.com/a/51272091/741027 if not is_windows(): std = options['cuda_std'] if std.value != 'none': args.append('--std=' + std.value) return args + self._to_host_flags(self.host_compiler.get_option_compile_args(self._to_host_compiler_options(options))) @classmethod def _cook_link_args(cls, args: T.List[str]) -> T.List[str]: # Prepare link args for nvcc cooked = [] # type: T.List[str] for arg in args: if arg.startswith('-Wl,'): # strip GNU-style -Wl prefix arg = arg.replace('-Wl,', '', 1) arg = arg.replace(' ', '\\') # espace whitespace cooked.append(arg) return cls._to_host_flags(cooked, 'linker') def get_option_link_args(self, options): return self._cook_link_args(self.host_compiler.get_option_link_args(self._to_host_compiler_options(options))) def name_string(self): return ' '.join(self.exelist) def get_soname_args(self, *args): return self._cook_link_args(self.host_compiler.get_soname_args(*args)) def get_dependency_gen_args(self, outtarget, outfile): return [] def get_compile_only_args(self): return ['-c'] def get_no_optimization_args(self): return ['-O0'] def get_optimization_args(self, optimization_level): # alternatively, consider simply redirecting this to the host compiler, which would # give us more control over options like "optimize for space" (which nvcc doesn't support): # return self._to_host_flags(self.host_compiler.get_optimization_args(optimization_level)) return cuda_optimization_args[optimization_level] def get_debug_args(self, is_debug): return cuda_debug_args[is_debug] def get_werror_args(self): return ['-Werror=cross-execution-space-call,deprecated-declarations,reorder'] def get_warn_args(self, level): return self.warn_args[level] def get_buildtype_args(self, buildtype): # nvcc doesn't support msvc's "Edit and Continue" PDB format; "downgrade" to # a regular PDB to avoid cl's warning to that effect (D9025 : overriding '/ZI' with '/Zi') host_args = ['/Zi' if arg == '/ZI' else arg for arg in self.host_compiler.get_buildtype_args(buildtype)] return cuda_buildtype_args[buildtype] + self._to_host_flags(host_args) def get_include_args(self, path, is_system): if path == '': path = '.' return ['-I' + path] def get_compile_debugfile_args(self, rel_obj, **kwargs): return self._to_host_flags(self.host_compiler.get_compile_debugfile_args(rel_obj, **kwargs)) def get_link_debugfile_args(self, targetfile): return self._cook_link_args(self.host_compiler.get_link_debugfile_args(targetfile)) def depfile_for_object(self, objfile): return objfile + '.' + self.get_depfile_suffix() def get_depfile_suffix(self): return 'd' def get_linker_debug_crt_args(self) -> T.List[str]: return self._cook_link_args(self.host_compiler.get_linker_debug_crt_args()) def get_buildtype_linker_args(self, buildtype): return self._cook_link_args(self.host_compiler.get_buildtype_linker_args(buildtype)) def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, install_rpath: str) -> T.List[str]: return self._cook_link_args(self.host_compiler.build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)) def linker_to_compiler_args(self, args): return args def get_pic_args(self): return self._to_host_flags(self.host_compiler.get_pic_args()) def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): return [] def get_output_args(self, target: str) -> T.List[str]: return ['-o', target] def get_std_exe_link_args(self) -> T.List[str]: return self._cook_link_args(self.host_compiler.get_std_exe_link_args()) def find_library(self, libname, env, extra_dirs, libtype: LibType = LibType.PREFER_SHARED): return ['-l' + libname] # FIXME def get_crt_compile_args(self, crt_val, buildtype): return self._to_host_flags(self.host_compiler.get_crt_compile_args(crt_val, buildtype)) def get_crt_link_args(self, crt_val, buildtype): # nvcc defaults to static, release version of msvc runtime and provides no # native option to override it; override it with /NODEFAULTLIB host_link_arg_overrides = [] host_crt_compile_args = self.host_compiler.get_crt_compile_args(crt_val, buildtype) if any(arg in ['/MDd', '/MD', '/MTd'] for arg in host_crt_compile_args): host_link_arg_overrides += ['/NODEFAULTLIB:LIBCMT.lib'] return self._cook_link_args(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val, buildtype)) def get_target_link_args(self, target): return self._cook_link_args(super().get_target_link_args(target)) def get_dependency_compile_args(self, dep): return self._to_host_flags(super().get_dependency_compile_args(dep)) def get_dependency_link_args(self, dep): return self._cook_link_args(super().get_dependency_link_args(dep)) meson-0.53.2/mesonbuild/compilers/d.py0000644000175000017500000007074313612313307021261 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os.path, subprocess import typing as T from ..mesonlib import ( EnvironmentException, MachineChoice, version_compare, ) from .compilers import ( d_dmd_buildtype_args, d_gdc_buildtype_args, d_ldc_buildtype_args, clike_debug_args, Compiler, CompilerArgs, ) from .mixins.gnu import GnuCompiler from .mixins.islinker import LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo d_feature_args = {'gcc': {'unittest': '-funittest', 'debug': '-fdebug', 'version': '-fversion', 'import_dir': '-J' }, 'llvm': {'unittest': '-unittest', 'debug': '-d-debug', 'version': '-d-version', 'import_dir': '-J' }, 'dmd': {'unittest': '-unittest', 'debug': '-debug', 'version': '-version', 'import_dir': '-J' } } ldc_optimization_args = {'0': [], 'g': [], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-Os'], } dmd_optimization_args = {'0': [], 'g': [], '1': ['-O'], '2': ['-O'], '3': ['-O'], 's': ['-O'], } class DmdLikeCompilerMixin: LINKER_PREFIX = '-L' def get_output_args(self, target): return ['-of=' + target] def get_linker_output_args(self, target): return ['-of=' + target] def get_include_args(self, path, is_system): return ['-I=' + path] def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): for idx, i in enumerate(parameter_list): if i[:3] == '-I=': parameter_list[idx] = i[:3] + os.path.normpath(os.path.join(build_dir, i[3:])) if i[:4] == '-L-L': parameter_list[idx] = i[:4] + os.path.normpath(os.path.join(build_dir, i[4:])) if i[:5] == '-L=-L': parameter_list[idx] = i[:5] + os.path.normpath(os.path.join(build_dir, i[5:])) if i[:6] == '-Wl,-L': parameter_list[idx] = i[:6] + os.path.normpath(os.path.join(build_dir, i[6:])) return parameter_list def get_warn_args(self, level): return ['-wi'] def get_werror_args(self): return ['-w'] def get_dependency_gen_args(self, outtarget, outfile): # DMD and LDC does not currently return Makefile-compatible dependency info. return [] def get_coverage_args(self): return ['-cov'] def get_preprocess_only_args(self): return ['-E'] def get_compile_only_args(self): return ['-c'] def depfile_for_object(self, objfile): return objfile + '.' + self.get_depfile_suffix() def get_depfile_suffix(self): return 'deps' def get_pic_args(self): if self.info.is_windows(): return [] return ['-fPIC'] def get_feature_args(self, kwargs, build_to_src): res = [] if 'unittest' in kwargs: unittest = kwargs.pop('unittest') unittest_arg = d_feature_args[self.id]['unittest'] if not unittest_arg: raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string()) if unittest: res.append(unittest_arg) if 'debug' in kwargs: debug_level = -1 debugs = kwargs.pop('debug') if not isinstance(debugs, list): debugs = [debugs] debug_arg = d_feature_args[self.id]['debug'] if not debug_arg: raise EnvironmentException('D compiler %s does not support conditional debug identifiers.' % self.name_string()) # Parse all debug identifiers and the largest debug level identifier for d in debugs: if isinstance(d, int): if d > debug_level: debug_level = d elif isinstance(d, str) and d.isdigit(): if int(d) > debug_level: debug_level = int(d) else: res.append('{0}={1}'.format(debug_arg, d)) if debug_level >= 0: res.append('{0}={1}'.format(debug_arg, debug_level)) if 'versions' in kwargs: version_level = -1 versions = kwargs.pop('versions') if not isinstance(versions, list): versions = [versions] version_arg = d_feature_args[self.id]['version'] if not version_arg: raise EnvironmentException('D compiler %s does not support conditional version identifiers.' % self.name_string()) # Parse all version identifiers and the largest version level identifier for v in versions: if isinstance(v, int): if v > version_level: version_level = v elif isinstance(v, str) and v.isdigit(): if int(v) > version_level: version_level = int(v) else: res.append('{0}={1}'.format(version_arg, v)) if version_level >= 0: res.append('{0}={1}'.format(version_arg, version_level)) if 'import_dirs' in kwargs: import_dirs = kwargs.pop('import_dirs') if not isinstance(import_dirs, list): import_dirs = [import_dirs] import_dir_arg = d_feature_args[self.id]['import_dir'] if not import_dir_arg: raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string()) for idir_obj in import_dirs: basedir = idir_obj.get_curdir() for idir in idir_obj.get_incdirs(): # Avoid superfluous '/.' at the end of paths when d is '.' if idir not in ('', '.'): expdir = os.path.join(basedir, idir) else: expdir = basedir srctreedir = os.path.join(build_to_src, expdir) res.append('{0}{1}'.format(import_dir_arg, srctreedir)) if kwargs: raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys())) return res def get_buildtype_linker_args(self, buildtype): if buildtype != 'plain': return self.get_target_arch_args() return [] def get_std_exe_link_args(self): return [] def gen_import_library_args(self, implibname): return ['-Wl,--out-implib=' + implibname] def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): if self.info.is_windows(): return [] # This method is to be used by LDC and DMD. # GDC can deal with the verbatim flags. if not rpath_paths and not install_rpath: return [] paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths]) if build_rpath != '': paths += ':' + build_rpath if len(paths) < len(install_rpath): padding = 'X' * (len(install_rpath) - len(paths)) if not paths: paths = padding else: paths = paths + ':' + padding return ['-Wl,-rpath,{}'.format(paths)] def translate_args_to_nongnu(self, args): dcargs = [] # Translate common arguments to flags the LDC/DMD compilers # can understand. # The flags might have been added by pkg-config files, # and are therefore out of the user's control. for arg in args: # Translate OS specific arguments first. osargs = [] if self.info.is_windows(): osargs = self.translate_arg_to_windows(arg) elif self.info.is_darwin(): osargs = self.translate_arg_to_osx(arg) if osargs: dcargs.extend(osargs) continue # Translate common D arguments here. if arg == '-pthread': continue if arg.startswith('-fstack-protector'): continue if arg.startswith('-D'): continue if arg.startswith('-Wl,'): # Translate linker arguments here. linkargs = arg[arg.index(',') + 1:].split(',') for la in linkargs: dcargs.append('-L=' + la.strip()) continue elif arg.startswith(('-link-defaultlib', '-linker', '-link-internally', '-linkonce-templates', '-lib')): # these are special arguments to the LDC linker call, # arguments like "-link-defaultlib-shared" do *not* # denote a library to be linked, but change the default # Phobos/DRuntime linking behavior, while "-linker" sets the # default linker. dcargs.append(arg) continue elif arg.startswith('-l'): # translate library link flag dcargs.append('-L=' + arg) continue elif arg.startswith('-isystem'): # translate -isystem system include path # this flag might sometimes be added by C library Cflags via # pkg-config. # NOTE: -isystem and -I are not 100% equivalent, so this is just # a workaround for the most common cases. if arg.startswith('-isystem='): dcargs.append('-I=' + arg[9:]) else: dcargs.append('-I' + arg[8:]) continue elif arg.startswith('-idirafter'): # same as -isystem, but appends the path instead if arg.startswith('-idirafter='): dcargs.append('-I=' + arg[11:]) else: dcargs.append('-I' + arg[10:]) continue elif arg.startswith('-L/') or arg.startswith('-L./'): # we need to handle cases where -L is set by e.g. a pkg-config # setting to select a linker search path. We can however not # unconditionally prefix '-L' with '-L' because the user might # have set this flag too to do what it is intended to for this # compiler (pass flag through to the linker) # Hence, we guess here whether the flag was intended to pass # a linker search path. # Make sure static library files are passed properly to the linker. if arg.endswith('.a') or arg.endswith('.lib'): if arg.startswith('-L='): farg = arg[3:] else: farg = arg[2:] if len(farg) > 0 and not farg.startswith('-'): dcargs.append('-L=' + farg) continue dcargs.append('-L=' + arg) continue elif not arg.startswith('-') and arg.endswith(('.a', '.lib')): # ensure static libraries are passed through to the linker dcargs.append('-L=' + arg) continue else: dcargs.append(arg) return dcargs @classmethod def translate_arg_to_windows(cls, arg): args = [] if arg.startswith('-Wl,'): # Translate linker arguments here. linkargs = arg[arg.index(',') + 1:].split(',') for la in linkargs: if la.startswith('--out-implib='): # Import library name args.append('-L=/IMPLIB:' + la[13:].strip()) elif arg.startswith('-mscrtlib='): args.append(arg) mscrtlib = arg[10:].lower() if cls is LLVMDCompiler: # Default crt libraries for LDC2 must be excluded for other # selected crt options. if mscrtlib != 'libcmt': args.append('-L=/NODEFAULTLIB:libcmt') args.append('-L=/NODEFAULTLIB:libvcruntime') # Fixes missing definitions for printf-functions in VS2017 if mscrtlib.startswith('msvcrt'): args.append('-L=/DEFAULTLIB:legacy_stdio_definitions.lib') return args @classmethod def translate_arg_to_osx(cls, arg): args = [] if arg.startswith('-install_name'): args.append('-L=' + arg) return args def get_debug_args(self, is_debug): ddebug_args = [] if is_debug: ddebug_args = [d_feature_args[self.id]['debug']] return clike_debug_args[is_debug] + ddebug_args def get_crt_args(self, crt_val, buildtype): if not self.info.is_windows(): return [] if crt_val in self.mscrt_args: return self.mscrt_args[crt_val] assert(crt_val == 'from_buildtype') # Match what build type flags used to do. if buildtype == 'plain': return [] elif buildtype == 'debug': return self.mscrt_args['mdd'] elif buildtype == 'debugoptimized': return self.mscrt_args['md'] elif buildtype == 'release': return self.mscrt_args['md'] elif buildtype == 'minsize': return self.mscrt_args['md'] else: assert(buildtype == 'custom') raise EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".') def get_soname_args(self, *args, **kwargs) -> T.List[str]: # LDC and DMD actually do use a linker, but they proxy all of that with # their own arguments soargs = [] for arg in Compiler.get_soname_args(self, *args, **kwargs): soargs.append('-L=' + arg) return soargs def get_allow_undefined_link_args(self) -> T.List[str]: args = [] for arg in self.linker.get_allow_undefined_args(): args.append('-L=' + arg) return args class DCompiler(Compiler): mscrt_args = { 'none': ['-mscrtlib='], 'md': ['-mscrtlib=msvcrt'], 'mdd': ['-mscrtlib=msvcrtd'], 'mt': ['-mscrtlib=libcmt'], 'mtd': ['-mscrtlib=libcmtd'], } language = 'd' def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', arch, is_cross, exe_wrapper, **kwargs): super().__init__(exelist, version, for_machine, info, **kwargs) self.id = 'unknown' self.arch = arch self.exe_wrapper = exe_wrapper self.is_cross = is_cross def sanity_check(self, work_dir, environment): source_name = os.path.join(work_dir, 'sanity.d') output_name = os.path.join(work_dir, 'dtest') with open(source_name, 'w') as ofile: ofile.write('''void main() { }''') pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + self.get_target_arch_args() + [source_name], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string()) if self.is_cross: if self.exe_wrapper is None: # Can't check if the binaries run so we have to assume they do return cmdlist = self.exe_wrapper.get_command() + [output_name] else: cmdlist = [output_name] if subprocess.call(cmdlist) != 0: raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string()) def needs_static_linker(self): return True def depfile_for_object(self, objfile): return objfile + '.' + self.get_depfile_suffix() def get_depfile_suffix(self): return 'deps' def get_pic_args(self): if self.info.is_windows(): return [] return ['-fPIC'] def get_feature_args(self, kwargs, build_to_src): res = [] if 'unittest' in kwargs: unittest = kwargs.pop('unittest') unittest_arg = d_feature_args[self.id]['unittest'] if not unittest_arg: raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string()) if unittest: res.append(unittest_arg) if 'debug' in kwargs: debug_level = -1 debugs = kwargs.pop('debug') if not isinstance(debugs, list): debugs = [debugs] debug_arg = d_feature_args[self.id]['debug'] if not debug_arg: raise EnvironmentException('D compiler %s does not support conditional debug identifiers.' % self.name_string()) # Parse all debug identifiers and the largest debug level identifier for d in debugs: if isinstance(d, int): if d > debug_level: debug_level = d elif isinstance(d, str) and d.isdigit(): if int(d) > debug_level: debug_level = int(d) else: res.append('{0}={1}'.format(debug_arg, d)) if debug_level >= 0: res.append('{0}={1}'.format(debug_arg, debug_level)) if 'versions' in kwargs: version_level = -1 versions = kwargs.pop('versions') if not isinstance(versions, list): versions = [versions] version_arg = d_feature_args[self.id]['version'] if not version_arg: raise EnvironmentException('D compiler %s does not support conditional version identifiers.' % self.name_string()) # Parse all version identifiers and the largest version level identifier for v in versions: if isinstance(v, int): if v > version_level: version_level = v elif isinstance(v, str) and v.isdigit(): if int(v) > version_level: version_level = int(v) else: res.append('{0}={1}'.format(version_arg, v)) if version_level >= 0: res.append('{0}={1}'.format(version_arg, version_level)) if 'import_dirs' in kwargs: import_dirs = kwargs.pop('import_dirs') if not isinstance(import_dirs, list): import_dirs = [import_dirs] import_dir_arg = d_feature_args[self.id]['import_dir'] if not import_dir_arg: raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string()) for idir_obj in import_dirs: basedir = idir_obj.get_curdir() for idir in idir_obj.get_incdirs(): # Avoid superfluous '/.' at the end of paths when d is '.' if idir not in ('', '.'): expdir = os.path.join(basedir, idir) else: expdir = basedir srctreedir = os.path.join(build_to_src, expdir) res.append('{0}{1}'.format(import_dir_arg, srctreedir)) if kwargs: raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys())) return res def get_buildtype_linker_args(self, buildtype): if buildtype != 'plain': return self.get_target_arch_args() return [] def get_std_exe_link_args(self): return [] def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): if callable(extra_args): extra_args = extra_args(mode) if extra_args is None: extra_args = [] elif isinstance(extra_args, str): extra_args = [extra_args] if dependencies is None: dependencies = [] elif not isinstance(dependencies, list): dependencies = [dependencies] # Collect compiler arguments args = CompilerArgs(self) for d in dependencies: # Add compile flags needed by dependencies args += d.get_compile_args() if mode == 'link': # Add link flags needed to find dependencies args += d.get_link_args() if mode == 'compile': # Add DFLAGS from the env args += env.coredata.get_external_args(self.for_machine, self.language) elif mode == 'link': # Add LDFLAGS from the env args += env.coredata.get_external_link_args(self.for_machine, self.language) # extra_args must override all other arguments, so we add them last args += extra_args return args def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'): args = self._get_compiler_check_args(env, extra_args, dependencies, mode) with self.cached_compile(code, env.coredata, extra_args=args, mode=mode) as p: return p.returncode == 0, p.cached def has_multi_arguments(self, args, env): return self.compiles('int i;\n', env, extra_args=args) def get_target_arch_args(self): # LDC2 on Windows targets to current OS architecture, but # it should follow the target specified by the MSVC toolchain. if self.info.is_windows(): if self.arch == 'x86_64': return ['-m64'] return ['-m32'] return [] def get_crt_compile_args(self, crt_val, buildtype): return [] def get_crt_link_args(self, crt_val, buildtype): return [] def thread_link_flags(self, env): return ['-pthread'] def name_string(self): return ' '.join(self.exelist) class GnuDCompiler(DCompiler, GnuCompiler): # we mostly want DCompiler, but that gives us the Compiler.LINKER_PREFIX instead LINKER_PREFIX = GnuCompiler.LINKER_PREFIX 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': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic', 'b_vscrt'] self._has_color_support = version_compare(self.version, '>=4.9') # dependencies were implemented before, but broken - support was fixed in GCC 7.1+ # (and some backported versions) self._has_deps_support = version_compare(self.version, '>=7.1') def get_colorout_args(self, colortype): if self._has_color_support: super().get_colorout_args(colortype) return [] def get_dependency_gen_args(self, outtarget, outfile): if self._has_deps_support: return super().get_dependency_gen_args(outtarget, outfile) return [] def get_warn_args(self, level): return self.warn_args[level] def get_coverage_args(self): return [] def get_buildtype_args(self, buildtype): return d_gdc_buildtype_args[buildtype] def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): for idx, i in enumerate(parameter_list): if i[:2] == '-I' or i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list def get_allow_undefined_link_args(self) -> T.List[str]: return self.linker.get_allow_undefined_args() class LLVMDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin, DCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', arch, **kwargs): DCompiler.__init__(self, exelist, version, for_machine, info, arch, False, None, **kwargs) self.id = 'llvm' self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt'] def get_colorout_args(self, colortype): if colortype == 'always': return ['-enable-color'] return [] def get_warn_args(self, level): if level == '2' or level == '3': return ['-wi', '-dw'] elif level == '1': return ['-wi'] else: return [] def get_buildtype_args(self, buildtype): if buildtype != 'plain': return self.get_target_arch_args() + d_ldc_buildtype_args[buildtype] return d_ldc_buildtype_args[buildtype] def get_pic_args(self): return ['-relocation-model=pic'] def get_std_shared_lib_link_args(self): return ['-shared'] def get_crt_link_args(self, crt_val, buildtype): return self.get_crt_args(crt_val, buildtype) def unix_args_to_native(self, args): return self.translate_args_to_nongnu(args) def get_optimization_args(self, optimization_level): return ldc_optimization_args[optimization_level] class DmdDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin, DCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', arch, **kwargs): DCompiler.__init__(self, exelist, version, for_machine, info, arch, False, None, **kwargs) self.id = 'dmd' self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt'] def get_colorout_args(self, colortype): if colortype == 'always': return ['-color=on'] return [] def get_buildtype_args(self, buildtype): if buildtype != 'plain': return self.get_target_arch_args() + d_dmd_buildtype_args[buildtype] return d_dmd_buildtype_args[buildtype] def get_std_exe_link_args(self): if self.info.is_windows(): # DMD links against D runtime only when main symbol is found, # so these needs to be inserted when linking static D libraries. if self.arch == 'x86_64': return ['phobos64.lib'] elif self.arch == 'x86_mscoff': return ['phobos32mscoff.lib'] return ['phobos.lib'] return [] def get_std_shared_lib_link_args(self): libname = 'libphobos2.so' if self.info.is_windows(): if self.arch == 'x86_64': libname = 'phobos64.lib' elif self.arch == 'x86_mscoff': libname = 'phobos32mscoff.lib' else: libname = 'phobos.lib' return ['-shared', '-defaultlib=' + libname] def get_target_arch_args(self): # DMD32 and DMD64 on 64-bit Windows defaults to 32-bit (OMF). # Force the target to 64-bit in order to stay consistent # across the different platforms. if self.info.is_windows(): if self.arch == 'x86_64': return ['-m64'] elif self.arch == 'x86_mscoff': return ['-m32mscoff'] return ['-m32'] return [] def get_crt_compile_args(self, crt_val, buildtype): return self.get_crt_args(crt_val, buildtype) def unix_args_to_native(self, args): return self.translate_args_to_nongnu(args) def get_optimization_args(self, optimization_level): return dmd_optimization_args[optimization_level] meson-0.53.2/mesonbuild/compilers/fortran.py0000644000175000017500000004410013625260316022502 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from pathlib import Path import typing as T import subprocess, os from .. import coredata from .compilers import ( clike_debug_args, Compiler, ) from .mixins.clike import CLikeCompiler from .mixins.gnu import ( GnuCompiler, gnulike_buildtype_args, gnu_optimization_args, ) from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler from .mixins.clang import ClangCompiler from .mixins.elbrus import ElbrusCompiler from .mixins.pgi import PGICompiler from .. import mlog from mesonbuild.mesonlib import ( version_compare, EnvironmentException, MesonException, MachineChoice, LibType ) if T.TYPE_CHECKING: from ..envconfig import MachineInfo class FortranCompiler(CLikeCompiler, Compiler): language = 'fortran' def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): Compiler.__init__(self, exelist, version, for_machine, info, **kwargs) CLikeCompiler.__init__(self, is_cross, exe_wrapper) self.id = 'unknown' def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None): raise MesonException('Fortran does not have "has_function" capability.\n' 'It is better to test if a Fortran capability is working like:\n\n' "meson.get_compiler('fortran').links('block; end block; end program')\n\n" 'that example is to see if the compiler has Fortran 2008 Block element.') def sanity_check(self, work_dir: Path, environment): """ Check to be sure a minimal program can compile and execute with this compiler & platform. """ work_dir = Path(work_dir) source_name = work_dir / 'sanitycheckf.f90' binary_name = work_dir / 'sanitycheckf' if binary_name.is_file(): binary_name.unlink() source_name.write_text('print *, "Fortran compilation is working."; end') extra_flags = environment.coredata.get_external_args(self.for_machine, self.language) extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language) extra_flags += self.get_always_args() # %% build the test executable "sanitycheckf" # cwd=work_dir is necessary on Windows especially for Intel compilers to avoid error: cannot write on sanitycheckf.obj # this is a defect with how Windows handles files and ifort's object file-writing behavior vis concurrent ProcessPoolExecutor. # This simple workaround solves the issue. # FIXME: cwd=str(work_dir) is for Python 3.5 on Windows, when 3.5 is deprcated, this can become cwd=work_dir returncode = subprocess.run(self.exelist + extra_flags + [str(source_name), '-o', str(binary_name)], cwd=str(work_dir)).returncode if returncode != 0: raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string()) if self.is_cross: if self.exe_wrapper is None: # Can't check if the binaries run so we have to assume they do return cmdlist = self.exe_wrapper + [str(binary_name)] else: cmdlist = [str(binary_name)] # %% Run the test executable try: returncode = subprocess.run(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode if returncode != 0: raise EnvironmentException('Executables created by Fortran compiler %s are not runnable.' % self.name_string()) except OSError: raise EnvironmentException('Executables created by Fortran compiler %s are not runnable.' % self.name_string()) def get_std_warn_args(self, level): return FortranCompiler.std_warn_args def get_buildtype_args(self, buildtype): return gnulike_buildtype_args[buildtype] def get_optimization_args(self, optimization_level): return gnu_optimization_args[optimization_level] def get_debug_args(self, is_debug): return clike_debug_args[is_debug] def get_dependency_gen_args(self, outtarget, outfile): return [] def get_preprocess_only_args(self): return ['-cpp'] + super().get_preprocess_only_args() def get_module_incdir_args(self): return ('-I', ) def get_module_outdir_args(self, path): return ['-module', path] def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): for idx, i in enumerate(parameter_list): if i[:2] == '-I' or i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list def module_name_to_filename(self, module_name: str) -> str: if '_' in module_name: # submodule s = module_name.lower() if self.id in ('gcc', 'intel', 'intel-cl'): filename = s.replace('_', '@') + '.smod' elif self.id in ('pgi', 'flang'): filename = s.replace('_', '-') + '.mod' else: filename = s + '.mod' else: # module filename = module_name.lower() + '.mod' return filename def find_library(self, libname, env, extra_dirs, libtype: LibType = LibType.PREFER_SHARED): code = '''stop; end program''' return self.find_library_impl(libname, env, extra_dirs, code, libtype) def has_multi_arguments(self, args, env): for arg in args[:]: # some compilers, e.g. GCC, don't warn for unsupported warning-disable # flags, so when we are testing a flag like "-Wno-forgotten-towel", also # check the equivalent enable flag too "-Wforgotten-towel" if arg.startswith('-Wno-'): args.append('-W' + arg[5:]) if arg.startswith('-Wl,'): mlog.warning('{} looks like a linker argument, ' 'but has_argument and other similar methods only ' 'support checking compiler arguments. Using them ' 'to check linker arguments are never supported, ' 'and results are likely to be wrong regardless of ' 'the compiler you are using. has_link_argument or ' 'other similar method can be used instead.' .format(arg)) code = 'stop; end program' return self.has_arguments(args, env, code, mode='compile') class GnuFortranCompiler(GnuCompiler, FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, defines=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) GnuCompiler.__init__(self, defines) default_warn_args = ['-Wall'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic', '-fimplicit-none']} def get_options(self): opts = FortranCompiler.get_options(self) fortran_stds = ['legacy', 'f95', 'f2003'] if version_compare(self.version, '>=4.4.0'): fortran_stds += ['f2008'] if version_compare(self.version, '>=8.0.0'): fortran_stds += ['f2018'] opts.update({'fortran_std': coredata.UserComboOption('Fortran language standard to use', ['none'] + fortran_stds, 'none')}) return opts def get_option_compile_args(self, options) -> T.List[str]: args = [] std = options['fortran_std'] if std.value != 'none': args.append('-std=' + std.value) return args def get_dependency_gen_args(self, outtarget, outfile): # Disabled until this is fixed: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62162 # return ['-cpp', '-MD', '-MQ', outtarget] return [] def get_module_outdir_args(self, path): return ['-J' + path] def language_stdlib_only_link_flags(self): return ['-lgfortran', '-lm'] class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, defines=None, **kwargs): GnuFortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, defines, **kwargs) ElbrusCompiler.__init__(self) class G95FortranCompiler(FortranCompiler): LINKER_PREFIX = '-Wl,' def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) self.id = 'g95' default_warn_args = ['-Wall'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-pedantic']} def get_module_outdir_args(self, path): return ['-fmod=' + path] def get_no_warn_args(self): # FIXME: Confirm that there's no compiler option to disable all warnings return [] class SunFortranCompiler(FortranCompiler): LINKER_PREFIX = '-Wl,' def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) self.id = 'sun' def get_dependency_gen_args(self, outtarget, outfile): return ['-fpp'] def get_always_args(self): return [] def get_warn_args(self, level): return [] def get_module_incdir_args(self): return ('-M', ) def get_module_outdir_args(self, path): return ['-moddir=' + path] def openmp_flags(self): return ['-xopenmp'] class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): self.file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp') FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) # FIXME: Add support for OS X and Windows in detect_fortran_compiler so # we are sent the type of compiler IntelGnuLikeCompiler.__init__(self) self.id = 'intel' default_warn_args = ['-warn', 'general', '-warn', 'truncated_source'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['-warn', 'unused'], '3': ['-warn', 'all']} def get_options(self): opts = FortranCompiler.get_options(self) fortran_stds = ['legacy', 'f95', 'f2003', 'f2008', 'f2018'] opts.update({'fortran_std': coredata.UserComboOption('Fortran language standard to use', ['none'] + fortran_stds, 'none')}) return opts def get_option_compile_args(self, options) -> T.List[str]: args = [] std = options['fortran_std'] stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} if std.value != 'none': args.append('-stand=' + stds[std.value]) return args def get_preprocess_only_args(self): return ['-cpp', '-EP'] def get_always_args(self): """Ifort doesn't have -pipe.""" val = super().get_always_args() val.remove('-pipe') return val def language_stdlib_only_link_flags(self): return ['-lifcore', '-limf'] def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['-gen-dep=' + outtarget, '-gen-depformat=make'] class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): file_suffixes = ['f90', 'f', 'for', 'ftn', 'fpp'] always_args = ['/nologo'] def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, target: str, info: 'MachineInfo', exe_wrapper=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) IntelVisualStudioLikeCompiler.__init__(self, target) default_warn_args = ['/warn:general', '/warn:truncated_source'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + ['/warn:unused'], '3': ['/warn:all']} def get_options(self): opts = FortranCompiler.get_options(self) fortran_stds = ['legacy', 'f95', 'f2003', 'f2008', 'f2018'] opts.update({'fortran_std': coredata.UserComboOption('Fortran language standard to use', ['none'] + fortran_stds, 'none')}) return opts def get_option_compile_args(self, options) -> T.List[str]: args = [] std = options['fortran_std'] stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} if std.value != 'none': args.append('/stand:' + stds[std.value]) return args def get_module_outdir_args(self, path) -> T.List[str]: return ['/module:' + path] class PathScaleFortranCompiler(FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) self.id = 'pathscale' default_warn_args = ['-fullwarn'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args, '3': default_warn_args} def openmp_flags(self): return ['-mp'] class PGIFortranCompiler(PGICompiler, FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) PGICompiler.__init__(self) default_warn_args = ['-Minform=inform'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args, '3': default_warn_args + ['-Mdclchk']} def language_stdlib_only_link_flags(self) -> T.List[str]: return ['-lpgf90rtl', '-lpgf90', '-lpgf90_rpm1', '-lpgf902', '-lpgf90rtl', '-lpgftnrtl', '-lrt'] class FlangFortranCompiler(ClangCompiler, FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) ClangCompiler.__init__(self) self.id = 'flang' default_warn_args = ['-Minform=inform'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args, '3': default_warn_args} def language_stdlib_only_link_flags(self) -> T.List[str]: return ['-lflang', '-lpgmath'] class Open64FortranCompiler(FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) self.id = 'open64' default_warn_args = ['-fullwarn'] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args, '3': default_warn_args} def openmp_flags(self): return ['-mp'] class NAGFortranCompiler(FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) self.id = 'nagfor' def get_warn_args(self, level): return [] def get_module_outdir_args(self, path): return ['-mdir', path] def openmp_flags(self): return ['-openmp'] meson-0.53.2/mesonbuild/compilers/java.py0000644000175000017500000000757313612313307021760 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os.path import shutil import subprocess import typing as T from ..mesonlib import EnvironmentException, MachineChoice from .compilers import Compiler, java_buildtype_args from .mixins.islinker import BasicLinkerIsCompilerMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler): language = 'java' def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo'): super().__init__(exelist, version, for_machine, info) self.id = 'unknown' self.is_cross = False self.javarunner = 'java' def get_werror_args(self): return ['-Werror'] def split_shlib_to_parts(self, fname): return None, fname def get_dependency_gen_args(self, outtarget, outfile): return [] def get_compile_only_args(self): return [] def get_output_args(self, subdir): if subdir == '': subdir = './' return ['-d', subdir, '-s', subdir] def get_coverage_args(self): return [] def get_std_exe_link_args(self): return [] def get_include_args(self, path): return [] def get_pic_args(self): return [] def name_string(self): return ' '.join(self.exelist) def get_pch_use_args(self, pch_dir, header): return [] def get_pch_name(self, header_name): return '' def get_buildtype_args(self, buildtype): return java_buildtype_args[buildtype] def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): for idx, i in enumerate(parameter_list): if i in ['-cp', '-classpath', '-sourcepath'] and idx + 1 < len(parameter_list): path_list = parameter_list[idx + 1].split(os.pathsep) path_list = [os.path.normpath(os.path.join(build_dir, x)) for x in path_list] parameter_list[idx + 1] = os.pathsep.join(path_list) return parameter_list def sanity_check(self, work_dir, environment): src = 'SanityCheck.java' obj = 'SanityCheck' source_name = os.path.join(work_dir, src) with open(source_name, 'w') as ofile: ofile.write('''class SanityCheck { public static void main(String[] args) { int i; } } ''') pc = subprocess.Popen(self.exelist + [src], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('Java compiler %s can not compile programs.' % self.name_string()) runner = shutil.which(self.javarunner) if runner: cmdlist = [runner, obj] pe = subprocess.Popen(cmdlist, cwd=work_dir) pe.wait() if pe.returncode != 0: raise EnvironmentException('Executables created by Java compiler %s are not runnable.' % self.name_string()) else: m = "Java Virtual Machine wasn't found, but it's needed by Meson. " \ "Please install a JRE.\nIf you have specific needs where this " \ "requirement doesn't make sense, please open a bug at " \ "https://github.com/mesonbuild/meson/issues/new and tell us " \ "all about it." raise EnvironmentException(m) def needs_static_linker(self): return False meson-0.53.2/mesonbuild/compilers/mixins/0000755000175000017500000000000013625242354021767 5ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/compilers/mixins/__init__.py0000644000175000017500000000000013531533273024065 0ustar jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/compilers/mixins/arm.py0000644000175000017500000001622213625260316023121 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Representations specific to the arm family of compilers.""" import os import re import typing as T from ... import mesonlib from ..compilers import clike_debug_args from .clang import clang_color_args if T.TYPE_CHECKING: from ...environment import Environment arm_buildtype_args = { 'plain': [], 'debug': ['-O0', '--debug'], 'debugoptimized': ['-O1', '--debug'], 'release': ['-O3', '-Otime'], 'minsize': ['-O3', '-Ospace'], 'custom': [], } # type: T.Dict[str, T.List[str]] arm_optimization_args = { '0': ['-O0'], 'g': ['-g'], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': [], } # type: T.Dict[str, T.List[str]] armclang_buildtype_args = { 'plain': [], 'debug': ['-O0', '-g'], 'debugoptimized': ['-O1', '-g'], 'release': ['-Os'], 'minsize': ['-Oz'], 'custom': [], } # type: T.Dict[str, T.List[str]] armclang_optimization_args = { '0': ['-O0'], 'g': ['-g'], '1': ['-O1'], '2': ['-O2'], '3': ['-O3'], 's': ['-Os'] } # type: T.Dict[str, T.List[str]] class ArmCompiler: # Functionality that is common to all ARM family compilers. def __init__(self): if not self.is_cross: raise mesonlib.EnvironmentException('armcc supports only cross-compilation.') self.id = 'arm' default_warn_args = [] # type: T.List[str] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + [], '3': default_warn_args + []} # Assembly self.can_compile_suffixes.add('s') def get_pic_args(self) -> T.List[str]: # FIXME: Add /ropi, /rwpi, /fpic etc. qualifiers to --apcs return [] def get_buildtype_args(self, buildtype: str) -> T.List[str]: return arm_buildtype_args[buildtype] # Override CCompiler.get_always_args def get_always_args(self) -> T.List[str]: return [] # Override CCompiler.get_dependency_gen_args def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return [] def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: # FIXME: Add required arguments # NOTE from armcc user guide: # "Support for Precompiled Header (PCH) files is deprecated from ARM Compiler 5.05 # onwards on all platforms. Note that ARM Compiler on Windows 8 never supported # PCH files." return [] def get_pch_suffix(self) -> str: # NOTE from armcc user guide: # "Support for Precompiled Header (PCH) files is deprecated from ARM Compiler 5.05 # onwards on all platforms. Note that ARM Compiler on Windows 8 never supported # PCH files." return 'pch' def thread_flags(self, env: 'Environment') -> T.List[str]: return [] def get_coverage_args(self) -> T.List[str]: return [] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return arm_optimization_args[optimization_level] def get_debug_args(self, is_debug: bool) -> T.List[str]: return clike_debug_args[is_debug] def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:2] == '-I' or i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list class ArmclangCompiler: def __init__(self): if not self.is_cross: raise mesonlib.EnvironmentException('armclang supports only cross-compilation.') # Check whether 'armlink' is available in path self.linker_exe = 'armlink' args = '--vsn' try: p, stdo, stderr = mesonlib.Popen_safe(self.linker_exe, args) except OSError as e: err_msg = 'Unknown linker\nRunning "{0}" gave \n"{1}"'.format(' '.join([self.linker_exe] + [args]), e) raise mesonlib.EnvironmentException(err_msg) # Verify the armlink version ver_str = re.search('.*Component.*', stdo) if ver_str: ver_str = ver_str.group(0) else: 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 version_regex = r'(? T.List[str]: # PIC support is not enabled by default for ARM, # if users want to use it, they need to add the required arguments explicitly return [] def get_colorout_args(self, colortype: str) -> T.List[str]: return clang_color_args[colortype][:] def get_buildtype_args(self, buildtype: str) -> T.List[str]: return armclang_buildtype_args[buildtype] def get_pch_suffix(self) -> str: return 'gch' def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: # Workaround for Clang bug http://llvm.org/bugs/show_bug.cgi?id=15136 # This flag is internal to Clang (or at least not documented on the man page) # so it might change semantics at any time. return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))] # Override CCompiler.get_dependency_gen_args def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return [] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return armclang_optimization_args[optimization_level] def get_debug_args(self, is_debug: bool) -> T.List[str]: return clike_debug_args[is_debug] def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:2] == '-I' or i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list meson-0.53.2/mesonbuild/compilers/mixins/ccrx.py0000644000175000017500000000750613625260316023306 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2019 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Representations specific to the Renesas CC-RX compiler family.""" import os import typing as T from ...mesonlib import EnvironmentException if T.TYPE_CHECKING: from ...environment import Environment ccrx_buildtype_args = { 'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], 'custom': [], } # type: T.Dict[str, T.List[str]] ccrx_optimization_args = { '0': ['-optimize=0'], 'g': ['-optimize=0'], '1': ['-optimize=1'], '2': ['-optimize=2'], '3': ['-optimize=max'], 's': ['-optimize=2', '-size'] } # type: T.Dict[str, T.List[str]] ccrx_debug_args = { False: [], True: ['-debug'] } # type: T.Dict[bool, T.List[str]] class CcrxCompiler: def __init__(self): if not self.is_cross: raise EnvironmentException('ccrx supports only cross-compilation.') self.id = 'ccrx' # Assembly self.can_compile_suffixes.add('src') default_warn_args = [] # type: T.List[str] self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + [], '3': default_warn_args + []} def get_pic_args(self) -> T.List[str]: # PIC support is not enabled by default for CCRX, # if users want to use it, they need to add the required arguments explicitly return [] def get_buildtype_args(self, buildtype: str) -> T.List[str]: return ccrx_buildtype_args[buildtype] def get_pch_suffix(self) -> str: return 'pch' def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return [] # Override CCompiler.get_dependency_gen_args def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return [] def thread_flags(self, env: 'Environment') -> T.List[str]: return [] def get_coverage_args(self) -> T.List[str]: return [] def get_no_stdinc_args(self) -> T.List[str]: return [] def get_no_stdlib_link_args(self) -> T.List[str]: return [] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return ccrx_optimization_args[optimization_level] def get_debug_args(self, is_debug: bool) -> T.List[str]: return ccrx_debug_args[is_debug] @classmethod def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]: result = [] for i in args: if i.startswith('-D'): i = '-define=' + i[2:] if i.startswith('-I'): i = '-include=' + i[2:] if i.startswith('-Wl,-rpath='): continue elif i == '--print-search-dirs': continue elif i.startswith('-L'): continue elif not i.startswith('-lib=') and i.endswith(('.a', '.lib')): i = '-lib=' + i result.append(i) return result def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:9] == '-include=': parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:])) return parameter_list meson-0.53.2/mesonbuild/compilers/mixins/clang.py0000644000175000017500000000767113612313307023431 0ustar jpakkanejpakkane00000000000000# Copyright 2019 The meson development team # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Abstractions for the LLVM/Clang compiler family.""" import os import typing as T from ... import mesonlib from ...linkers import AppleDynamicLinker from ..compilers import clike_optimization_args from .gnu import GnuLikeCompiler if T.TYPE_CHECKING: from ...environment import Environment from ...dependencies import Dependency # noqa: F401 clang_color_args = { 'auto': ['-Xclang', '-fcolor-diagnostics'], 'always': ['-Xclang', '-fcolor-diagnostics'], 'never': ['-Xclang', '-fno-color-diagnostics'], } # type: T.Dict[str, T.List[str]] class ClangCompiler(GnuLikeCompiler): def __init__(self): super().__init__() self.id = 'clang' self.base_options.append('b_colorout') # TODO: this really should be part of the linker base_options, but # linkers don't have base_options. if isinstance(self.linker, AppleDynamicLinker): self.base_options.append('b_bitcode') # All Clang backends can also do LLVM IR self.can_compile_suffixes.add('ll') def get_colorout_args(self, colortype: str) -> T.List[str]: return clang_color_args[colortype][:] def get_optimization_args(self, optimization_level: str) -> T.List[str]: return clike_optimization_args[optimization_level] def get_pch_suffix(self) -> str: return 'pch' def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: # Workaround for Clang bug http://llvm.org/bugs/show_bug.cgi?id=15136 # This flag is internal to Clang (or at least not documented on the man page) # so it might change semantics at any time. return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))] def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.List[str]: myargs = ['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument'] if mesonlib.version_compare(self.version, '>=3.6.0'): myargs.append('-Werror=ignored-optimization-argument') return super().has_multi_arguments( myargs + args, env) def has_function(self, funcname: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> bool: if extra_args is None: extra_args = [] # Starting with XCode 8, we need to pass this to force linker # visibility to obey OS X/iOS/tvOS minimum version targets with # -mmacosx-version-min, -miphoneos-version-min, -mtvos-version-min etc. # https://github.com/Homebrew/homebrew-core/issues/3727 # TODO: this really should be communicated by the linker if isinstance(self.linker, AppleDynamicLinker) and mesonlib.version_compare(self.version, '>=8.0'): extra_args.append('-Wl,-no_weak_imports') return super().has_function(funcname, prefix, env, extra_args=extra_args, dependencies=dependencies) def openmp_flags(self) -> T.List[str]: if mesonlib.version_compare(self.version, '>=3.8.0'): return ['-fopenmp'] elif mesonlib.version_compare(self.version, '>=3.7.0'): return ['-fopenmp=libomp'] else: # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency. return [] meson-0.53.2/mesonbuild/compilers/mixins/clike.py0000644000175000017500000013634513612313307023435 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Mixin classes to be shared between C and C++ compilers. Without this we'll end up with awful diamond inherintance problems. The goal of this is to have mixin's, which are classes that are designed *not* to be standalone, they only work through inheritance. """ import functools import glob import itertools import os import re import subprocess import typing as T from pathlib import Path from ... import mesonlib from ...mesonlib import LibType from ... import mlog from .. import compilers from .visualstudio import VisualStudioLikeCompiler if T.TYPE_CHECKING: from ...environment import Environment class CLikeCompiler: """Shared bits for the C and CPP Compilers.""" # TODO: Replace this manual cache with functools.lru_cache library_dirs_cache = {} program_dirs_cache = {} find_library_cache = {} find_framework_cache = {} internal_libs = compilers.unixy_compiler_internal_libs def __init__(self, is_cross: bool, exe_wrapper: T.Optional[str] = None): # If a child ObjC or CPP class has already set it, don't set it ourselves self.is_cross = is_cross self.can_compile_suffixes.add('h') # If the exe wrapper was not found, pretend it wasn't set so that the # sanity check is skipped and compiler checks use fallbacks. if not exe_wrapper or not exe_wrapper.found(): self.exe_wrapper = None else: self.exe_wrapper = exe_wrapper.get_command() def needs_static_linker(self): return True # When compiling static libraries, so yes. def get_always_args(self): ''' Args that are always-on for all C compilers other than MSVC ''' return ['-pipe'] + compilers.get_largefile_args(self) def get_no_stdinc_args(self): return ['-nostdinc'] def get_no_stdlib_link_args(self): return ['-nostdlib'] def get_warn_args(self, level): return self.warn_args[level] def get_no_warn_args(self): # Almost every compiler uses this for disabling warnings return ['-w'] def split_shlib_to_parts(self, fname): return None, fname def depfile_for_object(self, objfile): return objfile + '.' + self.get_depfile_suffix() def get_depfile_suffix(self): return 'd' def get_exelist(self): return self.exelist[:] def get_preprocess_only_args(self): return ['-E', '-P'] def get_compile_only_args(self): return ['-c'] def get_no_optimization_args(self): return ['-O0'] def get_compiler_check_args(self): ''' Get arguments useful for compiler checks such as being permissive in the code quality and not doing any optimization. ''' return self.get_no_optimization_args() def get_output_args(self, target): return ['-o', target] def get_coverage_args(self): return ['--coverage'] def get_coverage_link_args(self) -> T.List[str]: return self.linker.get_coverage_args() def get_werror_args(self): return ['-Werror'] def get_std_exe_link_args(self): # TODO: is this a linker property? return [] def get_include_args(self, path, is_system): if path == '': path = '.' if is_system: return ['-isystem', path] return ['-I' + path] def get_compiler_dirs(self, env: 'Environment', name: str) -> T.List[str]: ''' Get dirs from the compiler, either `libraries:` or `programs:` ''' return [] @functools.lru_cache() def get_library_dirs(self, env, elf_class = None): dirs = self.get_compiler_dirs(env, 'libraries') if elf_class is None or elf_class == 0: return dirs # if we do have an elf class for 32-bit or 64-bit, we want to check that # the directory in question contains libraries of the appropriate class. Since # system directories aren't mixed, we only need to check one file for each # directory and go by that. If we can't check the file for some reason, assume # the compiler knows what it's doing, and accept the directory anyway. retval = [] for d in dirs: files = [f for f in os.listdir(d) if f.endswith('.so') and os.path.isfile(os.path.join(d, f))] # if no files, accept directory and move on if not files: retval.append(d) continue file_to_check = os.path.join(d, files[0]) with open(file_to_check, 'rb') as fd: header = fd.read(5) # if file is not an ELF file, it's weird, but accept dir # if it is elf, and the class matches, accept dir if header[1:4] != b'ELF' or int(header[4]) == elf_class: retval.append(d) # at this point, it's an ELF file which doesn't match the # appropriate elf_class, so skip this one return tuple(retval) @functools.lru_cache() def get_program_dirs(self, env): ''' Programs used by the compiler. Also where toolchain DLLs such as libstdc++-6.dll are found with MinGW. ''' return self.get_compiler_dirs(env, 'programs') def get_pic_args(self) -> T.List[str]: return ['-fPIC'] def name_string(self) -> str: return ' '.join(self.exelist) def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return ['-include', os.path.basename(header)] def get_pch_name(self, header_name: str) -> str: return os.path.basename(header_name) + '.' + self.get_pch_suffix() def get_linker_search_args(self, dirname: str) -> T.List[str]: return self.linker.get_search_args(dirname) def get_default_include_dirs(self): return [] def gen_export_dynamic_link_args(self, env: 'Environment') -> T.List[str]: return self.linker.export_dynamic_args(env) def gen_import_library_args(self, implibname: str) -> T.List[str]: return self.linker.import_library_args(implibname) def sanity_check_impl(self, work_dir, environment, sname, code): mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist)) mlog.debug('Is cross compiler: %s.' % str(self.is_cross)) source_name = os.path.join(work_dir, sname) binname = sname.rsplit('.', 1)[0] mode = 'link' if self.is_cross: binname += '_cross' if self.exe_wrapper is None: # Linking cross built apps is painful. You can't really # tell if you should use -nostdlib or not and for example # on OSX the compiler binary is the same but you need # a ton of compiler flags to differentiate between # arm and x86_64. So just compile. mode = 'compile' cargs, largs = self._get_basic_compiler_args(environment, mode) extra_flags = cargs + self.linker_to_compiler_args(largs) # Is a valid executable output for all toolchains and platforms binname += '.exe' # Write binary check source binary_name = os.path.join(work_dir, binname) with open(source_name, 'w') as ofile: ofile.write(code) # Compile sanity check # NOTE: extra_flags must be added at the end. On MSVC, it might contain a '/link' argument # after which all further arguments will be passed directly to the linker cmdlist = self.exelist + [source_name] + self.get_output_args(binary_name) + extra_flags pc, stdo, stde = mesonlib.Popen_safe(cmdlist, cwd=work_dir) mlog.debug('Sanity check compiler command line:', ' '.join(cmdlist)) mlog.debug('Sanity check compile stdout:') mlog.debug(stdo) mlog.debug('-----\nSanity check compile stderr:') mlog.debug(stde) mlog.debug('-----') if pc.returncode != 0: raise mesonlib.EnvironmentException('Compiler {0} can not compile programs.'.format(self.name_string())) # Run sanity check if self.is_cross: if self.exe_wrapper is None: # Can't check if the binaries run so we have to assume they do return cmdlist = self.exe_wrapper + [binary_name] else: cmdlist = [binary_name] mlog.debug('Running test binary command: ' + ' '.join(cmdlist)) try: pe = subprocess.Popen(cmdlist) except Exception as e: raise mesonlib.EnvironmentException('Could not invoke sanity test executable: %s.' % str(e)) pe.wait() if pe.returncode != 0: raise mesonlib.EnvironmentException('Executables created by {0} compiler {1} are not runnable.'.format(self.language, self.name_string())) def sanity_check(self, work_dir, environment): code = 'int main(void) { int class=0; return class; }\n' return self.sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code) def check_header(self, hname, prefix, env, *, extra_args=None, dependencies=None): fargs = {'prefix': prefix, 'header': hname} code = '''{prefix} #include <{header}>''' return self.compiles(code.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) def has_header(self, hname, prefix, env, *, extra_args=None, dependencies=None, disable_cache=False): fargs = {'prefix': prefix, 'header': hname} code = '''{prefix} #ifdef __has_include #if !__has_include("{header}") #error "Header '{header}' could not be found" #endif #else #include <{header}> #endif''' return self.compiles(code.format(**fargs), env, extra_args=extra_args, dependencies=dependencies, mode='preprocess', disable_cache=disable_cache) def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None): fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol} t = '''{prefix} #include <{header}> int main(void) {{ /* If it's not defined as a macro, try to use as a symbol */ #ifndef {symbol} {symbol}; #endif return 0; }}''' return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) def _get_basic_compiler_args(self, env, mode): cargs, largs = [], [] # Select a CRT if needed since we're linking if mode == 'link': cargs += self.get_linker_debug_crt_args() # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env sys_args = env.coredata.get_external_args(self.for_machine, self.language) # Apparently it is a thing to inject linker flags both # via CFLAGS _and_ LDFLAGS, even though the former are # also used during linking. These flags can break # argument checks. Thanks, Autotools. cleaned_sys_args = self.remove_linkerlike_args(sys_args) cargs += cleaned_sys_args if mode == 'link': # Add LDFLAGS from the env sys_ld_args = env.coredata.get_external_link_args(self.for_machine, self.language) # CFLAGS and CXXFLAGS go to both linking and compiling, but we want them # to only appear on the command line once. Remove dupes. largs += [x for x in sys_ld_args if x not in sys_args] cargs += self.get_compiler_args_for_mode(mode) return cargs, largs def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): if extra_args is None: extra_args = [] else: extra_args = mesonlib.listify(extra_args) extra_args = mesonlib.listify([e(mode) if callable(e) else e for e in extra_args]) if dependencies is None: dependencies = [] elif not isinstance(dependencies, list): dependencies = [dependencies] # Collect compiler arguments cargs = compilers.CompilerArgs(self) largs = [] for d in dependencies: # Add compile flags needed by dependencies cargs += d.get_compile_args() if mode == 'link': # Add link flags needed to find dependencies largs += d.get_link_args() ca, la = self._get_basic_compiler_args(env, mode) cargs += ca largs += la cargs += self.get_compiler_check_args() # on MSVC compiler and linker flags must be separated by the "/link" argument # at this point, the '/link' argument may already be part of extra_args, otherwise, it is added here if self.linker_to_compiler_args([]) == ['/link'] and largs != [] and not ('/link' in extra_args): extra_args += ['/link'] args = cargs + extra_args + largs return args def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile', disable_cache=False): with self._build_wrapper(code, env, extra_args, dependencies, mode, disable_cache=disable_cache) as p: return p.returncode == 0, p.cached def _build_wrapper(self, code, env, extra_args, dependencies=None, mode='compile', want_output=False, disable_cache=False, temp_dir=None): args = self._get_compiler_check_args(env, extra_args, dependencies, mode) if disable_cache or want_output: return self.compile(code, extra_args=args, mode=mode, want_output=want_output, temp_dir=env.scratch_dir) return self.cached_compile(code, env.coredata, extra_args=args, mode=mode, temp_dir=env.scratch_dir) def links(self, code, env, *, extra_args=None, dependencies=None, disable_cache=False): return self.compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode='link', disable_cache=disable_cache) def run(self, code: str, env, *, extra_args=None, dependencies=None): if self.is_cross and self.exe_wrapper is None: raise compilers.CrossNoRunException('Can not run test applications in this cross environment.') with self._build_wrapper(code, env, extra_args, dependencies, mode='link', want_output=True) as p: if p.returncode != 0: mlog.debug('Could not compile test file %s: %d\n' % ( p.input_name, p.returncode)) return compilers.RunResult(False) if self.is_cross: cmdlist = self.exe_wrapper + [p.output_name] else: cmdlist = p.output_name try: pe, so, se = mesonlib.Popen_safe(cmdlist) except Exception as e: mlog.debug('Could not run: %s (error: %s)\n' % (cmdlist, e)) return compilers.RunResult(False) mlog.debug('Program stdout:\n') mlog.debug(so) mlog.debug('Program stderr:\n') mlog.debug(se) return compilers.RunResult(True, pe.returncode, so, se) def _compile_int(self, expression, prefix, env, extra_args, dependencies): fargs = {'prefix': prefix, 'expression': expression} t = '''#include {prefix} int main(void) {{ static int a[1-2*!({expression})]; a[0]=0; return 0; }}''' return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies)[0] def cross_compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies): # Try user's guess first if isinstance(guess, int): if self._compile_int('%s == %d' % (expression, guess), prefix, env, extra_args, dependencies): return guess # If no bounds are given, compute them in the limit of int32 maxint = 0x7fffffff minint = -0x80000000 if not isinstance(low, int) or not isinstance(high, int): if self._compile_int('%s >= 0' % (expression), prefix, env, extra_args, dependencies): low = cur = 0 while self._compile_int('%s > %d' % (expression, cur), prefix, env, extra_args, dependencies): low = cur + 1 if low > maxint: raise mesonlib.EnvironmentException('Cross-compile check overflowed') cur = cur * 2 + 1 if cur > maxint: cur = maxint high = cur else: high = cur = -1 while self._compile_int('%s < %d' % (expression, cur), prefix, env, extra_args, dependencies): high = cur - 1 if high < minint: raise mesonlib.EnvironmentException('Cross-compile check overflowed') cur = cur * 2 if cur < minint: cur = minint low = cur else: # Sanity check limits given by user if high < low: raise mesonlib.EnvironmentException('high limit smaller than low limit') condition = '%s <= %d && %s >= %d' % (expression, high, expression, low) if not self._compile_int(condition, prefix, env, extra_args, dependencies): raise mesonlib.EnvironmentException('Value out of given range') # Binary search while low != high: cur = low + int((high - low) / 2) if self._compile_int('%s <= %d' % (expression, cur), prefix, env, extra_args, dependencies): high = cur else: low = cur + 1 return low def compute_int(self, expression, low, high, guess, prefix, env, *, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] if self.is_cross: return self.cross_compute_int(expression, low, high, guess, prefix, env, extra_args, dependencies) fargs = {'prefix': prefix, 'expression': expression} t = '''#include {prefix} int main(void) {{ printf("%ld\\n", (long)({expression})); return 0; }};''' res = self.run(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) if not res.compiled: return -1 if res.returncode != 0: raise mesonlib.EnvironmentException('Could not run compute_int test binary.') return int(res.stdout) def cross_sizeof(self, typename, prefix, env, *, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'type': typename} t = '''#include {prefix} int main(void) {{ {type} something; return 0; }}''' if not self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies)[0]: return -1 return self.cross_compute_int('sizeof(%s)' % typename, None, None, None, prefix, env, extra_args, dependencies) def sizeof(self, typename, prefix, env, *, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'type': typename} if self.is_cross: return self.cross_sizeof(typename, prefix, env, extra_args=extra_args, dependencies=dependencies) t = '''#include {prefix} int main(void) {{ printf("%ld\\n", (long)(sizeof({type}))); return 0; }};''' res = self.run(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) if not res.compiled: return -1 if res.returncode != 0: raise mesonlib.EnvironmentException('Could not run sizeof test binary.') return int(res.stdout) def cross_alignment(self, typename, prefix, env, *, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'type': typename} t = '''#include {prefix} int main(void) {{ {type} something; return 0; }}''' if not self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies)[0]: return -1 t = '''#include {prefix} struct tmp {{ char c; {type} target; }};''' return self.cross_compute_int('offsetof(struct tmp, target)', None, None, None, t.format(**fargs), env, extra_args, dependencies) def alignment(self, typename, prefix, env, *, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] if self.is_cross: return self.cross_alignment(typename, prefix, env, extra_args=extra_args, dependencies=dependencies) fargs = {'prefix': prefix, 'type': typename} t = '''#include #include {prefix} struct tmp {{ char c; {type} target; }}; int main(void) {{ printf("%d", (int)offsetof(struct tmp, target)); return 0; }}''' res = self.run(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) if not res.compiled: raise mesonlib.EnvironmentException('Could not compile alignment test.') if res.returncode != 0: raise mesonlib.EnvironmentException('Could not run alignment test binary.') align = int(res.stdout) if align == 0: raise mesonlib.EnvironmentException('Could not determine alignment of %s. Sorry. You might want to file a bug.' % typename) return align def get_define(self, dname, prefix, env, extra_args, dependencies, disable_cache=False): delim = '"MESON_GET_DEFINE_DELIMITER"' fargs = {'prefix': prefix, 'define': dname, 'delim': delim} code = ''' {prefix} #ifndef {define} # define {define} #endif {delim}\n{define}''' args = self._get_compiler_check_args(env, extra_args, dependencies, mode='preprocess').to_native() func = lambda: self.cached_compile(code.format(**fargs), env.coredata, extra_args=args, mode='preprocess') if disable_cache: func = lambda: self.compile(code.format(**fargs), extra_args=args, mode='preprocess', temp_dir=env.scratch_dir) with func() as p: cached = p.cached if p.returncode != 0: raise mesonlib.EnvironmentException('Could not get define {!r}'.format(dname)) # Get the preprocessed value after the delimiter, # minus the extra newline at the end and # merge string literals. return self.concatenate_string_literals(p.stdo.split(delim + '\n')[-1][:-1]), cached def get_return_value(self, fname, rtype, prefix, env, extra_args, dependencies): if rtype == 'string': fmt = '%s' cast = '(char*)' elif rtype == 'int': fmt = '%lli' cast = '(long long int)' else: raise AssertionError('BUG: Unknown return type {!r}'.format(rtype)) fargs = {'prefix': prefix, 'f': fname, 'cast': cast, 'fmt': fmt} code = '''{prefix} #include int main(void) {{ printf ("{fmt}", {cast} {f}()); return 0; }}'''.format(**fargs) res = self.run(code, env, extra_args=extra_args, dependencies=dependencies) if not res.compiled: m = 'Could not get return value of {}()' raise mesonlib.EnvironmentException(m.format(fname)) if rtype == 'string': return res.stdout elif rtype == 'int': try: return int(res.stdout.strip()) except ValueError: m = 'Return value of {}() is not an int' raise mesonlib.EnvironmentException(m.format(fname)) @staticmethod def _no_prototype_templ(): """ Try to find the function without a prototype from a header by defining our own dummy prototype and trying to link with the C library (and whatever else the compiler links in by default). This is very similar to the check performed by Autoconf for AC_CHECK_FUNCS. """ # Define the symbol to something else since it is defined by the # includes or defines listed by the user or by the compiler. This may # include, for instance _GNU_SOURCE which must be defined before # limits.h, which includes features.h # Then, undef the symbol to get rid of it completely. head = ''' #define {func} meson_disable_define_of_{func} {prefix} #include #undef {func} ''' # Override any GCC internal prototype and declare our own definition for # the symbol. Use char because that's unlikely to be an actual return # value for a function which ensures that we override the definition. head += ''' #ifdef __cplusplus extern "C" #endif char {func} (void); ''' # The actual function call main = ''' int main(void) {{ return {func} (); }}''' return head, main @staticmethod def _have_prototype_templ(): """ Returns a head-er and main() call that uses the headers listed by the user for the function prototype while checking if a function exists. """ # Add the 'prefix', aka defines, includes, etc that the user provides # This may include, for instance _GNU_SOURCE which must be defined # before limits.h, which includes features.h head = '{prefix}\n#include \n' # We don't know what the function takes or returns, so return it as an int. # Just taking the address or comparing it to void is not enough because # compilers are smart enough to optimize it away. The resulting binary # is not run so we don't care what the return value is. main = '''\nint main(void) {{ void *a = (void*) &{func}; long b = (long) a; return (int) b; }}''' return head, main def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None): """ First, this function looks for the symbol in the default libraries provided by the compiler (stdlib + a few others usually). If that fails, it checks if any of the headers specified in the prefix provide an implementation of the function, and if that fails, it checks if it's implemented as a compiler-builtin. """ if extra_args is None: extra_args = [] # Short-circuit if the check is already provided by the cross-info file varname = 'has function ' + funcname varname = varname.replace(' ', '_') if self.is_cross: val = env.properties.host.get(varname, None) if val is not None: if isinstance(val, bool): return val, False raise mesonlib.EnvironmentException('Cross variable {0} is not a boolean.'.format(varname)) fargs = {'prefix': prefix, 'func': funcname} # glibc defines functions that are not available on Linux as stubs that # fail with ENOSYS (such as e.g. lchmod). In this case we want to fail # instead of detecting the stub as a valid symbol. # We already included limits.h earlier to ensure that these are defined # for stub functions. stubs_fail = ''' #if defined __stub_{func} || defined __stub___{func} fail fail fail this function is not going to work #endif ''' # If we have any includes in the prefix supplied by the user, assume # that the user wants us to use the symbol prototype defined in those # includes. If not, then try to do the Autoconf-style check with # a dummy prototype definition of our own. # This is needed when the linker determines symbol availability from an # SDK based on the prototype in the header provided by the SDK. # Ignoring this prototype would result in the symbol always being # marked as available. if '#include' in prefix: head, main = self._have_prototype_templ() else: head, main = self._no_prototype_templ() templ = head + stubs_fail + main res, cached = self.links(templ.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) if res: return True, cached # MSVC does not have compiler __builtin_-s. if self.get_id() in {'msvc', 'intel-cl'}: return False, False # Detect function as a built-in # # Some functions like alloca() are defined as compiler built-ins which # are inlined by the compiler and you can't take their address, so we # need to look for them differently. On nice compilers like clang, we # can just directly use the __has_builtin() macro. fargs['no_includes'] = '#include' not in prefix t = '''{prefix} int main(void) {{ #ifdef __has_builtin #if !__has_builtin(__builtin_{func}) #error "__builtin_{func} not found" #endif #elif ! defined({func}) /* Check for __builtin_{func} only if no includes were added to the * prefix above, which means no definition of {func} can be found. * We would always check for this, but we get false positives on * MSYS2 if we do. Their toolchain is broken, but we can at least * give them a workaround. */ #if {no_includes:d} __builtin_{func}; #else #error "No definition for __builtin_{func} found in the prefix" #endif #endif return 0; }}''' return self.links(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) def has_members(self, typename, membernames, prefix, env, *, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'type': typename, 'name': 'foo'} # Create code that accesses all members members = '' for member in membernames: members += '{}.{};\n'.format(fargs['name'], member) fargs['members'] = members t = '''{prefix} void bar(void) {{ {type} {name}; {members} }};''' return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) def has_type(self, typename, prefix, env, extra_args, dependencies=None): fargs = {'prefix': prefix, 'type': typename} t = '''{prefix} void bar(void) {{ sizeof({type}); }};''' return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) def symbols_have_underscore_prefix(self, env): ''' Check if the compiler prefixes an underscore to global C symbols ''' symbol_name = b'meson_uscore_prefix' code = '''#ifdef __cplusplus extern "C" { #endif void ''' + symbol_name.decode() + ''' (void) {} #ifdef __cplusplus } #endif ''' args = self.get_compiler_check_args() n = 'symbols_have_underscore_prefix' with self._build_wrapper(code, env, extra_args=args, mode='compile', want_output=True, temp_dir=env.scratch_dir) as p: if p.returncode != 0: m = 'BUG: Unable to compile {!r} check: {}' raise RuntimeError(m.format(n, p.stdo)) if not os.path.isfile(p.output_name): m = 'BUG: Can\'t find compiled test code for {!r} check' raise RuntimeError(m.format(n)) with open(p.output_name, 'rb') as o: for line in o: # Check if the underscore form of the symbol is somewhere # in the output file. if b'_' + symbol_name in line: mlog.debug("Symbols have underscore prefix: YES") return True # Else, check if the non-underscored form is present elif symbol_name in line: mlog.debug("Symbols have underscore prefix: NO") return False raise RuntimeError('BUG: {!r} check failed unexpectedly'.format(n)) def _get_patterns(self, env, prefixes, suffixes, shared=False): patterns = [] for p in prefixes: for s in suffixes: patterns.append(p + '{}.' + s) if shared and env.machines[self.for_machine].is_openbsd(): # Shared libraries on OpenBSD can be named libfoo.so.X.Y: # https://www.openbsd.org/faq/ports/specialtopics.html#SharedLibs # # This globbing is probably the best matching we can do since regex # is expensive. It's wrong in many edge cases, but it will match # correctly-named libraries and hopefully no one on OpenBSD names # their files libfoo.so.9a.7b.1.0 for p in prefixes: patterns.append(p + '{}.so.[0-9]*.[0-9]*') return patterns def get_library_naming(self, env, libtype: LibType, strict=False): ''' Get library prefixes and suffixes for the target platform ordered by priority ''' stlibext = ['a'] # We've always allowed libname to be both `foo` and `libfoo`, and now # people depend on it. Also, some people use prebuilt `foo.so` instead # of `libfoo.so` for unknown reasons, and may also want to create # `foo.so` by setting name_prefix to '' if strict and not isinstance(self, VisualStudioLikeCompiler): # lib prefix is not usually used with msvc prefixes = ['lib'] else: prefixes = ['lib', ''] # Library suffixes and prefixes if env.machines[self.for_machine].is_darwin(): shlibext = ['dylib', 'so'] elif env.machines[self.for_machine].is_windows(): # FIXME: .lib files can be import or static so we should read the # file, figure out which one it is, and reject the wrong kind. if isinstance(self, VisualStudioLikeCompiler): shlibext = ['lib'] else: shlibext = ['dll.a', 'lib', 'dll'] # Yep, static libraries can also be foo.lib stlibext += ['lib'] elif env.machines[self.for_machine].is_cygwin(): shlibext = ['dll', 'dll.a'] prefixes = ['cyg'] + prefixes else: # Linux/BSDs shlibext = ['so'] # Search priority if libtype is LibType.PREFER_SHARED: patterns = self._get_patterns(env, prefixes, shlibext, True) patterns.extend([x for x in self._get_patterns(env, prefixes, stlibext, False) if x not in patterns]) elif libtype is LibType.PREFER_STATIC: patterns = self._get_patterns(env, prefixes, stlibext, False) patterns.extend([x for x in self._get_patterns(env, prefixes, shlibext, True) if x not in patterns]) elif libtype is LibType.SHARED: patterns = self._get_patterns(env, prefixes, shlibext, True) else: assert libtype is LibType.STATIC patterns = self._get_patterns(env, prefixes, stlibext, False) return tuple(patterns) @staticmethod def _sort_shlibs_openbsd(libs): filtered = [] for lib in libs: # Validate file as a shared library of type libfoo.so.X.Y ret = lib.rsplit('.so.', maxsplit=1) if len(ret) != 2: continue try: float(ret[1]) except ValueError: continue filtered.append(lib) float_cmp = lambda x: float(x.rsplit('.so.', maxsplit=1)[1]) return sorted(filtered, key=float_cmp, reverse=True) @classmethod def _get_trials_from_pattern(cls, pattern, directory, libname): f = Path(directory) / pattern.format(libname) # Globbing for OpenBSD if '*' in pattern: # NOTE: globbing matches directories and broken symlinks # so we have to do an isfile test on it later return [Path(x) for x in cls._sort_shlibs_openbsd(glob.glob(str(f)))] return [f] @staticmethod def _get_file_from_list(env, files: T.List[str]) -> Path: ''' We just check whether the library exists. We can't do a link check because the library might have unresolved symbols that require other libraries. On macOS we check if the library matches our target architecture. ''' # If not building on macOS for Darwin, do a simple file check files = [Path(f) for f in files] if not env.machines.host.is_darwin() or not env.machines.build.is_darwin(): for f in files: if f.is_file(): return f # Run `lipo` and check if the library supports the arch we want for f in files: if not f.is_file(): continue archs = mesonlib.darwin_get_object_archs(f) if archs and env.machines.host.cpu_family in archs: return f else: mlog.debug('Rejected {}, supports {} but need {}' .format(f, archs, env.machines.host.cpu_family)) return None @functools.lru_cache() def output_is_64bit(self, env): ''' returns true if the output produced is 64-bit, false if 32-bit ''' return self.sizeof('void *', '', env) == 8 def find_library_real(self, libname, env, extra_dirs, code, libtype: LibType): # First try if we can just add the library as -l. # Gcc + co seem to prefer builtin lib dirs to -L dirs. # Only try to find std libs if no extra dirs specified. # The built-in search procedure will always favour .so and then always # search for .a. This is only allowed if libtype is LibType.PREFER_SHARED if ((not extra_dirs and libtype is LibType.PREFER_SHARED) or libname in self.internal_libs): cargs = ['-l' + libname] largs = self.get_allow_undefined_link_args() extra_args = cargs + self.linker_to_compiler_args(largs) if self.links(code, env, extra_args=extra_args, disable_cache=True)[0]: return cargs # Don't do a manual search for internal libs if libname in self.internal_libs: return None # Not found or we want to use a specific libtype? Try to find the # library file itself. patterns = self.get_library_naming(env, libtype) # try to detect if we are 64-bit or 32-bit. If we can't # detect, we will just skip path validity checks done in # get_library_dirs() call try: if self.output_is_64bit(env): elf_class = 2 else: elf_class = 1 except (mesonlib.MesonException, KeyError): # TODO evaluate if catching KeyError is wanted here elf_class = 0 # Search in the specified dirs, and then in the system libraries for d in itertools.chain(extra_dirs, self.get_library_dirs(env, elf_class)): for p in patterns: trial = self._get_trials_from_pattern(p, d, libname) if not trial: continue trial = self._get_file_from_list(env, trial) if not trial: continue return [trial.as_posix()] return None def find_library_impl(self, libname, env, extra_dirs, code, libtype: LibType): # These libraries are either built-in or invalid if libname in self.ignore_libs: return [] if isinstance(extra_dirs, str): extra_dirs = [extra_dirs] key = (tuple(self.exelist), libname, tuple(extra_dirs), code, libtype) if key not in self.find_library_cache: value = self.find_library_real(libname, env, extra_dirs, code, libtype) self.find_library_cache[key] = value else: value = self.find_library_cache[key] if value is None: return None return value[:] def find_library(self, libname, env, extra_dirs, libtype: LibType = LibType.PREFER_SHARED): code = 'int main(void) { return 0; }' return self.find_library_impl(libname, env, extra_dirs, code, libtype) def find_framework_paths(self, env): ''' These are usually /Library/Frameworks and /System/Library/Frameworks, unless you select a particular macOS SDK with the -isysroot flag. You can also add to this by setting -F in CFLAGS. ''' if self.id != 'clang': raise mesonlib.MesonException('Cannot find framework path with non-clang compiler') # Construct the compiler command-line commands = self.get_exelist() + ['-v', '-E', '-'] commands += self.get_always_args() # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env commands += env.coredata.get_external_args(self.for_machine, self.language) mlog.debug('Finding framework path by running: ', ' '.join(commands), '\n') os_env = os.environ.copy() os_env['LC_ALL'] = 'C' _, _, stde = mesonlib.Popen_safe(commands, env=os_env, stdin=subprocess.PIPE) paths = [] for line in stde.split('\n'): if '(framework directory)' not in line: continue # line is of the form: # ` /path/to/framework (framework directory)` paths.append(line[:-21].strip()) return paths def find_framework_real(self, name, env, extra_dirs, allow_system): code = 'int main(void) { return 0; }' link_args = [] for d in extra_dirs: link_args += ['-F' + d] # We can pass -Z to disable searching in the system frameworks, but # then we must also pass -L/usr/lib to pick up libSystem.dylib extra_args = [] if allow_system else ['-Z', '-L/usr/lib'] link_args += ['-framework', name] if self.links(code, env, extra_args=(extra_args + link_args), disable_cache=True)[0]: return link_args def find_framework_impl(self, name, env, extra_dirs, allow_system): if isinstance(extra_dirs, str): extra_dirs = [extra_dirs] key = (tuple(self.exelist), name, tuple(extra_dirs), allow_system) if key in self.find_framework_cache: value = self.find_framework_cache[key] else: value = self.find_framework_real(name, env, extra_dirs, allow_system) self.find_framework_cache[key] = value if value is None: return None return value[:] def find_framework(self, name, env, extra_dirs, allow_system=True): ''' Finds the framework with the specified name, and returns link args for the same or returns None when the framework is not found. ''' if self.id != 'clang': raise mesonlib.MesonException('Cannot find frameworks with non-clang compiler') return self.find_framework_impl(name, env, extra_dirs, allow_system) def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] def thread_flags(self, env): host_m = env.machines[self.for_machine] if host_m.is_haiku() or host_m.is_darwin(): return [] return ['-pthread'] def thread_link_flags(self, env: 'Environment') -> T.List[str]: return self.linker.thread_flags(env) def linker_to_compiler_args(self, args): return args def has_arguments(self, args, env, code, mode): return self.compiles(code, env, extra_args=args, mode=mode) def has_multi_arguments(self, args, env): for arg in args[:]: # some compilers, e.g. GCC, don't warn for unsupported warning-disable # flags, so when we are testing a flag like "-Wno-forgotten-towel", also # check the equivalent enable flag too "-Wforgotten-towel" if arg.startswith('-Wno-'): args.append('-W' + arg[5:]) if arg.startswith('-Wl,'): mlog.warning('{} looks like a linker argument, ' 'but has_argument and other similar methods only ' 'support checking compiler arguments. Using them ' 'to check linker arguments are never supported, ' 'and results are likely to be wrong regardless of ' 'the compiler you are using. has_link_argument or ' 'other similar method can be used instead.' .format(arg)) code = 'int i;\n' return self.has_arguments(args, env, code, mode='compile') def has_multi_link_arguments(self, args, env): # First time we check for link flags we need to first check if we have # --fatal-warnings, otherwise some linker checks could give some # false positive. args = self.linker.fatal_warnings() + args args = self.linker_to_compiler_args(args) code = 'int main(void) { return 0; }' return self.has_arguments(args, env, code, mode='link') @staticmethod def concatenate_string_literals(s): pattern = re.compile(r'(?P
.*([^\\]")|^")(?P([^\\"]|\\.)*)"\s+"(?P([^\\"]|\\.)*)(?P".*)')
        ret = s
        m = pattern.match(ret)
        while m:
            ret = ''.join(m.group('pre', 'str1', 'str2', 'post'))
            m = pattern.match(ret)
        return ret

    def has_func_attribute(self, name, env):
        # Just assume that if we're not on windows that dllimport and dllexport
        # don't work
        m = env.machines[self.for_machine]
        if not (m.is_windows() or m.is_cygwin()):
            if name in ['dllimport', 'dllexport']:
                return False, False

        # Clang and GCC both return warnings if the __attribute__ is undefined,
        # so set -Werror
        return self.compiles(self.attribute_check_func(name), env, extra_args='-Werror')
meson-0.53.2/mesonbuild/compilers/mixins/elbrus.py0000644000175000017500000000655213625260316023643 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Abstractions for the Elbrus family of compilers."""

import os
import typing as T
import subprocess
import re

from .gnu import GnuLikeCompiler
from .gnu import gnu_optimization_args
from ...mesonlib import Popen_safe

if T.TYPE_CHECKING:
    from ...environment import Environment


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):
        super().__init__()
        self.id = 'lcc'
        self.base_options = ['b_pgo', 'b_coverage',
                             'b_ndebug', 'b_staticpic',
                             'b_lundef', 'b_asneeded']

    # FIXME: use _build_wrapper to call this so that linker flags from the env
    # get applied
    def get_library_dirs(self, env: 'Environment', elf_class: T.Optional[int] = None) -> T.List[str]:
        os_env = os.environ.copy()
        os_env['LC_ALL'] = 'C'
        stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=os_env)[1]
        for line in stdo.split('\n'):
            if line.startswith('libraries:'):
                # lcc does not include '=' in --print-search-dirs output. Also it could show nonexistent dirs.
                libstr = line.split(' ', 1)[1]
                return [os.path.realpath(p) for p in libstr.split(':') if os.path.exists(p)]
        return []

    def get_program_dirs(self, env: 'Environment') -> T.List[str]:
        os_env = os.environ.copy()
        os_env['LC_ALL'] = 'C'
        stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=os_env)[1]
        for line in stdo.split('\n'):
            if line.startswith('programs:'):
                # lcc does not include '=' in --print-search-dirs output.
                libstr = line.split(' ', 1)[1]
                return [os.path.realpath(p) for p in libstr.split(':')]
        return []

    def get_default_include_dirs(self) -> T.List[str]:
        os_env = os.environ.copy()
        os_env['LC_ALL'] = 'C'
        p = subprocess.Popen(self.exelist + ['-xc', '-E', '-v', '-'], env=os_env, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stderr = p.stderr.read().decode('utf-8', errors='replace')
        includes = []
        for line in stderr.split('\n'):
            if line.lstrip().startswith('--sys_include'):
                includes.append(re.sub(r'\s*\\$', '', re.sub(r'^\s*--sys_include\s*', '', line)))
        return includes

    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        return gnu_optimization_args[optimization_level]

    def get_pch_suffix(self) -> str:
        # Actually it's not supported for now, but probably will be supported in future
        return 'pch'

    def openmp_flags(self) -> T.List[str]:
        return ['-fopenmp']
meson-0.53.2/mesonbuild/compilers/mixins/emscripten.py0000644000175000017500000000330113612313307024500 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Provides a mixin for shared code between C and C++ Emscripten compilers."""

import os.path
import typing as T

from ...mesonlib import MesonException

class EmscriptenMixin:
    def get_option_link_args(self, options):
        return []

    def get_soname_args(self, *args, **kwargs):
        raise MesonException('Emscripten does not support shared libraries.')

    def get_allow_undefined_link_args(self) -> T.List[str]:
        return ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=0']

    def get_linker_output_args(self, output: str) -> T.List[str]:
        return ['-o', output]

    def _get_compile_output(self, dirname, mode):
        # In pre-processor mode, the output is sent to stdout and discarded
        if mode == 'preprocess':
            return None
        # Unlike sane toolchains, emcc infers the kind of output from its name.
        # This is the only reason why this method is overridden; compiler tests
        # do not work well with the default exe/obj suffices.
        if mode == 'link':
            suffix = 'js'
        else:
            suffix = 'wasm'
        return os.path.join(dirname, 'output.' + suffix)
meson-0.53.2/mesonbuild/compilers/mixins/gnu.py0000644000175000017500000003132413612313307023126 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Provides mixins for GNU compilers and GNU-like compilers."""

import abc
import functools
import os
import pathlib
import re
import subprocess
import typing as T

from ... import mesonlib
from ... import mlog

if T.TYPE_CHECKING:
    from ...coredata import UserOption  # noqa: F401
    from ...environment import Environment

# XXX: prevent circular references.
# FIXME: this really is a posix interface not a c-like interface
clike_debug_args = {
    False: [],
    True: ['-g'],
}  # type: T.Dict[bool, T.List[str]]

gnulike_buildtype_args = {
    'plain': [],
    'debug': [],
    'debugoptimized': [],
    'release': [],
    'minsize': [],
    'custom': [],
}  # type: T.Dict[str, T.List[str]]

gnu_optimization_args = {
    '0': [],
    'g': ['-Og'],
    '1': ['-O1'],
    '2': ['-O2'],
    '3': ['-O3'],
    's': ['-Os'],
}  # type: T.Dict[str, T.List[str]]

gnulike_instruction_set_args = {
    'mmx': ['-mmmx'],
    'sse': ['-msse'],
    'sse2': ['-msse2'],
    'sse3': ['-msse3'],
    'ssse3': ['-mssse3'],
    'sse41': ['-msse4.1'],
    'sse42': ['-msse4.2'],
    'avx': ['-mavx'],
    'avx2': ['-mavx2'],
    'neon': ['-mfpu=neon'],
}  # type: T.Dict[str, T.List[str]]

gnu_symbol_visibility_args = {
    '': [],
    'default': ['-fvisibility=default'],
    'internal': ['-fvisibility=internal'],
    'hidden': ['-fvisibility=hidden'],
    'protected': ['-fvisibility=protected'],
    'inlineshidden': ['-fvisibility=hidden', '-fvisibility-inlines-hidden'],
}  # type: T.Dict[str, T.List[str]]

gnu_color_args = {
    'auto': ['-fdiagnostics-color=auto'],
    'always': ['-fdiagnostics-color=always'],
    'never': ['-fdiagnostics-color=never'],
}  # type: T.Dict[str, T.List[str]]


@functools.lru_cache(maxsize=None)
def gnulike_default_include_dirs(compiler: T.Tuple[str], lang: str) -> T.List[str]:
    lang_map = {
        'c': 'c',
        'cpp': 'c++',
        'objc': 'objective-c',
        'objcpp': 'objective-c++'
    }
    if lang not in lang_map:
        return []
    lang = lang_map[lang]
    env = os.environ.copy()
    env["LC_ALL"] = 'C'
    cmd = list(compiler) + ['-x{}'.format(lang), '-E', '-v', '-']
    p = subprocess.Popen(
        cmd,
        stdin=subprocess.DEVNULL,
        stderr=subprocess.STDOUT,
        stdout=subprocess.PIPE,
        env=env
    )
    stdout = p.stdout.read().decode('utf-8', errors='replace')
    parse_state = 0
    paths = []
    for line in stdout.split('\n'):
        line = line.strip(' \n\r\t')
        if parse_state == 0:
            if line == '#include "..." search starts here:':
                parse_state = 1
        elif parse_state == 1:
            if line == '#include <...> search starts here:':
                parse_state = 2
            else:
                paths.append(line)
        elif parse_state == 2:
            if line == 'End of search list.':
                break
            else:
                paths.append(line)
    if not paths:
        mlog.warning('No include directory found parsing "{cmd}" output'.format(cmd=" ".join(cmd)))
    # Append a normalized copy of paths to make path lookup easier
    paths += [os.path.normpath(x) for x in paths]
    return paths


class GnuLikeCompiler(metaclass=abc.ABCMeta):
    """
    GnuLikeCompiler is a common interface to all compilers implementing
    the GNU-style commandline interface. This includes GCC, Clang
    and ICC. Certain functionality between them is different and requires
    that the actual concrete subclass define their own implementation.
    """

    LINKER_PREFIX = '-Wl,'

    def __init__(self):
        self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage',
                             'b_ndebug', 'b_staticpic', 'b_pie']
        if not (self.info.is_windows() or self.info.is_cygwin() or self.info.is_openbsd()):
            self.base_options.append('b_lundef')
        if not self.info.is_windows() or self.info.is_cygwin():
            self.base_options.append('b_asneeded')
        # All GCC-like backends can do assembly
        self.can_compile_suffixes.add('s')

    def get_pic_args(self) -> T.List[str]:
        if self.info.is_windows() or self.info.is_cygwin() or self.info.is_darwin():
            return [] # On Window and OS X, pic is always on.
        return ['-fPIC']

    def get_pie_args(self) -> T.List[str]:
        return ['-fPIE']

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        return gnulike_buildtype_args[buildtype]

    @abc.abstractmethod
    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        raise NotImplementedError("get_optimization_args not implemented")

    def get_debug_args(self, is_debug: bool) -> T.List[str]:
        return clike_debug_args[is_debug]

    @abc.abstractmethod
    def get_pch_suffix(self) -> str:
        raise NotImplementedError("get_pch_suffix not implemented")

    def split_shlib_to_parts(self, fname: str) -> T.Tuple[str, str]:
        return os.path.dirname(fname), fname

    def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]:
        return gnulike_instruction_set_args.get(instruction_set, None)

    def get_default_include_dirs(self) -> T.List[str]:
        return gnulike_default_include_dirs(tuple(self.exelist), self.language)

    @abc.abstractmethod
    def openmp_flags(self) -> T.List[str]:
        raise NotImplementedError("openmp_flags not implemented")

    def gnu_symbol_visibility_args(self, vistype: str) -> T.List[str]:
        return gnu_symbol_visibility_args[vistype]

    def gen_vs_module_defs_args(self, defsfile: str) -> T.List[str]:
        if not isinstance(defsfile, str):
            raise RuntimeError('Module definitions file should be str')
        # On Windows targets, .def files may be specified on the linker command
        # line like an object file.
        if self.info.is_windows() or self.info.is_cygwin():
            return [defsfile]
        # For other targets, discard the .def file.
        return []

    def get_argument_syntax(self) -> str:
        return 'gcc'

    def get_profile_generate_args(self) -> T.List[str]:
        return ['-fprofile-generate']

    def get_profile_use_args(self) -> T.List[str]:
        return ['-fprofile-use', '-fprofile-correction']

    def get_gui_app_args(self, value: bool) -> T.List[str]:
        if self.info.is_windows() or self.info.is_cygwin():
            return ['-mwindows' if value else '-mconsole']
        return []

    def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]:
        for idx, i in enumerate(parameter_list):
            if i[:2] == '-I' or i[:2] == '-L':
                parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))

        return parameter_list

    @functools.lru_cache()
    def _get_search_dirs(self, env: 'Environment') -> str:
        extra_args = ['--print-search-dirs']
        stdo = None
        with self._build_wrapper('', env, extra_args=extra_args,
                                 dependencies=None, mode='compile',
                                 want_output=True) as p:
            stdo = p.stdo
        return stdo

    def _split_fetch_real_dirs(self, pathstr: str) -> T.List[str]:
        # We need to use the path separator used by the compiler for printing
        # lists of paths ("gcc --print-search-dirs"). By default
        # we assume it uses the platform native separator.
        pathsep = os.pathsep

        # clang uses ':' instead of ';' on Windows https://reviews.llvm.org/D61121
        # so we need to repair things like 'C:\foo:C:\bar'
        if pathsep == ';':
            pathstr = re.sub(r':([^/\\])', r';\1', pathstr)

        # pathlib treats empty paths as '.', so filter those out
        paths = [p for p in pathstr.split(pathsep) if p]

        result = []
        for p in paths:
            # GCC returns paths like this:
            # /usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/lib
            # It would make sense to normalize them to get rid of the .. parts
            # Sadly when you are on a merged /usr fs it also kills these:
            # /lib/x86_64-linux-gnu
            # since /lib is a symlink to /usr/lib. This would mean
            # paths under /lib would be considered not a "system path",
            # which is wrong and breaks things. Store everything, just to be sure.
            pobj = pathlib.Path(p)
            unresolved = pobj.as_posix()
            if pobj.exists():
                if unresolved not in result:
                    result.append(unresolved)
                try:
                    resolved = pathlib.Path(p).resolve().as_posix()
                    if resolved not in result:
                        result.append(resolved)
                except FileNotFoundError:
                    pass
        return result

    def get_compiler_dirs(self, env: 'Environment', name: str) -> T.List[str]:
        '''
        Get dirs from the compiler, either `libraries:` or `programs:`
        '''
        stdo = self._get_search_dirs(env)
        for line in stdo.split('\n'):
            if line.startswith(name + ':'):
                return self._split_fetch_real_dirs(line.split('=', 1)[1])
        return []

    def get_lto_compile_args(self) -> T.List[str]:
        return ['-flto']

    def sanitizer_compile_args(self, value: str) -> T.List[str]:
        if value == 'none':
            return []
        args = ['-fsanitize=' + value]
        if 'address' in value:  # for -fsanitize=address,undefined
            args.append('-fno-omit-frame-pointer')
        return args

    def get_output_args(self, target: str) -> T.List[str]:
        return ['-o', target]

    def get_dependency_gen_args(self, outtarget, outfile):
        return ['-MD', '-MQ', outtarget, '-MF', outfile]

    def get_compile_only_args(self) -> T.List[str]:
        return ['-c']

    def get_include_args(self, path: str, is_system: bool) -> T.List[str]:
        if not path:
            path = '.'
        if is_system:
            return ['-isystem' + path]
        return ['-I' + path]

    @classmethod
    def use_linker_args(cls, linker: str) -> T.List[str]:
        return ['-fuse-ld={}'.format(linker)]


class GnuCompiler(GnuLikeCompiler):
    """
    GnuCompiler represents an actual GCC in its many incarnations.
    Compilers imitating GCC (Clang/Intel) should use the GnuLikeCompiler ABC.
    """

    def __init__(self, defines: T.Dict[str, str]):
        super().__init__()
        self.id = 'gcc'
        self.defines = defines or {}
        self.base_options.append('b_colorout')

    def get_colorout_args(self, colortype: str) -> T.List[str]:
        if mesonlib.version_compare(self.version, '>=4.9.0'):
            return gnu_color_args[colortype][:]
        return []

    def get_warn_args(self, level: str) -> T.List[str]:
        args = super().get_warn_args(level)
        if mesonlib.version_compare(self.version, '<4.8.0') and '-Wpedantic' in args:
            # -Wpedantic was added in 4.8.0
            # https://gcc.gnu.org/gcc-4.8/changes.html
            args[args.index('-Wpedantic')] = '-pedantic'
        return args

    def has_builtin_define(self, define: str) -> bool:
        return define in self.defines

    def get_builtin_define(self, define: str) -> T.Optional[str]:
        if define in self.defines:
            return self.defines[define]
        return None

    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        return gnu_optimization_args[optimization_level]

    def get_pch_suffix(self) -> str:
        return 'gch'

    def openmp_flags(self) -> T.List[str]:
        return ['-fopenmp']

    def has_arguments(self, args, env, code, mode):
        # For some compiler command line arguments, the GNU compilers will
        # emit a warning on stderr indicating that an option is valid for a
        # another language, but still complete with exit_success
        with self._build_wrapper(code, env, args, None, mode, disable_cache=False, want_output=True) as p:
            result = p.returncode == 0
            if self.language in {'cpp', 'objcpp'} and 'is valid for C/ObjC' in p.stde:
                result = False
            if self.language in {'c', 'objc'} and 'is valid for C++/ObjC++' in p.stde:
                result = False
        return result, p.cached
meson-0.53.2/mesonbuild/compilers/mixins/intel.py0000644000175000017500000001615713612313307023457 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Abstractions for the Intel Compiler families.

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
import typing as T

from ... import mesonlib
from .gnu import GnuLikeCompiler
from .visualstudio import VisualStudioLikeCompiler

if T.TYPE_CHECKING:
    import subprocess  # noqa: F401

# 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


class IntelGnuLikeCompiler(GnuLikeCompiler):
    """
    Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1, 19.0
    debugoptimized: -g -O2
    release: -O3
    minsize: -O2
    """

    BUILD_ARGS = {
        'plain': [],
        'debug': ["-g", "-traceback"],
        'debugoptimized': ["-g", "-traceback"],
        'release': [],
        'minsize': [],
        'custom': [],
    }  # type: T.Dict[str, T.List[str]]

    OPTIM_ARGS = {
        '0': ['-O0'],
        'g': ['-O0'],
        '1': ['-O1'],
        '2': ['-O2'],
        '3': ['-O3'],
        's': ['-Os'],
    }

    def __init__(self):
        super().__init__()
        # As of 19.0.0 ICC doesn't have sanitizer, color, or lto support.
        #
        # It does have IPO, which serves much the same purpose as LOT, but
        # there is an unfortunate rule for using IPO (you can't control the
        # name of the output file) which break assumptions meson makes
        self.base_options = ['b_pch', 'b_lundef', 'b_asneeded', 'b_pgo',
                             'b_coverage', 'b_ndebug', 'b_staticpic', 'b_pie']
        self.id = 'intel'
        self.lang_header = 'none'

    def get_pch_suffix(self) -> str:
        return 'pchi'

    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
        return ['-pch', '-pch_dir', os.path.join(pch_dir), '-x',
                self.lang_header, '-include', header, '-x', 'none']

    def get_pch_name(self, header_name: str) -> str:
        return os.path.basename(header_name) + '.' + self.get_pch_suffix()

    def openmp_flags(self) -> T.List[str]:
        if mesonlib.version_compare(self.version, '>=15.0.0'):
            return ['-qopenmp']
        else:
            return ['-openmp']

    def compiles(self, *args, **kwargs) -> T.Tuple[bool, bool]:
        # This covers a case that .get('foo', []) doesn't, that extra_args is
        # defined and is None
        extra_args = kwargs.get('extra_args') or []
        kwargs['extra_args'] = [
            extra_args,
            '-diag-error', '10006',  # ignoring unknown option
            '-diag-error', '10148',  # Option not supported
            '-diag-error', '10155',  # ignoring argument required
            '-diag-error', '10156',  # ignoring not argument allowed
            '-diag-error', '10157',  # Ignoring argument of the wrong type
            '-diag-error', '10158',  # Argument must be separate. Can be hit by trying an option like -foo-bar=foo when -foo=bar is a valid option but -foo-bar isn't
            '-diag-error', '1292',   # unknown __attribute__
        ]
        return super().compiles(*args, **kwargs)

    def get_profile_generate_args(self) -> T.List[str]:
        return ['-prof-gen=threadsafe']

    def get_profile_use_args(self) -> T.List[str]:
        return ['-prof-use']

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        return self.BUILD_ARGS[buildtype]

    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        return self.OPTIM_ARGS[optimization_level]


class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler):

    """Abstractions for ICL, the Intel compiler on Windows."""

    BUILD_ARGS = {
        'plain': [],
        'debug': ["/Zi", "/traceback"],
        'debugoptimized': ["/Zi", "/traceback"],
        'release': [],
        'minsize': [],
        'custom': [],
    }  # type: T.Dict[str, T.List[str]]

    OPTIM_ARGS = {
        '0': ['/O0'],
        'g': ['/O0'],
        '1': ['/O1'],
        '2': ['/O2'],
        '3': ['/O3'],
        's': ['/Os'],
    }

    def __init__(self, target: str):
        super().__init__(target)
        self.id = 'intel-cl'

    def compile(self, code, *, extra_args: T.Optional[T.List[str]] = None, **kwargs) -> T.Iterator['subprocess.Popen']:
        # This covers a case that .get('foo', []) doesn't, that extra_args is
        if kwargs.get('mode', 'compile') != 'link':
            extra_args = extra_args.copy() if extra_args is not None else []
            extra_args.extend([
                '/Qdiag-error:10006',  # ignoring unknown option
                '/Qdiag-error:10148',  # Option not supported
                '/Qdiag-error:10155',  # ignoring argument required
                '/Qdiag-error:10156',  # ignoring not argument allowed
                '/Qdiag-error:10157',  # Ignoring argument of the wrong type
                '/Qdiag-error:10158',  # Argument must be separate. Can be hit by trying an option like -foo-bar=foo when -foo=bar is a valid option but -foo-bar isn't
            ])
        return super().compile(code, extra_args, **kwargs)

    def get_toolset_version(self) -> T.Optional[str]:
        # Avoid circular dependencies....
        from ...environment import search_version

        # ICL provides a cl.exe that returns the version of MSVC it tries to
        # emulate, so we'll get the version from that and pass it to the same
        # function the real MSVC uses to calculate the toolset version.
        _, _, err = mesonlib.Popen_safe(['cl.exe'])
        v1, v2, *_ = search_version(err).split('.')
        version = int(v1 + v2)
        return self._calculate_toolset_version(version)

    def openmp_flags(self) -> T.List[str]:
        return ['/Qopenmp']

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        return self.BUILD_ARGS[buildtype]

    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        return self.OPTIM_ARGS[optimization_level]
meson-0.53.2/mesonbuild/compilers/mixins/islinker.py0000644000175000017500000001062113612313307024152 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Mixins for compilers that *are* linkers.

While many compilers (such as gcc and clang) are used by meson to dispatch
linker commands and other (like MSVC) are not, a few (such as DMD) actually
are both the linker and compiler in one binary. This module provides mixin
classes for those cases.
"""

import os
import typing as T

from ... import mesonlib

if T.TYPE_CHECKING:
    from ...coredata import OptionDictType
    from ...environment import Environment


class LinkerEnvVarsMixin:

    """Mixin reading LDFLAGS from the environment."""

    def get_linker_args_from_envvars(self) -> T.List[str]:
        flags = os.environ.get('LDFLAGS')
        if not flags:
            return []
        return mesonlib.split_args(flags)


class BasicLinkerIsCompilerMixin:

    """Provides a baseline of methods that a linker would implement.

    In every case this provides a "no" or "empty" answer. If a compiler
    implements any of these it needs a different mixin or to override that
    functionality itself.
    """

    def sanitizer_link_args(self, value: str) -> T.List[str]:
        return []

    def get_lto_link_args(self) -> T.List[str]:
        return []

    def can_linker_accept_rsp(self) -> bool:
        return mesonlib.is_windows()

    def get_linker_exelist(self) -> T.List[str]:
        return self.exelist.copy()

    def get_linker_output_args(self, output: str) -> T.List[str]:
        return []

    def get_linker_always_args(self) -> T.List[str]:
        return []

    def get_linker_lib_prefix(self) -> str:
        return ''

    def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]:
        return []

    def has_multi_link_args(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]:
        return False, False

    def get_link_debugfile_args(self, targetfile: str) -> T.List[str]:
        return []

    def get_std_shared_lib_link_args(self) -> T.List[str]:
        return []

    def get_std_shared_module_args(self, options: 'OptionDictType') -> T.List[str]:
        return self.get_std_shared_lib_link_args()

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        raise mesonlib.EnvironmentException(
            'Linker {} does not support link_whole'.format(self.id))

    def get_allow_undefined_link_args(self) -> T.List[str]:
        raise mesonlib.EnvironmentException(
            'Linker {} does not support allow undefined'.format(self.id))

    def get_pie_link_args(self) -> T.List[str]:
        m = 'Linker {} does not support position-independent executable'
        raise mesonlib.EnvironmentException(m.format(self.id))

    def get_undefined_link_args(self) -> T.List[str]:
        return []

    def get_coverage_link_args(self) -> T.List[str]:
        m = "Linker {} doesn't implement coverage data generation.".format(self.id)
        raise mesonlib.EnvironmentException(m)

    def no_undefined_link_args(self) -> T.List[str]:
        return []

    def bitcode_args(self) -> T.List[str]:
        raise mesonlib.MesonException("This linker doesn't support bitcode bundles")

    def get_soname_args(self, for_machine: 'mesonlib.MachineChoice',
                        prefix: str, shlib_name: str, suffix: str, soversion: str,
                        darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        raise mesonlib.MesonException("This linker doesn't support soname args")

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: str, build_rpath: str,
                         install_rpath: str) -> T.List[str]:
        return []

    def get_linker_debug_crt_args(self) -> T.List[str]:
        return []

    def get_asneeded_args(self) -> T.List[str]:
        return []

    def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]:
        return []
meson-0.53.2/mesonbuild/compilers/mixins/pgi.py0000644000175000017500000000624413612313307023117 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Abstractions for the PGI family of compilers."""

import typing as T
import os
from pathlib import Path

from ..compilers import clike_debug_args, clike_optimization_args

pgi_buildtype_args = {
    'plain': [],
    'debug': [],
    'debugoptimized': [],
    'release': [],
    'minsize': [],
    'custom': [],
}  # type: T.Dict[str, T.List[str]]


class PGICompiler:
    def __init__(self):
        self.base_options = ['b_pch']
        self.id = 'pgi'

        default_warn_args = ['-Minform=inform']
        self.warn_args = {'0': [],
                          '1': default_warn_args,
                          '2': default_warn_args,
                          '3': default_warn_args}

    def get_module_incdir_args(self) -> T.Tuple[str]:
        return ('-module', )

    def get_no_warn_args(self) -> T.List[str]:
        return ['-silent']

    def gen_import_library_args(self, implibname: str) -> T.List[str]:
        return []

    def get_pic_args(self) -> T.List[str]:
        # PGI -fPIC is Linux only.
        if self.info.is_linux():
            return ['-fPIC']
        return []

    def openmp_flags(self) -> T.List[str]:
        return ['-mp']

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        return pgi_buildtype_args[buildtype]

    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        return clike_optimization_args[optimization_level]

    def get_debug_args(self, is_debug: bool) -> T.List[str]:
        return clike_debug_args[is_debug]

    def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]:
        for idx, i in enumerate(parameter_list):
            if i[:2] == '-I' or i[:2] == '-L':
                parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))
        return parameter_list

    def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
        return []

    def get_always_args(self) -> T.List[str]:
        return []

    def get_pch_suffix(self) -> str:
        # PGI defaults to .pch suffix for PCH on Linux and Windows with --pch option
        return 'pch'

    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
        # PGI supports PCH for C++ only.
        hdr = Path(pch_dir).resolve().parent / header
        if self.language == 'cpp':
            return ['--pch',
                    '--pch_dir', str(hdr.parent),
                    '-I{}'.format(hdr.parent)]
        else:
            return []

    def thread_flags(self, env):
        # PGI cannot accept -pthread, it's already threaded
        return []
meson-0.53.2/mesonbuild/compilers/mixins/visualstudio.py0000644000175000017500000003430513612313307025072 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Abstractions to simplify compilers that implement an MSVC compatible
interface.
"""

import abc
import os
import typing as T

from ... import mesonlib
from ... import mlog

if T.TYPE_CHECKING:
    from ...environment import Environment

vs32_instruction_set_args = {
    'mmx': ['/arch:SSE'], # There does not seem to be a flag just for MMX
    'sse': ['/arch:SSE'],
    'sse2': ['/arch:SSE2'],
    'sse3': ['/arch:AVX'], # VS leaped from SSE2 directly to AVX.
    'sse41': ['/arch:AVX'],
    'sse42': ['/arch:AVX'],
    'avx': ['/arch:AVX'],
    'avx2': ['/arch:AVX2'],
    'neon': None,
}  # T.Dicst[str, T.Optional[T.List[str]]]

# The 64 bit compiler defaults to /arch:avx.
vs64_instruction_set_args = {
    'mmx': ['/arch:AVX'],
    'sse': ['/arch:AVX'],
    'sse2': ['/arch:AVX'],
    'sse3': ['/arch:AVX'],
    'ssse3': ['/arch:AVX'],
    'sse41': ['/arch:AVX'],
    'sse42': ['/arch:AVX'],
    'avx': ['/arch:AVX'],
    'avx2': ['/arch:AVX2'],
    'neon': None,
}  # T.Dicst[str, T.Optional[T.List[str]]]

msvc_buildtype_args = {
    'plain': [],
    'debug': ["/ZI", "/Ob0", "/Od", "/RTC1"],
    'debugoptimized': ["/Zi", "/Ob1"],
    'release': ["/Ob2", "/Gw"],
    'minsize': ["/Zi", "/Gw"],
    'custom': [],
}  # type: T.Dict[str, T.List[str]]

msvc_optimization_args = {
    '0': [],
    'g': ['/O0'],
    '1': ['/O1'],
    '2': ['/O2'],
    '3': ['/O2'],
    's': ['/O1'], # Implies /Os.
}  # type: T.Dict[str, T.List[str]]

msvc_debug_args = {
    False: [],
    True: []  # Fixme!
}  # type: T.Dict[bool, T.List[str]]


class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):

    """A common interface for all compilers implementing an MSVC-style
    interface.

    A number of compilers attempt to mimic MSVC, with varying levels of
    success, such as Clang-CL and ICL (the Intel C/C++ Compiler for Windows).
    This class implements as much common logic as possible.
    """

    std_warn_args = ['/W3']
    std_opt_args = ['/O2']
    # XXX: this is copied in this patch only to avoid circular dependencies
    #ignore_libs = unixy_compiler_internal_libs
    ignore_libs = ('m', 'c', 'pthread', 'dl', 'rt', 'execinfo')
    internal_libs = ()

    crt_args = {
        'none': [],
        'md': ['/MD'],
        'mdd': ['/MDd'],
        'mt': ['/MT'],
        'mtd': ['/MTd'],
    }  # type: T.Dict[str, T.List[str]]

    # /showIncludes is needed for build dependency tracking in Ninja
    # See: https://ninja-build.org/manual.html#_deps
    always_args = ['/nologo', '/showIncludes']
    warn_args = {
        '0': ['/W1'],
        '1': ['/W2'],
        '2': ['/W3'],
        '3': ['/W4'],
    }  # type: T.Dict[str, T.List[str]]

    INVOKES_LINKER = False

    def __init__(self, target: str):
        self.base_options = ['b_pch', 'b_ndebug', 'b_vscrt'] # FIXME add lto, pgo and the like
        self.target = target
        self.is_64 = ('x64' in target) or ('x86_64' in target)
        # do some canonicalization of target machine
        if 'x86_64' in target:
            self.machine = 'x64'
        elif '86' in target:
            self.machine = 'x86'
        else:
            self.machine = target
        self.linker.machine = self.machine

    # Override CCompiler.get_always_args
    def get_always_args(self) -> T.List[str]:
        return self.always_args

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        args = msvc_buildtype_args[buildtype]
        if self.id == 'msvc' and mesonlib.version_compare(self.version, '<18.0'):
            args = [arg for arg in args if arg != '/Gw']
        return args

    def get_pch_suffix(self) -> str:
        return 'pch'

    def get_pch_name(self, header: str) -> str:
        chopped = os.path.basename(header).split('.')[:-1]
        chopped.append(self.get_pch_suffix())
        pchname = '.'.join(chopped)
        return pchname

    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
        base = os.path.basename(header)
        if self.id == 'clang-cl':
            base = header
        pchname = self.get_pch_name(header)
        return ['/FI' + base, '/Yu' + base, '/Fp' + os.path.join(pch_dir, pchname)]

    def get_preprocess_only_args(self) -> T.List[str]:
        return ['/EP']

    def get_compile_only_args(self) -> T.List[str]:
        return ['/c']

    def get_no_optimization_args(self) -> T.List[str]:
        return ['/Od']

    def get_output_args(self, target: str) -> T.List[str]:
        if target.endswith('.exe'):
            return ['/Fe' + target]
        return ['/Fo' + target]

    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
        return msvc_optimization_args[optimization_level]

    def get_debug_args(self, is_debug: bool) -> T.List[str]:
        return msvc_debug_args[is_debug]

    def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
        return []

    def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]:
        return ['/link'] + args

    def get_gui_app_args(self, value: bool) -> T.List[str]:
        # the default is for the linker to guess the subsystem based on presence
        # of main or WinMain symbols, so always be explicit
        if value:
            return ['/SUBSYSTEM:WINDOWS']
        else:
            return ['/SUBSYSTEM:CONSOLE']

    def get_pic_args(self) -> T.List[str]:
        return [] # PIC is handled by the loader on Windows

    def gen_vs_module_defs_args(self, defsfile: str) -> T.List[str]:
        if not isinstance(defsfile, str):
            raise RuntimeError('Module definitions file should be str')
        # With MSVC, DLLs only export symbols that are explicitly exported,
        # so if a module defs file is specified, we use that to export symbols
        return ['/DEF:' + defsfile]

    def gen_pch_args(self, header: str, source: str, pchname: str) -> T.Tuple[str, T.List[str]]:
        objname = os.path.splitext(pchname)[0] + '.obj'
        return objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname]

    def gen_import_library_args(self, implibname: str) -> T.List[str]:
        "The name of the outputted import library"
        return ['/IMPLIB:' + implibname]

    def openmp_flags(self) -> T.List[str]:
        return ['/openmp']

    # FIXME, no idea what these should be.
    def thread_flags(self, env: 'Environment') -> T.List[str]:
        return []

    @classmethod
    def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]:
        result = []
        for i in args:
            # -mms-bitfields is specific to MinGW-GCC
            # -pthread is only valid for GCC
            if i in ('-mms-bitfields', '-pthread'):
                continue
            if i.startswith('-LIBPATH:'):
                i = '/LIBPATH:' + i[9:]
            elif i.startswith('-L'):
                i = '/LIBPATH:' + i[2:]
            # Translate GNU-style -lfoo library name to the import library
            elif i.startswith('-l'):
                name = i[2:]
                if name in cls.ignore_libs:
                    # With MSVC, these are provided by the C runtime which is
                    # linked in by default
                    continue
                else:
                    i = name + '.lib'
            elif i.startswith('-isystem'):
                # just use /I for -isystem system include path s
                if i.startswith('-isystem='):
                    i = '/I' + i[9:]
                else:
                    i = '/I' + i[8:]
            elif i.startswith('-idirafter'):
                # same as -isystem, but appends the path instead
                if i.startswith('-idirafter='):
                    i = '/I' + i[11:]
                else:
                    i = '/I' + i[10:]
            # -pthread in link flags is only used on Linux
            elif i == '-pthread':
                continue
            result.append(i)
        return result

    @classmethod
    def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
        result = []
        for arg in args:
            if arg.startswith(('/LIBPATH:', '-LIBPATH:')):
                result.append('-L' + arg[9:])
            elif arg.endswith(('.a', '.lib')) and not os.path.isabs(arg):
                result.append('-l' + arg)
            else:
                result.append(arg)
        return result

    def get_werror_args(self) -> T.List[str]:
        return ['/WX']

    def get_include_args(self, path: str, is_system: bool) -> T.List[str]:
        if path == '':
            path = '.'
        # msvc does not have a concept of system header dirs.
        return ['-I' + path]

    def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]:
        for idx, i in enumerate(parameter_list):
            if i[:2] == '-I' or i[:2] == '/I':
                parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))
            elif i[:9] == '/LIBPATH:':
                parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:]))

        return parameter_list

    # Visual Studio is special. It ignores some arguments it does not
    # understand and you can't tell it to error out on those.
    # http://stackoverflow.com/questions/15259720/how-can-i-make-the-microsoft-c-compiler-treat-unknown-flags-as-errors-rather-t
    def has_arguments(self, args: T.List[str], env: 'Environment', code, mode: str) -> T.Tuple[bool, bool]:
        warning_text = '4044' if mode == 'link' else '9002'
        if self.id == 'clang-cl' and mode != 'link':
            args = args + ['-Werror=unknown-argument']
        with self._build_wrapper(code, env, extra_args=args, mode=mode) as p:
            if p.returncode != 0:
                return False, p.cached
            return not(warning_text in p.stde or warning_text in p.stdo), p.cached

    def get_compile_debugfile_args(self, rel_obj: str, pch: bool = False) -> T.List[str]:
        pdbarr = rel_obj.split('.')[:-1]
        pdbarr += ['pdb']
        args = ['/Fd' + '.'.join(pdbarr)]
        # When generating a PDB file with PCH, all compile commands write
        # to the same PDB file. Hence, we need to serialize the PDB
        # writes using /FS since we do parallel builds. This slows down the
        # build obviously, which is why we only do this when PCH is on.
        # This was added in Visual Studio 2013 (MSVC 18.0). Before that it was
        # always on: https://msdn.microsoft.com/en-us/library/dn502518.aspx
        if pch and self.id == 'msvc' and mesonlib.version_compare(self.version, '>=18.0'):
            args = ['/FS'] + args
        return args

    def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]:
        if self.is_64:
            return vs64_instruction_set_args.get(instruction_set, None)
        if self.id == 'msvc' and self.version.split('.')[0] == '16' and instruction_set == 'avx':
            # VS documentation says that this exists and should work, but
            # it does not. The headers do not contain AVX intrinsics
            # and the can not be called.
            return None
        return vs32_instruction_set_args.get(instruction_set, None)

    def _calculate_toolset_version(self, version: int) -> T.Optional[str]:
        if version < 1310:
            return '7.0'
        elif version < 1400:
            return '7.1' # (Visual Studio 2003)
        elif version < 1500:
            return '8.0' # (Visual Studio 2005)
        elif version < 1600:
            return '9.0' # (Visual Studio 2008)
        elif version < 1700:
            return '10.0' # (Visual Studio 2010)
        elif version < 1800:
            return '11.0' # (Visual Studio 2012)
        elif version < 1900:
            return '12.0' # (Visual Studio 2013)
        elif version < 1910:
            return '14.0' # (Visual Studio 2015)
        elif version < 1920:
            return '14.1' # (Visual Studio 2017)
        elif version < 1930:
            return '14.2' # (Visual Studio 2019)
        mlog.warning('Could not find toolset for version {!r}'.format(self.version))
        return None

    def get_toolset_version(self) -> T.Optional[str]:
        if self.id == 'clang-cl':
            # I have no idea
            return '14.1'

        # See boost/config/compiler/visualc.cpp for up to date mapping
        try:
            version = int(''.join(self.version.split('.')[0:2]))
        except ValueError:
            return None
        return self._calculate_toolset_version(version)

    def get_default_include_dirs(self) -> T.List[str]:
        if 'INCLUDE' not in os.environ:
            return []
        return os.environ['INCLUDE'].split(os.pathsep)

    def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]:
        if crt_val in self.crt_args:
            return self.crt_args[crt_val]
        assert(crt_val == 'from_buildtype')
        # Match what build type flags used to do.
        if buildtype == 'plain':
            return []
        elif buildtype == 'debug':
            return self.crt_args['mdd']
        elif buildtype == 'debugoptimized':
            return self.crt_args['md']
        elif buildtype == 'release':
            return self.crt_args['md']
        elif buildtype == 'minsize':
            return self.crt_args['md']
        else:
            assert(buildtype == 'custom')
            raise mesonlib.EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".')

    def has_func_attribute(self, name: str, env: 'Environment') -> T.Tuple[bool, bool]:
        # MSVC doesn't have __attribute__ like Clang and GCC do, so just return
        # false without compiling anything
        return name in ['dllimport', 'dllexport'], False

    def get_argument_syntax(self) -> str:
        return 'msvc'

    @classmethod
    def use_linker_args(cls, linker: str) -> T.List[str]:
        return []
meson-0.53.2/mesonbuild/compilers/objc.py0000644000175000017500000000766113612313307021752 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os.path, subprocess
import typing as T

from ..mesonlib import EnvironmentException, MachineChoice

from .compilers import Compiler
from .mixins.clike import CLikeCompiler
from .mixins.gnu import GnuCompiler
from .mixins.clang import ClangCompiler

if T.TYPE_CHECKING:
    from ..envconfig import MachineInfo


class ObjCCompiler(CLikeCompiler, Compiler):

    language = 'objc'

    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrap: T.Optional[str], **kwargs):
        Compiler.__init__(self, exelist, version, for_machine, info, **kwargs)
        CLikeCompiler.__init__(self, is_cross, exe_wrap)

    @staticmethod
    def get_display_language():
        return 'Objective-C'

    def sanity_check(self, work_dir, environment):
        # TODO try to use sanity_check_impl instead of duplicated code
        source_name = os.path.join(work_dir, 'sanitycheckobjc.m')
        binary_name = os.path.join(work_dir, 'sanitycheckobjc')
        extra_flags = environment.coredata.get_external_args(self.for_machine, self.language)
        if self.is_cross:
            extra_flags += self.get_compile_only_args()
        else:
            extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language)
        with open(source_name, 'w') as ofile:
            ofile.write('#import\n'
                        'int main(void) { return 0; }\n')
        pc = subprocess.Popen(self.exelist + extra_flags + [source_name, '-o', binary_name])
        pc.wait()
        if pc.returncode != 0:
            raise EnvironmentException('ObjC compiler %s can not compile programs.' % self.name_string())
        if self.is_cross:
            # Can't check if the binaries run so we have to assume they do
            return
        pe = subprocess.Popen(binary_name)
        pe.wait()
        if pe.returncode != 0:
            raise EnvironmentException('Executables created by ObjC compiler %s are not runnable.' % self.name_string())


class GnuObjCCompiler(GnuCompiler, ObjCCompiler):
    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross, info: 'MachineInfo', exe_wrapper=None,
                 defines=None, **kwargs):
        ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross,
                              info, exe_wrapper, **kwargs)
        GnuCompiler.__init__(self, defines)
        default_warn_args = ['-Wall', '-Winvalid-pch']
        self.warn_args = {'0': [],
                          '1': default_warn_args,
                          '2': default_warn_args + ['-Wextra'],
                          '3': default_warn_args + ['-Wextra', '-Wpedantic']}


class ClangObjCCompiler(ClangCompiler, ObjCCompiler):
    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross, info: 'MachineInfo', exe_wrapper=None,
                 **kwargs):
        ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross,
                              info, exe_wrapper, **kwargs)
        ClangCompiler.__init__(self)
        default_warn_args = ['-Wall', '-Winvalid-pch']
        self.warn_args = {'0': [],
                          '1': default_warn_args,
                          '2': default_warn_args + ['-Wextra'],
                          '3': default_warn_args + ['-Wextra', '-Wpedantic']}
meson-0.53.2/mesonbuild/compilers/objcpp.py0000644000175000017500000000774313612313307022313 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os.path, subprocess
import typing as T

from ..mesonlib import EnvironmentException, MachineChoice

from .mixins.clike import CLikeCompiler
from .compilers import Compiler
from .mixins.gnu import GnuCompiler
from .mixins.clang import ClangCompiler

if T.TYPE_CHECKING:
    from ..envconfig import MachineInfo

class ObjCPPCompiler(CLikeCompiler, Compiler):

    language = 'objcpp'

    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross: bool, info: 'MachineInfo',
                 exe_wrap: T.Optional[str], **kwargs):
        Compiler.__init__(self, exelist, version, for_machine, info, **kwargs)
        CLikeCompiler.__init__(self, is_cross, exe_wrap)

    @staticmethod
    def get_display_language():
        return 'Objective-C++'

    def sanity_check(self, work_dir, environment):
        # TODO try to use sanity_check_impl instead of duplicated code
        source_name = os.path.join(work_dir, 'sanitycheckobjcpp.mm')
        binary_name = os.path.join(work_dir, 'sanitycheckobjcpp')
        extra_flags = environment.coredata.get_external_args(self.for_machine, self.language)
        if self.is_cross:
            extra_flags += self.get_compile_only_args()
        else:
            extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language)
        with open(source_name, 'w') as ofile:
            ofile.write('#import\n'
                        'class MyClass;'
                        'int main(void) { return 0; }\n')
        pc = subprocess.Popen(self.exelist + extra_flags + [source_name, '-o', binary_name])
        pc.wait()
        if pc.returncode != 0:
            raise EnvironmentException('ObjC++ compiler %s can not compile programs.' % self.name_string())
        if self.is_cross:
            # Can't check if the binaries run so we have to assume they do
            return
        pe = subprocess.Popen(binary_name)
        pe.wait()
        if pe.returncode != 0:
            raise EnvironmentException('Executables created by ObjC++ compiler %s are not runnable.' % self.name_string())


class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler):
    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross, info: 'MachineInfo', exe_wrapper=None,
                 defines=None, **kwargs):
        ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs)
        GnuCompiler.__init__(self, defines)
        default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor']
        self.warn_args = {'0': [],
                          '1': default_warn_args,
                          '2': default_warn_args + ['-Wextra'],
                          '3': default_warn_args + ['-Wextra', '-Wpedantic']}


class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler):
    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross, info: 'MachineInfo', exe_wrapper=None,
                 **kwargs):
        ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs)
        ClangCompiler.__init__(self)
        default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor']
        self.warn_args = {'0': [],
                          '1': default_warn_args,
                          '2': default_warn_args + ['-Wextra'],
                          '3': default_warn_args + ['-Wextra', '-Wpedantic']}
meson-0.53.2/mesonbuild/compilers/rust.py0000644000175000017500000001063013612313307022020 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import subprocess, os.path
import typing as T

from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe
from .compilers import Compiler, rust_buildtype_args, clike_debug_args

if T.TYPE_CHECKING:
    from ..envconfig import MachineInfo
    from ..environment import Environment  # noqa: F401

rust_optimization_args = {'0': [],
                          'g': ['-C', 'opt-level=0'],
                          '1': ['-C', 'opt-level=1'],
                          '2': ['-C', 'opt-level=2'],
                          '3': ['-C', 'opt-level=3'],
                          's': ['-C', 'opt-level=s'],
                          }

class RustCompiler(Compiler):

    # rustc doesn't invoke the compiler itself, it doesn't need a LINKER_PREFIX
    language = 'rust'

    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
        super().__init__(exelist, version, for_machine, info, **kwargs)
        self.exe_wrapper = exe_wrapper
        self.id = 'rustc'
        self.is_cross = is_cross

    def needs_static_linker(self):
        return False

    def name_string(self):
        return ' '.join(self.exelist)

    def sanity_check(self, work_dir, environment):
        source_name = os.path.join(work_dir, 'sanity.rs')
        output_name = os.path.join(work_dir, 'rusttest')
        with open(source_name, 'w') as ofile:
            ofile.write('''fn main() {
}
''')
        pc = subprocess.Popen(self.exelist + ['-o', output_name, source_name],
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              cwd=work_dir)
        stdo, stde = pc.communicate()
        stdo = stdo.decode('utf-8', errors='replace')
        stde = stde.decode('utf-8', errors='replace')
        if pc.returncode != 0:
            raise EnvironmentException('Rust compiler %s can not compile programs.\n%s\n%s' % (
                self.name_string(),
                stdo,
                stde))
        if self.is_cross:
            if self.exe_wrapper is None:
                # Can't check if the binaries run so we have to assume they do
                return
            cmdlist = self.exe_wrapper + [output_name]
        else:
            cmdlist = [output_name]
        pe = subprocess.Popen(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        pe.wait()
        if pe.returncode != 0:
            raise EnvironmentException('Executables created by Rust compiler %s are not runnable.' % self.name_string())

    def get_dependency_gen_args(self, outfile):
        return ['--dep-info', outfile]

    def get_buildtype_args(self, buildtype):
        return rust_buildtype_args[buildtype]

    def get_sysroot(self):
        cmd = self.exelist + ['--print', 'sysroot']
        p, stdo, stde = Popen_safe(cmd)
        return stdo.split('\n')[0]

    def get_debug_args(self, is_debug):
        return clike_debug_args[is_debug]

    def get_optimization_args(self, optimization_level):
        return rust_optimization_args[optimization_level]

    def compute_parameters_with_absolute_paths(self, parameter_list, build_dir):
        for idx, i in enumerate(parameter_list):
            if i[:2] == '-L':
                for j in ['dependency', 'crate', 'native', 'framework', 'all']:
                    combined_len = len(j) + 3
                    if i[:combined_len] == '-L{}='.format(j):
                        parameter_list[idx] = i[:combined_len] + os.path.normpath(os.path.join(build_dir, i[combined_len:]))
                        break

        return parameter_list

    def get_std_exe_link_args(self):
        return []

    # Rust does not have a use_linker_args because it dispatches to a gcc-like
    # C compiler for dynamic linking, as such we invoke the C compiler's
    # use_linker_args method instead.
meson-0.53.2/mesonbuild/compilers/swift.py0000644000175000017500000001027313612313307022162 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import subprocess, os.path
import typing as T

from ..mesonlib import EnvironmentException, MachineChoice

from .compilers import Compiler, swift_buildtype_args, clike_debug_args

if T.TYPE_CHECKING:
    from ..envconfig import MachineInfo

swift_optimization_args = {'0': [],
                           'g': [],
                           '1': ['-O'],
                           '2': ['-O'],
                           '3': ['-O'],
                           's': ['-O'],
                           }

class SwiftCompiler(Compiler):

    LINKER_PREFIX = ['-Xlinker']
    language = 'swift'

    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross, info: 'MachineInfo', **kwargs):
        super().__init__(exelist, version, for_machine, info, **kwargs)
        self.version = version
        self.id = 'llvm'
        self.is_cross = is_cross

    def name_string(self):
        return ' '.join(self.exelist)

    def needs_static_linker(self):
        return True

    def get_werror_args(self):
        return ['--fatal-warnings']

    def get_dependency_gen_args(self, outtarget, outfile):
        return ['-emit-dependencies']

    def depfile_for_object(self, objfile):
        return os.path.splitext(objfile)[0] + '.' + self.get_depfile_suffix()

    def get_depfile_suffix(self):
        return 'd'

    def get_output_args(self, target):
        return ['-o', target]

    def get_header_import_args(self, headername):
        return ['-import-objc-header', headername]

    def get_warn_args(self, level):
        return []

    def get_buildtype_args(self, buildtype):
        return swift_buildtype_args[buildtype]

    def get_std_exe_link_args(self):
        return ['-emit-executable']

    def get_module_args(self, modname):
        return ['-module-name', modname]

    def get_mod_gen_args(self):
        return ['-emit-module']

    def get_include_args(self, dirname):
        return ['-I' + dirname]

    def get_compile_only_args(self):
        return ['-c']

    def compute_parameters_with_absolute_paths(self, parameter_list, build_dir):
        for idx, i in enumerate(parameter_list):
            if i[:2] == '-I' or i[:2] == '-L':
                parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))

        return parameter_list

    def sanity_check(self, work_dir, environment):
        src = 'swifttest.swift'
        source_name = os.path.join(work_dir, src)
        output_name = os.path.join(work_dir, 'swifttest')
        extra_flags = environment.coredata.get_external_args(self.for_machine, self.language)
        if self.is_cross:
            extra_flags += self.get_compile_only_args()
        else:
            extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language)
        with open(source_name, 'w') as ofile:
            ofile.write('''print("Swift compilation is working.")
''')
        pc = subprocess.Popen(self.exelist + extra_flags + ['-emit-executable', '-o', output_name, src], cwd=work_dir)
        pc.wait()
        if pc.returncode != 0:
            raise EnvironmentException('Swift compiler %s can not compile programs.' % self.name_string())
        if self.is_cross:
            # Can't check if the binaries run so we have to assume they do
            return
        if subprocess.call(output_name) != 0:
            raise EnvironmentException('Executables created by Swift compiler %s are not runnable.' % self.name_string())

    def get_debug_args(self, is_debug):
        return clike_debug_args[is_debug]

    def get_optimization_args(self, optimization_level):
        return swift_optimization_args[optimization_level]
meson-0.53.2/mesonbuild/compilers/vala.py0000644000175000017500000001151513612313307021751 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os.path
import typing as T

from .. import mlog
from ..mesonlib import EnvironmentException, MachineChoice, version_compare

from .compilers import Compiler

if T.TYPE_CHECKING:
    from ..envconfig import MachineInfo

class ValaCompiler(Compiler):

    language = 'vala'

    def __init__(self, exelist, version, for_machine: MachineChoice,
                 is_cross, info: 'MachineInfo'):
        super().__init__(exelist, version, for_machine, info)
        self.version = version
        self.is_cross = is_cross
        self.id = 'valac'
        self.base_options = ['b_colorout']

    def name_string(self):
        return ' '.join(self.exelist)

    def needs_static_linker(self):
        return False # Because compiles into C.

    def get_optimization_args(self, optimization_level):
        return []

    def get_debug_args(self, is_debug):
        return ['--debug'] if is_debug else []

    def get_output_args(self, target):
        return [] # Because compiles into C.

    def get_compile_only_args(self):
        return [] # Because compiles into C.

    def get_pic_args(self):
        return []

    def get_pie_args(self):
        return []

    def get_pie_link_args(self):
        return []

    def get_always_args(self):
        return ['-C']

    def get_warn_args(self, warning_level):
        return []

    def get_no_warn_args(self):
        return ['--disable-warnings']

    def get_werror_args(self):
        return ['--fatal-warnings']

    def get_colorout_args(self, colortype):
        if version_compare(self.version, '>=0.37.1'):
            return ['--color=' + colortype]
        return []

    def compute_parameters_with_absolute_paths(self, parameter_list, build_dir):
        for idx, i in enumerate(parameter_list):
            if i[:9] == '--girdir=':
                parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:]))
            if i[:10] == '--vapidir=':
                parameter_list[idx] = i[:10] + os.path.normpath(os.path.join(build_dir, i[10:]))
            if i[:13] == '--includedir=':
                parameter_list[idx] = i[:13] + os.path.normpath(os.path.join(build_dir, i[13:]))
            if i[:14] == '--metadatadir=':
                parameter_list[idx] = i[:14] + os.path.normpath(os.path.join(build_dir, i[14:]))

        return parameter_list

    def sanity_check(self, work_dir, environment):
        code = 'class MesonSanityCheck : Object { }'
        extra_flags = environment.coredata.get_external_args(self.for_machine, self.language)
        if self.is_cross:
            extra_flags += self.get_compile_only_args()
        else:
            extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language)
        with self.cached_compile(code, environment.coredata, extra_args=extra_flags, mode='compile') as p:
            if p.returncode != 0:
                msg = 'Vala compiler {!r} can not compile programs' \
                      ''.format(self.name_string())
                raise EnvironmentException(msg)

    def get_buildtype_args(self, buildtype):
        if buildtype == 'debug' or buildtype == 'debugoptimized' or buildtype == 'minsize':
            return ['--debug']
        return []

    def find_library(self, libname, env, extra_dirs, *args):
        if extra_dirs and isinstance(extra_dirs, str):
            extra_dirs = [extra_dirs]
        # Valac always looks in the default vapi dir, so only search there if
        # no extra dirs are specified.
        if not extra_dirs:
            code = 'class MesonFindLibrary : Object { }'
            args = env.coredata.get_external_args(self.for_machine, self.language)
            vapi_args = ['--pkg', libname]
            args += vapi_args
            with self.cached_compile(code, env.coredata, extra_args=args, mode='compile') as p:
                if p.returncode == 0:
                    return vapi_args
        # Not found? Try to find the vapi file itself.
        for d in extra_dirs:
            vapi = os.path.join(d, libname + '.vapi')
            if os.path.isfile(vapi):
                return [vapi]
        mlog.debug('Searched {!r} and {!r} wasn\'t found'.format(extra_dirs, libname))
        return None

    def thread_flags(self, env):
        return []

    def thread_link_flags(self, env):
        return []
meson-0.53.2/mesonbuild/coredata.py0000644000175000017500000013051313625260316020620 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import mlog
import pickle, os, uuid
import sys
from itertools import chain
from pathlib import PurePath
from collections import OrderedDict
from .mesonlib import (
    MesonException, MachineChoice, PerMachine,
    default_libdir, default_libexecdir, default_prefix, split_args
)
from .wrap import WrapMode
import ast
import argparse
import configparser
import enum
import shlex
import typing as T

if T.TYPE_CHECKING:
    from . import dependencies
    from .compilers import Compiler  # noqa: F401
    from .environment import Environment

    OptionDictType = T.Dict[str, 'UserOption[T.Any]']

version = '0.53.2'
backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode']

default_yielding = False

# Can't bind this near the class method it seems, sadly.
_T = T.TypeVar('_T')

class UserOption(T.Generic[_T]):
    def __init__(self, description, choices, yielding):
        super().__init__()
        self.choices = choices
        self.description = description
        if yielding is None:
            yielding = default_yielding
        if not isinstance(yielding, bool):
            raise MesonException('Value of "yielding" must be a boolean.')
        self.yielding = yielding

    def printable_value(self):
        return self.value

    # Check that the input is a valid value and return the
    # "cleaned" or "native" version. For example the Boolean
    # option could take the string "true" and return True.
    def validate_value(self, value: T.Any) -> _T:
        raise RuntimeError('Derived option class did not override validate_value.')

    def set_value(self, newvalue):
        self.value = self.validate_value(newvalue)

class UserStringOption(UserOption[str]):
    def __init__(self, description, value, choices=None, yielding=None):
        super().__init__(description, choices, yielding)
        self.set_value(value)

    def validate_value(self, value):
        if not isinstance(value, str):
            raise MesonException('Value "%s" for string option is not a string.' % str(value))
        return value

class UserBooleanOption(UserOption[bool]):
    def __init__(self, description, value, yielding=None):
        super().__init__(description, [True, False], yielding)
        self.set_value(value)

    def __bool__(self) -> bool:
        return self.value

    def validate_value(self, value) -> bool:
        if isinstance(value, bool):
            return value
        if value.lower() == 'true':
            return True
        if value.lower() == 'false':
            return False
        raise MesonException('Value %s is not boolean (true or false).' % value)

class UserIntegerOption(UserOption[int]):
    def __init__(self, description, min_value, max_value, value, yielding=None):
        super().__init__(description, [True, False], yielding)
        self.min_value = min_value
        self.max_value = max_value
        self.set_value(value)
        c = []
        if min_value is not None:
            c.append('>=' + str(min_value))
        if max_value is not None:
            c.append('<=' + str(max_value))
        self.choices = ', '.join(c)

    def validate_value(self, value) -> int:
        if isinstance(value, str):
            value = self.toint(value)
        if not isinstance(value, int):
            raise MesonException('New value for integer option is not an integer.')
        if self.min_value is not None and value < self.min_value:
            raise MesonException('New value %d is less than minimum value %d.' % (value, self.min_value))
        if self.max_value is not None and value > self.max_value:
            raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value))
        return value

    def toint(self, valuestring) -> int:
        try:
            return int(valuestring)
        except ValueError:
            raise MesonException('Value string "%s" is not convertible to an integer.' % valuestring)

class UserUmaskOption(UserIntegerOption, UserOption[T.Union[str, int]]):
    def __init__(self, description, value, yielding=None):
        super().__init__(description, 0, 0o777, value, yielding)
        self.choices = ['preserve', '0000-0777']

    def printable_value(self):
        if self.value == 'preserve':
            return self.value
        return format(self.value, '04o')

    def validate_value(self, value):
        if value is None or value == 'preserve':
            return 'preserve'
        return super().validate_value(value)

    def toint(self, valuestring):
        try:
            return int(valuestring, 8)
        except ValueError as e:
            raise MesonException('Invalid mode: {}'.format(e))

class UserComboOption(UserOption[str]):
    def __init__(self, description, choices: T.List[str], value, yielding=None):
        super().__init__(description, choices, yielding)
        if not isinstance(self.choices, list):
            raise MesonException('Combo choices must be an array.')
        for i in self.choices:
            if not isinstance(i, str):
                raise MesonException('Combo choice elements must be strings.')
        self.set_value(value)

    def validate_value(self, value):
        if value not in self.choices:
            optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices])
            raise MesonException('Value "%s" for combo option is not one of the choices. Possible choices are: %s.' % (value, optionsstring))
        return value

class UserArrayOption(UserOption[T.List[str]]):
    def __init__(self, description, value, split_args=False, user_input=False, allow_dups=False, **kwargs):
        super().__init__(description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None))
        self.split_args = split_args
        self.allow_dups = allow_dups
        self.value = self.validate_value(value, user_input=user_input)

    def validate_value(self, value, user_input: bool = True) -> T.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
        # should match that of a combo
        if not user_input and isinstance(value, str) and not value.startswith('['):
            raise MesonException('Value does not define an array: ' + value)

        if isinstance(value, str):
            if value.startswith('['):
                try:
                    newvalue = ast.literal_eval(value)
                except ValueError:
                    raise MesonException('malformed option {}'.format(value))
            elif value == '':
                newvalue = []
            else:
                if self.split_args:
                    newvalue = split_args(value)
                else:
                    newvalue = [v.strip() for v in value.split(',')]
        elif isinstance(value, list):
            newvalue = value
        else:
            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. ' \
                  'This will become a hard error in the future.'
            mlog.deprecation(msg)
        for i in newvalue:
            if not isinstance(i, str):
                raise MesonException('String array element "{0}" is not a string.'.format(str(newvalue)))
        if self.choices:
            bad = [x for x in newvalue if x not in self.choices]
            if bad:
                raise MesonException('Options "{}" are not in allowed choices: "{}"'.format(
                    ', '.join(bad), ', '.join(self.choices)))
        return newvalue


class UserFeatureOption(UserComboOption):
    static_choices = ['enabled', 'disabled', 'auto']

    def __init__(self, description, value, yielding=None):
        super().__init__(description, self.static_choices, value, yielding)

    def is_enabled(self):
        return self.value == 'enabled'

    def is_disabled(self):
        return self.value == 'disabled'

    def is_auto(self):
        return self.value == 'auto'


def load_configs(filenames: T.List[str]) -> configparser.ConfigParser:
    """Load configuration files from a named subdirectory."""
    config = configparser.ConfigParser()
    config.read(filenames)
    return config


if T.TYPE_CHECKING:
    CacheKeyType = T.Tuple[T.Tuple[T.Any, ...], ...]
    SubCacheKeyType = T.Tuple[T.Any, ...]


class DependencyCacheType(enum.Enum):

    OTHER = 0
    PKG_CONFIG = 1
    CMAKE = 2

    @classmethod
    def from_type(cls, dep: 'dependencies.Dependency') -> 'DependencyCacheType':
        from . import dependencies
        # As more types gain search overrides they'll need to be added here
        if isinstance(dep, dependencies.PkgConfigDependency):
            return cls.PKG_CONFIG
        if isinstance(dep, dependencies.CMakeDependency):
            return cls.CMAKE
        return cls.OTHER


class DependencySubCache:

    def __init__(self, type_: DependencyCacheType):
        self.types = [type_]
        self.__cache = {}  # type: T.Dict[SubCacheKeyType, dependencies.Dependency]

    def __getitem__(self, key: 'SubCacheKeyType') -> 'dependencies.Dependency':
        return self.__cache[key]

    def __setitem__(self, key: 'SubCacheKeyType', value: 'dependencies.Dependency') -> None:
        self.__cache[key] = value

    def __contains__(self, key: 'SubCacheKeyType') -> bool:
        return key in self.__cache

    def values(self) -> T.Iterable['dependencies.Dependency']:
        return self.__cache.values()


class DependencyCache:

    """Class that stores a cache of dependencies.

    This class is meant to encapsulate the fact that we need multiple keys to
    successfully lookup by providing a simple get/put interface.
    """

    def __init__(self, builtins_per_machine: PerMachine[T.Dict[str, UserOption[T.Any]]], for_machine: MachineChoice):
        self.__cache = OrderedDict()  # type: T.MutableMapping[CacheKeyType, DependencySubCache]
        self.__builtins_per_machine = builtins_per_machine
        self.__for_machine = for_machine

    def __calculate_subkey(self, type_: DependencyCacheType) -> T.Tuple[T.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:
            return tuple(self.__builtins_per_machine[self.__for_machine]['cmake_prefix_path'].value)
        assert type_ is DependencyCacheType.OTHER, 'Someone forgot to update subkey calculations for a new type'
        return tuple()

    def __iter__(self) -> T.Iterator['CacheKeyType']:
        return self.keys()

    def put(self, key: 'CacheKeyType', dep: 'dependencies.Dependency') -> None:
        t = DependencyCacheType.from_type(dep)
        if key not in self.__cache:
            self.__cache[key] = DependencySubCache(t)
        subkey = self.__calculate_subkey(t)
        self.__cache[key][subkey] = dep

    def get(self, key: 'CacheKeyType') -> T.Optional['dependencies.Dependency']:
        """Get a value from the cache.

        If there is no cache entry then None will be returned.
        """
        try:
            val = self.__cache[key]
        except KeyError:
            return None

        for t in val.types:
            subkey = self.__calculate_subkey(t)
            try:
                return val[subkey]
            except KeyError:
                pass
        return None

    def values(self) -> T.Iterator['dependencies.Dependency']:
        for c in self.__cache.values():
            yield from c.values()

    def keys(self) -> T.Iterator['CacheKeyType']:
        return iter(self.__cache.keys())

    def items(self) -> T.Iterator[T.Tuple['CacheKeyType', T.List['dependencies.Dependency']]]:
        for k, v in self.__cache.items():
            vs = []
            for t in v.types:
                subkey = self.__calculate_subkey(t)
                if subkey in v:
                    vs.append(v[subkey])
            yield k, vs

    def clear(self) -> None:
        self.__cache.clear()

# Can't bind this near the class method it seems, sadly.
_V = T.TypeVar('_V')

# This class contains all data that must persist over multiple
# invocations of Meson. It is roughly the same thing as
# cmakecache.

class CoreData:

    def __init__(self, options: argparse.Namespace, scratch_dir: str):
        self.lang_guids = {
            'default': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
            'c': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
            'cpp': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942',
            'test': '3AC096D0-A1C2-E12C-1390-A8335801FDAB',
            'directory': '2150E333-8FDC-42A3-9474-1A3956D46DE8',
        }
        self.test_guid = str(uuid.uuid4()).upper()
        self.regen_guid = str(uuid.uuid4()).upper()
        self.install_guid = str(uuid.uuid4()).upper()
        self.target_guids = {}
        self.version = version
        self.init_builtins()
        self.backend_options = {} # : T.Dict[str, UserOption]
        self.user_options = {} # : T.Dict[str, UserOption]
        self.compiler_options = PerMachine({}, {})
        self.base_options = {} # : T.Dict[str, UserOption]
        self.cross_files = self.__load_config_files(options, scratch_dir, 'cross')
        self.compilers = PerMachine(OrderedDict(), OrderedDict())

        build_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD)
        host_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD)
        self.deps = PerMachine(build_cache, host_cache)  # type: PerMachine[DependencyCache]
        self.compiler_check_cache = OrderedDict()
        # Only to print a warning if it changes between Meson invocations.
        self.config_files = self.__load_config_files(options, scratch_dir, 'native')
        self.libdir_cross_fixup()

    @staticmethod
    def __load_config_files(options: argparse.Namespace, scratch_dir: str, ftype: str) -> T.List[str]:
        # Need to try and make the passed filenames absolute because when the
        # files are parsed later we'll have chdir()d.
        if ftype == 'cross':
            filenames = options.cross_file
        else:
            filenames = options.native_file

        if not filenames:
            return []

        found_invalid = []  # type: T.List[str]
        missing = []        # type: T.List[str]
        real = []           # type: T.List[str]
        for i, f in enumerate(filenames):
            f = os.path.expanduser(os.path.expandvars(f))
            if os.path.exists(f):
                if os.path.isfile(f):
                    real.append(os.path.abspath(f))
                    continue
                elif os.path.isdir(f):
                    found_invalid.append(os.path.abspath(f))
                else:
                    # in this case we've been passed some kind of pipe, copy
                    # the contents of that file into the meson private (scratch)
                    # directory so that it can be re-read when wiping/reconfiguring
                    copy = os.path.join(scratch_dir, '{}.{}.ini'.format(uuid.uuid4(), ftype))
                    with open(f, 'r') as rf:
                        with open(copy, 'w') as wf:
                            wf.write(rf.read())
                    real.append(copy)

                    # Also replace the command line argument, as the pipe
                    # probably won't exist on reconfigure
                    filenames[i] = copy
                    continue
            if sys.platform != 'win32':
                paths = [
                    os.environ.get('XDG_DATA_HOME', os.path.expanduser('~/.local/share')),
                ] + os.environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share').split(':')
                for path in paths:
                    path_to_try = os.path.join(path, 'meson', ftype, f)
                    if os.path.isfile(path_to_try):
                        real.append(path_to_try)
                        break
                else:
                    missing.append(f)
            else:
                missing.append(f)

        if missing:
            if found_invalid:
                mlog.log('Found invalid candidates for', ftype, 'file:', *found_invalid)
            mlog.log('Could not find any valid candidate for', ftype, 'files:', *missing)
            raise MesonException('Cannot find specified {} file: {}'.format(ftype, f))
        return real

    def libdir_cross_fixup(self):
        # By default set libdir to "lib" when cross compiling since
        # getting the "system default" is always wrong on multiarch
        # platforms as it gets a value like lib/x86_64-linux-gnu.
        if self.cross_files:
            self.builtins['libdir'].value = 'lib'

    def sanitize_prefix(self, prefix):
        prefix = os.path.expanduser(prefix)
        if not os.path.isabs(prefix):
            raise MesonException('prefix value {!r} must be an absolute path'
                                 ''.format(prefix))
        if prefix.endswith('/') or prefix.endswith('\\'):
            # On Windows we need to preserve the trailing slash if the
            # string is of type 'C:\' because 'C:' is not an absolute path.
            if len(prefix) == 3 and prefix[1] == ':':
                pass
            # If prefix is a single character, preserve it since it is
            # the root directory.
            elif len(prefix) == 1:
                pass
            else:
                prefix = prefix[:-1]
        return prefix

    def sanitize_dir_option_value(self, prefix, option, value):
        '''
        If the option is an installation directory option and the value is an
        absolute path, check that it resides within prefix and return the value
        as a path relative to the prefix.

        This way everyone can do f.ex, get_option('libdir') and be sure to get
        the library directory relative to prefix.
        '''
        if option.endswith('dir') and os.path.isabs(value) and \
           option not in builtin_dir_noprefix_options:
            # Value must be a subdir of the prefix
            # commonpath will always return a path in the native format, so we
            # must use pathlib.PurePath to do the same conversion before
            # comparing.
            if os.path.commonpath([value, prefix]) != str(PurePath(prefix)):
                m = 'The value of the {!r} option is {!r} which must be a ' \
                    'subdir of the prefix {!r}.\nNote that if you pass a ' \
                    'relative path, it is assumed to be a subdir of prefix.'
                raise MesonException(m.format(option, value, prefix))
            # Convert path to be relative to prefix
            skip = len(prefix) + 1
            value = value[skip:]
        return value

    def init_builtins(self):
        # Create builtin options with default values
        self.builtins = {}
        for key, opt in builtin_options.items():
            self.builtins[key] = opt.init_option(key, default_prefix())
        self.builtins_per_machine = PerMachine({}, {})
        for for_machine in iter(MachineChoice):
            for key, opt in builtin_options_per_machine.items():
                self.builtins_per_machine[for_machine][key] = opt.init_option()

    def init_backend_options(self, backend_name):
        if backend_name == 'ninja':
            self.backend_options['backend_max_links'] = \
                UserIntegerOption(
                    'Maximum number of linker processes to run or 0 for no '
                    'limit',
                    0, None, 0)
        elif backend_name.startswith('vs'):
            self.backend_options['backend_startup_project'] = \
                UserStringOption(
                    'Default project to execute in Visual Studio',
                    '')

    def get_builtin_option(self, optname):
        for opts in self._get_all_builtin_options():
            v = opts.get(optname)
            if v is None:
                continue
            if optname == 'wrap_mode':
                return WrapMode.from_string(v.value)
            return v.value
        raise RuntimeError('Tried to get unknown builtin option %s.' % optname)

    def _try_set_builtin_option(self, optname, value):
        for opts in self._get_all_builtin_options():
            opt = opts.get(optname)
            if opt is None:
                continue
            if optname == 'prefix':
                value = self.sanitize_prefix(value)
            else:
                prefix = self.builtins['prefix'].value
                value = self.sanitize_dir_option_value(prefix, optname, value)
            break
        else:
            return False
        opt.set_value(value)
        # Make sure that buildtype matches other settings.
        if optname == 'buildtype':
            self.set_others_from_buildtype(value)
        else:
            self.set_buildtype_from_others()
        return True

    def set_builtin_option(self, optname, value):
        res = self._try_set_builtin_option(optname, value)
        if not res:
            raise RuntimeError('Tried to set unknown builtin option %s.' % optname)

    def set_others_from_buildtype(self, value):
        if value == 'plain':
            opt = '0'
            debug = False
        elif value == 'debug':
            opt = '0'
            debug = True
        elif value == 'debugoptimized':
            opt = '2'
            debug = True
        elif value == 'release':
            opt = '3'
            debug = False
        elif value == 'minsize':
            opt = 's'
            debug = True
        else:
            assert(value == 'custom')
            return
        self.builtins['optimization'].set_value(opt)
        self.builtins['debug'].set_value(debug)

    def set_buildtype_from_others(self):
        opt = self.builtins['optimization'].value
        debug = self.builtins['debug'].value
        if opt == '0' and not debug:
            mode = 'plain'
        elif opt == '0' and debug:
            mode = 'debug'
        elif opt == '2' and debug:
            mode = 'debugoptimized'
        elif opt == '3' and not debug:
            mode = 'release'
        elif opt == 's' and debug:
            mode = 'minsize'
        else:
            mode = 'custom'
        self.builtins['buildtype'].set_value(mode)

    @staticmethod
    def get_prefixed_options_per_machine(
        options_per_machine # : PerMachine[T.Dict[str, _V]]]
    ) -> T.Iterable[T.Dict[str, _V]]:
        for for_machine in iter(MachineChoice):
            prefix = for_machine.get_prefix()
            yield {
                prefix + k: v
                for k, v in options_per_machine[for_machine].items()
            }

    def _get_all_nonbuiltin_options(self) -> T.Iterable[T.Dict[str, UserOption]]:
        yield self.backend_options
        yield self.user_options
        yield from self.get_prefixed_options_per_machine(self.compiler_options)
        yield self.base_options

    def _get_all_builtin_options(self) -> T.Dict[str, UserOption]:
        yield from self.get_prefixed_options_per_machine(self.builtins_per_machine)
        yield self.builtins

    def get_all_options(self) -> T.Dict[str, UserOption]:
        yield from self._get_all_nonbuiltin_options()
        yield from self._get_all_builtin_options()

    def validate_option_value(self, option_name, override_value):
        for opts in self.get_all_options():
            opt = opts.get(option_name)
            if opt is not None:
                try:
                    return opt.validate_value(override_value)
                except MesonException as e:
                    raise type(e)(('Validation failed for option %s: ' % option_name) + str(e)) \
                        .with_traceback(sys.exc_info()[2])
        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

    def get_external_link_args(self, for_machine: MachineChoice, lang):
        return self.compiler_options[for_machine][lang + '_link_args'].value

    def merge_user_options(self, options):
        for (name, value) in options.items():
            if name not in self.user_options:
                self.user_options[name] = value
            else:
                oldval = self.user_options[name]
                if type(oldval) != type(value):
                    self.user_options[name] = value

    def is_cross_build(self) -> bool:
        return len(self.cross_files) > 0

    def strip_build_option_names(self, options):
        res = {}
        for k, v in options.items():
            if k.startswith('build.'):
                k = k.split('.', 1)[1]
            res[k] = v
        return res

    def copy_build_options_from_regular_ones(self):
        assert(not self.is_cross_build())
        for k, o in self.builtins_per_machine.host.items():
            self.builtins_per_machine.build[k].set_value(o.value)
        for k, o in self.compiler_options.host.items():
            if k in self.compiler_options.build:
                self.compiler_options.build[k].set_value(o.value)

    def set_options(self, options, *, subproject='', warn_unknown=True):
        if not self.is_cross_build():
            options = self.strip_build_option_names(options)
        # Set prefix first because it's needed to sanitize other options
        if 'prefix' in options:
            prefix = self.sanitize_prefix(options['prefix'])
            self.builtins['prefix'].set_value(prefix)
            for key in builtin_dir_noprefix_options:
                if key not in options:
                    self.builtins[key].set_value(builtin_options[key].prefixed_default(key, prefix))

        unknown_options = []
        for k, v in options.items():
            if k == 'prefix':
                continue
            if self._try_set_builtin_option(k, v):
                continue
            for opts in self._get_all_nonbuiltin_options():
                tgt = opts.get(k)
                if tgt is None:
                    continue
                tgt.set_value(v)
                break
            else:
                unknown_options.append(k)
        if unknown_options and warn_unknown:
            unknown_options = ', '.join(sorted(unknown_options))
            sub = 'In subproject {}: '.format(subproject) if subproject else ''
            mlog.warning('{}Unknown options: "{}"'.format(sub, unknown_options))
        if not self.is_cross_build():
            self.copy_build_options_from_regular_ones()

    def set_default_options(self, default_options, subproject, env):
        # Set defaults first from conf files (cross or native), then
        # override them as nec as necessary.
        for k, v in env.paths.host:
            if v is not None:
                env.cmd_line_options.setdefault(k, v)

        # Set default options as if they were passed to the command line.
        # Subprojects can only define default for user options.
        from . import optinterpreter
        for k, v in default_options.items():
            if subproject:
                if optinterpreter.is_invalid_name(k, log=False):
                    continue
                k = subproject + ':' + k
            env.cmd_line_options.setdefault(k, v)

        # Create a subset of cmd_line_options, keeping only options for this
        # subproject. Also take builtin options if it's the main project.
        # Language and backend specific options will be set later when adding
        # languages and setting the backend (builtin options must be set first
        # to know which backend we'll use).
        options = {}

        # Some options default to environment variables if they are
        # unset, set those now. These will either be overwritten
        # below, or they won't. These should only be set on the first run.
        if env.first_invocation:
            p_env = os.environ.get('PKG_CONFIG_PATH')
            if p_env:
                # PKG_CONFIG_PATH may contain duplicates, which must be
                # removed, else a duplicates-in-array-option warning arises.
                pkg_config_paths = []
                for k in p_env.split(':'):
                    if k not in pkg_config_paths:
                        pkg_config_paths.append(k)
                options['pkg_config_path'] = pkg_config_paths

        for k, v in env.cmd_line_options.items():
            if subproject:
                if not k.startswith(subproject + ':'):
                    continue
            elif k not in builtin_options.keys() \
                    and 'build.' + k not in builtin_options_per_machine.keys() \
                    and k not in builtin_options_per_machine.keys():
                if ':' in k:
                    continue
                if optinterpreter.is_invalid_name(k, log=False):
                    continue
            options[k] = v

        self.set_options(options, subproject=subproject)

    def add_lang_args(self, lang: str, comp: T.Type['Compiler'],
                      for_machine: MachineChoice, env: 'Environment') -> None:
        """Add global language arguments that are needed before compiler/linker detection."""
        from .compilers import compilers

        optprefix = lang + '_'
        for k, o in compilers.get_global_options(lang, comp, env.properties[for_machine]).items():
            if not k.startswith(optprefix):
                raise MesonException('Internal error, %s has incorrect prefix.' % k)
            # prefixed compiler options affect just this machine
            opt_prefix = for_machine.get_prefix()
            if opt_prefix + k in env.cmd_line_options:
                o.set_value(env.cmd_line_options[opt_prefix + k])
            self.compiler_options[for_machine].setdefault(k, o)

    def process_new_compiler(self, lang: str, comp: T.Type['Compiler'], env: 'Environment') -> None:
        from . import compilers

        self.compilers[comp.for_machine][lang] = comp
        enabled_opts = []

        optprefix = lang + '_'
        for k, o in comp.get_options().items():
            if not k.startswith(optprefix):
                raise MesonException('Internal error, %s has incorrect prefix.' % k)
            # prefixed compiler options affect just this machine
            opt_prefix = comp.for_machine.get_prefix()
            if opt_prefix + k in env.cmd_line_options:
                o.set_value(env.cmd_line_options[opt_prefix + k])
            self.compiler_options[comp.for_machine].setdefault(k, o)

        enabled_opts = []
        for optname in comp.base_options:
            if optname in self.base_options:
                continue
            oobj = compilers.base_options[optname]
            if optname in env.cmd_line_options:
                oobj.set_value(env.cmd_line_options[optname])
                enabled_opts.append(optname)
            self.base_options[optname] = oobj
        self.emit_base_options_warnings(enabled_opts)

    def emit_base_options_warnings(self, enabled_opts: list):
        if 'b_bitcode' in enabled_opts:
            mlog.warning('Base option \'b_bitcode\' is enabled, which is incompatible with many linker options. Incompatible options such as such as \'b_asneeded\' have been disabled.')
            mlog.warning('Please see https://mesonbuild.com/Builtin-options.html#Notes_about_Apple_Bitcode_support for more details.')

class CmdLineFileParser(configparser.ConfigParser):
    def __init__(self):
        # We don't want ':' as key delimiter, otherwise it would break when
        # storing subproject options like "subproject:option=value"
        super().__init__(delimiters=['='], interpolation=None)

def get_cmd_line_file(build_dir):
    return os.path.join(build_dir, 'meson-private', 'cmd_line.txt')

def read_cmd_line_file(build_dir, options):
    filename = get_cmd_line_file(build_dir)
    if not os.path.isfile(filename):
        return

    config = CmdLineFileParser()
    config.read(filename)

    # Do a copy because config is not really a dict. options.cmd_line_options
    # overrides values from the file.
    d = dict(config['options'])
    d.update(options.cmd_line_options)
    options.cmd_line_options = d

    properties = config['properties']
    if not options.cross_file:
        options.cross_file = ast.literal_eval(properties.get('cross_file', '[]'))
    if not options.native_file:
        # This will be a string in the form: "['first', 'second', ...]", use
        # literal_eval to get it into the list of strings.
        options.native_file = ast.literal_eval(properties.get('native_file', '[]'))

def cmd_line_options_to_string(options):
    return {k: str(v) for k, v in options.cmd_line_options.items()}

def write_cmd_line_file(build_dir, options):
    filename = get_cmd_line_file(build_dir)
    config = CmdLineFileParser()

    properties = {}
    if options.cross_file:
        properties['cross_file'] = options.cross_file
    if options.native_file:
        properties['native_file'] = options.native_file

    config['options'] = cmd_line_options_to_string(options)
    config['properties'] = properties
    with open(filename, 'w') as f:
        config.write(f)

def update_cmd_line_file(build_dir, options):
    filename = get_cmd_line_file(build_dir)
    config = CmdLineFileParser()
    config.read(filename)
    config['options'].update(cmd_line_options_to_string(options))
    with open(filename, 'w') as f:
        config.write(f)

def get_cmd_line_options(build_dir, options):
    copy = argparse.Namespace(**vars(options))
    read_cmd_line_file(build_dir, copy)
    cmdline = ['-D{}={}'.format(k, v) for k, v in copy.cmd_line_options.items()]
    if options.cross_file:
        cmdline += ['--cross-file {}'.format(f) for f in options.cross_file]
    if options.native_file:
        cmdline += ['--native-file {}'.format(f) for f in options.native_file]
    return ' '.join([shlex.quote(x) for x in cmdline])

def major_versions_differ(v1, v2):
    return v1.split('.')[0:2] != v2.split('.')[0:2]

def load(build_dir):
    filename = os.path.join(build_dir, 'meson-private', 'coredata.dat')
    load_fail_msg = 'Coredata file {!r} is corrupted. Try with a fresh build tree.'.format(filename)
    try:
        with open(filename, 'rb') as f:
            obj = pickle.load(f)
    except (pickle.UnpicklingError, EOFError):
        raise MesonException(load_fail_msg)
    except AttributeError:
        raise MesonException(
            "Coredata file {!r} references functions or classes that don't "
            "exist. This probably means that it was generated with an old "
            "version of meson.".format(filename))
    if not isinstance(obj, CoreData):
        raise MesonException(load_fail_msg)
    if major_versions_differ(obj.version, version):
        raise MesonException('Build directory has been generated with Meson version %s, '
                             'which is incompatible with current version %s.\n' %
                             (obj.version, version))
    return obj

def save(obj, build_dir):
    filename = os.path.join(build_dir, 'meson-private', 'coredata.dat')
    prev_filename = filename + '.prev'
    tempfilename = filename + '~'
    if major_versions_differ(obj.version, version):
        raise MesonException('Fatal version mismatch corruption.')
    if os.path.exists(filename):
        import shutil
        shutil.copyfile(filename, prev_filename)
    with open(tempfilename, 'wb') as f:
        pickle.dump(obj, f)
        f.flush()
        os.fsync(f.fileno())
    os.replace(tempfilename, filename)
    return filename


def register_builtin_arguments(parser):
    for n, b in builtin_options.items():
        b.add_to_argparse(n, parser, '', '')
    for n, b in builtin_options_per_machine.items():
        b.add_to_argparse(n, parser, '', ' (just for host machine)')
        b.add_to_argparse(n, parser, 'build.', ' (just for build machine)')
    parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option",
                        help='Set the value of an option, can be used several times to set multiple options.')

def create_options_dict(options):
    result = {}
    for o in options:
        try:
            (key, value) = o.split('=', 1)
        except ValueError:
            raise MesonException('Option {!r} must have a value separated by equals sign.'.format(o))
        result[key] = value
    return result

def parse_cmd_line_options(args):
    args.cmd_line_options = create_options_dict(args.projectoptions)

    # Merge builtin options set with --option into the dict.
    for name in chain(
            builtin_options.keys(),
            ('build.' + k for k in builtin_options_per_machine.keys()),
            builtin_options_per_machine.keys(),
    ):
        value = getattr(args, name, None)
        if value is not None:
            if name in args.cmd_line_options:
                cmdline_name = BuiltinOption.argparse_name_to_arg(name)
                raise MesonException(
                    'Got argument {0} as both -D{0} and {1}. Pick one.'.format(name, cmdline_name))
            args.cmd_line_options[name] = value
            delattr(args, name)


_U = T.TypeVar('_U', bound=UserOption[_T])

class BuiltinOption(T.Generic[_T, _U]):

    """Class for a builtin option type.

    Currently doesn't support UserIntegerOption, or a few other cases.
    """

    def __init__(self, opt_type: T.Type[_U], description: str, default: T.Any, yielding: T.Optional[bool] = None, *,
                 choices: T.Any = None):
        self.opt_type = opt_type
        self.description = description
        self.default = default
        self.choices = choices
        self.yielding = yielding

    def init_option(self, name: str = 'prefix', prefix: str = '') -> _U:
        """Create an instance of opt_type and return it."""
        keywords = {'yielding': self.yielding, 'value': self.prefixed_default(name, prefix)}
        if self.choices:
            keywords['choices'] = self.choices
        return self.opt_type(self.description, **keywords)

    def _argparse_action(self) -> T.Optional[str]:
        if self.default is True:
            return 'store_false'
        elif self.default is False:
            return 'store_true'
        return None

    def _argparse_choices(self) -> T.Any:
        if self.opt_type is UserBooleanOption:
            return [True, False]
        elif self.opt_type is UserFeatureOption:
            return UserFeatureOption.static_choices
        return self.choices

    @staticmethod
    def argparse_name_to_arg(name: str) -> str:
        if name == 'warning_level':
            return '--warnlevel'
        else:
            return '--' + name.replace('_', '-')

    def prefixed_default(self, name: str, prefix: str = '') -> T.Any:
        if self.opt_type in [UserComboOption, UserIntegerOption]:
            return self.default
        try:
            return builtin_dir_noprefix_options[name][prefix]
        except KeyError:
            pass
        return self.default

    def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, prefix: str, help_suffix: str) -> None:
        kwargs = {}

        c = self._argparse_choices()
        b = self._argparse_action()
        h = self.description
        if not b:
            h = '{} (default: {}).'.format(h.rstrip('.'), self.prefixed_default(name))
        else:
            kwargs['action'] = b
        if c and not b:
            kwargs['choices'] = c
        kwargs['default'] = argparse.SUPPRESS
        kwargs['dest'] = prefix + name

        cmdline_name = self.argparse_name_to_arg(prefix + name)
        parser.add_argument(cmdline_name, help=h + help_suffix, **kwargs)

# Update `docs/markdown/Builtin-options.md` after changing the options below
builtin_options = OrderedDict([
    # Directories
    ('prefix',     BuiltinOption(UserStringOption, 'Installation prefix', default_prefix())),
    ('bindir',     BuiltinOption(UserStringOption, 'Executable directory', 'bin')),
    ('datadir',    BuiltinOption(UserStringOption, 'Data file directory', 'share')),
    ('includedir', BuiltinOption(UserStringOption, 'Header file directory', 'include')),
    ('infodir',    BuiltinOption(UserStringOption, 'Info page directory', 'share/info')),
    ('libdir',     BuiltinOption(UserStringOption, 'Library directory', default_libdir())),
    ('libexecdir', BuiltinOption(UserStringOption, 'Library executable directory', default_libexecdir())),
    ('localedir',  BuiltinOption(UserStringOption, 'Locale data directory', 'share/locale')),
    ('localstatedir',   BuiltinOption(UserStringOption, 'Localstate data directory', 'var')),
    ('mandir',          BuiltinOption(UserStringOption, 'Manual page directory', 'share/man')),
    ('sbindir',         BuiltinOption(UserStringOption, 'System executable directory', 'sbin')),
    ('sharedstatedir',  BuiltinOption(UserStringOption, 'Architecture-independent data directory', 'com')),
    ('sysconfdir',      BuiltinOption(UserStringOption, 'Sysconf data directory', 'etc')),
    # Core options
    ('auto_features',   BuiltinOption(UserFeatureOption, "Override value of all 'auto' features", 'auto')),
    ('backend',         BuiltinOption(UserComboOption, 'Backend to use', 'ninja', choices=backendlist)),
    ('buildtype',       BuiltinOption(UserComboOption, 'Build type to use', 'debug',
                                      choices=['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'])),
    ('debug',           BuiltinOption(UserBooleanOption, 'Debug', True)),
    ('default_library', BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'])),
    ('errorlogs',       BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)),
    ('install_umask',   BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')),
    ('layout',          BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])),
    ('optimization',    BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['0', 'g', '1', '2', '3', 's'])),
    ('stdsplit',        BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)),
    ('strip',           BuiltinOption(UserBooleanOption, 'Strip targets on install', False)),
    ('unity',           BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects'])),
    ('warning_level',   BuiltinOption(UserComboOption, 'Compiler warning level to use', '1', choices=['0', '1', '2', '3'])),
    ('werror',          BuiltinOption(UserBooleanOption, 'Treat warnings as errors', False)),
    ('wrap_mode',       BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback'])),
])

builtin_options_per_machine = OrderedDict([
    ('pkg_config_path', BuiltinOption(UserArrayOption, 'T.List of additional paths for pkg-config to search', [])),
    ('cmake_prefix_path', BuiltinOption(UserArrayOption, 'T.List of additional prefixes for cmake to search', [])),
])

# Special prefix-dependent defaults for installation directories that reside in
# a path outside of the prefix in FHS and common usage.
builtin_dir_noprefix_options = {
    'sysconfdir':     {'/usr': '/etc'},
    'localstatedir':  {'/usr': '/var',     '/usr/local': '/var/local'},
    'sharedstatedir': {'/usr': '/var/lib', '/usr/local': '/var/local/lib'},
}

forbidden_target_names = {'clean': None,
                          'clean-ctlist': None,
                          'clean-gcno': None,
                          'clean-gcda': None,
                          'coverage': None,
                          'coverage-text': None,
                          'coverage-xml': None,
                          'coverage-html': None,
                          'phony': None,
                          'PHONY': None,
                          'all': None,
                          'test': None,
                          'benchmark': None,
                          'install': None,
                          'uninstall': None,
                          'build.ninja': None,
                          'scan-build': None,
                          'reconfigure': None,
                          'dist': None,
                          'distcheck': None,
                          }
meson-0.53.2/mesonbuild/dependencies/0000755000175000017500000000000013625242354021111 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/dependencies/__init__.py0000644000175000017500000000531213612417061023216 0ustar  jpakkanejpakkane00000000000000# Copyright 2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .boost import BoostDependency
from .cuda import CudaDependency
from .hdf5 import HDF5Dependency
from .base import (  # noqa: F401
    Dependency, DependencyException, DependencyMethods, ExternalProgram, EmptyExternalProgram, NonExistingExternalProgram,
    ExternalDependency, NotFoundDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency,
    PkgConfigDependency, CMakeDependency, find_external_dependency, get_dep_identifier, packages, _packages_accept_language)
from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency
from .coarrays import CoarrayDependency
from .mpi import MPIDependency
from .scalapack import ScalapackDependency
from .misc import (BlocksDependency, NetCDFDependency, OpenMPDependency, Python3Dependency, ThreadDependency, PcapDependency, CupsDependency, LibWmfDependency, LibGCryptDependency, GpgmeDependency, ShadercDependency)
from .platform import AppleFrameworks
from .ui import GLDependency, GnuStepDependency, Qt4Dependency, Qt5Dependency, SDL2Dependency, WxDependency, VulkanDependency


packages.update({
    # From dev:
    'gtest': GTestDependency,
    'gmock': GMockDependency,
    'llvm': LLVMDependency,
    'valgrind': ValgrindDependency,

    'boost': BoostDependency,
    'cuda': CudaDependency,

    # per-file
    'coarray': CoarrayDependency,
    'hdf5': HDF5Dependency,
    'mpi': MPIDependency,
    'scalapack': ScalapackDependency,

    # From misc:
    'blocks': BlocksDependency,
    'netcdf': NetCDFDependency,
    'openmp': OpenMPDependency,
    'python3': Python3Dependency,
    'threads': ThreadDependency,
    'pcap': PcapDependency,
    'cups': CupsDependency,
    'libwmf': LibWmfDependency,
    'libgcrypt': LibGCryptDependency,
    'gpgme': GpgmeDependency,
    'shaderc': ShadercDependency,

    # From platform:
    'appleframeworks': AppleFrameworks,

    # From ui:
    'gl': GLDependency,
    'gnustep': GnuStepDependency,
    'qt4': Qt4Dependency,
    'qt5': Qt5Dependency,
    'sdl2': SDL2Dependency,
    'wxwidgets': WxDependency,
    'vulkan': VulkanDependency,
})
_packages_accept_language.update({
    'hdf5',
    'mpi',
    'netcdf',
    'openmp',
})
meson-0.53.2/mesonbuild/dependencies/base.py0000644000175000017500000031034113625260316022375 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2018 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for external dependencies.
# Custom logic for several other packages are in separate files.
import copy
import functools
import os
import re
import json
import shlex
import shutil
import stat
import textwrap
import platform
import typing as T
from enum import Enum
from pathlib import Path, PurePath

from .. import mlog
from .. import mesonlib
from ..compilers import clib_langs
from ..environment import BinaryTable, Environment, MachineInfo
from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException
from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine
from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify, stringlistify, extract_as_list, split_args
from ..mesonlib import Version, LibType

# These must be defined in this file to avoid cyclical references.
packages = {}
_packages_accept_language = set()


class DependencyException(MesonException):
    '''Exceptions raised while trying to find dependencies'''


class DependencyMethods(Enum):
    # Auto means to use whatever dependency checking mechanisms in whatever order meson thinks is best.
    AUTO = 'auto'
    PKGCONFIG = 'pkg-config'
    QMAKE = 'qmake'
    CMAKE = 'cmake'
    # Just specify the standard link arguments, assuming the operating system provides the library.
    SYSTEM = 'system'
    # This is only supported on OSX - search the frameworks directory by name.
    EXTRAFRAMEWORK = 'extraframework'
    # Detect using the sysconfig module.
    SYSCONFIG = 'sysconfig'
    # Specify using a "program"-config style tool
    CONFIG_TOOL = 'config-tool'
    # For backwards compatibility
    SDLCONFIG = 'sdlconfig'
    CUPSCONFIG = 'cups-config'
    PCAPCONFIG = 'pcap-config'
    LIBWMFCONFIG = 'libwmf-config'
    # Misc
    DUB = 'dub'


class Dependency:
    @classmethod
    def _process_method_kw(cls, kwargs):
        method = kwargs.get('method', 'auto')
        if isinstance(method, DependencyMethods):
            return method
        if method not in [e.value for e in DependencyMethods]:
            raise DependencyException('method {!r} is invalid'.format(method))
        method = DependencyMethods(method)

        # This sets per-tool config methods which are deprecated to to the new
        # generic CONFIG_TOOL value.
        if method in [DependencyMethods.SDLCONFIG, DependencyMethods.CUPSCONFIG,
                      DependencyMethods.PCAPCONFIG, DependencyMethods.LIBWMFCONFIG]:
            mlog.warning(textwrap.dedent("""\
                Configuration method {} has been deprecated in favor of
                'config-tool'. This will be removed in a future version of
                meson.""".format(method)))
            method = DependencyMethods.CONFIG_TOOL

        # Set the detection method. If the method is set to auto, use any available method.
        # If method is set to a specific string, allow only that detection method.
        if method == DependencyMethods.AUTO:
            methods = cls.get_methods()
        elif method in cls.get_methods():
            methods = [method]
        else:
            raise DependencyException(
                'Unsupported detection method: {}, allowed methods are {}'.format(
                    method.value,
                    mlog.format_list([x.value for x in [DependencyMethods.AUTO] + cls.get_methods()])))

        return methods

    @classmethod
    def _process_include_type_kw(cls, kwargs) -> str:
        if 'include_type' not in kwargs:
            return 'preserve'
        if not isinstance(kwargs['include_type'], str):
            raise DependencyException('The include_type kwarg must be a string type')
        if kwargs['include_type'] not in ['preserve', 'system', 'non-system']:
            raise DependencyException("include_type may only be one of ['preserve', 'system', 'non-system']")
        return kwargs['include_type']

    def __init__(self, type_name, kwargs):
        self.name = "null"
        self.version = None
        self.language = None # None means C-like
        self.is_found = False
        self.type_name = type_name
        self.compile_args = []
        self.link_args = []
        # Raw -L and -l arguments without manual library searching
        # If None, self.link_args will be used
        self.raw_link_args = None
        self.sources = []
        self.methods = self._process_method_kw(kwargs)
        self.include_type = self._process_include_type_kw(kwargs)
        self.ext_deps = []  # type: T.List[Dependency]

    def __repr__(self):
        s = '<{0} {1}: {2}>'
        return s.format(self.__class__.__name__, self.name, self.is_found)

    def get_compile_args(self):
        if self.include_type == 'system':
            converted = []
            for i in self.compile_args:
                if i.startswith('-I') or i.startswith('/I'):
                    converted += ['-isystem' + i[2:]]
                else:
                    converted += [i]
            return converted
        if self.include_type == 'non-system':
            converted = []
            for i in self.compile_args:
                if i.startswith('-isystem'):
                    converted += ['-I' + i[8:]]
                else:
                    converted += [i]
            return converted
        return self.compile_args

    def get_link_args(self, raw: bool = False) -> T.List[str]:
        if raw and self.raw_link_args is not None:
            return self.raw_link_args
        return self.link_args

    def found(self):
        return self.is_found

    def get_sources(self):
        """Source files that need to be added to the target.
        As an example, gtest-all.cc when using GTest."""
        return self.sources

    @staticmethod
    def get_methods():
        return [DependencyMethods.AUTO]

    def get_name(self):
        return self.name

    def get_version(self):
        if self.version:
            return self.version
        else:
            return 'unknown'

    def get_include_type(self) -> str:
        return self.include_type

    def get_exe_args(self, compiler):
        return []

    def get_pkgconfig_variable(self, variable_name, kwargs):
        raise DependencyException('{!r} is not a pkgconfig dependency'.format(self.name))

    def get_configtool_variable(self, variable_name):
        raise DependencyException('{!r} is not a config-tool dependency'.format(self.name))

    def get_partial_dependency(self, *, compile_args: bool = False,
                               link_args: bool = False, links: bool = False,
                               includes: bool = False, sources: bool = False):
        """Create a new dependency that contains part of the parent dependency.

        The following options can be inherited:
            links -- all link_with arguments
            includes -- all include_directory and -I/-isystem calls
            sources -- any source, header, or generated sources
            compile_args -- any compile args
            link_args -- any link args

        Additionally the new dependency will have the version parameter of it's
        parent (if any) and the requested values of any dependencies will be
        added as well.
        """
        raise RuntimeError('Unreachable code in partial_dependency called')

    def _add_sub_dependency(self, dep_type: T.Type['Dependency'], env: Environment,
                            kwargs: T.Dict[str, T.Any], *,
                            method: DependencyMethods = DependencyMethods.AUTO) -> None:
        """Add an internal dependency of of the given type.

        This method is intended to simplify cases of adding a dependency on
        another dependency type (such as threads). This will by default set
        the method back to auto, but the 'method' keyword argument can be
        used to overwrite this behavior.
        """
        kwargs = kwargs.copy()
        kwargs['method'] = method
        self.ext_deps.append(dep_type(env, kwargs))

    def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
                     configtool: T.Optional[str] = None, default_value: T.Optional[str] = None,
                     pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.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) -> T.Type['Dependency']:
        new_dep = copy.deepcopy(self)
        new_dep.include_type = self._process_include_type_kw({'include_type': include_type})
        return new_dep

class InternalDependency(Dependency):
    def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps):
        super().__init__('internal', {})
        self.version = version
        self.is_found = True
        self.include_directories = incdirs
        self.compile_args = compile_args
        self.link_args = link_args
        self.libraries = libraries
        self.whole_libraries = whole_libraries
        self.sources = sources
        self.ext_deps = ext_deps

    def get_pkgconfig_variable(self, variable_name, kwargs):
        raise DependencyException('Method "get_pkgconfig_variable()" is '
                                  'invalid for an internal dependency')

    def get_configtool_variable(self, variable_name):
        raise DependencyException('Method "get_configtool_variable()" is '
                                  'invalid for an internal dependency')

    def get_partial_dependency(self, *, compile_args: bool = False,
                               link_args: bool = False, links: bool = False,
                               includes: bool = False, sources: bool = False):
        final_compile_args = self.compile_args.copy() if compile_args else []
        final_link_args = self.link_args.copy() if link_args else []
        final_libraries = self.libraries.copy() if links else []
        final_whole_libraries = self.whole_libraries.copy() if links else []
        final_sources = self.sources.copy() if sources else []
        final_includes = self.include_directories.copy() if includes else []
        final_deps = [d.get_partial_dependency(
            compile_args=compile_args, link_args=link_args, links=links,
            includes=includes, sources=sources) for d in self.ext_deps]
        return InternalDependency(
            self.version, final_includes, final_compile_args,
            final_link_args, final_libraries, final_whole_libraries,
            final_sources, final_deps)

class HasNativeKwarg:
    def __init__(self, kwargs):
        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):
        Dependency.__init__(self, type_name, kwargs)
        self.env = environment
        self.name = type_name # default
        self.is_found = False
        self.language = language
        self.version_reqs = kwargs.get('version', None)
        if isinstance(self.version_reqs, str):
            self.version_reqs = [self.version_reqs]
        self.required = kwargs.get('required', True)
        self.silent = kwargs.get('silent', False)
        self.static = kwargs.get('static', False)
        if not isinstance(self.static, bool):
            raise DependencyException('Static keyword must be boolean')
        # Is this dependency to be run on the build platform?
        HasNativeKwarg.__init__(self, kwargs)
        self.clib_compiler = None
        # Set the compiler that will be used by this dependency
        # This is only used for configuration checks
        compilers = self.env.coredata.compilers[self.for_machine]
        # Set the compiler for this dependency if a language is specified,
        # else try to pick something that looks usable.
        if self.language:
            if self.language not in compilers:
                m = self.name.capitalize() + ' requires a {0} compiler, but ' \
                    '{0} is not in the list of project languages'
                raise DependencyException(m.format(self.language.capitalize()))
            self.clib_compiler = compilers[self.language]
        else:
            # Try to find a compiler that can find C libraries for
            # running compiler.find_library()
            for lang in clib_langs:
                self.clib_compiler = compilers.get(lang, None)
                if self.clib_compiler:
                    break

    def get_compiler(self):
        return self.clib_compiler

    def get_partial_dependency(self, *, compile_args: bool = False,
                               link_args: bool = False, links: bool = False,
                               includes: bool = False, sources: bool = False):
        new = copy.copy(self)
        if not compile_args:
            new.compile_args = []
        if not link_args:
            new.link_args = []
        if not sources:
            new.sources = []
        if not includes:
            new.include_directories = []
        if not sources:
            new.sources = []

        return new

    def log_details(self):
        return ''

    def log_info(self):
        return ''

    def log_tried(self):
        return ''

    # Check if dependency version meets the requirements
    def _check_version(self):
        if not self.is_found:
            return

        if self.version_reqs:
            # an unknown version can never satisfy any requirement
            if not self.version:
                found_msg = ['Dependency', mlog.bold(self.name), 'found:']
                found_msg += [mlog.red('NO'), 'unknown version, but need:',
                              self.version_reqs]
                mlog.log(*found_msg)

                if self.required:
                    m = 'Unknown version of dependency {!r}, but need {!r}.'
                    raise DependencyException(m.format(self.name, self.version_reqs))

            else:
                (self.is_found, not_found, found) = \
                    version_compare_many(self.version, self.version_reqs)
                if not self.is_found:
                    found_msg = ['Dependency', mlog.bold(self.name), 'found:']
                    found_msg += [mlog.red('NO'),
                                  'found', mlog.normal_cyan(self.version), 'but need:',
                                  mlog.bold(', '.join(["'{}'".format(e) for e in not_found]))]
                    if found:
                        found_msg += ['; matched:',
                                      ', '.join(["'{}'".format(e) for e in found])]
                    mlog.log(*found_msg)

                    if self.required:
                        m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
                        raise DependencyException(m.format(self.name, not_found, self.version))
                    return


class NotFoundDependency(Dependency):
    def __init__(self, environment):
        super().__init__('not-found', {})
        self.env = environment
        self.name = 'not-found'
        self.is_found = False

    def get_partial_dependency(self, *, compile_args: bool = False,
                               link_args: bool = False, links: bool = False,
                               includes: bool = False, sources: bool = False):
        return copy.copy(self)


class ConfigToolDependency(ExternalDependency):

    """Class representing dependencies found using a config tool."""

    tools = None
    tool_name = None
    __strip_version = re.compile(r'^[0-9][0-9.]+')

    def __init__(self, name, environment, language, kwargs):
        super().__init__('config-tool', environment, language, kwargs)
        self.name = name
        self.tools = listify(kwargs.get('tools', self.tools))

        req_version = kwargs.get('version', None)
        tool, version = self.find_config(req_version)
        self.config = tool
        self.is_found = self.report_config(version, req_version)
        if not self.is_found:
            self.config = None
            return
        self.version = version
        if getattr(self, 'finish_init', None):
            self.finish_init(self)

    def _sanitize_version(self, version):
        """Remove any non-numeric, non-point version suffixes."""
        m = self.__strip_version.match(version)
        if m:
            # Ensure that there isn't a trailing '.', such as an input like
            # `1.2.3.git-1234`
            return m.group(0).rstrip('.')
        return version

    @classmethod
    def factory(cls, name, environment, language, kwargs, tools, tool_name, finish_init=None):
        """Constructor for use in dependencies that can be found multiple ways.

        In addition to the standard constructor values, this constructor sets
        the tool_name and tools values of the instance.
        """
        # This deserves some explanation, because metaprogramming is hard.
        # This uses type() to create a dynamic subclass of ConfigToolDependency
        # with the tools and tool_name class attributes set, this class is then
        # instantiated and returned. The reduce function (method) is also
        # attached, since python's pickle module won't be able to do anything
        # with this dynamically generated class otherwise.
        def reduce(self):
            return (cls._unpickle, (), self.__dict__)
        sub = type('{}Dependency'.format(name.capitalize()), (cls, ),
                   {'tools': tools, 'tool_name': tool_name, '__reduce__': reduce, 'finish_init': staticmethod(finish_init)})

        return sub(name, environment, language, kwargs)

    @classmethod
    def _unpickle(cls):
        return cls.__new__(cls)

    def find_config(self, versions=None):
        """Helper method that searches for config tool binaries in PATH and
        returns the one that best matches the given version requirements.
        """
        if not isinstance(versions, list) and versions is not None:
            versions = listify(versions)

        tool = self.env.binaries[self.for_machine].lookup_entry(self.tool_name)
        if tool is not None:
            tools = [tool]
        else:
            if not self.env.machines.matches_build_machine(self.for_machine):
                mlog.deprecation('No entry for {0} specified in your cross file. '
                                 'Falling back to searching PATH. This may find a '
                                 'native version of {0}! This will become a hard '
                                 'error in a future version of meson'.format(self.tool_name))
            tools = [[t] for t in self.tools]

        best_match = (None, None)
        for tool in tools:
            if len(tool) == 1:
                # In some situations the command can't be directly executed.
                # For example Shell scripts need to be called through sh on
                # Windows (see issue #1423).
                potential_bin = ExternalProgram(tool[0], silent=True)
                if not potential_bin.found():
                    continue
                tool = potential_bin.get_command()
            try:
                p, out = Popen_safe(tool + ['--version'])[:2]
            except (FileNotFoundError, PermissionError):
                continue
            if p.returncode != 0:
                continue

            out = self._sanitize_version(out.strip())
            # Some tools, like pcap-config don't supply a version, but also
            # don't fail with --version, in that case just assume that there is
            # only one version and return it.
            if not out:
                return (tool, None)
            if versions:
                is_found = version_compare_many(out, versions)[0]
                # This allows returning a found version without a config tool,
                # which is useful to inform the user that you found version x,
                # but y was required.
                if not is_found:
                    tool = None
            if best_match[1]:
                if version_compare(out, '> {}'.format(best_match[1])):
                    best_match = (tool, out)
            else:
                best_match = (tool, out)

        return best_match

    def report_config(self, version, req_version):
        """Helper method to print messages about the tool."""

        found_msg = [mlog.bold(self.tool_name), 'found:']

        if self.config is None:
            found_msg.append(mlog.red('NO'))
            if version is not None and req_version is not None:
                found_msg.append('found {!r} but need {!r}'.format(version, req_version))
            elif req_version:
                found_msg.append('need {!r}'.format(req_version))
        else:
            found_msg += [mlog.green('YES'), '({})'.format(' '.join(self.config)), version]

        mlog.log(*found_msg)

        return self.config is not None

    def get_config_value(self, args, stage):
        p, out, err = Popen_safe(self.config + args)
        if p.returncode != 0:
            if self.required:
                raise DependencyException(
                    'Could not generate {} for {}.\n{}'.format(
                        stage, self.name, err))
            return []
        return split_args(out)

    @staticmethod
    def get_methods():
        return [DependencyMethods.AUTO, DependencyMethods.CONFIG_TOOL]

    def get_configtool_variable(self, variable_name):
        p, out, _ = Popen_safe(self.config + ['--{}'.format(variable_name)])
        if p.returncode != 0:
            if self.required:
                raise DependencyException(
                    'Could not get variable "{}" for dependency {}'.format(
                        variable_name, self.name))
        variable = out.strip()
        mlog.debug('Got config-tool variable {} : {}'.format(variable_name, variable))
        return variable

    def log_tried(self):
        return self.type_name

    def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
                     configtool: T.Optional[str] = None, default_value: T.Optional[str] = None,
                     pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.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
            # set required to True here to force and error, and use the
            # finally clause to ensure it's restored.
            restore = self.required
            self.required = True
            try:
                return self.get_configtool_variable(configtool)
            except DependencyException:
                pass
            finally:
                self.required = restore
        if default_value is not None:
            return default_value
        raise DependencyException('Could not get config-tool variable and no default provided for {!r}'.format(self))


class PkgConfigDependency(ExternalDependency):
    # The class's copy of the pkg-config path. Avoids having to search for it
    # multiple times in the same Meson invocation.
    class_pkgbin = PerMachine(None, None)
    # We cache all pkg-config subprocess invocations to avoid redundant calls
    pkgbin_cache = {}

    def __init__(self, name, environment, kwargs, language=None):
        super().__init__('pkgconfig', environment, language, kwargs)
        self.name = name
        self.is_libtool = False
        # Store a copy of the pkg-config path on the object itself so it is
        # stored in the pickled coredata and recovered.
        self.pkgbin = None

        # Create an iterator of options
        def search():
            # Lookup in cross or machine file.
            potential_pkgpath = environment.binaries[self.for_machine].lookup_entry('pkgconfig')
            if potential_pkgpath is not None:
                mlog.debug('Pkg-config binary for {} specified from cross file, native file, '
                           'or env var as {}'.format(self.for_machine, potential_pkgpath))
                yield ExternalProgram.from_entry('pkgconfig', potential_pkgpath)
                # We never fallback if the user-specified option is no good, so
                # stop returning options.
                return
            mlog.debug('Pkg-config binary missing from cross or native file, or env var undefined.')
            # Fallback on hard-coded defaults.
            # TODO prefix this for the cross case instead of ignoring thing.
            if environment.machines.matches_build_machine(self.for_machine):
                for potential_pkgpath in environment.default_pkgconfig:
                    mlog.debug('Trying a default pkg-config fallback at', potential_pkgpath)
                    yield ExternalProgram(potential_pkgpath, silent=True)

        # Only search for pkg-config for each machine the first time and store
        # the result in the class definition
        if PkgConfigDependency.class_pkgbin[self.for_machine] is False:
            mlog.debug('Pkg-config binary for %s is cached as not found.' % self.for_machine)
        elif PkgConfigDependency.class_pkgbin[self.for_machine] is not None:
            mlog.debug('Pkg-config binary for %s is cached.' % self.for_machine)
        else:
            assert PkgConfigDependency.class_pkgbin[self.for_machine] is None
            mlog.debug('Pkg-config binary for %s is not cached.' % self.for_machine)
            for potential_pkgbin in search():
                mlog.debug('Trying pkg-config binary {} for machine {} at {}'
                           .format(potential_pkgbin.name, self.for_machine, potential_pkgbin.command))
                version_if_ok = self.check_pkgconfig(potential_pkgbin)
                if not version_if_ok:
                    continue
                if not self.silent:
                    mlog.log('Found pkg-config:', mlog.bold(potential_pkgbin.get_path()),
                             '(%s)' % version_if_ok)
                PkgConfigDependency.class_pkgbin[self.for_machine] = potential_pkgbin
                break
            else:
                if not self.silent:
                    mlog.log('Found Pkg-config:', mlog.red('NO'))
                # Set to False instead of None to signify that we've already
                # searched for it and not found it
                PkgConfigDependency.class_pkgbin[self.for_machine] = False

        self.pkgbin = PkgConfigDependency.class_pkgbin[self.for_machine]
        if self.pkgbin is False:
            self.pkgbin = None
            msg = 'Pkg-config binary for machine %s not found. Giving up.' % self.for_machine
            if self.required:
                raise DependencyException(msg)
            else:
                mlog.debug(msg)
                return

        mlog.debug('Determining dependency {!r} with pkg-config executable '
                   '{!r}'.format(name, self.pkgbin.get_path()))
        ret, self.version, _ = self._call_pkgbin(['--modversion', name])
        if ret != 0:
            return

        self.is_found = True

        try:
            # Fetch cargs to be used while using this dependency
            self._set_cargs()
            # Fetch the libraries and library paths needed for using this
            self._set_libs()
        except DependencyException as e:
            mlog.debug("pkg-config error with '%s': %s" % (name, e))
            if self.required:
                raise
            else:
                self.compile_args = []
                self.link_args = []
                self.is_found = False
                self.reason = e

    def __repr__(self):
        s = '<{0} {1}: {2} {3}>'
        return s.format(self.__class__.__name__, self.name, self.is_found,
                        self.version_reqs)

    def _call_pkgbin_real(self, args, env):
        cmd = self.pkgbin.get_command() + args
        p, out, err = Popen_safe(cmd, env=env)
        rc, out, err = p.returncode, out.strip(), err.strip()
        call = ' '.join(cmd)
        mlog.debug("Called `{}` -> {}\n{}".format(call, rc, out))
        return rc, out, err

    def _call_pkgbin(self, args, env=None):
        # Always copy the environment since we're going to modify it
        # with pkg-config variables
        if env is None:
            env = os.environ.copy()
        else:
            env = env.copy()

        extra_paths = self.env.coredata.builtins_per_machine[self.for_machine]['pkg_config_path'].value
        sysroot = self.env.properties[self.for_machine].get_sys_root()
        if sysroot:
            env['PKG_CONFIG_SYSROOT_DIR'] = sysroot
        new_pkg_config_path = ':'.join([p for p in extra_paths])
        mlog.debug('PKG_CONFIG_PATH: ' + new_pkg_config_path)
        env['PKG_CONFIG_PATH'] = new_pkg_config_path

        fenv = frozenset(env.items())
        targs = tuple(args)
        cache = PkgConfigDependency.pkgbin_cache
        if (self.pkgbin, targs, fenv) not in cache:
            cache[(self.pkgbin, targs, fenv)] = self._call_pkgbin_real(args, env)
        return cache[(self.pkgbin, targs, fenv)]

    def _convert_mingw_paths(self, args: T.List[str]) -> T.List[str]:
        '''
        Both MSVC and native Python on Windows cannot handle MinGW-esque /c/foo
        paths so convert them to C:/foo. We cannot resolve other paths starting
        with / like /home/foo so leave them as-is so that the user gets an
        error/warning from the compiler/linker.
        '''
        if not mesonlib.is_windows():
            return args
        converted = []
        for arg in args:
            pargs = []
            # Library search path
            if arg.startswith('-L/'):
                pargs = PurePath(arg[2:]).parts
                tmpl = '-L{}:/{}'
            elif arg.startswith('-I/'):
                pargs = PurePath(arg[2:]).parts
                tmpl = '-I{}:/{}'
            # Full path to library or .la file
            elif arg.startswith('/'):
                pargs = PurePath(arg).parts
                tmpl = '{}:/{}'
            elif arg.startswith(('-L', '-I')) or (len(arg) > 2 and arg[1] == ':'):
                # clean out improper '\\ ' as comes from some Windows pkg-config files
                arg = arg.replace('\\ ', ' ')
            if len(pargs) > 1 and len(pargs[1]) == 1:
                arg = tmpl.format(pargs[1], '/'.join(pargs[2:]))
            converted.append(arg)
        return converted

    def _split_args(self, cmd):
        # pkg-config paths follow Unix conventions, even on Windows; split the
        # output using shlex.split rather than mesonlib.split_args
        return shlex.split(cmd)

    def _set_cargs(self):
        env = None
        if self.language == 'fortran':
            # gfortran doesn't appear to look in system paths for INCLUDE files,
            # so don't allow pkg-config to suppress -I flags for system paths
            env = os.environ.copy()
            env['PKG_CONFIG_ALLOW_SYSTEM_CFLAGS'] = '1'
        ret, out, err = self._call_pkgbin(['--cflags', self.name], env=env)
        if ret != 0:
            raise DependencyException('Could not generate cargs for %s:\n%s\n' %
                                      (self.name, err))
        self.compile_args = self._convert_mingw_paths(self._split_args(out))

    def _search_libs(self, out, out_raw):
        '''
        @out: PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs
        @out_raw: pkg-config --libs

        We always look for the file ourselves instead of depending on the
        compiler to find it with -lfoo or foo.lib (if possible) because:
        1. We want to be able to select static or shared
        2. We need the full path of the library to calculate RPATH values
        3. De-dup of libraries is easier when we have absolute paths

        Libraries that are provided by the toolchain or are not found by
        find_library() will be added with -L -l pairs.
        '''
        # Library paths should be safe to de-dup
        #
        # First, figure out what library paths to use. Originally, we were
        # doing this as part of the loop, but due to differences in the order
        # of -L values between pkg-config and pkgconf, we need to do that as
        # a separate step. See:
        # https://github.com/mesonbuild/meson/issues/3951
        # https://github.com/mesonbuild/meson/issues/4023
        #
        # Separate system and prefix paths, and ensure that prefix paths are
        # always searched first.
        prefix_libpaths = OrderedSet()
        # We also store this raw_link_args on the object later
        raw_link_args = self._convert_mingw_paths(self._split_args(out_raw))
        for arg in raw_link_args:
            if arg.startswith('-L') and not arg.startswith(('-L-l', '-L-L')):
                path = arg[2:]
                if not os.path.isabs(path):
                    # Resolve the path as a compiler in the build directory would
                    path = os.path.join(self.env.get_build_dir(), path)
                prefix_libpaths.add(path)
        # Library paths are not always ordered in a meaningful way
        #
        # Instead of relying on pkg-config or pkgconf to provide -L flags in a
        # specific order, we reorder library paths ourselves, according to th
        # order specified in PKG_CONFIG_PATH. See:
        # https://github.com/mesonbuild/meson/issues/4271
        #
        # Only prefix_libpaths are reordered here because there should not be
        # too many system_libpaths to cause library version issues.
        pkg_config_path = os.environ.get('PKG_CONFIG_PATH')
        if pkg_config_path:
            pkg_config_path = pkg_config_path.split(os.pathsep)
        else:
            pkg_config_path = []
        pkg_config_path = self._convert_mingw_paths(pkg_config_path)
        prefix_libpaths = sort_libpaths(prefix_libpaths, pkg_config_path)
        system_libpaths = OrderedSet()
        full_args = self._convert_mingw_paths(self._split_args(out))
        for arg in full_args:
            if arg.startswith(('-L-l', '-L-L')):
                # These are D language arguments, not library paths
                continue
            if arg.startswith('-L') and arg[2:] not in prefix_libpaths:
                system_libpaths.add(arg[2:])
        # Use this re-ordered path list for library resolution
        libpaths = list(prefix_libpaths) + list(system_libpaths)
        # Track -lfoo libraries to avoid duplicate work
        libs_found = OrderedSet()
        # Track not-found libraries to know whether to add library paths
        libs_notfound = []
        libtype = LibType.STATIC if self.static else LibType.PREFER_SHARED
        # Generate link arguments for this library
        link_args = []
        for lib in full_args:
            if lib.startswith(('-L-l', '-L-L')):
                # These are D language arguments, add them as-is
                pass
            elif lib.startswith('-L'):
                # We already handled library paths above
                continue
            elif lib.startswith('-l'):
                # Don't resolve the same -lfoo argument again
                if lib in libs_found:
                    continue
                if self.clib_compiler:
                    args = self.clib_compiler.find_library(lib[2:], self.env,
                                                           libpaths, libtype)
                # If the project only uses a non-clib language such as D, Rust,
                # C#, Python, etc, all we can do is limp along by adding the
                # arguments as-is and then adding the libpaths at the end.
                else:
                    args = None
                if args is not None:
                    libs_found.add(lib)
                    # Replace -l arg with full path to library if available
                    # else, library is either to be ignored, or is provided by
                    # the compiler, can't be resolved, and should be used as-is
                    if args:
                        if not args[0].startswith('-l'):
                            lib = args[0]
                    else:
                        continue
                else:
                    # Library wasn't found, maybe we're looking in the wrong
                    # places or the library will be provided with LDFLAGS or
                    # LIBRARY_PATH from the environment (on macOS), and many
                    # other edge cases that we can't account for.
                    #
                    # Add all -L paths and use it as -lfoo
                    if lib in libs_notfound:
                        continue
                    if self.static:
                        mlog.warning('Static library {!r} not found for dependency {!r}, may '
                                     'not be statically linked'.format(lib[2:], self.name))
                    libs_notfound.append(lib)
            elif lib.endswith(".la"):
                shared_libname = self.extract_libtool_shlib(lib)
                shared_lib = os.path.join(os.path.dirname(lib), shared_libname)
                if not os.path.exists(shared_lib):
                    shared_lib = os.path.join(os.path.dirname(lib), ".libs", shared_libname)

                if not os.path.exists(shared_lib):
                    raise DependencyException('Got a libtools specific "%s" dependencies'
                                              'but we could not compute the actual shared'
                                              'library path' % lib)
                self.is_libtool = True
                lib = shared_lib
                if lib in link_args:
                    continue
            link_args.append(lib)
        # Add all -Lbar args if we have -lfoo args in link_args
        if libs_notfound:
            # Order of -L flags doesn't matter with ld, but it might with other
            # linkers such as MSVC, so prepend them.
            link_args = ['-L' + lp for lp in prefix_libpaths] + link_args
        return link_args, raw_link_args

    def _set_libs(self):
        env = None
        libcmd = [self.name, '--libs']
        if self.static:
            libcmd.append('--static')
        # Force pkg-config to output -L fields even if they are system
        # paths so we can do manual searching with cc.find_library() later.
        env = os.environ.copy()
        env['PKG_CONFIG_ALLOW_SYSTEM_LIBS'] = '1'
        ret, out, err = self._call_pkgbin(libcmd, env=env)
        if ret != 0:
            raise DependencyException('Could not generate libs for %s:\n%s\n' %
                                      (self.name, err))
        # Also get the 'raw' output without -Lfoo system paths for adding -L
        # args with -lfoo when a library can't be found, and also in
        # gnome.generate_gir + gnome.gtkdoc which need -L -l arguments.
        ret, out_raw, err_raw = self._call_pkgbin(libcmd)
        if ret != 0:
            raise DependencyException('Could not generate libs for %s:\n\n%s' %
                                      (self.name, out_raw))
        self.link_args, self.raw_link_args = self._search_libs(out, out_raw)

    def get_pkgconfig_variable(self, variable_name, kwargs):
        options = ['--variable=' + variable_name, self.name]

        if 'define_variable' in kwargs:
            definition = kwargs.get('define_variable', [])
            if not isinstance(definition, list):
                raise DependencyException('define_variable takes a list')

            if len(definition) != 2 or not all(isinstance(i, str) for i in definition):
                raise DependencyException('define_variable must be made up of 2 strings for VARIABLENAME and VARIABLEVALUE')

            options = ['--define-variable=' + '='.join(definition)] + options

        ret, out, err = self._call_pkgbin(options)
        variable = ''
        if ret != 0:
            if self.required:
                raise DependencyException('dependency %s not found:\n%s\n' %
                                          (self.name, err))
        else:
            variable = out.strip()

            # pkg-config doesn't distinguish between empty and non-existent variables
            # use the variable list to check for variable existence
            if not variable:
                ret, out, _ = self._call_pkgbin(['--print-variables', self.name])
                if not re.search(r'^' + variable_name + r'$', out, re.MULTILINE):
                    if 'default' in kwargs:
                        variable = kwargs['default']
                    else:
                        mlog.warning("pkgconfig variable '%s' not defined for dependency %s." % (variable_name, self.name))

        mlog.debug('Got pkgconfig variable %s : %s' % (variable_name, variable))
        return variable

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG]

    def check_pkgconfig(self, pkgbin):
        if not pkgbin.found():
            mlog.log('Did not find pkg-config by name {!r}'.format(pkgbin.name))
            return None
        try:
            p, out = Popen_safe(pkgbin.get_command() + ['--version'])[0:2]
            if p.returncode != 0:
                mlog.warning('Found pkg-config {!r} but it failed when run'
                             ''.format(' '.join(pkgbin.get_command())))
                return None
        except FileNotFoundError:
            mlog.warning('We thought we found pkg-config {!r} but now it\'s not there. How odd!'
                         ''.format(' '.join(pkgbin.get_command())))
            return None
        except PermissionError:
            msg = 'Found pkg-config {!r} but didn\'t have permissions to run it.'.format(' '.join(pkgbin.get_command()))
            if not mesonlib.is_windows():
                msg += '\n\nOn Unix-like systems this is often caused by scripts that are not executable.'
            mlog.warning(msg)
            return None
        return out.strip()

    def extract_field(self, la_file, fieldname):
        with open(la_file) as f:
            for line in f:
                arr = line.strip().split('=')
                if arr[0] == fieldname:
                    return arr[1][1:-1]
        return None

    def extract_dlname_field(self, la_file):
        return self.extract_field(la_file, 'dlname')

    def extract_libdir_field(self, la_file):
        return self.extract_field(la_file, 'libdir')

    def extract_libtool_shlib(self, la_file):
        '''
        Returns the path to the shared library
        corresponding to this .la file
        '''
        dlname = self.extract_dlname_field(la_file)
        if dlname is None:
            return None

        # Darwin uses absolute paths where possible; since the libtool files never
        # contain absolute paths, use the libdir field
        if mesonlib.is_osx():
            dlbasename = os.path.basename(dlname)
            libdir = self.extract_libdir_field(la_file)
            if libdir is None:
                return dlbasename
            return os.path.join(libdir, dlbasename)
        # From the comments in extract_libtool(), older libtools had
        # a path rather than the raw dlname
        return os.path.basename(dlname)

    def log_tried(self):
        return self.type_name

    def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
                     configtool: T.Optional[str] = None, default_value: T.Optional[str] = None,
                     pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.List[str]]:
        if pkgconfig:
            kwargs = {}
            if default_value is not None:
                kwargs['default'] = default_value
            if pkgconfig_define is not None:
                kwargs['define_variable'] = pkgconfig_define
            try:
                return self.get_pkgconfig_variable(pkgconfig, kwargs)
            except DependencyException:
                pass
        if default_value is not None:
            return default_value
        raise DependencyException('Could not get pkg-config variable and no default provided for {!r}'.format(self))

class CMakeDependency(ExternalDependency):
    # The class's copy of the CMake path. Avoids having to search for it
    # multiple times in the same Meson invocation.
    class_cmakeinfo = PerMachine(None, None)
    # Version string for the minimum CMake version
    class_cmake_version = '>=3.4'
    # CMake generators to try (empty for no generator)
    class_cmake_generators = ['', 'Ninja', 'Unix Makefiles', 'Visual Studio 10 2010']
    class_working_generator = None

    def _gen_exception(self, msg):
        return DependencyException('Dependency {} not found: {}'.format(self.name, msg))

    def _main_cmake_file(self) -> str:
        return 'CMakeLists.txt'

    def _extra_cmake_opts(self) -> T.List[str]:
        return []

    def _map_module_list(self, modules: T.List[T.Tuple[str, bool]]) -> T.List[T.Tuple[str, bool]]:
        # Map the input module list to something else
        # This function will only be executed AFTER the initial CMake
        # interpreter pass has completed. Thus variables defined in the
        # CMakeLists.txt can be accessed here.
        return modules

    def _original_module_name(self, module: str) -> str:
        # Reverse the module mapping done by _map_module_list for
        # one module
        return module

    def __init__(self, name: str, environment: Environment, kwargs, language: str = None):
        # Gather a list of all languages to support
        self.language_list = []  # type: T.List[str]
        if language is None:
            compilers = None
            if kwargs.get('native', False):
                compilers = environment.coredata.compilers.build
            else:
                compilers = environment.coredata.compilers.host

            candidates = ['c', 'cpp', 'fortran', 'objc', 'objcxx']
            self.language_list += [x for x in candidates if x in compilers]
        else:
            self.language_list += [language]

        # Add additional languages if required
        if 'fortran' in self.language_list:
            self.language_list += ['c']

        # Ensure that the list is unique
        self.language_list = list(set(self.language_list))

        super().__init__('cmake', environment, language, kwargs)
        self.name = name
        self.is_libtool = False
        # Store a copy of the CMake path on the object itself so it is
        # stored in the pickled coredata and recovered.
        self.cmakebin = None
        self.cmakeinfo = None
        self.traceparser = CMakeTraceParser()

        # Where all CMake "build dirs" are located
        self.cmake_root_dir = environment.scratch_dir

        # T.List of successfully found modules
        self.found_modules = []

        self.cmakebin = CMakeExecutor(environment, CMakeDependency.class_cmake_version, self.for_machine, silent=self.silent)
        if not self.cmakebin.found():
            self.cmakebin = None
            msg = 'No CMake binary for machine %s not found. Giving up.' % self.for_machine
            if self.required:
                raise DependencyException(msg)
            mlog.debug(msg)
            return

        if CMakeDependency.class_cmakeinfo[self.for_machine] is None:
            CMakeDependency.class_cmakeinfo[self.for_machine] = self._get_cmake_info()
        self.cmakeinfo = CMakeDependency.class_cmakeinfo[self.for_machine]
        if self.cmakeinfo is None:
            raise self._gen_exception('Unable to obtain CMake system information')

        modules = [(x, True) for x in stringlistify(extract_as_list(kwargs, 'modules'))]
        modules += [(x, False) for x in stringlistify(extract_as_list(kwargs, 'optional_modules'))]
        cm_path = stringlistify(extract_as_list(kwargs, 'cmake_module_path'))
        cm_path = [x if os.path.isabs(x) else os.path.join(environment.get_source_dir(), x) for x in cm_path]
        cm_args = stringlistify(extract_as_list(kwargs, 'cmake_args'))
        if cm_path:
            cm_args.append('-DCMAKE_MODULE_PATH=' + ';'.join(cm_path))

        pref_path = self.env.coredata.builtins_per_machine[self.for_machine]['cmake_prefix_path'].value
        if 'CMAKE_PREFIX_PATH' in os.environ:
            env_pref_path = os.environ['CMAKE_PREFIX_PATH'].split(os.pathsep)
            env_pref_path = [x for x in env_pref_path if x]  # Filter out empty strings
            if not pref_path:
                pref_path = []
            pref_path += env_pref_path
        if pref_path:
            cm_args.append('-DCMAKE_PREFIX_PATH={}'.format(';'.join(pref_path)))

        if not self._preliminary_find_check(name, cm_path, pref_path, environment.machines[self.for_machine]):
            mlog.debug('Preliminary CMake check failed. Aborting.')
            return
        self._detect_dep(name, modules, cm_args)

    def __repr__(self):
        s = '<{0} {1}: {2} {3}>'
        return s.format(self.__class__.__name__, self.name, self.is_found,
                        self.version_reqs)

    def _get_cmake_info(self):
        mlog.debug("Extracting basic cmake information")
        res = {}

        # Try different CMake generators since specifying no generator may fail
        # in cygwin for some reason
        gen_list = []
        # First try the last working generator
        if CMakeDependency.class_working_generator is not None:
            gen_list += [CMakeDependency.class_working_generator]
        gen_list += CMakeDependency.class_cmake_generators

        for i in gen_list:
            mlog.debug('Try CMake generator: {}'.format(i if len(i) > 0 else 'auto'))

            # Prepare options
            cmake_opts = ['--trace-expand', '.']
            if len(i) > 0:
                cmake_opts = ['-G', i] + cmake_opts

            # Run CMake
            ret1, out1, err1 = self._call_cmake(cmake_opts, 'CMakePathInfo.txt')

            # Current generator was successful
            if ret1 == 0:
                CMakeDependency.class_working_generator = i
                break

            mlog.debug('CMake failed to gather system information for generator {} with error code {}'.format(i, ret1))
            mlog.debug('OUT:\n{}\n\n\nERR:\n{}\n\n'.format(out1, err1))

        # Check if any generator succeeded
        if ret1 != 0:
            return None

        try:
            temp_parser = CMakeTraceParser()
            temp_parser.parse(err1)
        except MesonException:
            return None

        # Extract the variables and sanity check them
        root_paths = set(temp_parser.get_cmake_var('MESON_FIND_ROOT_PATH'))
        root_paths.update(set(temp_parser.get_cmake_var('MESON_CMAKE_SYSROOT')))
        root_paths = sorted(root_paths)
        root_paths = list(filter(lambda x: os.path.isdir(x), root_paths))
        module_paths = set(temp_parser.get_cmake_var('MESON_PATHS_LIST'))
        rooted_paths = []
        for j in [Path(x) for x in root_paths]:
            for i in [Path(x) for x in module_paths]:
                rooted_paths.append(str(j / i.relative_to(i.anchor)))
        module_paths = sorted(module_paths.union(rooted_paths))
        module_paths = list(filter(lambda x: os.path.isdir(x), module_paths))
        archs = temp_parser.get_cmake_var('MESON_ARCH_LIST')

        common_paths = ['lib', 'lib32', 'lib64', 'libx32', 'share']
        for i in archs:
            common_paths += [os.path.join('lib', i)]

        res = {
            'module_paths': module_paths,
            'cmake_root': temp_parser.get_cmake_var('MESON_CMAKE_ROOT')[0],
            'archs': archs,
            'common_paths': common_paths
        }

        mlog.debug('  -- Module search paths:    {}'.format(res['module_paths']))
        mlog.debug('  -- CMake root:             {}'.format(res['cmake_root']))
        mlog.debug('  -- CMake architectures:    {}'.format(res['archs']))
        mlog.debug('  -- CMake lib search paths: {}'.format(res['common_paths']))

        return res

    @staticmethod
    @functools.lru_cache(maxsize=None)
    def _cached_listdir(path: str) -> T.Tuple[T.Tuple[str, str]]:
        try:
            return tuple((x, str(x).lower()) for x in os.listdir(path))
        except OSError:
            return ()

    @staticmethod
    @functools.lru_cache(maxsize=None)
    def _cached_isdir(path: str) -> bool:
        try:
            return os.path.isdir(path)
        except OSError:
            return False

    def _preliminary_find_check(self, name: str, module_path: T.List[str], prefix_path: T.List[str], machine: MachineInfo) -> bool:
        lname = str(name).lower()

        # Checks , /cmake, /CMake
        def find_module(path: str) -> bool:
            for i in [path, os.path.join(path, 'cmake'), os.path.join(path, 'CMake')]:
                if not self._cached_isdir(i):
                    continue

                # Check the directory case insensitve
                content = self._cached_listdir(i)
                candidates = ['Find{}.cmake', '{}Config.cmake', '{}-config.cmake']
                candidates = [x.format(name).lower() for x in candidates]
                if any([x[1] in candidates for x in content]):
                    return True
            return False

        # Search in /(lib/|lib*|share) for cmake files
        def search_lib_dirs(path: str) -> bool:
            for i in [os.path.join(path, x) for x in self.cmakeinfo['common_paths']]:
                if not self._cached_isdir(i):
                    continue

                # Check /(lib/|lib*|share)/cmake/*/
                cm_dir = os.path.join(i, 'cmake')
                if self._cached_isdir(cm_dir):
                    content = self._cached_listdir(cm_dir)
                    content = list(filter(lambda x: x[1].startswith(lname), content))
                    for k in content:
                        if find_module(os.path.join(cm_dir, k[0])):
                            return True

                # /(lib/|lib*|share)/*/
                # /(lib/|lib*|share)/*/(cmake|CMake)/
                content = self._cached_listdir(i)
                content = list(filter(lambda x: x[1].startswith(lname), content))
                for k in content:
                    if find_module(os.path.join(i, k[0])):
                        return True

            return False

        # Check the user provided and system module paths
        for i in module_path + [os.path.join(self.cmakeinfo['cmake_root'], 'Modules')]:
            if find_module(i):
                return True

        # Check the user provided prefix paths
        for i in prefix_path:
            if search_lib_dirs(i):
                return True

        # Check the system paths
        for i in self.cmakeinfo['module_paths']:
            if find_module(i):
                return True

            if search_lib_dirs(i):
                return True

            content = self._cached_listdir(i)
            content = list(filter(lambda x: x[1].startswith(lname), content))
            for k in content:
                if search_lib_dirs(os.path.join(i, k[0])):
                    return True

            # Mac framework support
            if machine.is_darwin():
                for j in ['{}.framework', '{}.app']:
                    j = j.format(lname)
                    if j in content:
                        if find_module(os.path.join(i, j[0], 'Resources')) or find_module(os.path.join(i, j[0], 'Version')):
                            return True

        # Check the environment path
        env_path = os.environ.get('{}_DIR'.format(name))
        if env_path and find_module(env_path):
            return True

        return False

    def _detect_dep(self, name: str, modules: T.List[T.Tuple[str, bool]], args: T.List[str]):
        # Detect a dependency with CMake using the '--find-package' mode
        # and the trace output (stderr)
        #
        # When the trace output is enabled CMake prints all functions with
        # parameters to stderr as they are executed. Since CMake 3.4.0
        # variables ("${VAR}") are also replaced in the trace output.
        mlog.debug('\nDetermining dependency {!r} with CMake executable '
                   '{!r}'.format(name, self.cmakebin.executable_path()))

        # Try different CMake generators since specifying no generator may fail
        # in cygwin for some reason
        gen_list = []
        # First try the last working generator
        if CMakeDependency.class_working_generator is not None:
            gen_list += [CMakeDependency.class_working_generator]
        gen_list += CMakeDependency.class_cmake_generators

        for i in gen_list:
            mlog.debug('Try CMake generator: {}'.format(i if len(i) > 0 else 'auto'))

            # Prepare options
            cmake_opts = ['--trace-expand', '-DNAME={}'.format(name), '-DARCHS={}'.format(';'.join(self.cmakeinfo['archs']))] + args + ['.']
            cmake_opts += self._extra_cmake_opts()
            if len(i) > 0:
                cmake_opts = ['-G', i] + cmake_opts

            # Run CMake
            ret1, out1, err1 = self._call_cmake(cmake_opts, self._main_cmake_file())

            # Current generator was successful
            if ret1 == 0:
                CMakeDependency.class_working_generator = i
                break

            mlog.debug('CMake failed for generator {} and package {} with error code {}'.format(i, name, ret1))
            mlog.debug('OUT:\n{}\n\n\nERR:\n{}\n\n'.format(out1, err1))

        # Check if any generator succeeded
        if ret1 != 0:
            return

        try:
            self.traceparser.parse(err1)
        except CMakeException as e:
            e = self._gen_exception(str(e))
            if self.required:
                raise
            else:
                self.compile_args = []
                self.link_args = []
                self.is_found = False
                self.reason = e
                return

        # Whether the package is found or not is always stored in PACKAGE_FOUND
        self.is_found = self.traceparser.var_to_bool('PACKAGE_FOUND')
        if not self.is_found:
            return

        # Try to detect the version
        vers_raw = self.traceparser.get_cmake_var('PACKAGE_VERSION')

        if len(vers_raw) > 0:
            self.version = vers_raw[0]
            self.version.strip('"\' ')

        # Post-process module list. Used in derived classes to modify the
        # module list (append prepend a string, etc.).
        modules = self._map_module_list(modules)
        autodetected_module_list = False

        # Try guessing a CMake target if none is provided
        if len(modules) == 0:
            for i in self.traceparser.targets:
                tg = i.lower()
                lname = name.lower()
                if '{}::{}'.format(lname, lname) == tg or lname == tg.replace('::', ''):
                    mlog.debug('Guessed CMake target \'{}\''.format(i))
                    modules = [(i, True)]
                    autodetected_module_list = True
                    break

        # Failed to guess a target --> try the old-style method
        if len(modules) == 0:
            incDirs = [x for x in self.traceparser.get_cmake_var('PACKAGE_INCLUDE_DIRS') if x]
            defs = [x for x in self.traceparser.get_cmake_var('PACKAGE_DEFINITIONS') if x]
            libs = [x for x in self.traceparser.get_cmake_var('PACKAGE_LIBRARIES') if x]

            # Try to use old style variables if no module is specified
            if len(libs) > 0:
                self.compile_args = list(map(lambda x: '-I{}'.format(x), incDirs)) + defs
                self.link_args = libs
                mlog.debug('using old-style CMake variables for dependency {}'.format(name))
                mlog.debug('Include Dirs:         {}'.format(incDirs))
                mlog.debug('Compiler Definitions: {}'.format(defs))
                mlog.debug('Libraries:            {}'.format(libs))
                return

            # Even the old-style approach failed. Nothing else we can do here
            self.is_found = False
            raise self._gen_exception('CMake: failed to guess a CMake target for {}.\n'
                                      'Try to explicitly specify one or more targets with the "modules" property.\n'
                                      'Valid targets are:\n{}'.format(name, list(self.traceparser.targets.keys())))

        # Set dependencies with CMake targets
        reg_is_lib = re.compile(r'^(-l[a-zA-Z0-9_]+|-pthread)$')
        processed_targets = []
        incDirs = []
        compileDefinitions = []
        compileOptions = []
        libraries = []
        for i, required in modules:
            if i not in self.traceparser.targets:
                if not required:
                    mlog.warning('CMake: T.Optional module', mlog.bold(self._original_module_name(i)), 'for', mlog.bold(name), 'was not found')
                    continue
                raise self._gen_exception('CMake: invalid module {} for {}.\n'
                                          'Try to explicitly specify one or more targets with the "modules" property.\n'
                                          'Valid targets are:\n{}'.format(self._original_module_name(i), name, list(self.traceparser.targets.keys())))

            targets = [i]
            if not autodetected_module_list:
                self.found_modules += [i]

            while len(targets) > 0:
                curr = targets.pop(0)

                # Skip already processed targets
                if curr in processed_targets:
                    continue

                tgt = self.traceparser.targets[curr]
                cfgs = []
                cfg = ''
                otherDeps = []
                mlog.debug(tgt)

                if 'INTERFACE_INCLUDE_DIRECTORIES' in tgt.properties:
                    incDirs += [x for x in tgt.properties['INTERFACE_INCLUDE_DIRECTORIES'] if x]

                if 'INTERFACE_COMPILE_DEFINITIONS' in tgt.properties:
                    compileDefinitions += ['-D' + re.sub('^-D', '', x) for x in tgt.properties['INTERFACE_COMPILE_DEFINITIONS'] if x]

                if 'INTERFACE_COMPILE_OPTIONS' in tgt.properties:
                    compileOptions += [x for x in tgt.properties['INTERFACE_COMPILE_OPTIONS'] if x]

                if 'IMPORTED_CONFIGURATIONS' in tgt.properties:
                    cfgs = [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x]
                    cfg = cfgs[0]

                if 'RELEASE' in cfgs:
                    cfg = 'RELEASE'

                if 'IMPORTED_IMPLIB_{}'.format(cfg) in tgt.properties:
                    libraries += [x for x in tgt.properties['IMPORTED_IMPLIB_{}'.format(cfg)] if x]
                elif 'IMPORTED_IMPLIB' in tgt.properties:
                    libraries += [x for x in tgt.properties['IMPORTED_IMPLIB'] if x]
                elif 'IMPORTED_LOCATION_{}'.format(cfg) in tgt.properties:
                    libraries += [x for x in tgt.properties['IMPORTED_LOCATION_{}'.format(cfg)] if x]
                elif 'IMPORTED_LOCATION' in tgt.properties:
                    libraries += [x for x in tgt.properties['IMPORTED_LOCATION'] if x]

                if 'INTERFACE_LINK_LIBRARIES' in tgt.properties:
                    otherDeps += [x for x in tgt.properties['INTERFACE_LINK_LIBRARIES'] if x]

                if 'IMPORTED_LINK_DEPENDENT_LIBRARIES_{}'.format(cfg) in tgt.properties:
                    otherDeps += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES_{}'.format(cfg)] if x]
                elif 'IMPORTED_LINK_DEPENDENT_LIBRARIES' in tgt.properties:
                    otherDeps += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES'] if x]

                for j in otherDeps:
                    if j in self.traceparser.targets:
                        targets += [j]
                    elif reg_is_lib.match(j) or os.path.exists(j):
                        libraries += [j]

                processed_targets += [curr]

        # Make sure all elements in the lists are unique and sorted
        incDirs = sorted(set(incDirs))
        compileDefinitions = sorted(set(compileDefinitions))
        compileOptions = sorted(set(compileOptions))
        libraries = sorted(set(libraries))

        mlog.debug('Include Dirs:         {}'.format(incDirs))
        mlog.debug('Compiler Definitions: {}'.format(compileDefinitions))
        mlog.debug('Compiler Options:     {}'.format(compileOptions))
        mlog.debug('Libraries:            {}'.format(libraries))

        self.compile_args = compileOptions + compileDefinitions + ['-I{}'.format(x) for x in incDirs]
        self.link_args = libraries

    def _setup_cmake_dir(self, cmake_file: str) -> str:
        # Setup the CMake build environment and return the "build" directory
        build_dir = Path(self.cmake_root_dir) / 'cmake_{}'.format(self.name)
        build_dir.mkdir(parents=True, exist_ok=True)

        # Insert language parameters into the CMakeLists.txt and write new CMakeLists.txt
        src_cmake = Path(__file__).parent / 'data' / cmake_file
        cmake_txt = src_cmake.read_text()

        # In general, some Fortran CMake find_package() also require C language enabled,
        # even if nothing from C is directly used. An easy Fortran example that fails
        # without C language is
        #   find_package(Threads)
        # To make this general to
        # any other language that might need this, we use a list for all
        # languages and expand in the cmake Project(... LANGUAGES ...) statement.
        from ..cmake import language_map
        cmake_language = [language_map[x] for x in self.language_list if x in language_map]
        if not cmake_language:
            cmake_language += ['NONE']

        cmake_txt = """
cmake_minimum_required(VERSION ${{CMAKE_VERSION}})
project(MesonTemp LANGUAGES {})
""".format(' '.join(cmake_language)) + cmake_txt

        cm_file = build_dir / 'CMakeLists.txt'
        cm_file.write_text(cmake_txt)
        mlog.cmd_ci_include(cm_file.absolute().as_posix())

        return str(build_dir)

    def _call_cmake(self, args, cmake_file: str, env=None):
        build_dir = self._setup_cmake_dir(cmake_file)
        return self.cmakebin.call_with_fake_build(args, build_dir, env=env)

    @staticmethod
    def get_methods():
        return [DependencyMethods.CMAKE]

    def log_tried(self):
        return self.type_name

    def log_details(self) -> str:
        modules = [self._original_module_name(x) for x in self.found_modules]
        modules = sorted(set(modules))
        if modules:
            return 'modules: ' + ', '.join(modules)
        return ''

    def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
                     configtool: T.Optional[str] = None, default_value: T.Optional[str] = None,
                     pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.List[str]]:
        if cmake:
            try:
                v = self.traceparser.vars[cmake]
            except KeyError:
                pass
            else:
                if len(v) == 1:
                    return v[0]
                elif v:
                    return v
        if default_value is not None:
            return default_value
        raise DependencyException('Could not get cmake variable and no default provided for {!r}'.format(self))

class DubDependency(ExternalDependency):
    class_dubbin = None

    def __init__(self, name, environment, kwargs):
        super().__init__('dub', environment, 'd', kwargs)
        self.name = name
        self.compiler = super().get_compiler()
        self.module_path = None

        if 'required' in kwargs:
            self.required = kwargs.get('required')

        if DubDependency.class_dubbin is None:
            self.dubbin = self._check_dub()
            DubDependency.class_dubbin = self.dubbin
        else:
            self.dubbin = DubDependency.class_dubbin

        if not self.dubbin:
            if self.required:
                raise DependencyException('DUB not found.')
            self.is_found = False
            return

        mlog.debug('Determining dependency {!r} with DUB executable '
                   '{!r}'.format(name, self.dubbin.get_path()))

        # we need to know the target architecture
        arch = self.compiler.arch

        # Ask dub for the package
        ret, res = self._call_dubbin(['describe', name, '--arch=' + arch])

        if ret != 0:
            self.is_found = False
            return

        comp = self.compiler.get_id().replace('llvm', 'ldc').replace('gcc', 'gdc')
        packages = []
        description = json.loads(res)
        for package in description['packages']:
            packages.append(package['name'])
            if package['name'] == name:
                self.is_found = True

                not_lib = True
                if 'targetType' in package:
                    if package['targetType'] in ['library', 'sourceLibrary', 'staticLibrary', 'dynamicLibrary']:
                        not_lib = False

                if not_lib:
                    mlog.error(mlog.bold(name), "found but it isn't a library")
                    self.is_found = False
                    return

                self.module_path = self._find_right_lib_path(package['path'], comp, description, True, package['targetFileName'])
                if not os.path.exists(self.module_path):
                    # check if the dependency was built for other archs
                    archs = [['x86_64'], ['x86'], ['x86', 'x86_mscoff']]
                    for a in archs:
                        description_a = copy.deepcopy(description)
                        description_a['architecture'] = a
                        arch_module_path = self._find_right_lib_path(package['path'], comp, description_a, True, package['targetFileName'])
                        if arch_module_path:
                            mlog.error(mlog.bold(name), "found but it wasn't compiled for", mlog.bold(arch))
                            self.is_found = False
                            return

                    mlog.error(mlog.bold(name), "found but it wasn't compiled with", mlog.bold(comp))
                    self.is_found = False
                    return

                self.version = package['version']
                self.pkg = package

        if self.pkg['targetFileName'].endswith('.a'):
            self.static = True

        self.compile_args = []
        for flag in self.pkg['dflags']:
            self.link_args.append(flag)
        for path in self.pkg['importPaths']:
            self.compile_args.append('-I' + os.path.join(self.pkg['path'], path))

        self.link_args = self.raw_link_args = []
        for flag in self.pkg['lflags']:
            self.link_args.append(flag)

        self.link_args.append(os.path.join(self.module_path, self.pkg['targetFileName']))

        # Handle dependencies
        libs = []

        def add_lib_args(field_name, target):
            if field_name in target['buildSettings']:
                for lib in target['buildSettings'][field_name]:
                    if lib not in libs:
                        libs.append(lib)
                        if os.name != 'nt':
                            pkgdep = PkgConfigDependency(lib, environment, {'required': 'true', 'silent': 'true'})
                            for arg in pkgdep.get_compile_args():
                                self.compile_args.append(arg)
                            for arg in pkgdep.get_link_args():
                                self.link_args.append(arg)
                            for arg in pkgdep.get_link_args(raw=True):
                                self.raw_link_args.append(arg)

        for target in description['targets']:
            if target['rootPackage'] in packages:
                add_lib_args('libs', target)
                add_lib_args('libs-{}'.format(platform.machine()), target)
                for file in target['buildSettings']['linkerFiles']:
                    lib_path = self._find_right_lib_path(file, comp, description)
                    if lib_path:
                        self.link_args.append(lib_path)
                    else:
                        self.is_found = False

    def get_compiler(self):
        return self.compiler

    def _find_right_lib_path(self, default_path, comp, description, folder_only=False, file_name=''):
        module_path = lib_file_name = ''
        if folder_only:
            module_path = default_path
            lib_file_name = file_name
        else:
            module_path = os.path.dirname(default_path)
            lib_file_name = os.path.basename(default_path)
        module_build_path = os.path.join(module_path, '.dub', 'build')

        # Get D version implemented in the compiler
        # gdc doesn't support this
        ret, res = self._call_dubbin(['--version'])

        if ret != 0:
            mlog.error('Failed to run {!r}', mlog.bold(comp))
            return

        d_ver = re.search('v[0-9].[0-9][0-9][0-9].[0-9]', res) # Ex.: v2.081.2
        if d_ver is not None:
            d_ver = d_ver.group().rsplit('.', 1)[0].replace('v', '').replace('.', '') # Fix structure. Ex.: 2081
        else:
            d_ver = '' # gdc

        if not os.path.isdir(module_build_path):
            return ''

        # Ex.: library-debug-linux.posix-x86_64-ldc_2081-EF934983A3319F8F8FF2F0E107A363BA
        build_name = '-{}-{}-{}-{}_{}'.format(description['buildType'], '.'.join(description['platform']), '.'.join(description['architecture']), comp, d_ver)
        for entry in os.listdir(module_build_path):
            if build_name in entry:
                for file in os.listdir(os.path.join(module_build_path, entry)):
                    if file == lib_file_name:
                        if folder_only:
                            return os.path.join(module_build_path, entry)
                        else:
                            return os.path.join(module_build_path, entry, lib_file_name)

        return ''

    def _call_dubbin(self, args, env=None):
        p, out = Popen_safe(self.dubbin.get_command() + args, env=env)[0:2]
        return p.returncode, out.strip()

    def _call_copmbin(self, args, env=None):
        p, out = Popen_safe(self.compiler.get_exelist() + args, env=env)[0:2]
        return p.returncode, out.strip()

    def _check_dub(self):
        dubbin = ExternalProgram('dub', silent=True)
        if dubbin.found():
            try:
                p, out = Popen_safe(dubbin.get_command() + ['--version'])[0:2]
                if p.returncode != 0:
                    mlog.warning('Found dub {!r} but couldn\'t run it'
                                 ''.format(' '.join(dubbin.get_command())))
                    # Set to False instead of None to signify that we've already
                    # searched for it and not found it
                    dubbin = False
            except (FileNotFoundError, PermissionError):
                dubbin = False
        else:
            dubbin = False
        if dubbin:
            mlog.log('Found DUB:', mlog.bold(dubbin.get_path()),
                     '(%s)' % out.strip())
        else:
            mlog.log('Found DUB:', mlog.red('NO'))
        return dubbin

    @staticmethod
    def get_methods():
        return [DependencyMethods.DUB]

class ExternalProgram:
    windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd')
    # An 'ExternalProgram' always runs on the build machine
    for_machine = MachineChoice.BUILD

    def __init__(self, name: str, command: T.Optional[T.List[str]] = None,
                 silent: bool = False, search_dir: T.Optional[str] = None,
                 extra_search_dirs: T.Optional[T.List[str]] = None):
        self.name = name
        if command is not None:
            self.command = listify(command)
        else:
            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
        # can't find any components, default to the last component of the path.
        self.path = self.command[-1]
        for i in range(len(self.command) - 1, -1, -1):
            arg = self.command[i]
            if arg is not None and os.path.isfile(arg):
                self.path = arg
                break

        if not silent:
            # 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:
                mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))

    def __repr__(self) -> str:
        r = '<{} {!r} -> {!r}>'
        return r.format(self.__class__.__name__, self.name, self.command)

    def description(self) -> str:
        '''Human friendly description of the command'''
        return ' '.join(self.command)

    @classmethod
    def from_bin_list(cls, bt: BinaryTable, name):
        command = bt.lookup_entry(name)
        if command is None:
            return NonExistingExternalProgram()
        return cls.from_entry(name, command)

    @staticmethod
    @functools.lru_cache(maxsize=None)
    def _windows_sanitize_path(path: str) -> str:
        # Ensure that we use USERPROFILE even when inside MSYS, MSYS2, Cygwin, etc.
        if 'USERPROFILE' not in os.environ:
            return path
        # Ignore executables in the WindowsApps directory which are
        # zero-sized wrappers that magically open the Windows Store to
        # install the application.
        appstore_dir = Path(os.environ['USERPROFILE']) / 'AppData' / 'Local' / 'Microsoft' / 'WindowsApps'
        paths = []
        for each in path.split(os.pathsep):
            if Path(each) != appstore_dir:
                paths.append(each)
        return os.pathsep.join(paths)

    @staticmethod
    def from_entry(name, command):
        if isinstance(command, list):
            if len(command) == 1:
                command = command[0]
        # We cannot do any searching if the command is a list, and we don't
        # need to search if the path is an absolute path.
        if isinstance(command, list) or os.path.isabs(command):
            return ExternalProgram(name, command=command, silent=True)
        assert isinstance(command, str)
        # Search for the command using the specified string!
        return ExternalProgram(command, silent=True)

    @staticmethod
    def _shebang_to_cmd(script):
        """
        Check if the file has a shebang and manually parse it to figure out
        the interpreter to use. This is useful if the script is not executable
        or if we're on Windows (which does not understand shebangs).
        """
        try:
            with open(script) as f:
                first_line = f.readline().strip()
            if first_line.startswith('#!'):
                # In a shebang, everything before the first space is assumed to
                # be the command to run and everything after the first space is
                # the single argument to pass to that command. So we must split
                # exactly once.
                commands = first_line[2:].split('#')[0].strip().split(maxsplit=1)
                if mesonlib.is_windows():
                    # Windows does not have UNIX paths so remove them,
                    # but don't remove Windows paths
                    if commands[0].startswith('/'):
                        commands[0] = commands[0].split('/')[-1]
                    if len(commands) > 0 and commands[0] == 'env':
                        commands = commands[1:]
                    # Windows does not ship python3.exe, but we know the path to it
                    if len(commands) > 0 and commands[0] == 'python3':
                        commands = mesonlib.python_command + commands[1:]
                elif mesonlib.is_haiku():
                    # Haiku does not have /usr, but a lot of scripts assume that
                    # /usr/bin/env always exists. Detect that case and run the
                    # script with the interpreter after it.
                    if commands[0] == '/usr/bin/env':
                        commands = commands[1:]
                    # We know what python3 is, we're running on it
                    if len(commands) > 0 and commands[0] == 'python3':
                        commands = mesonlib.python_command + commands[1:]
                else:
                    # Replace python3 with the actual python3 that we are using
                    if commands[0] == '/usr/bin/env' and commands[1] == 'python3':
                        commands = mesonlib.python_command + commands[2:]
                    elif commands[0].split('/')[-1] == 'python3':
                        commands = mesonlib.python_command + commands[1:]
                return commands + [script]
        except Exception as e:
            mlog.debug(e)
        mlog.debug('Unusable script {!r}'.format(script))
        return False

    def _is_executable(self, path):
        suffix = os.path.splitext(path)[-1].lower()[1:]
        execmask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
        if mesonlib.is_windows():
            if suffix in self.windows_exts:
                return True
        elif os.stat(path).st_mode & execmask:
            return not os.path.isdir(path)
        return False

    def _search_dir(self, name, search_dir):
        if search_dir is None:
            return False
        trial = os.path.join(search_dir, name)
        if os.path.exists(trial):
            if self._is_executable(trial):
                return [trial]
            # Now getting desperate. Maybe it is a script file that is
            # a) not chmodded executable, or
            # b) we are on windows so they can't be directly executed.
            return self._shebang_to_cmd(trial)
        else:
            if mesonlib.is_windows():
                for ext in self.windows_exts:
                    trial_ext = '{}.{}'.format(trial, ext)
                    if os.path.exists(trial_ext):
                        return [trial_ext]
        return False

    def _search_windows_special_cases(self, name, command):
        '''
        Lots of weird Windows quirks:
        1. PATH search for @name returns files with extensions from PATHEXT,
           but only self.windows_exts are executable without an interpreter.
        2. @name might be an absolute path to an executable, but without the
           extension. This works inside MinGW so people use it a lot.
        3. The script is specified without an extension, in which case we have
           to manually search in PATH.
        4. More special-casing for the shebang inside the script.
        '''
        if command:
            # On Windows, even if the PATH search returned a full path, we can't be
            # sure that it can be run directly if it's not a native executable.
            # For instance, interpreted scripts sometimes need to be run explicitly
            # with an interpreter if the file association is not done properly.
            name_ext = os.path.splitext(command)[1]
            if name_ext[1:].lower() in self.windows_exts:
                # Good, it can be directly executed
                return [command]
            # Try to extract the interpreter from the shebang
            commands = self._shebang_to_cmd(command)
            if commands:
                return commands
            return [None]
        # Maybe the name is an absolute path to a native Windows
        # executable, but without the extension. This is technically wrong,
        # but many people do it because it works in the MinGW shell.
        if os.path.isabs(name):
            for ext in self.windows_exts:
                command = '{}.{}'.format(name, ext)
                if os.path.exists(command):
                    return [command]
        # On Windows, interpreted scripts must have an extension otherwise they
        # cannot be found by a standard PATH search. So we do a custom search
        # where we manually search for a script with a shebang in PATH.
        search_dirs = self._windows_sanitize_path(os.environ.get('PATH', '')).split(';')
        for search_dir in search_dirs:
            commands = self._search_dir(name, search_dir)
            if commands:
                return commands
        return [None]

    def _search(self, name, search_dir):
        '''
        Search in the specified dir for the specified executable by name
        and if not found search in PATH
        '''
        commands = self._search_dir(name, search_dir)
        if commands:
            return commands
        # Do a standard search in PATH
        path = os.environ.get('PATH', None)
        if mesonlib.is_windows() and path:
            path = self._windows_sanitize_path(path)
        command = shutil.which(name, path=path)
        if mesonlib.is_windows():
            return self._search_windows_special_cases(name, command)
        # On UNIX-like platforms, shutil.which() is enough to find
        # all executables whether in PATH or with an absolute path
        return [command]

    def found(self) -> bool:
        return self.command[0] is not None

    def get_command(self):
        return self.command[:]

    def get_path(self):
        return self.path

    def get_name(self):
        return self.name


class NonExistingExternalProgram(ExternalProgram):  # lgtm [py/missing-call-to-init]
    "A program that will never exist"

    def __init__(self, name='nonexistingprogram'):
        self.name = name
        self.command = [None]
        self.path = None

    def __repr__(self):
        r = '<{} {!r} -> {!r}>'
        return r.format(self.__class__.__name__, self.name, self.command)

    def found(self):
        return False


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.
    '''

    def __init__(self):
        self.name = None
        self.command = []
        self.path = None

    def __repr__(self):
        r = '<{} {!r} -> {!r}>'
        return r.format(self.__class__.__name__, self.name, self.command)

    def found(self):
        return True


class ExternalLibrary(ExternalDependency):
    def __init__(self, name, link_args, environment, language, silent=False):
        super().__init__('library', environment, language, {})
        self.name = name
        self.language = language
        self.is_found = False
        if link_args:
            self.is_found = True
            self.link_args = link_args
        if not silent:
            if self.is_found:
                mlog.log('Library', mlog.bold(name), 'found:', mlog.green('YES'))
            else:
                mlog.log('Library', mlog.bold(name), 'found:', mlog.red('NO'))

    def get_link_args(self, language=None, **kwargs):
        '''
        External libraries detected using a compiler must only be used with
        compatible code. For instance, Vala libraries (.vapi files) cannot be
        used with C code, and not all Rust library types can be linked with
        C-like code. Note that C++ libraries *can* be linked with C code with
        a C++ linker (and vice-versa).
        '''
        # Using a vala library in a non-vala target, or a non-vala library in a vala target
        # XXX: This should be extended to other non-C linkers such as Rust
        if (self.language == 'vala' and language != 'vala') or \
           (language == 'vala' and self.language != 'vala'):
            return []
        return super().get_link_args(**kwargs)

    def get_partial_dependency(self, *, compile_args: bool = False,
                               link_args: bool = False, links: bool = False,
                               includes: bool = False, sources: bool = False):
        # External library only has link_args, so ignore the rest of the
        # interface.
        new = copy.copy(self)
        if not link_args:
            new.link_args = []
        return new


class ExtraFrameworkDependency(ExternalDependency):
    system_framework_paths = None

    def __init__(self, name, required, paths, env, lang, kwargs):
        super().__init__('extraframeworks', env, lang, kwargs)
        self.name = name
        self.required = required
        # Full path to framework directory
        self.framework_path = None
        if not self.clib_compiler:
            raise DependencyException('No C-like compilers are available')
        if self.system_framework_paths is None:
            try:
                self.system_framework_paths = self.clib_compiler.find_framework_paths(self.env)
            except MesonException as e:
                if 'non-clang' in str(e):
                    # Apple frameworks can only be found (and used) with the
                    # system compiler. It is not available so bail immediately.
                    self.is_found = False
                    return
                raise
        self.detect(name, paths)

    def detect(self, name, paths):
        if not paths:
            paths = self.system_framework_paths
        for p in paths:
            mlog.debug('Looking for framework {} in {}'.format(name, p))
            # We need to know the exact framework path because it's used by the
            # Qt5 dependency class, and for setting the include path. We also
            # want to avoid searching in an invalid framework path which wastes
            # time and can cause a false positive.
            framework_path = self._get_framework_path(p, name)
            if framework_path is None:
                continue
            # We want to prefer the specified paths (in order) over the system
            # paths since these are "extra" frameworks.
            # For example, Python2's framework is in /System/Library/Frameworks and
            # Python3's framework is in /Library/Frameworks, but both are called
            # Python.framework. We need to know for sure that the framework was
            # found in the path we expect.
            allow_system = p in self.system_framework_paths
            args = self.clib_compiler.find_framework(name, self.env, [p], allow_system)
            if args is None:
                continue
            self.link_args = args
            self.framework_path = framework_path.as_posix()
            self.compile_args = ['-F' + self.framework_path]
            # We need to also add -I includes to the framework because all
            # cross-platform projects such as OpenGL, Python, Qt, GStreamer,
            # etc do not use "framework includes":
            # https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Tasks/IncludingFrameworks.html
            incdir = self._get_framework_include_path(framework_path)
            if incdir:
                self.compile_args += ['-I' + incdir]
            self.is_found = True
            return

    def _get_framework_path(self, path, name):
        p = Path(path)
        lname = name.lower()
        for d in p.glob('*.framework/'):
            if lname == d.name.rsplit('.', 1)[0].lower():
                return d
        return None

    def _get_framework_latest_version(self, path):
        versions = []
        for each in path.glob('Versions/*'):
            # macOS filesystems are usually case-insensitive
            if each.name.lower() == 'current':
                continue
            versions.append(Version(each.name))
        if len(versions) == 0:
            # most system frameworks do not have a 'Versions' directory
            return 'Headers'
        return 'Versions/{}/Headers'.format(sorted(versions)[-1]._s)

    def _get_framework_include_path(self, path):
        # According to the spec, 'Headers' must always be a symlink to the
        # Headers directory inside the currently-selected version of the
        # framework, but sometimes frameworks are broken. Look in 'Versions'
        # for the currently-selected version or pick the latest one.
        trials = ('Headers', 'Versions/Current/Headers',
                  self._get_framework_latest_version(path))
        for each in trials:
            trial = path / each
            if trial.is_dir():
                return trial.as_posix()
        return None

    @staticmethod
    def get_methods():
        return [DependencyMethods.EXTRAFRAMEWORK]

    def log_info(self):
        return self.framework_path

    def log_tried(self):
        return 'framework'


def get_dep_identifier(name, kwargs) -> T.Tuple:
    identifier = (name, )
    for key, value in kwargs.items():
        # 'version' is irrelevant for caching; the caller must check version matches
        # 'native' is handled above with `for_machine`
        # 'required' is irrelevant for caching; the caller handles it separately
        # 'fallback' subprojects cannot be cached -- they must be initialized
        # 'default_options' is only used in fallback case
        if key in ('version', 'native', 'required', 'fallback', 'default_options'):
            continue
        # All keyword arguments are strings, ints, or lists (or lists of lists)
        if isinstance(value, list):
            value = frozenset(listify(value))
        identifier += (key, value)
    return identifier

display_name_map = {
    'boost': 'Boost',
    'cuda': 'CUDA',
    'dub': 'DUB',
    'gmock': 'GMock',
    'gtest': 'GTest',
    'hdf5': 'HDF5',
    'llvm': 'LLVM',
    'mpi': 'MPI',
    'netcdf': 'NetCDF',
    'openmp': 'OpenMP',
    'wxwidgets': 'WxWidgets',
}

def find_external_dependency(name, env, kwargs):
    assert(name)
    required = kwargs.get('required', True)
    if not isinstance(required, bool):
        raise DependencyException('Keyword "required" must be a boolean.')
    if not isinstance(kwargs.get('method', ''), str):
        raise DependencyException('Keyword "method" must be a string.')
    lname = name.lower()
    if lname not in _packages_accept_language and 'language' in kwargs:
        raise DependencyException('%s dependency does not accept "language" keyword argument' % (name, ))
    if not isinstance(kwargs.get('version', ''), (str, list)):
        raise DependencyException('Keyword "Version" must be string or list.')

    # display the dependency name with correct casing
    display_name = display_name_map.get(lname, lname)

    for_machine = MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST

    type_text = PerMachine('Build-time', 'Run-time')[for_machine] + ' dependency'

    # build a list of dependency methods to try
    candidates = _build_external_dependency_list(name, env, kwargs)

    pkg_exc = []
    pkgdep = []
    details = ''

    for c in candidates:
        # try this dependency method
        try:
            d = c()
            d._check_version()
            pkgdep.append(d)
        except DependencyException as e:
            pkg_exc.append(e)
            mlog.debug(str(e))
        else:
            pkg_exc.append(None)
            details = d.log_details()
            if details:
                details = '(' + details + ') '
            if 'language' in kwargs:
                details += 'for ' + d.language + ' '

            # if the dependency was found
            if d.found():

                info = []
                if d.version:
                    info.append(mlog.normal_cyan(d.version))

                log_info = d.log_info()
                if log_info:
                    info.append('(' + log_info + ')')

                mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.green('YES'), *info)

                return d

    # otherwise, the dependency could not be found
    tried_methods = [d.log_tried() for d in pkgdep if d.log_tried()]
    if tried_methods:
        tried = '{}'.format(mlog.format_list(tried_methods))
    else:
        tried = ''

    mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.red('NO'),
             '(tried {})'.format(tried) if tried else '')

    if required:
        # if an exception occurred with the first detection method, re-raise it
        # (on the grounds that it came from the preferred dependency detection
        # method)
        if pkg_exc and pkg_exc[0]:
            raise pkg_exc[0]

        # we have a list of failed ExternalDependency objects, so we can report
        # the methods we tried to find the dependency
        raise DependencyException('Dependency "%s" not found' % (name) +
                                  (', tried %s' % (tried) if tried else ''))

    return NotFoundDependency(env)


def _build_external_dependency_list(name, env: Environment, kwargs: T.Dict[str, T.Any]) -> list:
    # First check if the method is valid
    if 'method' in kwargs and kwargs['method'] not in [e.value for e in DependencyMethods]:
        raise DependencyException('method {!r} is invalid'.format(kwargs['method']))

    # Is there a specific dependency detector for this dependency?
    lname = name.lower()
    if lname in packages:
        # Create the list of dependency object constructors using a factory
        # class method, if one exists, otherwise the list just consists of the
        # constructor
        if getattr(packages[lname], '_factory', None):
            dep = packages[lname]._factory(env, kwargs)
        else:
            dep = [functools.partial(packages[lname], env, kwargs)]
        return dep

    candidates = []

    # If it's explicitly requested, use the dub detection method (only)
    if 'dub' == kwargs.get('method', ''):
        candidates.append(functools.partial(DubDependency, name, env, kwargs))
        return candidates

    # If it's explicitly requested, use the pkgconfig detection method (only)
    if 'pkg-config' == kwargs.get('method', ''):
        candidates.append(functools.partial(PkgConfigDependency, name, env, kwargs))
        return candidates

    # If it's explicitly requested, use the CMake detection method (only)
    if 'cmake' == kwargs.get('method', ''):
        candidates.append(functools.partial(CMakeDependency, name, env, kwargs))
        return candidates

    # If it's explicitly requested, use the Extraframework detection method (only)
    if 'extraframework' == kwargs.get('method', ''):
        # On OSX, also try framework dependency detector
        if mesonlib.is_osx():
            candidates.append(functools.partial(ExtraFrameworkDependency, name,
                                                False, None, env, None, kwargs))
        return candidates

    # Otherwise, just use the pkgconfig and cmake dependency detector
    if 'auto' == kwargs.get('method', 'auto'):
        candidates.append(functools.partial(PkgConfigDependency, name, env, kwargs))

        # On OSX, also try framework dependency detector
        if mesonlib.is_osx():
            candidates.append(functools.partial(ExtraFrameworkDependency, name,
                                                False, None, env, None, kwargs))

        # Only use CMake as a last resort, since it might not work 100% (see #6113)
        candidates.append(functools.partial(CMakeDependency, name, env, kwargs))

    return candidates


def sort_libpaths(libpaths: T.List[str], refpaths: T.List[str]) -> T.List[str]:
    """Sort  according to 

    It is intended to be used to sort -L flags returned by pkg-config.
    Pkg-config returns flags in random order which cannot be relied on.
    """
    if len(refpaths) == 0:
        return list(libpaths)

    def key_func(libpath):
        common_lengths = []
        for refpath in refpaths:
            try:
                common_path = os.path.commonpath([libpath, refpath])
            except ValueError:
                common_path = ''
            common_lengths.append(len(common_path))
        max_length = max(common_lengths)
        max_index = common_lengths.index(max_length)
        reversed_max_length = len(refpaths[max_index]) - max_length
        return (max_index, reversed_max_length)
    return sorted(libpaths, key=key_func)


def strip_system_libdirs(environment, for_machine: MachineChoice, link_args):
    """Remove -L arguments.

    leaving these in will break builds where a user has a version of a library
    in the system path, and a different version not in the system path if they
    want to link against the non-system path version.
    """
    exclude = {'-L{}'.format(p) for p in environment.get_compiler_system_dirs(for_machine)}
    return [l for l in link_args if l not in exclude]
meson-0.53.2/mesonbuild/dependencies/boost.py0000644000175000017500000005777713531533273022637 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for miscellaneous external dependencies.

import glob
import os

from .. import mlog
from .. import mesonlib
from ..environment import detect_cpu_family

from .base import (DependencyException, ExternalDependency)
from .misc import ThreadDependency

# On windows 3 directory layouts are supported:
# * The default layout (versioned) installed:
#   - $BOOST_ROOT/include/boost-x_x/boost/*.hpp
#   - $BOOST_ROOT/lib/*.lib
# * The non-default layout (system) installed:
#   - $BOOST_ROOT/include/boost/*.hpp
#   - $BOOST_ROOT/lib/*.lib
# * The pre-built binaries from sf.net:
#   - $BOOST_ROOT/boost/*.hpp
#   - $BOOST_ROOT/lib-/*.lib where arch=32/64 and compiler=msvc-14.1
#
# Note that we should also try to support:
# mingw-w64 / Windows : libboost_-mt.a            (location = /mingw64/lib/)
#                       libboost_-mt.dll.a
#
# Library names supported:
#   - libboost_--mt-gd-x_x.lib (static)
#   - boost_--mt-gd-x_x.lib|.dll (shared)
#   - libboost_.lib (static)
#   - boost_.lib|.dll (shared)
#   where compiler is vc141 for example.
#
# NOTE: -gd means runtime and build time debugging is on
#       -mt means threading=multi
#
# The `modules` argument accept library names. This is because every module that
# has libraries to link against also has multiple options regarding how to
# link. See for example:
# * http://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/boost_test/usage_variants.html
# * http://www.boost.org/doc/libs/1_65_1/doc/html/stacktrace/configuration_and_build.html
# * http://www.boost.org/doc/libs/1_65_1/libs/math/doc/html/math_toolkit/main_tr1.html

# **On Unix**, official packaged versions of boost libraries follow the following schemes:
#
# Linux / Debian:   libboost_.so -> libboost_.so.1.66.0
# Linux / Red Hat:  libboost_.so -> libboost_.so.1.66.0
# Linux / OpenSuse: libboost_.so -> libboost_.so.1.66.0
# Win   / Cygwin:   libboost_.dll.a                                 (location = /usr/lib)
#                   libboost_.a
#                   cygboost__1_64.dll                              (location = /usr/bin)
# Win   / VS:       boost_-vc-mt[-gd]--1_67.dll          (location = C:/local/boost_1_67_0)
# Mac   / homebrew: libboost_.dylib + libboost_-mt.dylib    (location = /usr/local/lib)
# Mac   / macports: libboost_.dylib + libboost_-mt.dylib    (location = /opt/local/lib)
#
# Its not clear that any other abi tags (e.g. -gd) are used in official packages.
#
# On Linux systems, boost libs have multithreading support enabled, but without the -mt tag.
#
# Boost documentation recommends using complex abi tags like "-lboost_regex-gcc34-mt-d-1_36".
# (See http://www.boost.org/doc/libs/1_66_0/more/getting_started/unix-variants.html#library-naming)
# However, its not clear that any Unix distribution follows this scheme.
# Furthermore, the boost documentation for unix above uses examples from windows like
#   "libboost_regex-vc71-mt-d-x86-1_34.lib", so apparently the abi tags may be more aimed at windows.
#
# Probably we should use the linker search path to decide which libraries to use.  This will
# make it possible to find the macports boost libraries without setting BOOST_ROOT, and will
# also mean that it would be possible to use user-installed boost libraries when official
# packages are installed.
#
# We thus follow the following strategy:
# 1. Look for libraries using compiler.find_library( )
#   1.1 On Linux, just look for boost_
#   1.2 On other systems (e.g. Mac) look for boost_-mt if multithreading.
#   1.3 Otherwise look for boost_
# 2. Fall back to previous approach
#   2.1. Search particular directories.
#   2.2. Find boost libraries with unknown suffixes using file-name globbing.

# TODO: Unix: Don't assume we know where the boost dir is, rely on -Idir and -Ldir being set.
# TODO: Allow user to specify suffix in BOOST_SUFFIX, or add specific options like BOOST_DEBUG for 'd' for debug.

class BoostDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('boost', environment, 'cpp', kwargs)
        self.need_static_link = ['boost_exception', 'boost_test_exec_monitor']
        self.is_debug = environment.coredata.get_builtin_option('buildtype').startswith('debug')
        threading = kwargs.get("threading", "multi")
        self.is_multithreading = threading == "multi"

        self.requested_modules = self.get_requested(kwargs)
        if 'thread' in self.requested_modules:
            self._add_sub_dependency(ThreadDependency, environment, kwargs)

        self.boost_root = None
        self.boost_roots = []
        self.incdir = None
        self.libdir = None

        if 'BOOST_ROOT' in os.environ:
            self.boost_root = os.environ['BOOST_ROOT']
            self.boost_roots = [self.boost_root]
            if not os.path.isabs(self.boost_root):
                raise DependencyException('BOOST_ROOT must be an absolute path.')
        if 'BOOST_INCLUDEDIR' in os.environ:
            self.incdir = os.environ['BOOST_INCLUDEDIR']
        if 'BOOST_LIBRARYDIR' in os.environ:
            self.libdir = os.environ['BOOST_LIBRARYDIR']

        if self.boost_root is None:
            if self.env.machines[self.for_machine].is_windows():
                self.boost_roots = self.detect_win_roots()
            else:
                self.boost_roots = self.detect_nix_roots()

        if self.incdir is None:
            if self.env.machines[self.for_machine].is_windows():
                self.incdir = self.detect_win_incdir()
            else:
                self.incdir = self.detect_nix_incdir()

        mlog.debug('Boost library root dir is', mlog.bold(self.boost_root))
        mlog.debug('Boost include directory is', mlog.bold(self.incdir))

        # 1. check if we can find BOOST headers.
        self.detect_headers_and_version()

        if not self.is_found:
            return # if we can not find 'boost/version.hpp'

        # 2. check if we can find BOOST libraries.
        self.detect_lib_modules()
        mlog.debug('Boost library directory is', mlog.bold(self.libdir))

        mlog.debug('Installed Boost libraries: ')
        for key in sorted(self.lib_modules.keys()):
            mlog.debug(key, self.lib_modules[key])

        # 3. check if requested modules are valid, that is, either found or in the list of known boost libraries
        self.check_invalid_modules()

        # 4. final check whether or not we find all requested and valid modules
        self.check_find_requested_modules()

    def check_invalid_modules(self):
        invalid_modules = [c for c in self.requested_modules if 'boost_' + c not in self.lib_modules and 'boost_' + c not in BOOST_LIBS]

        # previous versions of meson allowed include dirs as modules
        remove = []
        for m in invalid_modules:
            if m in BOOST_DIRS:
                mlog.warning('Requested boost library', mlog.bold(m), 'that doesn\'t exist. '
                             'This will be an error in the future')
                remove.append(m)

        self.requested_modules = [x for x in self.requested_modules if x not in remove]
        invalid_modules = [x for x in invalid_modules if x not in remove]

        if invalid_modules:
            mlog.error('Invalid Boost modules: ' + ', '.join(invalid_modules))
            return True
        else:
            return False

    def log_details(self):
        module_str = ', '.join(self.requested_modules)
        return module_str

    def log_info(self):
        if self.boost_root:
            return self.boost_root
        return ''

    def detect_nix_roots(self):
        return [os.path.abspath(os.path.join(x, '..'))
                for x in self.clib_compiler.get_default_include_dirs()]

    def detect_win_roots(self):
        res = []
        # Where boost documentation says it should be
        globtext = 'C:\\Program Files\\boost\\boost_*'
        files = glob.glob(globtext)
        res.extend(files)

        # Where boost built from source actually installs it
        if os.path.isdir('C:\\Boost'):
            res.append('C:\\Boost')

        # Where boost prebuilt binaries are
        globtext = 'C:\\local\\boost_*'
        files = glob.glob(globtext)
        res.extend(files)
        return res

    def detect_nix_incdir(self):
        if self.boost_root:
            return os.path.join(self.boost_root, 'include')
        return None

    # FIXME: Should pick a version that matches the requested version
    # Returns the folder that contains the boost folder.
    def detect_win_incdir(self):
        for root in self.boost_roots:
            globtext = os.path.join(root, 'include', 'boost-*')
            incdirs = glob.glob(globtext)
            if incdirs:
                return incdirs[0]
            incboostdir = os.path.join(root, 'include', 'boost')
            if os.path.isdir(incboostdir):
                return os.path.join(root, 'include')
            incboostdir = os.path.join(root, 'boost')
            if os.path.isdir(incboostdir):
                return root
        return None

    def get_compile_args(self):
        args = []
        include_dir = self.incdir

        # Use "-isystem" when including boost headers instead of "-I"
        # to avoid compiler warnings/failures when "-Werror" is used

        # Careful not to use "-isystem" on default include dirs as it
        # breaks some of the headers for certain gcc versions

        # For example, doing g++ -isystem /usr/include on a simple
        # "int main()" source results in the error:
        # "/usr/include/c++/6.3.1/cstdlib:75:25: fatal error: stdlib.h: No such file or directory"

        # See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129
        # and http://stackoverflow.com/questions/37218953/isystem-on-a-system-include-directory-causes-errors
        # for more details

        if include_dir and include_dir not in self.clib_compiler.get_default_include_dirs():
            args.append("".join(self.clib_compiler.get_include_args(include_dir, True)))
        return args

    def get_requested(self, kwargs):
        candidates = mesonlib.extract_as_list(kwargs, 'modules')
        for c in candidates:
            if not isinstance(c, str):
                raise DependencyException('Boost module argument is not a string.')
        return candidates

    def detect_headers_and_version(self):
        try:
            version = self.clib_compiler.get_define('BOOST_LIB_VERSION', '#include ', self.env, self.get_compile_args(), [], disable_cache=True)[0]
        except mesonlib.EnvironmentException:
            return
        except TypeError:
            return
        # Remove quotes
        version = version[1:-1]
        # Fix version string
        self.version = version.replace('_', '.')
        self.is_found = True

    def detect_lib_modules(self):
        self.lib_modules = {}
        # 1. Try to find modules using compiler.find_library( )
        if self.find_libraries_with_abi_tags(self.abi_tags()):
            pass
        # 2. Fall back to the old method
        else:
            if self.env.machines[self.for_machine].is_windows():
                self.detect_lib_modules_win()
            else:
                self.detect_lib_modules_nix()

    def check_find_requested_modules(self):
        # 3. Check if we can find the modules
        for m in self.requested_modules:
            if 'boost_' + m not in self.lib_modules:
                mlog.debug('Requested Boost library {!r} not found'.format(m))
                self.is_found = False

    def modname_from_filename(self, filename):
        modname = os.path.basename(filename)
        modname = modname.split('.', 1)[0]
        modname = modname.split('-', 1)[0]
        if modname.startswith('libboost'):
            modname = modname[3:]
        return modname

    def compiler_tag(self):
        tag = None
        compiler = self.env.detect_cpp_compiler(self.for_machine)
        if self.env.machines[self.for_machine].is_windows():
            if compiler.get_id() in ['msvc', 'clang-cl']:
                comp_ts_version = compiler.get_toolset_version()
                compiler_ts = comp_ts_version.split('.')
                # FIXME - what about other compilers?
                tag = '-vc{}{}'.format(compiler_ts[0], compiler_ts[1])
            else:
                tag = ''
        return tag

    def threading_tag(self):
        if not self.is_multithreading:
            return ''

        if self.env.machines[self.for_machine].is_darwin():
            # - Mac:      requires -mt for multithreading, so should not fall back to non-mt libraries.
            return '-mt'
        elif self.env.machines[self.for_machine].is_windows():
            # - Windows:  requires -mt for multithreading, so should not fall back to non-mt libraries.
            return '-mt'
        else:
            # - Linux:    leaves off -mt but libraries are multithreading-aware.
            # - Cygwin:   leaves off -mt but libraries are multithreading-aware.
            return ''

    def version_tag(self):
        return '-' + self.version.replace('.', '_')

    def debug_tag(self):
        return '-gd' if self.is_debug else ''

    def arch_tag(self):
        # currently only applies to windows msvc installed binaries
        if self.env.detect_cpp_compiler(self.for_machine).get_id() not in ['msvc', 'clang-cl']:
            return ''
        # pre-compiled binaries only added arch tag for versions > 1.64
        if float(self.version) < 1.65:
            return ''
        arch = detect_cpu_family(self.env.coredata.compilers.host)
        if arch == 'x86':
            return '-x32'
        elif arch == 'x86_64':
            return '-x64'
        return ''

    def versioned_abi_tag(self):
        return self.compiler_tag() + self.threading_tag() + self.debug_tag() + self.arch_tag() + self.version_tag()

    # FIXME - how to handle different distributions, e.g. for Mac? Currently we handle homebrew and macports, but not fink.
    def abi_tags(self):
        if self.env.machines[self.for_machine].is_windows():
            return [self.versioned_abi_tag(), self.threading_tag()]
        else:
            return [self.threading_tag()]

    def sourceforge_dir(self):
        if self.env.detect_cpp_compiler(self.for_machine).get_id() != 'msvc':
            return None
        comp_ts_version = self.env.detect_cpp_compiler(self.for_machine).get_toolset_version()
        arch = detect_cpu_family(self.env.coredata.compilers.host)
        if arch == 'x86':
            return 'lib32-msvc-{}'.format(comp_ts_version)
        elif arch == 'x86_64':
            return 'lib64-msvc-{}'.format(comp_ts_version)
        else:
            # Does anyone do Boost cross-compiling to other archs on Windows?
            return None

    def find_libraries_with_abi_tag(self, tag):

        # All modules should have the same tag
        self.lib_modules = {}

        all_found = True

        for module in self.requested_modules:
            libname = 'boost_' + module + tag

            args = self.clib_compiler.find_library(libname, self.env, self.extra_lib_dirs())
            if args is None:
                mlog.debug("Couldn\'t find library '{}' for boost module '{}'  (ABI tag = '{}')".format(libname, module, tag))
                all_found = False
            else:
                mlog.debug('Link args for boost module "{}" are {}'.format(module, args))
                self.lib_modules['boost_' + module] = args

        return all_found

    def find_libraries_with_abi_tags(self, tags):
        for tag in tags:
            if self.find_libraries_with_abi_tag(tag):
                return True
        return False

    def detect_lib_modules_win(self):
        if not self.libdir:
            # The libdirs in the distributed binaries (from sf)
            lib_sf = self.sourceforge_dir()

            if self.boost_root:
                roots = [self.boost_root]
            else:
                roots = self.boost_roots
            for root in roots:
                # The default libdir when building
                libdir = os.path.join(root, 'lib')
                if os.path.isdir(libdir):
                    self.libdir = libdir
                    break
                if lib_sf:
                    full_path = os.path.join(root, lib_sf)
                    if os.path.isdir(full_path):
                        self.libdir = full_path
                        break

        if not self.libdir:
            return

        for name in self.need_static_link:
            # FIXME - why are we only looking for *.lib? Mingw provides *.dll.a and *.a
            libname = 'lib' + name + self.versioned_abi_tag() + '.lib'
            if os.path.isfile(os.path.join(self.libdir, libname)):
                self.lib_modules[self.modname_from_filename(libname)] = [libname]
            else:
                libname = "lib{}.lib".format(name)
                if os.path.isfile(os.path.join(self.libdir, libname)):
                    self.lib_modules[name[3:]] = [libname]

        # globber1 applies to a layout=system installation
        # globber2 applies to a layout=versioned installation
        globber1 = 'libboost_*' if self.static else 'boost_*'
        globber2 = globber1 + self.versioned_abi_tag()
        # FIXME - why are we only looking for *.lib? Mingw provides *.dll.a and *.a
        globber2_matches = glob.glob(os.path.join(self.libdir, globber2 + '.lib'))
        for entry in globber2_matches:
            fname = os.path.basename(entry)
            self.lib_modules[self.modname_from_filename(fname)] = [fname]
        if not globber2_matches:
            # FIXME - why are we only looking for *.lib? Mingw provides *.dll.a and *.a
            for entry in glob.glob(os.path.join(self.libdir, globber1 + '.lib')):
                if self.static:
                    fname = os.path.basename(entry)
                    self.lib_modules[self.modname_from_filename(fname)] = [fname]

    def detect_lib_modules_nix(self):
        if self.static:
            libsuffix = 'a'
        elif self.env.machines[self.for_machine].is_darwin():
            libsuffix = 'dylib'
        else:
            libsuffix = 'so'

        globber = 'libboost_*.{}'.format(libsuffix)
        if self.libdir:
            libdirs = [self.libdir]
        elif self.boost_root is None:
            libdirs = mesonlib.get_library_dirs()
        else:
            libdirs = [os.path.join(self.boost_root, 'lib')]
        for libdir in libdirs:
            for name in self.need_static_link:
                libname = 'lib{}.a'.format(name)
                if os.path.isfile(os.path.join(libdir, libname)):
                    self.lib_modules[name] = [libname]
            for entry in glob.glob(os.path.join(libdir, globber)):
                # I'm not 100% sure what to do here. Some distros
                # have modules such as thread only as -mt versions.
                # On debian all packages are built threading=multi
                # but not suffixed with -mt.
                # FIXME: implement detect_lib_modules_{debian, redhat, ...}
                # FIXME: this wouldn't work with -mt-gd either. -BDR
                if self.is_multithreading and mesonlib.is_debianlike():
                    pass
                elif self.is_multithreading and entry.endswith('-mt.{}'.format(libsuffix)):
                    pass
                elif not entry.endswith('-mt.{}'.format(libsuffix)):
                    pass
                else:
                    continue
                modname = self.modname_from_filename(entry)
                if modname not in self.lib_modules:
                    self.lib_modules[modname] = [entry]

    def extra_lib_dirs(self):
        if self.libdir:
            return [self.libdir]
        elif self.boost_root:
            return [os.path.join(self.boost_root, 'lib')]
        return []

    def get_link_args(self, **kwargs):
        args = []
        for d in self.extra_lib_dirs():
            args += self.clib_compiler.get_linker_search_args(d)
        for lib in self.requested_modules:
            args += self.lib_modules['boost_' + lib]
        return args

    def get_sources(self):
        return []

# Generated with boost_names.py
BOOST_LIBS = [
    'boost_atomic',
    'boost_chrono',
    'boost_chrono',
    'boost_container',
    'boost_context',
    'boost_coroutine',
    'boost_date_time',
    'boost_exception',
    'boost_fiber',
    'boost_filesystem',
    'boost_graph',
    'boost_iostreams',
    'boost_locale',
    'boost_log',
    'boost_log_setup',
    'boost_math_tr1',
    'boost_math_tr1f',
    'boost_math_tr1l',
    'boost_math_c99',
    'boost_math_c99f',
    'boost_math_c99l',
    'boost_math_tr1',
    'boost_math_tr1f',
    'boost_math_tr1l',
    'boost_math_c99',
    'boost_math_c99f',
    'boost_math_c99l',
    'boost_math_tr1',
    'boost_math_tr1f',
    'boost_math_tr1l',
    'boost_math_c99',
    'boost_math_c99f',
    'boost_math_c99l',
    'boost_math_tr1',
    'boost_math_tr1f',
    'boost_math_tr1l',
    'boost_math_c99',
    'boost_math_c99f',
    'boost_math_c99l',
    'boost_math_tr1',
    'boost_math_tr1f',
    'boost_math_tr1l',
    'boost_math_c99',
    'boost_math_c99f',
    'boost_math_c99l',
    'boost_math_tr1',
    'boost_math_tr1f',
    'boost_math_tr1l',
    'boost_math_c99',
    'boost_math_c99f',
    'boost_math_c99l',
    'boost_mpi',
    'boost_program_options',
    'boost_random',
    'boost_regex',
    'boost_serialization',
    'boost_wserialization',
    'boost_signals',
    'boost_stacktrace_noop',
    'boost_stacktrace_backtrace',
    'boost_stacktrace_addr2line',
    'boost_stacktrace_basic',
    'boost_stacktrace_windbg',
    'boost_stacktrace_windbg_cached',
    'boost_system',
    'boost_prg_exec_monitor',
    'boost_test_exec_monitor',
    'boost_unit_test_framework',
    'boost_thread',
    'boost_timer',
    'boost_type_erasure',
    'boost_wave'
]

BOOST_DIRS = [
    'lambda',
    'optional',
    'convert',
    'system',
    'uuid',
    'archive',
    'align',
    'timer',
    'chrono',
    'gil',
    'logic',
    'signals',
    'predef',
    'tr1',
    'multi_index',
    'property_map',
    'multi_array',
    'context',
    'random',
    'endian',
    'circular_buffer',
    'proto',
    'assign',
    'format',
    'math',
    'phoenix',
    'graph',
    'locale',
    'mpl',
    'pool',
    'unordered',
    'core',
    'exception',
    'ptr_container',
    'flyweight',
    'range',
    'typeof',
    'thread',
    'move',
    'spirit',
    'dll',
    'compute',
    'serialization',
    'ratio',
    'msm',
    'config',
    'metaparse',
    'coroutine2',
    'qvm',
    'program_options',
    'concept',
    'detail',
    'hana',
    'concept_check',
    'compatibility',
    'variant',
    'type_erasure',
    'mpi',
    'test',
    'fusion',
    'log',
    'sort',
    'local_function',
    'units',
    'functional',
    'preprocessor',
    'integer',
    'container',
    'polygon',
    'interprocess',
    'numeric',
    'iterator',
    'wave',
    'lexical_cast',
    'multiprecision',
    'utility',
    'tti',
    'asio',
    'dynamic_bitset',
    'algorithm',
    'xpressive',
    'bimap',
    'signals2',
    'type_traits',
    'regex',
    'statechart',
    'parameter',
    'icl',
    'python',
    'lockfree',
    'intrusive',
    'io',
    'pending',
    'geometry',
    'tuple',
    'iostreams',
    'heap',
    'atomic',
    'filesystem',
    'smart_ptr',
    'function',
    'fiber',
    'type_index',
    'accumulators',
    'function_types',
    'coroutine',
    'vmd',
    'date_time',
    'property_tree',
    'bind'
]
meson-0.53.2/mesonbuild/dependencies/coarrays.py0000644000175000017500000000715013602226377023313 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from ..mesonlib import listify
from .base import CMakeDependency, DependencyMethods, ExternalDependency, PkgConfigDependency


class CoarrayDependency(ExternalDependency):
    """
    Coarrays are a Fortran 2008 feature.

    Coarrays are sometimes implemented via external library (GCC+OpenCoarrays),
    while other compilers just build in support (Cray, IBM, Intel, NAG).
    Coarrays may be thought of as a high-level language abstraction of
    low-level MPI calls.
    """
    def __init__(self, environment, kwargs: dict):
        super().__init__('coarray', environment, 'fortran', kwargs)
        kwargs['required'] = False
        kwargs['silent'] = True
        self.is_found = False
        methods = listify(self.methods)

        cid = self.get_compiler().get_id()
        if cid == 'gcc':
            """ OpenCoarrays is the most commonly used method for Fortran Coarray with GCC """

            if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
                for pkg in ['caf-openmpi', 'caf']:
                    pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
                    if pkgdep.found():
                        self.compile_args = pkgdep.get_compile_args()
                        self.link_args = pkgdep.get_link_args()
                        self.version = pkgdep.get_version()
                        self.is_found = True
                        self.pcdep = pkgdep
                        return

            if set([DependencyMethods.AUTO, DependencyMethods.CMAKE]).intersection(methods):
                if not kwargs.get('modules'):
                    kwargs['modules'] = 'OpenCoarrays::caf_mpi'
                cmakedep = CMakeDependency('OpenCoarrays', environment, kwargs, language=self.language)
                if cmakedep.found():
                    self.compile_args = cmakedep.get_compile_args()
                    self.link_args = cmakedep.get_link_args()
                    self.version = cmakedep.get_version()
                    self.is_found = True
                    return

            if DependencyMethods.AUTO in methods:
                # fallback to single image
                self.compile_args = ['-fcoarray=single']
                self.version = 'single image (fallback)'
                self.is_found = True
                return

        elif cid == 'intel':
            """ Coarrays are built into Intel compilers, no external library needed """
            self.is_found = True
            self.link_args = ['-coarray=shared']
            self.compile_args = self.link_args
        elif cid == 'intel-cl':
            """ Coarrays are built into Intel compilers, no external library needed """
            self.is_found = True
            self.compile_args = ['/Qcoarray:shared']
        elif cid == 'nagfor':
            """ NAG doesn't require any special arguments for Coarray """
            self.is_found = True

    @staticmethod
    def get_methods():
        return [DependencyMethods.AUTO, DependencyMethods.CMAKE, DependencyMethods.PKGCONFIG]
meson-0.53.2/mesonbuild/dependencies/cuda.py0000644000175000017500000002601013602226377022400 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import glob
import re
import os

from .. import mlog
from .. import mesonlib
from ..environment import detect_cpu_family

from .base import (DependencyException, ExternalDependency)


class CudaDependency(ExternalDependency):

    supported_languages = ['cuda', 'cpp', 'c'] # see also _default_language

    def __init__(self, environment, kwargs):
        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))

        super().__init__('cuda', environment, language, kwargs)
        self.requested_modules = self.get_requested(kwargs)
        if 'cudart' not in self.requested_modules:
            self.requested_modules = ['cudart'] + self.requested_modules

        (self.cuda_path, self.version, self.is_found) = self._detect_cuda_path_and_version()
        if not self.is_found:
            return

        if not os.path.isabs(self.cuda_path):
            raise DependencyException('CUDA Toolkit path must be absolute, got \'{}\'.'.format(self.cuda_path))

        # nvcc already knows where to find the CUDA Toolkit, but if we're compiling
        # a mixed C/C++/CUDA project, we still need to make the include dir searchable
        if self.language != 'cuda' or len(compilers) > 1:
            self.incdir = os.path.join(self.cuda_path, 'include')
            self.compile_args += ['-I{}'.format(self.incdir)]

        if self.language != 'cuda':
            arch_libdir = self._detect_arch_libdir()
            self.libdir = os.path.join(self.cuda_path, arch_libdir)
            mlog.debug('CUDA library directory is', mlog.bold(self.libdir))
        else:
            self.libdir = None

        self.is_found = self._find_requested_libraries()

    @classmethod
    def _detect_language(cls, compilers):
        for lang in cls.supported_languages:
            if lang in compilers:
                return lang
        return list(compilers.keys())[0]

    def _detect_cuda_path_and_version(self):
        self.env_var = self._default_path_env_var()
        mlog.debug('Default path env var:', mlog.bold(self.env_var))

        version_reqs = self.version_reqs
        if self.language == 'cuda':
            nvcc_version = self._strip_patch_version(self.get_compiler().version)
            mlog.debug('nvcc version:', mlog.bold(nvcc_version))
            if version_reqs:
                # make sure nvcc version satisfies specified version requirements
                (found_some, not_found, found) = mesonlib.version_compare_many(nvcc_version, version_reqs)
                if not_found:
                    msg = 'The current nvcc version {} does not satisfy the specified CUDA Toolkit version requirements {}.'.format(nvcc_version, version_reqs)
                    return self._report_dependency_error(msg, (None, None, False))

            # use nvcc version to find a matching CUDA Toolkit
            version_reqs = ['={}'.format(nvcc_version)]
        else:
            nvcc_version = None

        paths = [(path, self._cuda_toolkit_version(path), default) for (path, default) in self._cuda_paths()]
        if version_reqs:
            return self._find_matching_toolkit(paths, version_reqs, nvcc_version)

        defaults = [(path, version) for (path, version, default) in paths if default]
        if defaults:
            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'
        msg = 'Please specify the desired CUDA Toolkit version (e.g. dependency(\'cuda\', version : \'>=10.1\')) or {} to point to the location of your desired version.'.format(platform_msg)
        return self._report_dependency_error(msg, (None, None, False))

    def _find_matching_toolkit(self, paths, version_reqs, nvcc_version):
        # keep the default paths order intact, sort the rest in the descending order
        # according to the toolkit version
        defaults, rest = mesonlib.partition(lambda t: not t[2], paths)
        defaults = list(defaults)
        paths = defaults + sorted(rest, key=lambda t: mesonlib.Version(t[1]), reverse=True)
        mlog.debug('Search paths: {}'.format(paths))

        if nvcc_version and defaults:
            default_src = "the {} environment variable".format(self.env_var) if self.env_var else "the \'/usr/local/cuda\' symbolic link"
            nvcc_warning = 'The default CUDA Toolkit as designated by {} ({}) doesn\'t match the current nvcc version {} and will be ignored.'.format(default_src, os.path.realpath(defaults[0][0]), nvcc_version)
        else:
            nvcc_warning = None

        for (path, version, default) in paths:
            (found_some, not_found, found) = mesonlib.version_compare_many(version, version_reqs)
            if not not_found:
                if not default and nvcc_warning:
                    mlog.warning(nvcc_warning)
                return (path, version, True)

        if nvcc_warning:
            mlog.warning(nvcc_warning)
        return (None, None, False)

    def _default_path_env_var(self):
        env_vars = ['CUDA_PATH'] if self._is_windows() else ['CUDA_PATH', 'CUDA_HOME', 'CUDA_ROOT']
        env_vars = [var for var in env_vars if var in os.environ]
        user_defaults = set([os.environ[var] for var in env_vars])
        if len(user_defaults) > 1:
            mlog.warning('Environment variables {} point to conflicting toolkit locations ({}). Toolkit selection might produce unexpected results.'.format(', '.join(env_vars), ', '.join(user_defaults)))
        return env_vars[0] if env_vars else None

    def _cuda_paths(self):
        return ([(os.environ[self.env_var], True)] if self.env_var else []) \
            + (self._cuda_paths_win() if self._is_windows() else self._cuda_paths_nix())

    def _cuda_paths_win(self):
        env_vars = os.environ.keys()
        return [(os.environ[var], False) for var in env_vars if var.startswith('CUDA_PATH_')]

    def _cuda_paths_nix(self):
        # include /usr/local/cuda default only if no env_var was found
        pattern = '/usr/local/cuda-*' if self.env_var else '/usr/local/cuda*'
        return [(path, os.path.basename(path) == 'cuda') for path in glob.iglob(pattern)]

    toolkit_version_regex = re.compile(r'^CUDA Version\s+(.*)$')
    path_version_win_regex = re.compile(r'^v(.*)$')
    path_version_nix_regex = re.compile(r'^cuda-(.*)$')

    def _cuda_toolkit_version(self, path):
        version = self._read_toolkit_version_txt(path)
        if version:
            return version

        mlog.debug('Falling back to extracting version from path')
        path_version_regex = self.path_version_win_regex if self._is_windows() else self.path_version_nix_regex
        m = path_version_regex.match(os.path.basename(path))
        if m:
            return m[1]

        mlog.warning('Could not detect CUDA Toolkit version for {}'.format(path))
        return '0.0'

    def _read_toolkit_version_txt(self, path):
        # Read 'version.txt' at the root of the CUDA Toolkit directory to determine the tookit version
        version_file_path = os.path.join(path, 'version.txt')
        try:
            with open(version_file_path) as version_file:
                version_str = version_file.readline() # e.g. 'CUDA Version 10.1.168'
                m = self.toolkit_version_regex.match(version_str)
                if m:
                    return self._strip_patch_version(m[1])
        except Exception as e:
            mlog.debug('Could not read CUDA Toolkit\'s version file {}: {}'.format(version_file_path, str(e)))

        return None

    @classmethod
    def _strip_patch_version(cls, version):
        return '.'.join(version.split('.')[:2])

    def _detect_arch_libdir(self):
        arch = detect_cpu_family(self.env.coredata.compilers.host)
        machine = self.env.machines[self.for_machine]
        msg = '{} architecture is not supported in {} version of the CUDA Toolkit.'
        if machine.is_windows():
            libdirs = {'x86': 'Win32', 'x86_64': 'x64'}
            if arch not in libdirs:
                raise DependencyException(msg.format(arch, 'Windows'))
            return os.path.join('lib', libdirs[arch])
        elif machine.is_linux():
            libdirs = {'x86_64': 'lib64', 'ppc64': 'lib'}
            if arch not in libdirs:
                raise DependencyException(msg.format(arch, 'Linux'))
            return libdirs[arch]
        elif machine.is_osx():
            libdirs = {'x86_64': 'lib64'}
            if arch not in libdirs:
                raise DependencyException(msg.format(arch, 'macOS'))
            return libdirs[arch]
        else:
            raise DependencyException('CUDA Toolkit: unsupported platform.')

    def _find_requested_libraries(self):
        self.lib_modules = {}
        all_found = True

        for module in self.requested_modules:
            args = self.clib_compiler.find_library(module, self.env, [self.libdir] if self.libdir else [])
            if args is None:
                self._report_dependency_error('Couldn\'t find requested CUDA module \'{}\''.format(module))
                all_found = False
            else:
                mlog.debug('Link args for CUDA module \'{}\' are {}'.format(module, args))
                self.lib_modules[module] = args

        return all_found

    def _is_windows(self):
        return self.env.machines[self.for_machine].is_windows()

    def _report_dependency_error(self, msg, ret_val=None):
        if self.required:
            raise DependencyException(msg)

        mlog.debug(msg)
        return ret_val

    def log_details(self):
        module_str = ', '.join(self.requested_modules)
        return 'modules: ' + module_str

    def log_info(self):
        return self.cuda_path if self.cuda_path else ''

    def get_requested(self, kwargs):
        candidates = mesonlib.extract_as_list(kwargs, 'modules')
        for c in candidates:
            if not isinstance(c, str):
                raise DependencyException('CUDA module argument is not a string.')
        return candidates

    def get_link_args(self, **kwargs):
        args = []
        if self.libdir:
            args += self.clib_compiler.get_linker_search_args(self.libdir)
        for lib in self.requested_modules:
            args += self.lib_modules[lib]
        return args
meson-0.53.2/mesonbuild/dependencies/data/0000755000175000017500000000000013625242354022022 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/dependencies/data/CMakeLists.txt0000644000175000017500000000537613602226377024577 0ustar  jpakkanejpakkane00000000000000# fail noisily if attempt to use this file without setting:
# cmake_minimum_required(VERSION ${CMAKE_VERSION})
# project(... LANGUAGES ...)

cmake_policy(SET CMP0000 NEW)

set(PACKAGE_FOUND FALSE)
set(_packageName "${NAME}")
string(TOUPPER "${_packageName}" PACKAGE_NAME)

while(TRUE)
  find_package("${NAME}" QUIET)

  # ARCHS has to be set via the CMD interface
  if(${_packageName}_FOUND OR ${PACKAGE_NAME}_FOUND OR "${ARCHS}" STREQUAL "")
    break()
  endif()

  list(GET       ARCHS 0 CMAKE_LIBRARY_ARCHITECTURE)
  list(REMOVE_AT ARCHS 0)
endwhile()

if(${_packageName}_FOUND  OR  ${PACKAGE_NAME}_FOUND)
  set(PACKAGE_FOUND TRUE)

  # Check the following variables:
  # FOO_VERSION
  # Foo_VERSION
  # FOO_VERSION_STRING
  # Foo_VERSION_STRING
  if(NOT DEFINED PACKAGE_VERSION)
    if(DEFINED ${_packageName}_VERSION)
      set(PACKAGE_VERSION "${${_packageName}_VERSION}")
    elseif(DEFINED ${PACKAGE_NAME}_VERSION)
      set(PACKAGE_VERSION "${${PACKAGE_NAME}_VERSION}")
    elseif(DEFINED ${_packageName}_VERSION_STRING)
      set(PACKAGE_VERSION "${${_packageName}_VERSION_STRING}")
    elseif(DEFINED ${PACKAGE_NAME}_VERSION_STRING)
      set(PACKAGE_VERSION "${${PACKAGE_NAME}_VERSION_STRING}")
    endif()
  endif()

  # Check the following variables:
  # FOO_LIBRARIES
  # Foo_LIBRARIES
  # FOO_LIBS
  # Foo_LIBS
  set(libs)
  if(DEFINED ${_packageName}_LIBRARIES)
    set(libs ${_packageName}_LIBRARIES)
  elseif(DEFINED ${PACKAGE_NAME}_LIBRARIES)
    set(libs ${PACKAGE_NAME}_LIBRARIES)
  elseif(DEFINED ${_packageName}_LIBS)
    set(libs ${_packageName}_LIBS)
  elseif(DEFINED ${PACKAGE_NAME}_LIBS)
    set(libs ${PACKAGE_NAME}_LIBS)
  endif()

  # Check the following variables:
  # FOO_INCLUDE_DIRS
  # Foo_INCLUDE_DIRS
  # FOO_INCLUDES
  # Foo_INCLUDES
  # FOO_INCLUDE_DIR
  # Foo_INCLUDE_DIR
  set(includes)
  if(DEFINED ${_packageName}_INCLUDE_DIRS)
    set(includes ${_packageName}_INCLUDE_DIRS)
  elseif(DEFINED ${PACKAGE_NAME}_INCLUDE_DIRS)
    set(includes ${PACKAGE_NAME}_INCLUDE_DIRS)
  elseif(DEFINED ${_packageName}_INCLUDES)
    set(includes ${_packageName}_INCLUDES)
  elseif(DEFINED ${PACKAGE_NAME}_INCLUDES)
    set(includes ${PACKAGE_NAME}_INCLUDES)
  elseif(DEFINED ${_packageName}_INCLUDE_DIR)
    set(includes ${_packageName}_INCLUDE_DIR)
  elseif(DEFINED ${PACKAGE_NAME}_INCLUDE_DIR)
    set(includes ${PACKAGE_NAME}_INCLUDE_DIR)
  endif()

  # Check the following variables:
  # FOO_DEFINITIONS
  # Foo_DEFINITIONS
  set(definitions)
  if(DEFINED ${_packageName}_DEFINITIONS)
    set(definitions ${_packageName}_DEFINITIONS)
  elseif(DEFINED ${PACKAGE_NAME}_DEFINITIONS)
    set(definitions ${PACKAGE_NAME}_DEFINITIONS)
  endif()

  set(PACKAGE_INCLUDE_DIRS "${${includes}}")
  set(PACKAGE_DEFINITIONS  "${${definitions}}")
  set(PACKAGE_LIBRARIES    "${${libs}}")
endif()
meson-0.53.2/mesonbuild/dependencies/data/CMakeListsLLVM.txt0000644000175000017500000000456513463632524025271 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} )

set(PACKAGE_FOUND FALSE)

while(TRUE)
  find_package(LLVM REQUIRED CONFIG QUIET)

  # ARCHS has to be set via the CMD interface
  if(LLVM_FOUND OR "${ARCHS}" STREQUAL "")
    break()
  endif()

  list(GET       ARCHS 0 CMAKE_LIBRARY_ARCHITECTURE)
  list(REMOVE_AT ARCHS 0)
endwhile()

if(LLVM_FOUND)
  set(PACKAGE_FOUND TRUE)

  foreach(mod IN LISTS LLVM_MESON_MODULES)
    # Reset variables
    set(out_mods)
    set(real_mods)

    # Generate a lower and upper case version
    string(TOLOWER "${mod}" mod_L)
    string(TOUPPER "${mod}" mod_U)

    # Get the mapped components
    llvm_map_components_to_libnames(out_mods ${mod} ${mod_L} ${mod_U})
    list(SORT              out_mods)
    list(REMOVE_DUPLICATES out_mods)

    # Make sure that the modules exist
    foreach(i IN LISTS out_mods)
      if(TARGET ${i})
        list(APPEND real_mods ${i})
      endif()
    endforeach()

    # Set the output variables
    set(MESON_LLVM_TARGETS_${mod} ${real_mods})
    foreach(i IN LISTS real_mods)
      set(MESON_TARGET_TO_LLVM_${i} ${mod})
    endforeach()
  endforeach()

  # Check the following variables:
  # LLVM_PACKAGE_VERSION
  # LLVM_VERSION
  # LLVM_VERSION_STRING
  if(NOT DEFINED PACKAGE_VERSION)
    if(DEFINED LLVM_PACKAGE_VERSION)
      set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
    elseif(DEFINED LLVM_VERSION)
      set(PACKAGE_VERSION "${LLVM_VERSION}")
    elseif(DEFINED LLVM_VERSION_STRING)
      set(PACKAGE_VERSION "${LLVM_VERSION_STRING}")
    endif()
  endif()

  # Check the following variables:
  # LLVM_LIBRARIES
  # LLVM_LIBS
  set(libs)
  if(DEFINED LLVM_LIBRARIES)
    set(libs LLVM_LIBRARIES)
  elseif(DEFINED LLVM_LIBS)
    set(libs LLVM_LIBS)
  endif()

  # Check the following variables:
  # LLVM_INCLUDE_DIRS
  # LLVM_INCLUDES
  # LLVM_INCLUDE_DIR
  set(includes)
  if(DEFINED LLVM_INCLUDE_DIRS)
    set(includes LLVM_INCLUDE_DIRS)
  elseif(DEFINED LLVM_INCLUDES)
    set(includes LLVM_INCLUDES)
  elseif(DEFINED LLVM_INCLUDE_DIR)
    set(includes LLVM_INCLUDE_DIR)
  endif()

  # Check the following variables:
  # LLVM_DEFINITIONS
  set(definitions)
  if(DEFINED LLVM_DEFINITIONS)
    set(definitions LLVM_DEFINITIONS)
  endif()

  set(PACKAGE_INCLUDE_DIRS "${${includes}}")
  set(PACKAGE_DEFINITIONS  "${${definitions}}")
  set(PACKAGE_LIBRARIES    "${${libs}}")
endif()
meson-0.53.2/mesonbuild/dependencies/data/CMakePathInfo.txt0000644000175000017500000000222213531533273025171 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION})

set(TMP_PATHS_LIST)
list(APPEND TMP_PATHS_LIST ${CMAKE_PREFIX_PATH})
list(APPEND TMP_PATHS_LIST ${CMAKE_FRAMEWORK_PATH})
list(APPEND TMP_PATHS_LIST ${CMAKE_APPBUNDLE_PATH})
list(APPEND TMP_PATHS_LIST $ENV{CMAKE_PREFIX_PATH})
list(APPEND TMP_PATHS_LIST $ENV{CMAKE_FRAMEWORK_PATH})
list(APPEND TMP_PATHS_LIST $ENV{CMAKE_APPBUNDLE_PATH})
list(APPEND TMP_PATHS_LIST ${CMAKE_SYSTEM_PREFIX_PATH})
list(APPEND TMP_PATHS_LIST ${CMAKE_SYSTEM_FRAMEWORK_PATH})
list(APPEND TMP_PATHS_LIST ${CMAKE_SYSTEM_APPBUNDLE_PATH})

set(LIB_ARCH_LIST)
if(CMAKE_LIBRARY_ARCHITECTURE_REGEX)
  file(GLOB implicit_dirs RELATIVE /lib /lib/*-linux-gnu* )
  foreach(dir ${implicit_dirs})
    if("${dir}" MATCHES "${CMAKE_LIBRARY_ARCHITECTURE_REGEX}")
      list(APPEND LIB_ARCH_LIST "${dir}")
    endif()
  endforeach()
endif()

# "Export" these variables:
set(MESON_ARCH_LIST ${LIB_ARCH_LIST})
set(MESON_PATHS_LIST ${TMP_PATHS_LIST})
set(MESON_CMAKE_ROOT ${CMAKE_ROOT})
set(MESON_CMAKE_SYSROOT ${CMAKE_SYSROOT})
set(MESON_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH})

message(STATUS ${TMP_PATHS_LIST})
meson-0.53.2/mesonbuild/dependencies/dev.py0000644000175000017500000004474313612313307022246 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for external dependencies useful for
# development purposes, such as testing, debugging, etc..

import functools
import glob
import os
import re

from .. import mesonlib, mlog
from ..mesonlib import version_compare, stringlistify, extract_as_list, MachineChoice
from ..environment import get_llvm_tool_names
from .base import (
    DependencyException, DependencyMethods, ExternalDependency, PkgConfigDependency,
    strip_system_libdirs, ConfigToolDependency, CMakeDependency
)
from .misc import ThreadDependency

import typing as T


def get_shared_library_suffix(environment, for_machine: MachineChoice):
    """This is only guaranteed to work for languages that compile to machine
    code, not for languages like C# that use a bytecode and always end in .dll
    """
    m = environment.machines[for_machine]
    if m.is_windows():
        return '.dll'
    elif m.is_darwin():
        return '.dylib'
    return '.so'


class GTestDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('gtest', environment, 'cpp', kwargs)
        self.main = kwargs.get('main', False)
        self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src']
        self.detect()
        self._add_sub_dependency(ThreadDependency, environment, kwargs)

    def detect(self):
        gtest_detect = self.clib_compiler.find_library("gtest", self.env, [])
        gtest_main_detect = self.clib_compiler.find_library("gtest_main", self.env, [])
        if gtest_detect and (not self.main or gtest_main_detect):
            self.is_found = True
            self.compile_args = []
            self.link_args = gtest_detect
            if self.main:
                self.link_args += gtest_main_detect
            self.sources = []
            self.prebuilt = True
        elif self.detect_srcdir():
            self.is_found = True
            self.compile_args = ['-I' + d for d in self.src_include_dirs]
            self.link_args = []
            if self.main:
                self.sources = [self.all_src, self.main_src]
            else:
                self.sources = [self.all_src]
            self.prebuilt = False
        else:
            self.is_found = False

    def detect_srcdir(self):
        for s in self.src_dirs:
            if os.path.exists(s):
                self.src_dir = s
                self.all_src = mesonlib.File.from_absolute_file(
                    os.path.join(self.src_dir, 'gtest-all.cc'))
                self.main_src = mesonlib.File.from_absolute_file(
                    os.path.join(self.src_dir, 'gtest_main.cc'))
                self.src_include_dirs = [os.path.normpath(os.path.join(self.src_dir, '..')),
                                         os.path.normpath(os.path.join(self.src_dir, '../include')),
                                         ]
                return True
        return False

    def log_info(self):
        if self.prebuilt:
            return 'prebuilt'
        else:
            return 'building self'

    def log_tried(self):
        return 'system'

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            pcname = 'gtest_main' if kwargs.get('main', False) else 'gtest'
            candidates.append(functools.partial(PkgConfigDependency, pcname, environment, kwargs))

        if DependencyMethods.SYSTEM in methods:
            candidates.append(functools.partial(GTestDependency, environment, kwargs))

        return candidates

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]


class GMockDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('gmock', environment, 'cpp', kwargs)
        self.main = kwargs.get('main', False)
        self._add_sub_dependency(ThreadDependency, environment, kwargs)

        # If we are getting main() from GMock, we definitely
        # want to avoid linking in main() from GTest
        gtest_kwargs = kwargs.copy()
        if self.main:
            gtest_kwargs['main'] = False

        # GMock without GTest is pretty much useless
        # this also mimics the structure given in WrapDB,
        # where GMock always pulls in GTest
        gtest_dep = GTestDependency(environment, gtest_kwargs)
        if not gtest_dep.is_found:
            self.is_found = False
            return
        self.ext_deps.append(gtest_dep)

        # GMock may be a library or just source.
        # Work with both.
        gmock_detect = self.clib_compiler.find_library("gmock", self.env, [])
        gmock_main_detect = self.clib_compiler.find_library("gmock_main", self.env, [])
        if gmock_detect and (not self.main or gmock_main_detect):
            self.is_found = True
            self.link_args += gmock_detect
            if self.main:
                self.link_args += gmock_main_detect
            self.prebuilt = True
            return

        for d in ['/usr/src/googletest/googlemock/src', '/usr/src/gmock/src', '/usr/src/gmock']:
            if os.path.exists(d):
                self.is_found = True
                # Yes, we need both because there are multiple
                # versions of gmock that do different things.
                d2 = os.path.normpath(os.path.join(d, '..'))
                self.compile_args += ['-I' + d, '-I' + d2, '-I' + os.path.join(d2, 'include')]
                all_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock-all.cc'))
                main_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock_main.cc'))
                if self.main:
                    self.sources += [all_src, main_src]
                else:
                    self.sources += [all_src]
                self.prebuilt = False
                return

        self.is_found = False

    def log_info(self):
        if self.prebuilt:
            return 'prebuilt'
        else:
            return 'building self'

    def log_tried(self):
        return 'system'

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            pcname = 'gmock_main' if kwargs.get('main', False) else 'gmock'
            candidates.append(functools.partial(PkgConfigDependency, pcname, environment, kwargs))

        if DependencyMethods.SYSTEM in methods:
            candidates.append(functools.partial(GMockDependency, environment, kwargs))

        return candidates

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]


class LLVMDependencyConfigTool(ConfigToolDependency):
    """
    LLVM uses a special tool, llvm-config, which has arguments for getting
    c args, cxx args, and ldargs as well as version.
    """
    tool_name = 'llvm-config'
    __cpp_blacklist = {'-DNDEBUG'}

    def __init__(self, environment, 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.get_for_machine_from_kwargs(kwargs)].is_64_bit:
            self.tools.append('llvm-config-64')
        else:
            self.tools.append('llvm-config-32')

        # It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0
        # the C linker works fine if only using the C API.
        super().__init__('LLVM', environment, 'cpp', kwargs)
        self.provided_modules = []
        self.required_modules = set()
        self.module_details = []
        if not self.is_found:
            return
        self.static = kwargs.get('static', False)

        self.provided_modules = self.get_config_value(['--components'], 'modules')
        modules = stringlistify(extract_as_list(kwargs, 'modules'))
        self.check_components(modules)
        opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules'))
        self.check_components(opt_modules, required=False)

        cargs = set(self.get_config_value(['--cppflags'], 'compile_args'))
        self.compile_args = list(cargs.difference(self.__cpp_blacklist))

        if version_compare(self.version, '>= 3.9'):
            self._set_new_link_args(environment)
        else:
            self._set_old_link_args()
        self.link_args = strip_system_libdirs(environment, self.for_machine, self.link_args)
        self.link_args = self.__fix_bogus_link_args(self.link_args)
        self._add_sub_dependency(ThreadDependency, environment, kwargs)

    def __fix_bogus_link_args(self, args):
        """This function attempts to fix bogus link arguments that llvm-config
        generates.

        Currently it works around the following:
            - FreeBSD: when statically linking -l/usr/lib/libexecinfo.so will
              be generated, strip the -l in cases like this.
            - Windows: We may get -LIBPATH:... which is later interpreted as
              "-L IBPATH:...", if we're using an msvc like compilers convert
              that to "/LIBPATH", otherwise to "-L ..."
        """
        cpp = self.env.coredata.compilers[self.for_machine]['cpp']

        new_args = []
        for arg in args:
            if arg.startswith('-l') and arg.endswith('.so'):
                new_args.append(arg.lstrip('-l'))
            elif arg.startswith('-LIBPATH:'):
                new_args.extend(cpp.get_linker_search_args(arg.lstrip('-LIBPATH:')))
            else:
                new_args.append(arg)
        return new_args

    def __check_libfiles(self, shared):
        """Use llvm-config's --libfiles to check if libraries exist."""
        mode = '--link-shared' if shared else '--link-static'

        # Set self.required to true to force an exception in get_config_value
        # if the returncode != 0
        restore = self.required
        self.required = True

        try:
            # It doesn't matter what the stage is, the caller needs to catch
            # the exception anyway.
            self.link_args = self.get_config_value(['--libfiles', mode], '')
        finally:
            self.required = restore

    def _set_new_link_args(self, environment):
        """How to set linker args for LLVM versions >= 3.9"""
        mode = self.get_config_value(['--shared-mode'], 'link_args')[0]
        if not self.static and mode == 'static':
            # If llvm is configured with LLVM_BUILD_LLVM_DYLIB but not with
            # LLVM_LINK_LLVM_DYLIB and not LLVM_BUILD_SHARED_LIBS (which
            # upstream doesn't recommend using), then llvm-config will lie to
            # you about how to do shared-linking. It wants to link to a a bunch
            # of individual shared libs (which don't exist because llvm wasn't
            # built with LLVM_BUILD_SHARED_LIBS.
            #
            # Therefore, we'll try to get the libfiles, if the return code is 0
            # or we get an empty list, then we'll try to build a working
            # configuration by hand.
            try:
                self.__check_libfiles(True)
            except DependencyException:
                lib_ext = get_shared_library_suffix(environment, self.for_machine)
                libdir = self.get_config_value(['--libdir'], 'link_args')[0]
                # Sort for reproducibility
                matches = sorted(glob.iglob(os.path.join(libdir, 'libLLVM*{}'.format(lib_ext))))
                if not matches:
                    if self.required:
                        raise
                    self.is_found = False
                    return

                self.link_args = self.get_config_value(['--ldflags'], 'link_args')
                libname = os.path.basename(matches[0]).rstrip(lib_ext).lstrip('lib')
                self.link_args.append('-l{}'.format(libname))
                return
        elif self.static and mode == 'shared':
            # If, however LLVM_BUILD_SHARED_LIBS is true # (*cough* gentoo *cough*)
            # then this is correct. Building with LLVM_BUILD_SHARED_LIBS has a side
            # effect, it stops the generation of static archives. Therefore we need
            # to check for that and error out on static if this is the case
            try:
                self.__check_libfiles(False)
            except DependencyException:
                if self.required:
                    raise
                self.is_found = False
                return

        link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared']
        self.link_args = self.get_config_value(
            ['--libs', '--ldflags'] + link_args + list(self.required_modules),
            'link_args')

    def _set_old_link_args(self):
        """Setting linker args for older versions of llvm.

        Old versions of LLVM bring an extra level of insanity with them.
        llvm-config will provide the correct arguments for static linking, but
        not for shared-linnking, we have to figure those out ourselves, because
        of course we do.
        """
        if self.static:
            self.link_args = self.get_config_value(
                ['--libs', '--ldflags', '--system-libs'] + list(self.required_modules),
                'link_args')
        else:
            # llvm-config will provide arguments for static linking, so we get
            # to figure out for ourselves what to link with. We'll do that by
            # checking in the directory provided by --libdir for a library
            # called libLLVM-.(so|dylib|dll)
            libdir = self.get_config_value(['--libdir'], 'link_args')[0]

            expected_name = 'libLLVM-{}'.format(self.version)
            re_name = re.compile(r'{}.(so|dll|dylib)$'.format(expected_name))

            for file_ in os.listdir(libdir):
                if re_name.match(file_):
                    self.link_args = ['-L{}'.format(libdir),
                                      '-l{}'.format(os.path.splitext(file_.lstrip('lib'))[0])]
                    break
            else:
                raise DependencyException(
                    'Could not find a dynamically linkable library for LLVM.')

    def check_components(self, modules, required=True):
        """Check for llvm components (modules in meson terms).

        The required option is whether the module is required, not whether LLVM
        is required.
        """
        for mod in sorted(set(modules)):
            status = ''

            if mod not in self.provided_modules:
                if required:
                    self.is_found = False
                    if self.required:
                        raise DependencyException(
                            'Could not find required LLVM Component: {}'.format(mod))
                    status = '(missing)'
                else:
                    status = '(missing but optional)'
            else:
                self.required_modules.add(mod)

            self.module_details.append(mod + status)

    def log_details(self):
        if self.module_details:
            return 'modules: ' + ', '.join(self.module_details)
        return ''

class LLVMDependencyCMake(CMakeDependency):
    def __init__(self, env, kwargs):
        self.llvm_modules = stringlistify(extract_as_list(kwargs, 'modules'))
        self.llvm_opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules'))
        super().__init__(name='LLVM', environment=env, language='cpp', kwargs=kwargs)

        # Extract extra include directories and definitions
        inc_dirs = self.traceparser.get_cmake_var('PACKAGE_INCLUDE_DIRS')
        defs = self.traceparser.get_cmake_var('PACKAGE_DEFINITIONS')
        temp = ['-I' + x for x in inc_dirs] + defs
        self.compile_args += [x for x in temp if x not in self.compile_args]
        self._add_sub_dependency(ThreadDependency, env, kwargs)

    def _main_cmake_file(self) -> str:
        # Use a custom CMakeLists.txt for LLVM
        return 'CMakeListsLLVM.txt'

    def _extra_cmake_opts(self) -> T.List[str]:
        return ['-DLLVM_MESON_MODULES={}'.format(';'.join(self.llvm_modules + self.llvm_opt_modules))]

    def _map_module_list(self, modules: T.List[T.Tuple[str, bool]]) -> T.List[T.Tuple[str, bool]]:
        res = []
        for mod, required in modules:
            cm_targets = self.traceparser.get_cmake_var('MESON_LLVM_TARGETS_{}'.format(mod))
            if not cm_targets:
                if required:
                    raise self._gen_exception('LLVM module {} was not found'.format(mod))
                else:
                    mlog.warning('Optional LLVM module', mlog.bold(mod), 'was not found')
                    continue
            for i in cm_targets:
                res += [(i, required)]
        return res

    def _original_module_name(self, module: str) -> str:
        orig_name = self.traceparser.get_cmake_var('MESON_TARGET_TO_LLVM_{}'.format(module))
        if orig_name:
            return orig_name[0]
        return module

class LLVMDependency(ExternalDependency):
    def __init__(self, env, kwargs):
        super().__init__('LLVM', env, 'cpp', kwargs)

    @classmethod
    def _factory(cls, env, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.CONFIG_TOOL in methods:
            candidates.append(functools.partial(LLVMDependencyConfigTool, env, kwargs))

        if DependencyMethods.CMAKE in methods:
            candidates.append(functools.partial(LLVMDependencyCMake, env, kwargs))

        return candidates

    @staticmethod
    def get_methods():
        return [DependencyMethods.CMAKE, DependencyMethods.CONFIG_TOOL]

class ValgrindDependency(PkgConfigDependency):
    '''
    Consumers of Valgrind usually only need the compile args and do not want to
    link to its (static) libraries.
    '''
    def __init__(self, env, kwargs):
        super().__init__('valgrind', env, kwargs)

    def get_link_args(self, **kwargs):
        return []
meson-0.53.2/mesonbuild/dependencies/hdf5.py0000644000175000017500000001364313612313307022311 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for miscellaneous external dependencies.

import subprocess
import shutil
from pathlib import Path

from .. import mlog
from ..mesonlib import split_args, listify
from .base import (DependencyException, DependencyMethods, ExternalDependency, ExternalProgram,
                   PkgConfigDependency)

class HDF5Dependency(ExternalDependency):

    def __init__(self, environment, kwargs):
        language = kwargs.get('language', 'c')
        super().__init__('hdf5', environment, language, kwargs)
        kwargs['required'] = False
        kwargs['silent'] = True
        self.is_found = False
        methods = listify(self.methods)

        if language not in ('c', 'cpp', 'fortran'):
            raise DependencyException('Language {} is not supported with HDF5.'.format(language))

        if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
            pkgconfig_files = ['hdf5', 'hdf5-serial']
            PCEXE = shutil.which('pkg-config')
            if PCEXE:
                # some distros put hdf5-1.2.3.pc with version number in .pc filename.
                ret = subprocess.run([PCEXE, '--list-all'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
                                     universal_newlines=True)
                if ret.returncode == 0:
                    for pkg in ret.stdout.split('\n'):
                        if pkg.startswith(('hdf5')):
                            pkgconfig_files.append(pkg.split(' ', 1)[0])
                    pkgconfig_files = list(set(pkgconfig_files))  # dedupe

            for pkg in pkgconfig_files:
                pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
                if not pkgdep.found():
                    continue

                self.compile_args = pkgdep.get_compile_args()
                # some broken pkgconfig don't actually list the full path to the needed includes
                newinc = []
                for arg in self.compile_args:
                    if arg.startswith('-I'):
                        stem = 'static' if kwargs.get('static', False) else 'shared'
                        if (Path(arg[2:]) / stem).is_dir():
                            newinc.append('-I' + str(Path(arg[2:]) / stem))
                self.compile_args += newinc

                # derive needed libraries by language
                pd_link_args = pkgdep.get_link_args()
                link_args = []
                for larg in pd_link_args:
                    lpath = Path(larg)
                    # some pkg-config hdf5.pc (e.g. Ubuntu) don't include the commonly-used HL HDF5 libraries,
                    # so let's add them if they exist
                    # additionally, some pkgconfig HDF5 HL files are malformed so let's be sure to find HL anyway
                    if lpath.is_file():
                        hl = []
                        if language == 'cpp':
                            hl += ['_hl_cpp', '_cpp']
                        elif language == 'fortran':
                            hl += ['_hl_fortran', 'hl_fortran', '_fortran']
                        hl += ['_hl']  # C HL library, always needed

                        suffix = '.' + lpath.name.split('.', 1)[1]  # in case of .dll.a
                        for h in hl:
                            hlfn = lpath.parent / (lpath.name.split('.', 1)[0] + h + suffix)
                            if hlfn.is_file():
                                link_args.append(str(hlfn))
                        # HDF5 C libs are required by other HDF5 languages
                        link_args.append(larg)
                    else:
                        link_args.append(larg)

                self.link_args = link_args
                self.version = pkgdep.get_version()
                self.is_found = True
                self.pcdep = pkgdep
                return

        if DependencyMethods.AUTO in methods:
            wrappers = {'c': 'h5cc', 'cpp': 'h5c++', 'fortran': 'h5fc'}
            comp_args = []
            link_args = []
            # have to always do C as well as desired language
            for lang in set([language, 'c']):
                prog = ExternalProgram(wrappers[lang], silent=True)
                if not prog.found():
                    return
                cmd = prog.get_command() + ['-show']
                p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15)
                if p.returncode != 0:
                    mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
                    mlog.debug(mlog.bold('Standard output\n'), p.stdout)
                    mlog.debug(mlog.bold('Standard error\n'), p.stderr)
                    return
                args = split_args(p.stdout)
                for arg in args[1:]:
                    if arg.startswith(('-I', '-f', '-D')) or arg == '-pthread':
                        comp_args.append(arg)
                    elif arg.startswith(('-L', '-l', '-Wl')):
                        link_args.append(arg)
                    elif Path(arg).is_file():
                        link_args.append(arg)
            self.compile_args = comp_args
            self.link_args = link_args
            self.is_found = True
            return

    @staticmethod
    def get_methods():
        return [DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]
meson-0.53.2/mesonbuild/dependencies/misc.py0000644000175000017500000005253013612417061022416 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for miscellaneous external dependencies.

from pathlib import Path
import functools
import re
import sysconfig

from .. import mlog
from .. import mesonlib
from ..environment import detect_cpu_family
from ..mesonlib import listify

from .base import (
    DependencyException, DependencyMethods, ExternalDependency,
    ExtraFrameworkDependency, PkgConfigDependency,
    CMakeDependency, ConfigToolDependency,
)


class NetCDFDependency(ExternalDependency):

    def __init__(self, environment, kwargs):
        language = kwargs.get('language', 'c')
        super().__init__('netcdf', environment, language, kwargs)
        kwargs['required'] = False
        kwargs['silent'] = True
        self.is_found = False
        methods = listify(self.methods)

        if language not in ('c', 'cpp', 'fortran'):
            raise DependencyException('Language {} is not supported with NetCDF.'.format(language))

        if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
            pkgconfig_files = ['netcdf']

            if language == 'fortran':
                pkgconfig_files.append('netcdf-fortran')

            self.compile_args = []
            self.link_args = []
            self.pcdep = []
            for pkg in pkgconfig_files:
                pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
                if pkgdep.found():
                    self.compile_args.extend(pkgdep.get_compile_args())
                    self.link_args.extend(pkgdep.get_link_args())
                    self.version = pkgdep.get_version()
                    self.is_found = True
                    self.pcdep.append(pkgdep)
            if self.is_found:
                return

        if set([DependencyMethods.AUTO, DependencyMethods.CMAKE]).intersection(methods):
            cmakedep = CMakeDependency('NetCDF', environment, kwargs, language=self.language)
            if cmakedep.found():
                self.compile_args = cmakedep.get_compile_args()
                self.link_args = cmakedep.get_link_args()
                self.version = cmakedep.get_version()
                self.is_found = True
                return

    @staticmethod
    def get_methods():
        return [DependencyMethods.AUTO, DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE]


class OpenMPDependency(ExternalDependency):
    # Map date of specification release (which is the macro value) to a version.
    VERSIONS = {
        '201811': '5.0',
        '201611': '5.0-revision1',  # This is supported by ICC 19.x
        '201511': '4.5',
        '201307': '4.0',
        '201107': '3.1',
        '200805': '3.0',
        '200505': '2.5',
        '200203': '2.0',
        '199810': '1.0',
    }

    def __init__(self, environment, kwargs):
        language = kwargs.get('language')
        super().__init__('openmp', environment, language, kwargs)
        self.is_found = False
        if self.clib_compiler.get_id() == 'pgi':
            # through at least PGI 19.4, there is no macro defined for OpenMP, but OpenMP 3.1 is supported.
            self.version = '3.1'
            self.is_found = True
            self.compile_args = self.link_args = self.clib_compiler.openmp_flags()
            return
        try:
            openmp_date = self.clib_compiler.get_define(
                '_OPENMP', '', self.env, self.clib_compiler.openmp_flags(), [self], disable_cache=True)[0]
        except mesonlib.EnvironmentException as e:
            mlog.debug('OpenMP support not available in the compiler')
            mlog.debug(e)
            openmp_date = None

        if openmp_date:
            self.version = self.VERSIONS[openmp_date]
            # Flang has omp_lib.h
            header_names = ('omp.h', 'omp_lib.h')
            for name in header_names:
                if self.clib_compiler.has_header(name, '', self.env, dependencies=[self], disable_cache=True)[0]:
                    self.is_found = True
                    self.compile_args = self.link_args = self.clib_compiler.openmp_flags()
                    break
            if not self.is_found:
                mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.')


class ThreadDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('threads', environment, None, kwargs)
        self.name = 'threads'
        self.is_found = False
        methods = listify(self.methods)
        if DependencyMethods.AUTO in methods:
            self.is_found = True
            # Happens if you are using a language with threads
            # concept without C, such as plain Cuda.
            if self.clib_compiler is None:
                self.compile_args = []
                self.link_args = []
            else:
                self.compile_args = self.clib_compiler.thread_flags(environment)
                self.link_args = self.clib_compiler.thread_link_flags(environment)
            return

        if DependencyMethods.CMAKE in methods:
            # for unit tests and for those who simply want
            # dependency('threads', method: 'cmake')
            cmakedep = CMakeDependency('Threads', environment, kwargs)
            if cmakedep.found():
                self.compile_args = cmakedep.get_compile_args()
                self.link_args = cmakedep.get_link_args()
                self.version = cmakedep.get_version()
                self.is_found = True
                return

    @staticmethod
    def get_methods():
        return [DependencyMethods.AUTO, DependencyMethods.CMAKE]


class BlocksDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('blocks', environment, None, kwargs)
        self.name = 'blocks'
        self.is_found = False

        if self.env.machines[self.for_machine].is_darwin():
            self.compile_args = []
            self.link_args = []
        else:
            self.compile_args = ['-fblocks']
            self.link_args = ['-lBlocksRuntime']

            if not self.clib_compiler.has_header('Block.h', '', environment, disable_cache=True) or \
               not self.clib_compiler.find_library('BlocksRuntime', environment, []):
                mlog.log(mlog.red('ERROR:'), 'BlocksRuntime not found.')
                return

        source = '''
            int main(int argc, char **argv)
            {
                int (^callback)(void) = ^ int (void) { return 0; };
                return callback();
            }'''

        with self.clib_compiler.compile(source, extra_args=self.compile_args + self.link_args) as p:
            if p.returncode != 0:
                mlog.log(mlog.red('ERROR:'), 'Compiler does not support blocks extension.')
                return

            self.is_found = True


class Python3Dependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('python3', environment, None, kwargs)

        if not environment.machines.matches_build_machine(self.for_machine):
            return

        self.name = 'python3'
        self.static = kwargs.get('static', False)
        # We can only be sure that it is Python 3 at this point
        self.version = '3'
        self._find_libpy3_windows(environment)

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'python3', environment, kwargs))

        if DependencyMethods.SYSCONFIG in methods:
            candidates.append(functools.partial(Python3Dependency, environment, kwargs))

        if DependencyMethods.EXTRAFRAMEWORK in methods:
            # In OSX the Python 3 framework does not have a version
            # number in its name.
            # There is a python in /System/Library/Frameworks, but that's
            # python 2, Python 3 will always be in /Library
            candidates.append(functools.partial(
                ExtraFrameworkDependency, 'Python', False, ['/Library/Frameworks'],
                environment, kwargs.get('language', None), kwargs))

        return candidates

    @staticmethod
    def get_windows_python_arch():
        pyplat = sysconfig.get_platform()
        if pyplat == 'mingw':
            pycc = sysconfig.get_config_var('CC')
            if pycc.startswith('x86_64'):
                return '64'
            elif pycc.startswith(('i686', 'i386')):
                return '32'
            else:
                mlog.log('MinGW Python built with unknown CC {!r}, please file'
                         'a bug'.format(pycc))
                return None
        elif pyplat == 'win32':
            return '32'
        elif pyplat in ('win64', 'win-amd64'):
            return '64'
        mlog.log('Unknown Windows Python platform {!r}'.format(pyplat))
        return None

    def get_windows_link_args(self):
        pyplat = sysconfig.get_platform()
        if pyplat.startswith('win'):
            vernum = sysconfig.get_config_var('py_version_nodot')
            if self.static:
                libpath = Path('libs') / 'libpython{}.a'.format(vernum)
            else:
                comp = self.get_compiler()
                if comp.id == "gcc":
                    libpath = 'python{}.dll'.format(vernum)
                else:
                    libpath = Path('libs') / 'python{}.lib'.format(vernum)
            lib = Path(sysconfig.get_config_var('base')) / libpath
        elif pyplat == 'mingw':
            if self.static:
                libname = sysconfig.get_config_var('LIBRARY')
            else:
                libname = sysconfig.get_config_var('LDLIBRARY')
            lib = Path(sysconfig.get_config_var('LIBDIR')) / libname
        if not lib.exists():
            mlog.log('Could not find Python3 library {!r}'.format(str(lib)))
            return None
        return [str(lib)]

    def _find_libpy3_windows(self, env):
        '''
        Find python3 libraries on Windows and also verify that the arch matches
        what we are building for.
        '''
        pyarch = self.get_windows_python_arch()
        if pyarch is None:
            self.is_found = False
            return
        arch = detect_cpu_family(env.coredata.compilers.host)
        if arch == 'x86':
            arch = '32'
        elif arch == 'x86_64':
            arch = '64'
        else:
            # We can't cross-compile Python 3 dependencies on Windows yet
            mlog.log('Unknown architecture {!r} for'.format(arch),
                     mlog.bold(self.name))
            self.is_found = False
            return
        # Pyarch ends in '32' or '64'
        if arch != pyarch:
            mlog.log('Need', mlog.bold(self.name), 'for {}-bit, but '
                     'found {}-bit'.format(arch, pyarch))
            self.is_found = False
            return
        # This can fail if the library is not found
        largs = self.get_windows_link_args()
        if largs is None:
            self.is_found = False
            return
        self.link_args = largs
        # Compile args
        inc = sysconfig.get_path('include')
        platinc = sysconfig.get_path('platinclude')
        self.compile_args = ['-I' + inc]
        if inc != platinc:
            self.compile_args.append('-I' + platinc)
        self.version = sysconfig.get_config_var('py_version')
        self.is_found = True

    @staticmethod
    def get_methods():
        if mesonlib.is_windows():
            return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSCONFIG]
        elif mesonlib.is_osx():
            return [DependencyMethods.PKGCONFIG, DependencyMethods.EXTRAFRAMEWORK]
        else:
            return [DependencyMethods.PKGCONFIG]

    def log_tried(self):
        return 'sysconfig'

class PcapDependency(ExternalDependency):

    def __init__(self, environment, kwargs):
        super().__init__('pcap', environment, None, kwargs)

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'pcap', environment, kwargs))

        if DependencyMethods.CONFIG_TOOL in methods:
            candidates.append(functools.partial(ConfigToolDependency.factory,
                                                'pcap', environment, None,
                                                kwargs, ['pcap-config'],
                                                'pcap-config',
                                                PcapDependency.tool_finish_init))

        return candidates

    @staticmethod
    def tool_finish_init(ctdep):
        ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
        ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
        ctdep.version = PcapDependency.get_pcap_lib_version(ctdep)

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]

    @staticmethod
    def get_pcap_lib_version(ctdep):
        # Since we seem to need to run a program to discover the pcap version,
        # we can't do that when cross-compiling
        if not ctdep.env.machines.matches_build_machine(ctdep.for_machine):
            return None

        v = ctdep.clib_compiler.get_return_value('pcap_lib_version', 'string',
                                                 '#include ', ctdep.env, [], [ctdep])
        v = re.sub(r'libpcap version ', '', v)
        v = re.sub(r' -- Apple version.*$', '', v)
        return v


class CupsDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('cups', environment, None, kwargs)

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'cups', environment, kwargs))

        if DependencyMethods.CONFIG_TOOL in methods:
            candidates.append(functools.partial(ConfigToolDependency.factory,
                                                'cups', environment, None,
                                                kwargs, ['cups-config'],
                                                'cups-config', CupsDependency.tool_finish_init))

        if DependencyMethods.EXTRAFRAMEWORK in methods:
            if mesonlib.is_osx():
                candidates.append(functools.partial(
                    ExtraFrameworkDependency, 'cups', False, None, environment,
                    kwargs.get('language', None), kwargs))

        if DependencyMethods.CMAKE in methods:
            candidates.append(functools.partial(CMakeDependency, 'Cups', environment, kwargs))

        return candidates

    @staticmethod
    def tool_finish_init(ctdep):
        ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
        ctdep.link_args = ctdep.get_config_value(['--ldflags', '--libs'], 'link_args')

    @staticmethod
    def get_methods():
        if mesonlib.is_osx():
            return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE]
        else:
            return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.CMAKE]


class LibWmfDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('libwmf', environment, None, kwargs)

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'libwmf', environment, kwargs))

        if DependencyMethods.CONFIG_TOOL in methods:
            candidates.append(functools.partial(ConfigToolDependency.factory,
                                                'libwmf', environment, None, kwargs, ['libwmf-config'], 'libwmf-config', LibWmfDependency.tool_finish_init))

        return candidates

    @staticmethod
    def tool_finish_init(ctdep):
        ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
        ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]


class LibGCryptDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('libgcrypt', environment, None, kwargs)

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'libgcrypt', environment, kwargs))

        if DependencyMethods.CONFIG_TOOL in methods:
            candidates.append(functools.partial(ConfigToolDependency.factory,
                                                'libgcrypt', environment, None, kwargs, ['libgcrypt-config'],
                                                'libgcrypt-config',
                                                LibGCryptDependency.tool_finish_init))

        return candidates

    @staticmethod
    def tool_finish_init(ctdep):
        ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
        ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
        ctdep.version = ctdep.get_config_value(['--version'], 'version')[0]

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]


class GpgmeDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('gpgme', environment, None, kwargs)

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'gpgme', environment, kwargs))

        if DependencyMethods.CONFIG_TOOL in methods:
            candidates.append(functools.partial(ConfigToolDependency.factory,
                                                'gpgme', environment, None, kwargs, ['gpgme-config'],
                                                'gpgme-config',
                                                GpgmeDependency.tool_finish_init))

        return candidates

    @staticmethod
    def tool_finish_init(ctdep):
        ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
        ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
        ctdep.version = ctdep.get_config_value(['--version'], 'version')[0]

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]


class ShadercDependency(ExternalDependency):

    def __init__(self, environment, kwargs):
        super().__init__('shaderc', environment, None, kwargs)

        static_lib = 'shaderc_combined'
        shared_lib = 'shaderc_shared'

        libs = [shared_lib, static_lib]
        if self.static:
            libs.reverse()

        cc = self.get_compiler()

        for lib in libs:
            self.link_args = cc.find_library(lib, environment, [])
            if self.link_args is not None:
                self.is_found = True

                if self.static and lib != static_lib:
                    mlog.warning('Static library {!r} not found for dependency {!r}, may '
                                 'not be statically linked'.format(static_lib, self.name))

                break

    def log_tried(self):
        return 'system'

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            # ShaderC packages their shared and static libs together
            # and provides different pkg-config files for each one. We
            # smooth over this difference by handling the static
            # keyword before handing off to the pkg-config handler.
            shared_libs = ['shaderc']
            static_libs = ['shaderc_combined', 'shaderc_static']

            if kwargs.get('static', False):
                c = [functools.partial(PkgConfigDependency, name, environment, kwargs)
                     for name in static_libs + shared_libs]
            else:
                c = [functools.partial(PkgConfigDependency, name, environment, kwargs)
                     for name in shared_libs + static_libs]
            candidates.extend(c)

        if DependencyMethods.SYSTEM in methods:
            candidates.append(functools.partial(ShadercDependency, environment, kwargs))

        return candidates

    @staticmethod
    def get_methods():
        return [DependencyMethods.SYSTEM, DependencyMethods.PKGCONFIG]
meson-0.53.2/mesonbuild/dependencies/mpi.py0000644000175000017500000002623513612313307022251 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import typing as T
import os
import re
import subprocess

from .. import mlog
from .. import mesonlib
from ..mesonlib import split_args, listify
from ..environment import detect_cpu_family
from .base import (DependencyException, DependencyMethods, ExternalDependency, ExternalProgram,
                   PkgConfigDependency)


class MPIDependency(ExternalDependency):

    def __init__(self, environment, kwargs: dict):
        language = kwargs.get('language', 'c')
        super().__init__('mpi', environment, language, kwargs)
        kwargs['required'] = False
        kwargs['silent'] = True
        self.is_found = False
        methods = listify(self.methods)

        env_vars = []
        default_wrappers = []
        pkgconfig_files = []
        if language == 'c':
            cid = environment.detect_c_compiler(self.for_machine).get_id()
            if cid in ('intel', 'intel-cl'):
                env_vars.append('I_MPI_CC')
                # IntelMPI doesn't have .pc files
                default_wrappers.append('mpiicc')
            else:
                env_vars.append('MPICC')
                pkgconfig_files.append('ompi-c')
            default_wrappers.append('mpicc')
        elif language == 'cpp':
            cid = environment.detect_cpp_compiler(self.for_machine).get_id()
            if cid in ('intel', 'intel-cl'):
                env_vars.append('I_MPI_CXX')
                # IntelMPI doesn't have .pc files
                default_wrappers.append('mpiicpc')
            else:
                env_vars.append('MPICXX')
                pkgconfig_files.append('ompi-cxx')
                default_wrappers += ['mpic++', 'mpicxx', 'mpiCC']  # these are not for intelmpi
        elif language == 'fortran':
            cid = environment.detect_fortran_compiler(self.for_machine).get_id()
            if cid in ('intel', 'intel-cl'):
                env_vars.append('I_MPI_F90')
                # IntelMPI doesn't have .pc files
                default_wrappers.append('mpiifort')
            else:
                env_vars += ['MPIFC', 'MPIF90', 'MPIF77']
                pkgconfig_files.append('ompi-fort')
            default_wrappers += ['mpifort', 'mpif90', 'mpif77']
        else:
            raise DependencyException('Language {} is not supported with MPI.'.format(language))

        if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
            for pkg in pkgconfig_files:
                pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
                if pkgdep.found():
                    self.compile_args = pkgdep.get_compile_args()
                    self.link_args = pkgdep.get_link_args()
                    self.version = pkgdep.get_version()
                    self.is_found = True
                    self.pcdep = pkgdep
                    return

        if DependencyMethods.AUTO in methods:
            for var in env_vars:
                if var in os.environ:
                    wrappers = [os.environ[var]]
                    break
            else:
                # Or search for default wrappers.
                wrappers = default_wrappers

            for prog in wrappers:
                # Note: Some use OpenMPI with Intel compilers on Linux
                result = self._try_openmpi_wrapper(prog, cid)
                if result is not None:
                    self.is_found = True
                    self.version = result[0]
                    self.compile_args = self._filter_compile_args(result[1])
                    self.link_args = self._filter_link_args(result[2], cid)
                    break
                result = self._try_other_wrapper(prog, cid)
                if result is not None:
                    self.is_found = True
                    self.version = result[0]
                    self.compile_args = self._filter_compile_args(result[1])
                    self.link_args = self._filter_link_args(result[2], cid)
                    break

            if not self.is_found and mesonlib.is_windows():
                # only Intel Fortran compiler is compatible with Microsoft MPI at this time.
                if language == 'fortran' and cid != 'intel-cl':
                    return
                result = self._try_msmpi()
                if result is not None:
                    self.is_found = True
                    self.version, self.compile_args, self.link_args = result
            return

    def _filter_compile_args(self, args: T.Sequence[str]) -> T.List[str]:
        """
        MPI wrappers return a bunch of garbage args.
        Drop -O2 and everything that is not needed.
        """
        result = []
        multi_args = ('-I', )
        if self.language == 'fortran':
            fc = self.env.coredata.compilers[self.for_machine]['fortran']
            multi_args += fc.get_module_incdir_args()

        include_next = False
        for f in args:
            if f.startswith(('-D', '-f') + multi_args) or f == '-pthread' \
                    or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')):
                result.append(f)
                if f in multi_args:
                    # Path is a separate argument.
                    include_next = True
            elif include_next:
                include_next = False
                result.append(f)
        return result

    def _filter_link_args(self, args: T.Sequence[str], cid: str) -> T.List[str]:
        """
        MPI wrappers return a bunch of garbage args.
        Drop -O2 and everything that is not needed.
        """
        result = []
        include_next = False
        for f in args:
            if self._is_link_arg(f, cid):
                result.append(f)
                if f in ('-L', '-Xlinker'):
                    include_next = True
            elif include_next:
                include_next = False
                result.append(f)
        return result

    @staticmethod
    def _is_link_arg(f: str, cid: str) -> bool:
        if cid == 'intel-cl':
            return f == '/link' or f.startswith('/LIBPATH') or f.endswith('.lib')   # always .lib whether static or dynamic
        else:
            return (f.startswith(('-L', '-l', '-Xlinker')) or
                    f == '-pthread' or
                    (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')))

    def _try_openmpi_wrapper(self, prog, cid: str):
        # https://www.open-mpi.org/doc/v4.0/man1/mpifort.1.php
        if cid == 'intel-cl':  # IntelCl doesn't support OpenMPI
            return None
        prog = ExternalProgram(prog, silent=True)
        if not prog.found():
            return None

        # compiler args
        cmd = prog.get_command() + ['--showme:compile']
        p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15)
        if p.returncode != 0:
            mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
            mlog.debug(mlog.bold('Standard output\n'), p.stdout)
            mlog.debug(mlog.bold('Standard error\n'), p.stderr)
            return None
        cargs = split_args(p.stdout)
        # link args
        cmd = prog.get_command() + ['--showme:link']
        p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15)
        if p.returncode != 0:
            mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
            mlog.debug(mlog.bold('Standard output\n'), p.stdout)
            mlog.debug(mlog.bold('Standard error\n'), p.stderr)
            return None
        libs = split_args(p.stdout)
        # version
        cmd = prog.get_command() + ['--showme:version']
        p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15)
        if p.returncode != 0:
            mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
            mlog.debug(mlog.bold('Standard output\n'), p.stdout)
            mlog.debug(mlog.bold('Standard error\n'), p.stderr)
            return None
        v = re.search(r'\d+.\d+.\d+', p.stdout)
        if v:
            version = v.group(0)
        else:
            version = None

        return version, cargs, libs

    def _try_other_wrapper(self, prog, cid: str) -> T.Tuple[str, T.List[str], T.List[str]]:
        prog = ExternalProgram(prog, silent=True)
        if not prog.found():
            return None

        cmd = prog.get_command()
        if cid == 'intel-cl':
            cmd.append('/show')
        else:
            cmd.append('-show')
        p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15)
        if p.returncode != 0:
            mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
            mlog.debug(mlog.bold('Standard output\n'), p.stdout)
            mlog.debug(mlog.bold('Standard error\n'), p.stderr)
            return None

        version = None
        stdout = p.stdout
        if 'Intel(R) MPI Library' in p.stdout:  # intel-cl: remove messy compiler logo
            out = stdout.split('\n', 2)
            version = out[0]
            stdout = out[2]

        if version is None:
            p = subprocess.run(cmd + ['-v'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15)
            if p.returncode == 0:
                version = p.stdout.split('\n', 1)[0]

        args = split_args(stdout)

        return version, args, args

    def _try_msmpi(self) -> T.Tuple[str, T.List[str], T.List[str]]:
        if self.language == 'cpp':
            # MS-MPI does not support the C++ version of MPI, only the standard C API.
            return None
        if 'MSMPI_INC' not in os.environ:
            return None

        incdir = os.environ['MSMPI_INC']
        arch = detect_cpu_family(self.env.coredata.compilers.host)
        if arch == 'x86':
            if 'MSMPI_LIB32' not in os.environ:
                return None
            libdir = os.environ['MSMPI_LIB32']
            post = 'x86'
        elif arch == 'x86_64':
            if 'MSMPI_LIB64' not in os.environ:
                return None
            libdir = os.environ['MSMPI_LIB64']
            post = 'x64'
        else:
            return None

        if self.language == 'fortran':
            return (None,
                    ['-I' + incdir, '-I' + os.path.join(incdir, post)],
                    [os.path.join(libdir, 'msmpi.lib'), os.path.join(libdir, 'msmpifec.lib')])
        else:
            return (None,
                    ['-I' + incdir, '-I' + os.path.join(incdir, post)],
                    [os.path.join(libdir, 'msmpi.lib')])

    @staticmethod
    def get_methods():
        return [DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]
meson-0.53.2/mesonbuild/dependencies/platform.py0000644000175000017500000000403713462637046023320 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for external dependencies that are
# platform-specific (generally speaking).

from .base import ExternalDependency, DependencyException
from ..mesonlib import MesonException

class AppleFrameworks(ExternalDependency):
    def __init__(self, env, kwargs):
        super().__init__('appleframeworks', env, None, kwargs)
        modules = kwargs.get('modules', [])
        if isinstance(modules, str):
            modules = [modules]
        if not modules:
            raise DependencyException("AppleFrameworks dependency requires at least one module.")
        self.frameworks = modules
        if not self.clib_compiler:
            raise DependencyException('No C-like compilers are available, cannot find the framework')
        self.is_found = True
        for f in self.frameworks:
            try:
                args = self.clib_compiler.find_framework(f, env, [])
            except MesonException as e:
                if 'non-clang' in str(e):
                    self.is_found = False
                    self.link_args = []
                    self.compile_args = []
                    return
                raise

            if args is not None:
                # No compile args are needed for system frameworks
                self.link_args += args
            else:
                self.is_found = False

    def log_info(self):
        return ', '.join(self.frameworks)

    def log_tried(self):
        return 'framework'
meson-0.53.2/mesonbuild/dependencies/scalapack.py0000644000175000017500000001236713602226377023420 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from pathlib import Path
import os

from .. import mesonlib
from .base import CMakeDependency, DependencyMethods, ExternalDependency, PkgConfigDependency


class ScalapackDependency(ExternalDependency):
    def __init__(self, environment, kwargs: dict):
        super().__init__('scalapack', environment, None, kwargs)
        kwargs['required'] = False
        kwargs['silent'] = True
        self.is_found = False
        self.static = kwargs.get('static', False)
        methods = mesonlib.listify(self.methods)

        if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
            pkgconfig_files = []
            mklroot = None
            is_gcc = self.clib_compiler.get_id() == 'gcc'
            # Intel MKL works with non-Intel compilers too -- but not gcc on windows
            if 'MKLROOT' in os.environ and not (mesonlib.is_windows() and is_gcc):
                try:
                    mklroot = Path(os.environ['MKLROOT']).resolve()
                except Exception:
                    pass
            if mklroot is not None:
                # MKL pkg-config is a start, but you have to add / change stuff
                # https://software.intel.com/en-us/articles/intel-math-kernel-library-intel-mkl-and-pkg-config-tool
                pkgconfig_files = (
                    ['mkl-static-lp64-iomp'] if self.static else ['mkl-dynamic-lp64-iomp']
                )
                if mesonlib.is_windows():
                    suffix = '.lib'
                elif self.static:
                    suffix = '.a'
                else:
                    suffix = ''
                libdir = mklroot / 'lib/intel64'
            # Intel compiler might not have Parallel Suite
            pkgconfig_files += ['scalapack-openmpi', 'scalapack']

            for pkg in pkgconfig_files:
                pkgdep = PkgConfigDependency(
                    pkg, environment, kwargs, language=self.language
                )
                if pkgdep.found():
                    self.compile_args = pkgdep.get_compile_args()
                    if mklroot:
                        link_args = pkgdep.get_link_args()
                        if is_gcc:
                            for i, a in enumerate(link_args):
                                if 'mkl_intel_lp64' in a:
                                    link_args[i] = a.replace('intel', 'gf')
                                    break
                        # MKL pkg-config omits scalapack
                        # be sure "-L" and "-Wl" are first if present
                        i = 0
                        for j, a in enumerate(link_args):
                            if a.startswith(('-L', '-Wl')):
                                i = j + 1
                            elif j > 3:
                                break
                        if mesonlib.is_windows() or self.static:
                            link_args.insert(
                                i, str(libdir / ('mkl_scalapack_lp64' + suffix))
                            )
                            link_args.insert(
                                i + 1, str(libdir / ('mkl_blacs_intelmpi_lp64' + suffix))
                            )
                        else:
                            link_args.insert(i, '-lmkl_scalapack_lp64')
                            link_args.insert(i + 1, '-lmkl_blacs_intelmpi_lp64')
                    else:
                        link_args = pkgdep.get_link_args()
                    self.link_args = link_args

                    self.version = pkgdep.get_version()
                    if self.version == 'unknown' and mklroot:
                        try:
                            v = (
                                mklroot.as_posix()
                                .split('compilers_and_libraries_')[1]
                                .split('/', 1)[0]
                            )
                            if v:
                                self.version = v
                        except IndexError:
                            pass

                    self.is_found = True
                    self.pcdep = pkgdep
                    return

        if set([DependencyMethods.AUTO, DependencyMethods.CMAKE]).intersection(methods):
            cmakedep = CMakeDependency('Scalapack', environment, kwargs, language=self.language)
            if cmakedep.found():
                self.compile_args = cmakedep.get_compile_args()
                self.link_args = cmakedep.get_link_args()
                self.version = cmakedep.get_version()
                self.is_found = True
                return

    @staticmethod
    def get_methods():
        return [DependencyMethods.AUTO, DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE]
meson-0.53.2/mesonbuild/dependencies/ui.py0000644000175000017500000006566313612313307022111 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for external dependencies that
# are UI-related.
import functools
import os
import re
import subprocess
from collections import OrderedDict

from .. import mlog
from .. import mesonlib
from ..mesonlib import (
    MesonException, Popen_safe, extract_as_list, version_compare_many
)
from ..environment import detect_cpu_family

from .base import DependencyException, DependencyMethods
from .base import ExternalDependency, ExternalProgram, NonExistingExternalProgram
from .base import ExtraFrameworkDependency, PkgConfigDependency
from .base import ConfigToolDependency


class GLDependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('gl', environment, None, kwargs)

        if self.env.machines[self.for_machine].is_darwin():
            self.is_found = True
            # FIXME: Use AppleFrameworks dependency
            self.link_args = ['-framework', 'OpenGL']
            # FIXME: Detect version using self.clib_compiler
            return
        if self.env.machines[self.for_machine].is_windows():
            self.is_found = True
            # FIXME: Use self.clib_compiler.find_library()
            self.link_args = ['-lopengl32']
            # FIXME: Detect version using self.clib_compiler
            return

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'gl', environment, kwargs))

        if DependencyMethods.SYSTEM in methods:
            candidates.append(functools.partial(GLDependency, environment, kwargs))

        return candidates

    @staticmethod
    def get_methods():
        if mesonlib.is_osx() or mesonlib.is_windows():
            return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]
        else:
            return [DependencyMethods.PKGCONFIG]

    def log_tried(self):
        return 'system'

class GnuStepDependency(ConfigToolDependency):

    tools = ['gnustep-config']
    tool_name = 'gnustep-config'

    def __init__(self, environment, kwargs):
        super().__init__('gnustep', environment, 'objc', kwargs)
        if not self.is_found:
            return
        self.modules = kwargs.get('modules', [])
        self.compile_args = self.filter_args(
            self.get_config_value(['--objc-flags'], 'compile_args'))
        self.link_args = self.weird_filter(self.get_config_value(
            ['--gui-libs' if 'gui' in self.modules else '--base-libs'],
            'link_args'))

    def find_config(self, versions=None):
        tool = [self.tools[0]]
        try:
            p, out = Popen_safe(tool + ['--help'])[:2]
        except (FileNotFoundError, PermissionError):
            return (None, None)
        if p.returncode != 0:
            return (None, None)
        self.config = tool
        found_version = self.detect_version()
        if versions and not version_compare_many(found_version, versions)[0]:
            return (None, found_version)

        return (tool, found_version)

    def weird_filter(self, elems):
        """When building packages, the output of the enclosing Make is
        sometimes mixed among the subprocess output. I have no idea why. As a
        hack filter out everything that is not a flag.
        """
        return [e for e in elems if e.startswith('-')]

    def filter_args(self, args):
        """gnustep-config returns a bunch of garbage args such as -O2 and so
        on. Drop everything that is not needed.
        """
        result = []
        for f in args:
            if f.startswith('-D') \
                    or f.startswith('-f') \
                    or f.startswith('-I') \
                    or f == '-pthread' \
                    or (f.startswith('-W') and not f == '-Wall'):
                result.append(f)
        return result

    def detect_version(self):
        gmake = self.get_config_value(['--variable=GNUMAKE'], 'variable')[0]
        makefile_dir = self.get_config_value(['--variable=GNUSTEP_MAKEFILES'], 'variable')[0]
        # This Makefile has the GNUStep version set
        base_make = os.path.join(makefile_dir, 'Additional', 'base.make')
        # Print the Makefile variable passed as the argument. For instance, if
        # you run the make target `print-SOME_VARIABLE`, this will print the
        # value of the variable `SOME_VARIABLE`.
        printver = "print-%:\n\t@echo '$($*)'"
        env = os.environ.copy()
        # See base.make to understand why this is set
        env['FOUNDATION_LIB'] = 'gnu'
        p, o, e = Popen_safe([gmake, '-f', '-', '-f', base_make,
                              'print-GNUSTEP_BASE_VERSION'],
                             env=env, write=printver, stdin=subprocess.PIPE)
        version = o.strip()
        if not version:
            mlog.debug("Couldn't detect GNUStep version, falling back to '1'")
            # Fallback to setting some 1.x version
            version = '1'
        return version


def _qt_get_private_includes(mod_inc_dir, module, mod_version):
    # usually Qt5 puts private headers in /QT_INSTALL_HEADERS/module/VERSION/module/private
    # except for at least QtWebkit and Enginio where the module version doesn't match Qt version
    # as an example with Qt 5.10.1 on linux you would get:
    # /usr/include/qt5/QtCore/5.10.1/QtCore/private/
    # /usr/include/qt5/QtWidgets/5.10.1/QtWidgets/private/
    # /usr/include/qt5/QtWebKit/5.212.0/QtWebKit/private/

    # on Qt4 when available private folder is directly in module folder
    # like /usr/include/QtCore/private/
    if int(mod_version.split('.')[0]) < 5:
        return tuple()

    private_dir = os.path.join(mod_inc_dir, mod_version)
    # fallback, let's try to find a directory with the latest version
    if not os.path.exists(private_dir):
        dirs = [filename for filename in os.listdir(mod_inc_dir)
                if os.path.isdir(os.path.join(mod_inc_dir, filename))]
        dirs.sort(reverse=True)

        for dirname in dirs:
            if len(dirname.split('.')) == 3:
                private_dir = dirname
                break
    return (private_dir,
            os.path.join(private_dir, 'Qt' + module))

class QtExtraFrameworkDependency(ExtraFrameworkDependency):
    def __init__(self, name, required, paths, env, lang, kwargs):
        super().__init__(name, required, paths, env, lang, kwargs)
        self.mod_name = name[2:]

    def get_compile_args(self, with_private_headers=False, qt_version="0"):
        if self.found():
            mod_inc_dir = os.path.join(self.framework_path, 'Headers')
            args = ['-I' + mod_inc_dir]
            if with_private_headers:
                args += ['-I' + dirname for dirname in _qt_get_private_includes(mod_inc_dir, self.mod_name, qt_version)]
            return args
        return []

class QtBaseDependency(ExternalDependency):
    def __init__(self, name, env, kwargs):
        super().__init__(name, env, 'cpp', kwargs)
        self.qtname = name.capitalize()
        self.qtver = name[-1]
        if self.qtver == "4":
            self.qtpkgname = 'Qt'
        else:
            self.qtpkgname = self.qtname
        self.root = '/usr'
        self.bindir = None
        self.private_headers = kwargs.get('private_headers', False)
        mods = extract_as_list(kwargs, 'modules')
        self.requested_modules = mods
        if not mods:
            raise DependencyException('No ' + self.qtname + '  modules specified.')
        self.from_text = 'pkg-config'

        self.qtmain = kwargs.get('main', False)
        if not isinstance(self.qtmain, bool):
            raise DependencyException('"main" argument must be a boolean')

        # Keep track of the detection methods used, for logging purposes.
        methods = []
        # Prefer pkg-config, then fallback to `qmake -query`
        if DependencyMethods.PKGCONFIG in self.methods:
            mlog.debug('Trying to find qt with pkg-config')
            self._pkgconfig_detect(mods, kwargs)
            methods.append('pkgconfig')
        if not self.is_found and DependencyMethods.QMAKE in self.methods:
            mlog.debug('Trying to find qt with qmake')
            self.from_text = self._qmake_detect(mods, kwargs)
            methods.append('qmake-' + self.name)
            methods.append('qmake')
        if not self.is_found:
            # Reset compile args and link args
            self.compile_args = []
            self.link_args = []
            self.from_text = mlog.format_list(methods)
            self.version = None

    def compilers_detect(self, interp_obj):
        "Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH"
        # It is important that this list does not change order as the order of
        # the returned ExternalPrograms will change as well
        bins = ['moc', 'uic', 'rcc', 'lrelease']
        found = {b: NonExistingExternalProgram(name='{}-{}'.format(b, self.name))
                 for b in bins}

        def gen_bins():
            for b in bins:
                if self.bindir:
                    yield os.path.join(self.bindir, b), b, False
                yield '{}-{}'.format(b, self.name), b, False
                yield b, b, self.required if b != 'lrelease' else False

        for b, name, required in gen_bins():
            if found[name].found():
                continue

            # prefer the -qt of the tool to the plain one, as we
            # don't know what the unsuffixed one points to without calling it.
            p = interp_obj.find_program_impl([b], silent=True, required=required).held_object
            if not p.found():
                continue

            if name == 'lrelease':
                arg = ['-version']
            elif mesonlib.version_compare(self.version, '>= 5'):
                arg = ['--version']
            else:
                arg = ['-v']

            # Ensure that the version of qt and each tool are the same
            _, out, err = mesonlib.Popen_safe(p.get_command() + arg)
            if b.startswith('lrelease') or not self.version.startswith('4'):
                care = out
            else:
                care = err
            if mesonlib.version_compare(self.version, '== {}'.format(care.split(' ')[-1])):
                found[name] = p

        return tuple([found[b] for b in bins])

    def _pkgconfig_detect(self, mods, kwargs):
        # We set the value of required to False so that we can try the
        # qmake-based fallback if pkg-config fails.
        kwargs['required'] = False
        modules = OrderedDict()
        for module in mods:
            modules[module] = PkgConfigDependency(self.qtpkgname + module, self.env,
                                                  kwargs, language=self.language)
        for m_name, m in modules.items():
            if not m.found():
                self.is_found = False
                return
            self.compile_args += m.get_compile_args()
            if self.private_headers:
                qt_inc_dir = m.get_pkgconfig_variable('includedir', dict())
                mod_private_dir = os.path.join(qt_inc_dir, 'Qt' + m_name)
                if not os.path.isdir(mod_private_dir):
                    # At least some versions of homebrew don't seem to set this
                    # up correctly. /usr/local/opt/qt/include/Qt + m_name is a
                    # symlink to /usr/local/opt/qt/include, but the pkg-config
                    # file points to /usr/local/Cellar/qt/x.y.z/Headers/, and
                    # the Qt + m_name there is not a symlink, it's a file
                    mod_private_dir = qt_inc_dir
                mod_private_inc = _qt_get_private_includes(mod_private_dir, m_name, m.version)
                for directory in mod_private_inc:
                    self.compile_args.append('-I' + directory)
            self.link_args += m.get_link_args()

        if 'Core' in modules:
            core = modules['Core']
        else:
            corekwargs = {'required': 'false', 'silent': 'true'}
            core = PkgConfigDependency(self.qtpkgname + 'Core', self.env, corekwargs,
                                       language=self.language)
            modules['Core'] = core

        if self.env.machines[self.for_machine].is_windows() and self.qtmain:
            # Check if we link with debug binaries
            debug_lib_name = self.qtpkgname + 'Core' + self._get_modules_lib_suffix(True)
            is_debug = False
            for arg in core.get_link_args():
                if arg == '-l%s' % debug_lib_name or arg.endswith('%s.lib' % debug_lib_name) or arg.endswith('%s.a' % debug_lib_name):
                    is_debug = True
                    break
            libdir = core.get_pkgconfig_variable('libdir', {})
            if not self._link_with_qtmain(is_debug, libdir):
                self.is_found = False
                return

        self.is_found = True
        self.version = m.version
        self.pcdep = list(modules.values())
        # Try to detect moc, uic, rcc
        # Used by self.compilers_detect()
        self.bindir = self.get_pkgconfig_host_bins(core)
        if not self.bindir:
            # If exec_prefix is not defined, the pkg-config file is broken
            prefix = core.get_pkgconfig_variable('exec_prefix', {})
            if prefix:
                self.bindir = os.path.join(prefix, 'bin')

    def _qmake_detect(self, mods, kwargs):
        for qmake in ('qmake-' + self.name, 'qmake'):
            self.qmake = ExternalProgram.from_bin_list(
                self.env.binaries.host, qmake)
            if not self.qmake.found():
                # Even when cross-compiling, if a cross-info qmake is not
                # specified, we fallback to using the qmake in PATH because
                # that's what we used to do
                self.qmake = ExternalProgram.from_bin_list(
                    self.env.binaries.build, qmake)
            if not self.qmake.found():
                self.qmake = ExternalProgram(qmake, silent=True)
            if not self.qmake.found():
                continue
            # Check that the qmake is for qt5
            pc, stdo = Popen_safe(self.qmake.get_command() + ['-v'])[0:2]
            if pc.returncode != 0:
                continue
            if not 'Qt version ' + self.qtver in stdo:
                mlog.log('QMake is not for ' + self.qtname)
                continue
            # Found qmake for Qt5!
            break
        else:
            # Didn't find qmake :(
            self.is_found = False
            return
        self.version = re.search(self.qtver + r'(\.\d+)+', stdo).group(0)
        # Query library path, header path, and binary path
        mlog.log("Found qmake:", mlog.bold(self.qmake.get_path()), '(%s)' % self.version)
        stdo = Popen_safe(self.qmake.get_command() + ['-query'])[1]
        qvars = {}
        for line in stdo.split('\n'):
            line = line.strip()
            if line == '':
                continue
            (k, v) = tuple(line.split(':', 1))
            qvars[k] = v
        # Qt on macOS uses a framework, but Qt for iOS/tvOS does not
        xspec = qvars.get('QMAKE_XSPEC', '')
        if self.env.machines.host.is_darwin() and not any(s in xspec for s in ['ios', 'tvos']):
            mlog.debug("Building for macOS, looking for framework")
            self._framework_detect(qvars, mods, kwargs)
            return qmake
        incdir = qvars['QT_INSTALL_HEADERS']
        self.compile_args.append('-I' + incdir)
        libdir = qvars['QT_INSTALL_LIBS']
        # Used by self.compilers_detect()
        self.bindir = self.get_qmake_host_bins(qvars)
        self.is_found = True

        is_debug = self.env.coredata.get_builtin_option('buildtype') == 'debug'
        modules_lib_suffix = self._get_modules_lib_suffix(is_debug)

        for module in mods:
            mincdir = os.path.join(incdir, 'Qt' + module)
            self.compile_args.append('-I' + mincdir)

            if module == 'QuickTest':
                define_base = 'QMLTEST'
            elif module == 'Test':
                define_base = 'TESTLIB'
            else:
                define_base = module.upper()
            self.compile_args.append('-DQT_%s_LIB' % define_base)

            if self.private_headers:
                priv_inc = self.get_private_includes(mincdir, module)
                for directory in priv_inc:
                    self.compile_args.append('-I' + directory)
            libfile = self.clib_compiler.find_library(self.qtpkgname + module + modules_lib_suffix,
                                                      self.env,
                                                      libdir)
            if libfile:
                libfile = libfile[0]
            else:
                self.is_found = False
                break
            self.link_args.append(libfile)

        if self.env.machines[self.for_machine].is_windows() and self.qtmain:
            if not self._link_with_qtmain(is_debug, libdir):
                self.is_found = False

        return qmake

    def _get_modules_lib_suffix(self, is_debug):
        suffix = ''
        if self.env.machines[self.for_machine].is_windows():
            if is_debug:
                suffix += 'd'
            if self.qtver == '4':
                suffix += '4'
        return suffix

    def _link_with_qtmain(self, is_debug, libdir):
        base_name = 'qtmaind' if is_debug else 'qtmain'
        qtmain = self.clib_compiler.find_library(base_name, self.env, libdir)
        if qtmain:
            self.link_args.append(qtmain[0])
            return True
        return False

    def _framework_detect(self, qvars, modules, kwargs):
        libdir = qvars['QT_INSTALL_LIBS']

        # ExtraFrameworkDependency doesn't support any methods
        fw_kwargs = kwargs.copy()
        fw_kwargs.pop('method', None)

        for m in modules:
            fname = 'Qt' + m
            mlog.debug('Looking for qt framework ' + fname)
            fwdep = QtExtraFrameworkDependency(fname, False, [libdir], self.env,
                                               self.language, fw_kwargs)
            self.compile_args.append('-F' + libdir)
            if fwdep.found():
                self.compile_args += fwdep.get_compile_args(with_private_headers=self.private_headers,
                                                            qt_version=self.version)
                self.link_args += fwdep.get_link_args()
            else:
                break
        else:
            self.is_found = True
        # Used by self.compilers_detect()
        self.bindir = self.get_qmake_host_bins(qvars)

    def get_qmake_host_bins(self, qvars):
        # Prefer QT_HOST_BINS (qt5, correct for cross and native compiling)
        # but fall back to QT_INSTALL_BINS (qt4)
        if 'QT_HOST_BINS' in qvars:
            return qvars['QT_HOST_BINS']
        else:
            return qvars['QT_INSTALL_BINS']

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG, DependencyMethods.QMAKE]

    def get_exe_args(self, compiler):
        # Originally this was -fPIE but nowadays the default
        # for upstream and distros seems to be -reduce-relocations
        # which requires -fPIC. This may cause a performance
        # penalty when using self-built Qt or on platforms
        # where -fPIC is not required. If this is an issue
        # for you, patches are welcome.
        return compiler.get_pic_args()

    def get_private_includes(self, mod_inc_dir, module):
        return tuple()

    def log_details(self):
        module_str = ', '.join(self.requested_modules)
        return 'modules: ' + module_str

    def log_info(self):
        return '{}'.format(self.from_text)

    def log_tried(self):
        return self.from_text


class Qt4Dependency(QtBaseDependency):
    def __init__(self, env, kwargs):
        QtBaseDependency.__init__(self, 'qt4', env, kwargs)

    def get_pkgconfig_host_bins(self, core):
        # Only return one bins dir, because the tools are generally all in one
        # directory for Qt4, in Qt5, they must all be in one directory. Return
        # the first one found among the bin variables, in case one tool is not
        # configured to be built.
        applications = ['moc', 'uic', 'rcc', 'lupdate', 'lrelease']
        for application in applications:
            try:
                return os.path.dirname(core.get_pkgconfig_variable('%s_location' % application, {}))
            except MesonException:
                pass


class Qt5Dependency(QtBaseDependency):
    def __init__(self, env, kwargs):
        QtBaseDependency.__init__(self, 'qt5', env, kwargs)

    def get_pkgconfig_host_bins(self, core):
        return core.get_pkgconfig_variable('host_bins', {})

    def get_private_includes(self, mod_inc_dir, module):
        return _qt_get_private_includes(mod_inc_dir, module, self.version)


# There are three different ways of depending on SDL2:
# sdl2-config, pkg-config and OSX framework
class SDL2Dependency(ExternalDependency):
    def __init__(self, environment, kwargs):
        super().__init__('sdl2', environment, None, kwargs)

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'sdl2', environment, kwargs))

        if DependencyMethods.CONFIG_TOOL in methods:
            candidates.append(functools.partial(ConfigToolDependency.factory,
                                                'sdl2', environment, None,
                                                kwargs, ['sdl2-config'],
                                                'sdl2-config', SDL2Dependency.tool_finish_init))

        if DependencyMethods.EXTRAFRAMEWORK in methods:
            if mesonlib.is_osx():
                candidates.append(functools.partial(ExtraFrameworkDependency,
                                                    'sdl2', False, None, environment,
                                                    kwargs.get('language', None), kwargs))
                # fwdep.version = '2'  # FIXME
        return candidates

    @staticmethod
    def tool_finish_init(ctdep):
        ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
        ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')

    @staticmethod
    def get_methods():
        if mesonlib.is_osx():
            return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
        else:
            return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]


class WxDependency(ConfigToolDependency):

    tools = ['wx-config-3.0', 'wx-config', 'wx-config-gtk3']
    tool_name = 'wx-config'

    def __init__(self, environment, kwargs):
        super().__init__('WxWidgets', environment, None, kwargs)
        if not self.is_found:
            return
        self.requested_modules = self.get_requested(kwargs)
        # wx-config seems to have a cflags as well but since it requires C++,
        # this should be good, at least for now.
        self.compile_args = self.get_config_value(['--cxxflags'] + self.requested_modules, 'compile_args')
        self.link_args = self.get_config_value(['--libs'] + self.requested_modules, 'link_args')

    def get_requested(self, kwargs):
        if 'modules' not in kwargs:
            return []
        candidates = extract_as_list(kwargs, 'modules')
        for c in candidates:
            if not isinstance(c, str):
                raise DependencyException('wxwidgets module argument is not a string')
        return candidates


class VulkanDependency(ExternalDependency):

    def __init__(self, environment, kwargs):
        super().__init__('vulkan', environment, None, kwargs)

        try:
            self.vulkan_sdk = os.environ['VULKAN_SDK']
            if not os.path.isabs(self.vulkan_sdk):
                raise DependencyException('VULKAN_SDK must be an absolute path.')
        except KeyError:
            self.vulkan_sdk = None

        if self.vulkan_sdk:
            # 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'

            # make sure header and lib are valid
            inc_path = os.path.join(self.vulkan_sdk, inc_dir)
            header = os.path.join(inc_path, 'vulkan', 'vulkan.h')
            lib_path = os.path.join(self.vulkan_sdk, lib_dir)
            find_lib = self.clib_compiler.find_library(lib_name, environment, lib_path)

            if not find_lib:
                raise DependencyException('VULKAN_SDK point to invalid directory (no lib)')

            if not os.path.isfile(header):
                raise DependencyException('VULKAN_SDK point to invalid directory (no include)')

            self.type_name = 'vulkan_sdk'
            self.is_found = True
            self.compile_args.append('-I' + inc_path)
            self.link_args.append('-L' + lib_path)
            self.link_args.append('-l' + lib_name)

            # TODO: find a way to retrieve the version from the sdk?
            # Usually it is a part of the path to it (but does not have to be)
            return
        else:
            # simply try to guess it, usually works on linux
            libs = self.clib_compiler.find_library('vulkan', environment, [])
            if libs is not None and self.clib_compiler.has_header('vulkan/vulkan.h', '', environment, disable_cache=True)[0]:
                self.type_name = 'system'
                self.is_found = True
                for lib in libs:
                    self.link_args.append(lib)
                return

    @classmethod
    def _factory(cls, environment, kwargs):
        methods = cls._process_method_kw(kwargs)
        candidates = []

        if DependencyMethods.PKGCONFIG in methods:
            candidates.append(functools.partial(PkgConfigDependency, 'vulkan', environment, kwargs))

        if DependencyMethods.SYSTEM in methods:
            candidates.append(functools.partial(VulkanDependency, environment, kwargs))

        return candidates

    @staticmethod
    def get_methods():
        return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]

    def log_tried(self):
        return 'system'
meson-0.53.2/mesonbuild/depfile.py0000644000175000017500000000511113546416757020457 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 Red Hat, Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import collections

def parse(lines):
    rules = []
    targets = []
    deps = []
    in_deps = False
    out = ''
    for line in lines:
        if not line.endswith('\n'):
            line += '\n'
        escape = None
        for c in line:
            if escape:
                if escape == '$' and c != '$':
                    out += '$'
                if escape == '\\' and c == '\n':
                    continue
                out += c
                escape = None
                continue
            if c == '\\' or c == '$':
                escape = c
                continue
            elif c in (' ', '\n'):
                if out != '':
                    if in_deps:
                        deps.append(out)
                    else:
                        targets.append(out)
                out = ''
                if c == '\n':
                    rules.append((targets, deps))
                    targets = []
                    deps = []
                    in_deps = False
                continue
            elif c == ':':
                targets.append(out)
                out = ''
                in_deps = True
                continue
            out += c
    return rules

Target = collections.namedtuple('Target', ['deps'])

class DepFile:
    def __init__(self, lines):
        rules = parse(lines)
        depfile = {}
        for (targets, deps) in rules:
            for target in targets:
                t = depfile.setdefault(target, Target(deps=set()))
                for dep in deps:
                    t.deps.add(dep)
        self.depfile = depfile

    def get_all_dependencies(self, target, visited=None):
        deps = set()
        if not visited:
            visited = set()
        if target in visited:
            return set()
        visited.add(target)
        target = self.depfile.get(target)
        if not target:
            return set()
        deps.update(target.deps)
        for dep in target.deps:
            deps.update(self.get_all_dependencies(dep, visited))
        return deps
meson-0.53.2/mesonbuild/envconfig.py0000644000175000017500000003422313612417564021022 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import configparser, os, subprocess
import typing as T

from . import mesonlib
from .mesonlib import EnvironmentException, split_args
from . import mlog

_T = T.TypeVar('_T')


# These classes contains all the data pulled from configuration files (native
# and cross file currently), and also assists with the reading environment
# variables.
#
# At this time there isn't an ironclad difference between this an other sources
# of state like `coredata`. But one rough guide is much what is in `coredata` is
# the *output* of the configuration process: the final decisions after tests.
# This, on the other hand has *inputs*. The config files are parsed, but
# otherwise minimally transformed. When more complex fallbacks (environment
# detection) exist, they are defined elsewhere as functions that construct
# instances of these classes.


known_cpu_families = (
    'aarch64',
    'alpha',
    'arc',
    'arm',
    'e2k',
    'ia64',
    'm68k',
    'microblaze',
    'mips',
    'mips64',
    'parisc',
    'ppc',
    'ppc64',
    'riscv32',
    'riscv64',
    'rl78',
    'rx',
    's390',
    's390x',
    'sparc',
    'sparc64',
    'wasm32',
    'wasm64',
    'x86',
    'x86_64'
)

# It would feel more natural to call this "64_BIT_CPU_FAMILES", but
# python identifiers cannot start with numbers
CPU_FAMILES_64_BIT = [
    'aarch64',
    'alpha',
    'ia64',
    'mips64',
    'ppc64',
    'riscv64',
    's390x',
    'sparc64',
    'wasm64',
    'x86_64',
]

class MesonConfigFile:
    @classmethod
    def from_config_parser(cls, parser: configparser.ConfigParser) -> T.Dict[str, T.Dict[str, T.Dict[str, str]]]:
        out = {}
        # This is a bit hackish at the moment.
        for s in parser.sections():
            section = {}
            for entry in parser[s]:
                value = parser[s][entry]
                # Windows paths...
                value = value.replace('\\', '\\\\')
                if ' ' in entry or '\t' in entry or "'" in entry or '"' in entry:
                    raise EnvironmentException('Malformed variable name %s in cross file..' % entry)
                try:
                    res = eval(value, {'__builtins__': None}, {'true': True, 'false': False})
                except Exception:
                    raise EnvironmentException('Malformed value in cross file variable %s.' % entry)

                for i in (res if isinstance(res, list) else [res]):
                    if not isinstance(i, (str, int, bool)):
                        raise EnvironmentException('Malformed value in cross file variable %s.' % entry)

                section[entry] = res

            out[s] = section
        return out

class HasEnvVarFallback:
    """
    A tiny class to indicate that this class contains data that can be
    initialized from either a config file or environment file. The `fallback`
    field says whether env vars should be used. Downstream logic (e.g. subclass
    methods) can check it to decide what to do, since env vars are currently
    lazily decoded.

    Frankly, this is a pretty silly class at the moment. The hope is the way
    that we deal with environment variables will become more structured, and
    this can be starting point.
    """
    def __init__(self, fallback: bool = True):
        self.fallback = fallback

class Properties(HasEnvVarFallback):
    def __init__(
            self,
            properties: T.Optional[T.Dict[str, T.Union[str, T.List[str]]]] = None,
            fallback: bool = True):
        super().__init__(fallback)
        self.properties = properties or {}  # type: T.Dict[str, T.Union[str, T.List[str]]]

    def has_stdlib(self, language: str) -> bool:
        return language + '_stdlib' in self.properties

    # Some of get_stdlib, get_root, get_sys_root are wider than is actually
    # true, but without heterogenious dict annotations it's not practical to
    # narrow them
    def get_stdlib(self, language: str) -> T.Union[str, T.List[str]]:
        return self.properties[language + '_stdlib']

    def get_root(self) -> T.Optional[T.Union[str, T.List[str]]]:
        return self.properties.get('root', None)

    def get_sys_root(self) -> T.Optional[T.Union[str, T.List[str]]]:
        return self.properties.get('sys_root', None)

    def __eq__(self, other: T.Any) -> 'T.Union[bool, NotImplemented]':
        if isinstance(other, type(self)):
            return self.properties == other.properties
        return NotImplemented

    # TODO consider removing so Properties is less freeform
    def __getitem__(self, key: str) -> T.Any:
        return self.properties[key]

    # TODO consider removing so Properties is less freeform
    def __contains__(self, item: T.Any) -> bool:
        return item in self.properties

    # TODO consider removing, for same reasons as above
    def get(self, key: str, default: T.Any = None) -> T.Any:
        return self.properties.get(key, default)

class MachineInfo:
    def __init__(self, system: str, cpu_family: str, cpu: str, endian: str):
        self.system = system
        self.cpu_family = cpu_family
        self.cpu = cpu
        self.endian = endian
        self.is_64_bit = cpu_family in CPU_FAMILES_64_BIT  # type: bool

    def __eq__(self, other: T.Any) -> 'T.Union[bool, NotImplemented]':
        if self.__class__ is not other.__class__:
            return NotImplemented
        return \
            self.system == other.system and \
            self.cpu_family == other.cpu_family and \
            self.cpu == other.cpu and \
            self.endian == other.endian

    def __ne__(self, other: T.Any) -> 'T.Union[bool, NotImplemented]':
        if self.__class__ is not other.__class__:
            return NotImplemented
        return not self.__eq__(other)

    def __repr__(self) -> str:
        return ''.format(self.system, self.cpu_family, self.cpu)

    @classmethod
    def from_literal(cls, literal: T.Dict[str, str]) -> 'MachineInfo':
        minimum_literal = {'cpu', 'cpu_family', 'endian', 'system'}
        if set(literal) < minimum_literal:
            raise EnvironmentException(
                'Machine info is currently {}\n'.format(literal) +
                'but is missing {}.'.format(minimum_literal - set(literal)))

        cpu_family = literal['cpu_family']
        if cpu_family not in known_cpu_families:
            mlog.warning('Unknown CPU family %s, please report this at https://github.com/mesonbuild/meson/issues/new' % cpu_family)

        endian = literal['endian']
        if endian not in ('little', 'big'):
            mlog.warning('Unknown endian %s' % endian)

        return cls(literal['system'], cpu_family, literal['cpu'], endian)

    def is_windows(self) -> bool:
        """
        Machine is windows?
        """
        return self.system == 'windows' or 'mingw' in self.system

    def is_cygwin(self) -> bool:
        """
        Machine is cygwin?
        """
        return self.system.startswith('cygwin')

    def is_linux(self) -> bool:
        """
        Machine is linux?
        """
        return self.system == 'linux'

    def is_darwin(self) -> bool:
        """
        Machine is Darwin (iOS/tvOS/OS X)?
        """
        return self.system in {'darwin', 'ios', 'tvos'}

    def is_android(self) -> bool:
        """
        Machine is Android?
        """
        return self.system == 'android'

    def is_haiku(self) -> bool:
        """
        Machine is Haiku?
        """
        return self.system == 'haiku'

    def is_netbsd(self) -> bool:
        """
        Machine is NetBSD?
        """
        return self.system == 'netbsd'

    def is_openbsd(self) -> bool:
        """
        Machine is OpenBSD?
        """
        return self.system == 'openbsd'

    def is_dragonflybsd(self) -> bool:
        """Machine is DragonflyBSD?"""
        return self.system == 'dragonfly'

    def is_freebsd(self) -> bool:
        """Machine is FreeBSD?"""
        return self.system == 'freebsd'

    def is_sunos(self) -> bool:
        """Machine is illumos or Solaris?"""
        return self.system == 'sunos'

    # Various prefixes and suffixes for import libraries, shared libraries,
    # static libraries, and executables.
    # Versioning is added to these names in the backends as-needed.
    def get_exe_suffix(self) -> str:
        if self.is_windows() or self.is_cygwin():
            return 'exe'
        else:
            return ''

    def get_object_suffix(self) -> str:
        if self.is_windows():
            return 'obj'
        else:
            return 'o'

    def libdir_layout_is_win(self) -> bool:
        return self.is_windows() or self.is_cygwin()

class BinaryTable(HasEnvVarFallback):
    def __init__(
            self,
            binaries: T.Optional[T.Dict[str, T.Union[str, T.List[str]]]] = None,
            fallback: bool = True):
        super().__init__(fallback)
        self.binaries = binaries or {}  # type: T.Dict[str, T.Union[str, T.List[str]]]
        for name, command in self.binaries.items():
            if not isinstance(command, (list, str)):
                # TODO generalize message
                raise mesonlib.MesonException(
                    'Invalid type {!r} for binary {!r} in cross file'
                    ''.format(command, name))

    # Map from language identifiers to environment variables.
    evarMap = {
        # Compilers
        'c': 'CC',
        'cpp': 'CXX',
        'cs': 'CSC',
        'd': 'DC',
        'fortran': 'FC',
        'objc': 'OBJC',
        'objcpp': 'OBJCXX',
        'rust': 'RUSTC',
        'vala': 'VALAC',

        # Linkers
        'c_ld': 'CC_LD',
        'cpp_ld': 'CXX_LD',
        'd_ld': 'D_LD',
        'fortran_ld': 'F_LD',
        'objc_ld': 'OBJC_LD',
        'objcpp_ld': 'OBJCPP_LD',
        'rust_ld': 'RUST_LD',

        # Binutils
        'strip': 'STRIP',
        'ar': 'AR',
        'windres': 'WINDRES',

        # Other tools
        'cmake': 'CMAKE',
        'qmake': 'QMAKE',
        'pkgconfig': 'PKG_CONFIG',
    }  # type: T.Dict[str, str]

    @staticmethod
    def detect_ccache() -> T.List[str]:
        try:
            subprocess.check_call(['ccache', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        except (OSError, subprocess.CalledProcessError):
            return []
        return ['ccache']

    @classmethod
    def _warn_about_lang_pointing_to_cross(cls, compiler_exe: str, evar: str) -> None:
        evar_str = os.environ.get(evar, 'WHO_WOULD_CALL_THEIR_COMPILER_WITH_THIS_NAME')
        if evar_str == compiler_exe:
            mlog.warning('''Env var %s seems to point to the cross compiler.
This is probably wrong, it should always point to the native compiler.''' % evar)

    @classmethod
    def parse_entry(cls, entry: T.Union[str, T.List[str]]) -> T.Tuple[T.List[str], T.List[str]]:
        compiler = mesonlib.stringlistify(entry)
        # Ensure ccache exists and remove it if it doesn't
        if compiler[0] == 'ccache':
            compiler = compiler[1:]
            ccache = cls.detect_ccache()
        else:
            ccache = []
        # Return value has to be a list of compiler 'choices'
        return compiler, ccache

    def lookup_entry(self, name: str) -> T.Optional[T.List[str]]:
        """Lookup binaryk

        Returns command with args as list if found, Returns `None` if nothing is
        found.

        First tries looking in explicit map, then tries environment variable.
        """
        # Try explicit map, don't fall back on env var
        command = self.binaries.get(name)
        if command is not None:
            command = mesonlib.stringlistify(command)
            # Relies on there being no "" env var
            evar = self.evarMap.get(name, "")
            self._warn_about_lang_pointing_to_cross(command[0], evar)
        elif self.fallback:
            # Relies on there being no "" env var
            evar = self.evarMap.get(name, "")
            command = os.environ.get(evar)
            if command is not None:
                command = split_args(command)

        # Do not return empty or blank string entries
        if command is not None and (len(command) == 0 or len(command[0].strip()) == 0):
            return None
        return command

class Directories:

    """Data class that holds information about directories for native and cross
    builds.
    """

    def __init__(self, bindir: T.Optional[str] = None, datadir: T.Optional[str] = None,
                 includedir: T.Optional[str] = None, infodir: T.Optional[str] = None,
                 libdir: T.Optional[str] = None, libexecdir: T.Optional[str] = None,
                 localedir: T.Optional[str] = None, localstatedir: T.Optional[str] = None,
                 mandir: T.Optional[str] = None, prefix: T.Optional[str] = None,
                 sbindir: T.Optional[str] = None, sharedstatedir: T.Optional[str] = None,
                 sysconfdir: T.Optional[str] = None):
        self.bindir = bindir
        self.datadir = datadir
        self.includedir = includedir
        self.infodir = infodir
        self.libdir = libdir
        self.libexecdir = libexecdir
        self.localedir = localedir
        self.localstatedir = localstatedir
        self.mandir = mandir
        self.prefix = prefix
        self.sbindir = sbindir
        self.sharedstatedir = sharedstatedir
        self.sysconfdir = sysconfdir

    def __contains__(self, key: str) -> bool:
        return hasattr(self, key)

    def __getitem__(self, key: str) -> T.Optional[str]:
        # Mypy can't figure out what to do with getattr here, so we'll case for it
        return T.cast(T.Optional[str], getattr(self, key))

    def __setitem__(self, key: str, value: T.Optional[str]) -> None:
        setattr(self, key, value)

    def __iter__(self) -> T.Iterator[T.Tuple[str, str]]:
        return iter(self.__dict__.items())
meson-0.53.2/mesonbuild/environment.py0000644000175000017500000022656013625260316021412 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os, platform, re, sys, shutil, subprocess
import tempfile
import shlex
import typing as T

from . import coredata
from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, IntelVisualStudioLinker
from . import mesonlib
from .mesonlib import (
    MesonException, EnvironmentException, MachineChoice, Popen_safe,
    PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg
)
from . import mlog

from .envconfig import (
    BinaryTable, Directories, MachineInfo, MesonConfigFile,
    Properties, known_cpu_families,
)
from . import compilers
from .compilers import (
    Compiler,
    is_assembly,
    is_header,
    is_library,
    is_llvm_ir,
    is_object,
    is_source,
)
from .linkers import (
    AppleDynamicLinker,
    ArmClangDynamicLinker,
    ArmDynamicLinker,
    CcrxDynamicLinker,
    ClangClDynamicLinker,
    DynamicLinker,
    GnuBFDDynamicLinker,
    GnuGoldDynamicLinker,
    LLVMDynamicLinker,
    MSVCDynamicLinker,
    OptlinkDynamicLinker,
    PGIDynamicLinker,
    PGIStaticLinker,
    SolarisDynamicLinker,
    XilinkDynamicLinker,
    CudaLinker,
    VisualStudioLikeLinkerMixin,
)
from functools import lru_cache
from .compilers import (
    ArmCCompiler,
    ArmCPPCompiler,
    ArmclangCCompiler,
    ArmclangCPPCompiler,
    AppleClangCCompiler,
    AppleClangCPPCompiler,
    ClangCCompiler,
    ClangCPPCompiler,
    ClangObjCCompiler,
    ClangObjCPPCompiler,
    ClangClCCompiler,
    ClangClCPPCompiler,
    FlangFortranCompiler,
    G95FortranCompiler,
    GnuCCompiler,
    GnuCPPCompiler,
    GnuFortranCompiler,
    GnuObjCCompiler,
    GnuObjCPPCompiler,
    ElbrusCCompiler,
    ElbrusCPPCompiler,
    ElbrusFortranCompiler,
    EmscriptenCCompiler,
    EmscriptenCPPCompiler,
    IntelCCompiler,
    IntelClCCompiler,
    IntelCPPCompiler,
    IntelClCPPCompiler,
    IntelFortranCompiler,
    IntelClFortranCompiler,
    JavaCompiler,
    MonoCompiler,
    CudaCompiler,
    VisualStudioCsCompiler,
    NAGFortranCompiler,
    Open64FortranCompiler,
    PathScaleFortranCompiler,
    PGICCompiler,
    PGICPPCompiler,
    PGIFortranCompiler,
    RustCompiler,
    CcrxCCompiler,
    CcrxCPPCompiler,
    SunFortranCompiler,
    ValaCompiler,
    VisualStudioCCompiler,
    VisualStudioCPPCompiler,
)

build_filename = 'meson.build'

CompilersDict = T.Dict[str, Compiler]

def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
    gcovr_exe = 'gcovr'
    try:
        p, found = Popen_safe([gcovr_exe, '--version'])[0:2]
    except (FileNotFoundError, PermissionError):
        # Doesn't exist in PATH or isn't executable
        return None, None
    found = search_version(found)
    if p.returncode == 0 and mesonlib.version_compare(found, '>=' + min_version):
        if log:
            mlog.log('Found gcovr-{} at {}'.format(found, quote_arg(shutil.which(gcovr_exe))))
        return gcovr_exe, mesonlib.version_compare(found, '>=' + new_rootdir_version)
    return None, None

def find_coverage_tools():
    gcovr_exe, gcovr_new_rootdir = detect_gcovr()

    lcov_exe = 'lcov'
    genhtml_exe = 'genhtml'

    if not mesonlib.exe_exists([lcov_exe, '--version']):
        lcov_exe = None
    if not mesonlib.exe_exists([genhtml_exe, '--version']):
        genhtml_exe = None

    return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe

def detect_ninja(version: str = '1.5', log: bool = False) -> str:
    r = detect_ninja_command_and_version(version, log)
    return r[0] if r else None

def detect_ninja_command_and_version(version: str = '1.5', log: bool = False) -> (str, str):
    env_ninja = os.environ.get('NINJA', None)
    for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']:
        try:
            p, found = Popen_safe([n, '--version'])[0:2]
        except (FileNotFoundError, PermissionError):
            # Doesn't exist in PATH or isn't executable
            continue
        found = found.strip()
        # Perhaps we should add a way for the caller to know the failure mode
        # (not found or too old)
        if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version):
            n = shutil.which(n)
            if log:
                name = os.path.basename(n)
                if name.endswith('-' + found):
                    name = name[0:-1 - len(found)]
                if name == 'ninja-build':
                    name = 'ninja'
                if name == 'samu':
                    name = 'samurai'
                mlog.log('Found {}-{} at {}'.format(name, found, quote_arg(n)))
            return (n, found)

def get_llvm_tool_names(tool: str) -> T.List[str]:
    # Ordered list of possible suffixes of LLVM executables to try. Start with
    # base, then try newest back to oldest (3.5 is arbitrary), and finally the
    # devel version. Please note that the development snapshot in Debian does
    # not have a distinct name. Do not move it to the beginning of the list
    # unless it becomes a stable release.
    suffixes = [
        '', # base (no suffix)
        '-9',   '90',
        '-8',   '80',
        '-7',   '70',
        '-6.0', '60',
        '-5.0', '50',
        '-4.0', '40',
        '-3.9', '39',
        '-3.8', '38',
        '-3.7', '37',
        '-3.6', '36',
        '-3.5', '35',
        '-10',    # Debian development snapshot
        '-devel', # FreeBSD development snapshot
    ]
    names = []
    for suffix in suffixes:
        names.append(tool + suffix)
    return names

def detect_scanbuild() -> T.List[str]:
    """ Look for scan-build binary on build platform

    First, if a SCANBUILD env variable has been provided, give it precedence
    on all platforms.

    For most platforms, scan-build is found is the PATH contains a binary
    named "scan-build". However, some distribution's package manager (FreeBSD)
    don't. For those, loop through a list of candidates to see if one is
    available.

    Return: a single-element list of the found scan-build binary ready to be
        passed to Popen()
    """
    exelist = []
    if 'SCANBUILD' in os.environ:
        exelist = split_args(os.environ['SCANBUILD'])

    else:
        tools = get_llvm_tool_names('scan-build')
        for tool in tools:
            if shutil.which(tool) is not None:
                exelist = [shutil.which(tool)]
                break

    if exelist:
        tool = exelist[0]
        if os.path.isfile(tool) and os.access(tool, os.X_OK):
            return [tool]
    return []

def detect_clangformat() -> T.List[str]:
    """ Look for clang-format binary on build platform

    Do the same thing as detect_scanbuild to find clang-format except it
    currently does not check the environment variable.

    Return: a single-element list of the found clang-format binary ready to be
        passed to Popen()
    """
    tools = get_llvm_tool_names('clang-format')
    for tool in tools:
        path = shutil.which(tool)
        if path is not None:
            return [path]
    return []

def detect_native_windows_arch():
    """
    The architecture of Windows itself: x86, amd64 or arm64
    """
    # These env variables are always available. See:
    # https://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx
    # https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/
    arch = os.environ.get('PROCESSOR_ARCHITEW6432', '').lower()
    if not arch:
        try:
            # If this doesn't exist, something is messing with the environment
            arch = os.environ['PROCESSOR_ARCHITECTURE'].lower()
        except KeyError:
            raise EnvironmentException('Unable to detect native OS architecture')
    return arch

def detect_windows_arch(compilers: CompilersDict) -> str:
    """
    Detecting the 'native' architecture of Windows is not a trivial task. We
    cannot trust that the architecture that Python is built for is the 'native'
    one because you can run 32-bit apps on 64-bit Windows using WOW64 and
    people sometimes install 32-bit Python on 64-bit Windows.

    We also can't rely on the architecture of the OS itself, since it's
    perfectly normal to compile and run 32-bit applications on Windows as if
    they were native applications. It's a terrible experience to require the
    user to supply a cross-info file to compile 32-bit applications on 64-bit
    Windows. Thankfully, the only way to compile things with Visual Studio on
    Windows is by entering the 'msvc toolchain' environment, which can be
    easily detected.

    In the end, the sanest method is as follows:
    1. Check environment variables that are set by Windows and WOW64 to find out
       if this is x86 (possibly in WOW64), if so use that as our 'native'
       architecture.
    2. If the compiler toolchain target architecture is x86, use that as our
      'native' architecture.
    3. Otherwise, use the actual Windows architecture

    """
    os_arch = detect_native_windows_arch()
    if os_arch == 'x86':
        return os_arch
    # If we're on 64-bit Windows, 32-bit apps can be compiled without
    # cross-compilation. So if we're doing that, just set the native arch as
    # 32-bit and pretend like we're running under WOW64. Else, return the
    # actual Windows architecture that we deduced above.
    for compiler in compilers.values():
        if compiler.id == 'msvc' and (compiler.target == 'x86' or compiler.target == '80x86'):
            return 'x86'
        if compiler.id == 'clang-cl' and compiler.target == 'x86':
            return 'x86'
        if compiler.id == 'gcc' and compiler.has_builtin_define('__i386__'):
            return 'x86'
    return os_arch

def any_compiler_has_define(compilers: CompilersDict, define):
    for c in compilers.values():
        try:
            if c.has_builtin_define(define):
                return True
        except mesonlib.MesonException:
            # Ignore compilers that do not support has_builtin_define.
            pass
    return False

def detect_cpu_family(compilers: CompilersDict) -> str:
    """
    Python is inconsistent in its platform module.
    It returns different values for the same cpu.
    For x86 it might return 'x86', 'i686' or somesuch.
    Do some canonicalization.
    """
    if mesonlib.is_windows():
        trial = detect_windows_arch(compilers)
    elif mesonlib.is_freebsd() or mesonlib.is_netbsd() or mesonlib.is_openbsd():
        trial = platform.processor().lower()
    else:
        trial = platform.machine().lower()
    if trial.startswith('i') and trial.endswith('86'):
        trial = 'x86'
    elif trial == 'bepc':
        trial = 'x86'
    elif trial.startswith('arm') or trial.startswith('earm'):
        trial = 'arm'
    elif trial.startswith(('powerpc64', 'ppc64')):
        trial = 'ppc64'
    elif trial.startswith(('powerpc', 'ppc')):
        trial = 'ppc'
    elif trial == 'macppc':
        trial = 'ppc'
    elif trial in ('amd64', 'x64', 'i86pc'):
        trial = 'x86_64'
    elif trial in {'sun4u', 'sun4v'}:
        trial = 'sparc64'

    # On Linux (and maybe others) there can be any mixture of 32/64 bit code in
    # the kernel, Python, system, 32-bit chroot on 64-bit host, etc. The only
    # reliable way to know is to check the compiler defines.
    if trial == 'x86_64':
        if any_compiler_has_define(compilers, '__i386__'):
            trial = 'x86'
    elif trial == 'aarch64':
        if any_compiler_has_define(compilers, '__arm__'):
            trial = 'arm'
    # Add more quirks here as bugs are reported. Keep in sync with detect_cpu()
    # below.
    elif trial == 'parisc64':
        # ATM there is no 64 bit userland for PA-RISC. Thus always
        # report it as 32 bit for simplicity.
        trial = 'parisc'

    if trial not in known_cpu_families:
        mlog.warning('Unknown CPU family {!r}, please report this at '
                     'https://github.com/mesonbuild/meson/issues/new with the '
                     'output of `uname -a` and `cat /proc/cpuinfo`'.format(trial))

    return trial

def detect_cpu(compilers: CompilersDict):
    if mesonlib.is_windows():
        trial = detect_windows_arch(compilers)
    elif mesonlib.is_freebsd() or mesonlib.is_netbsd() or mesonlib.is_openbsd():
        trial = platform.processor().lower()
    else:
        trial = platform.machine().lower()
    if trial in ('amd64', 'x64', 'i86pc'):
        trial = 'x86_64'
    if trial == 'x86_64':
        # Same check as above for cpu_family
        if any_compiler_has_define(compilers, '__i386__'):
            trial = 'i686' # All 64 bit cpus have at least this level of x86 support.
    elif trial == 'aarch64':
        # Same check as above for cpu_family
        if any_compiler_has_define(compilers, '__arm__'):
            trial = 'arm'
    elif trial.startswith('earm'):
        trial = 'arm'
    elif trial == 'e2k':
        # Make more precise CPU detection for Elbrus platform.
        trial = platform.processor().lower()
    # Add more quirks here as bugs are reported. Keep in sync with
    # detect_cpu_family() above.
    return trial

def detect_system():
    system = platform.system().lower()
    if system.startswith('cygwin'):
        return 'cygwin'
    return system

def detect_msys2_arch():
    if 'MSYSTEM_CARCH' in os.environ:
        return os.environ['MSYSTEM_CARCH']
    return None

def detect_machine_info(compilers: T.Optional[CompilersDict] = None) -> MachineInfo:
    """Detect the machine we're running on

    If compilers are not provided, we cannot know as much. None out those
    fields to avoid accidentally depending on partial knowledge. The
    underlying ''detect_*'' method can be called to explicitly use the
    partial information.
    """
    return MachineInfo(
        detect_system(),
        detect_cpu_family(compilers) if compilers is not None else None,
        detect_cpu(compilers) if compilers is not None else None,
        sys.byteorder)

# TODO make this compare two `MachineInfo`s purely. How important is the
# `detect_cpu_family({})` distinction? It is the one impediment to that.
def machine_info_can_run(machine_info: MachineInfo):
    """Whether we can run binaries for this machine on the current machine.

    Can almost always run 32-bit binaries on 64-bit natively if the host
    and build systems are the same. We don't pass any compilers to
    detect_cpu_family() here because we always want to know the OS
    architecture, not what the compiler environment tells us.
    """
    if machine_info.system != detect_system():
        return False
    true_build_cpu_family = detect_cpu_family({})
    return \
        (machine_info.cpu_family == true_build_cpu_family) or \
        ((true_build_cpu_family == 'x86_64') and (machine_info.cpu_family == 'x86'))

def search_version(text):
    # Usually of the type 4.1.4 but compiler output may contain
    # stuff like this:
    # (Sourcery CodeBench Lite 2014.05-29) 4.8.3 20140320 (prerelease)
    # Limiting major version number to two digits seems to work
    # thus far. When we get to GCC 100, this will break, but
    # if we are still relevant when that happens, it can be
    # considered an achievement in itself.
    #
    # This regex is reaching magic levels. If it ever needs
    # to be updated, do not complexify but convert to something
    # saner instead.
    # We'll demystify it a bit with a verbose definition.
    version_regex = re.compile(r"""
    (? bool:
        return self.coredata.is_cross_build()

    def dump_coredata(self):
        return coredata.save(self.coredata, self.get_build_dir())

    def get_script_dir(self):
        import mesonbuild.scripts
        return os.path.dirname(mesonbuild.scripts.__file__)

    def get_log_dir(self):
        return self.log_dir

    def get_coredata(self):
        return self.coredata

    def get_build_command(self, unbuffered=False):
        cmd = mesonlib.meson_command[:]
        if unbuffered and 'python' in os.path.basename(cmd[0]):
            cmd.insert(1, '-u')
        return cmd

    def is_header(self, fname):
        return is_header(fname)

    def is_source(self, fname):
        return is_source(fname)

    def is_assembly(self, fname):
        return is_assembly(fname)

    def is_llvm_ir(self, fname):
        return is_llvm_ir(fname)

    def is_object(self, fname):
        return is_object(fname)

    @lru_cache(maxsize=None)
    def is_library(self, fname):
        return is_library(fname)

    @staticmethod
    def get_gnu_compiler_defines(compiler):
        """
        Detect GNU compiler platform type (Apple, MinGW, Unix)
        """
        # Arguments to output compiler pre-processor defines to stdout
        # gcc, g++, and gfortran all support these arguments
        args = compiler + ['-E', '-dM', '-']
        p, output, error = Popen_safe(args, write='', stdin=subprocess.PIPE)
        if p.returncode != 0:
            raise EnvironmentException('Unable to detect GNU compiler type:\n' + output + error)
        # Parse several lines of the type:
        # `#define ___SOME_DEF some_value`
        # and extract `___SOME_DEF`
        defines = {}
        for line in output.split('\n'):
            if not line:
                continue
            d, *rest = line.split(' ', 2)
            if d != '#define':
                continue
            if len(rest) == 1:
                defines[rest] = True
            if len(rest) == 2:
                defines[rest[0]] = rest[1]
        return defines

    @staticmethod
    def get_gnu_version_from_defines(defines):
        dot = '.'
        major = defines.get('__GNUC__', '0')
        minor = defines.get('__GNUC_MINOR__', '0')
        patch = defines.get('__GNUC_PATCHLEVEL__', '0')
        return dot.join((major, minor, patch))

    @staticmethod
    def get_lcc_version_from_defines(defines):
        dot = '.'
        generation_and_major = defines.get('__LCC__', '100')
        generation = generation_and_major[:1]
        major = generation_and_major[1:]
        minor = defines.get('__LCC_MINOR__', '0')
        return dot.join((generation, major, minor))

    def _get_compilers(self, lang, for_machine):
        '''
        The list of compilers is detected in the exact same way for
        C, C++, ObjC, ObjC++, Fortran, CS so consolidate it here.
        '''
        value = self.binaries[for_machine].lookup_entry(lang)
        if value is not None:
            compilers, ccache = BinaryTable.parse_entry(value)
            # Return value has to be a list of compiler 'choices'
            compilers = [compilers]
        else:
            if not self.machines.matches_build_machine(for_machine):
                raise EnvironmentException('{!r} compiler binary not defined in cross or native file'.format(lang))
            compilers = getattr(self, 'default_' + lang)
            ccache = BinaryTable.detect_ccache()

        if self.machines.matches_build_machine(for_machine):
            exe_wrap = None
        else:
            exe_wrap = self.get_exe_wrapper()

        return compilers, ccache, exe_wrap

    def _handle_exceptions(self, exceptions, binaries, bintype='compiler'):
        errmsg = 'Unknown {}(s): {}'.format(bintype, binaries)
        if exceptions:
            errmsg += '\nThe follow exceptions were encountered:'
            for (c, e) in exceptions.items():
                errmsg += '\nRunning "{0}" gave "{1}"'.format(c, e)
        raise EnvironmentException(errmsg)

    def _guess_win_linker(self, compiler: T.List[str], comp_class: Compiler,
                          for_machine: MachineChoice, *,
                          use_linker_prefix: bool = True) -> 'DynamicLinker':
        self.coredata.add_lang_args(comp_class.language, comp_class, for_machine, self)

        # Explicitly pass logo here so that we can get the version of link.exe
        if not use_linker_prefix or comp_class.LINKER_PREFIX is None:
            check_args = ['/logo', '--version']
        elif isinstance(comp_class.LINKER_PREFIX, str):
            check_args = [comp_class.LINKER_PREFIX + '/logo', comp_class.LINKER_PREFIX + '--version']
        elif isinstance(comp_class.LINKER_PREFIX, list):
            check_args = comp_class.LINKER_PREFIX + ['/logo'] + comp_class.LINKER_PREFIX + ['--version']

        check_args += self.coredata.compiler_options[for_machine][comp_class.language + '_args'].value

        override = []  # type: T.List[str]
        value = self.binaries[for_machine].lookup_entry(comp_class.language + '_ld')
        if value is not None:
            override = comp_class.use_linker_args(value[0])
            check_args += override

        p, o, _ = Popen_safe(compiler + check_args)
        if o.startswith('LLD'):
            if '(compatible with GNU linkers)' in o:
                return LLVMDynamicLinker(
                    compiler, for_machine, comp_class.LINKER_PREFIX,
                    override, version=search_version(o))

        if value is not None:
            compiler = value

        p, o, e = Popen_safe(compiler + check_args)
        if o.startswith('LLD'):
            return ClangClDynamicLinker(
                for_machine, [],
                prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [],
                exelist=compiler, version=search_version(o))
        elif 'OPTLINK' in o:
            # Opltink's stdout *may* beging with a \r character.
            return OptlinkDynamicLinker(for_machine, version=search_version(o))
        elif o.startswith('Microsoft') or e.startswith('Microsoft'):
            out = o or e
            match = re.search(r'.*(X86|X64|ARM|ARM64).*', out)
            if match:
                target = str(match.group(1))
            else:
                target = 'x86'

            return MSVCDynamicLinker(
                for_machine, [], machine=target, exelist=compiler,
                prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [],
                version=search_version(out))
        elif 'GNU coreutils' in o:
            raise EnvironmentException(
                "Found GNU link.exe instead of MSVC link.exe. This link.exe "
                "is not a linker. You may need to reorder entries to your "
                "%PATH% variable to resolve this.")
        raise EnvironmentException('Unable to determine dynamic linker')

    def _guess_nix_linker(self, compiler: T.List[str], comp_class: T.Type[Compiler],
                          for_machine: MachineChoice, *,
                          extra_args: T.Optional[T.List[str]] = None) -> 'DynamicLinker':
        """Helper for guessing what linker to use on Unix-Like OSes.

        :compiler: Invocation to use to get linker
        :comp_class: The Compiler Type (uninstantiated)
        :for_machine: which machine this linker targets
        :extra_args: Any additional arguments required (such as a source file)
        """
        self.coredata.add_lang_args(comp_class.language, comp_class, for_machine, self)
        extra_args = T.cast(T.List[str], extra_args or [])
        extra_args += self.coredata.compiler_options[for_machine][comp_class.language + '_args'].value

        if isinstance(comp_class.LINKER_PREFIX, str):
            check_args = [comp_class.LINKER_PREFIX + '--version'] + extra_args
        else:
            check_args = comp_class.LINKER_PREFIX + ['--version'] + extra_args

        override = []  # type: T.List[str]
        value = self.binaries[for_machine].lookup_entry(comp_class.language + '_ld')
        if value is not None:
            override = comp_class.use_linker_args(value[0])
            check_args += override

        _, o, e = Popen_safe(compiler + check_args)
        v = search_version(o)
        if o.startswith('LLD'):
            linker = LLVMDynamicLinker(
                compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)  # type: DynamicLinker
        elif e.startswith('lld-link: '):
            # Toolchain wrapper got in the way; this happens with e.g. https://github.com/mstorsjo/llvm-mingw
            # Let's try to extract the linker invocation command to grab the version.

            _, o, e = Popen_safe(compiler + check_args + ['-v'])

            try:
                linker_cmd = re.match(r'.*\n(.*?)\nlld-link: ', e, re.DOTALL).group(1)
                linker_cmd = shlex.split(linker_cmd)[0]
            except (AttributeError, IndexError, ValueError):
                pass
            else:
                _, o, e = Popen_safe([linker_cmd, '--version'])
                v = search_version(o)

            linker = LLVMDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
        # first is for apple clang, second is for real gcc, the third is icc
        elif e.endswith('(use -v to see invocation)\n') or 'macosx_version' in e or 'ld: unknown option:' in e:
            if isinstance(comp_class.LINKER_PREFIX, str):
                _, _, e = Popen_safe(compiler + [comp_class.LINKER_PREFIX + '-v'] + extra_args)
            else:
                _, _, e = Popen_safe(compiler + comp_class.LINKER_PREFIX + ['-v'] + extra_args)
            for line in e.split('\n'):
                if 'PROJECT:ld' in line:
                    v = line.split('-')[1]
                    break
            else:
                v = 'unknown version'
            linker = AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
        elif 'GNU' in o:
            if 'gold' in o:
                cls = GnuGoldDynamicLinker
            else:
                cls = GnuBFDDynamicLinker
            linker = cls(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
        elif 'Solaris' in e or 'Solaris' in o:
            linker = SolarisDynamicLinker(
                compiler, for_machine, comp_class.LINKER_PREFIX, override,
                version=search_version(e))
        else:
            raise EnvironmentException('Unable to determine dynamic linker')
        return linker

    def _detect_c_or_cpp_compiler(self, lang: str, for_machine: MachineChoice) -> Compiler:
        popen_exceptions = {}
        compilers, ccache, exe_wrap = self._get_compilers(lang, for_machine)
        is_cross = not self.machines.matches_build_machine(for_machine)
        info = self.machines[for_machine]

        for compiler in compilers:
            if isinstance(compiler, str):
                compiler = [compiler]
            compiler_name = os.path.basename(compiler[0])

            if not set(['cl', 'cl.exe', 'clang-cl', 'clang-cl.exe']).isdisjoint(compiler):
                # Watcom C provides it's own cl.exe clone that mimics an older
                # version of Microsoft's compiler. Since Watcom's cl.exe is
                # just a wrapper, we skip using it if we detect its presence
                # so as not to confuse Meson when configuring for MSVC.
                #
                # Additionally the help text of Watcom's cl.exe is paged, and
                # the binary will not exit without human intervention. In
                # practice, Meson will block waiting for Watcom's cl.exe to
                # exit, which requires user input and thus will never exit.
                if 'WATCOM' in os.environ:
                    def sanitize(p):
                        return os.path.normcase(os.path.abspath(p))

                    watcom_cls = [sanitize(os.path.join(os.environ['WATCOM'], 'BINNT', 'cl')),
                                  sanitize(os.path.join(os.environ['WATCOM'], 'BINNT', 'cl.exe'))]
                    found_cl = sanitize(shutil.which('cl'))
                    if found_cl in watcom_cls:
                        continue
                arg = '/?'
            elif 'armcc' in compiler_name:
                arg = '--vsn'
            elif 'ccrx' in compiler_name:
                arg = '-v'
            elif 'icl' in compiler_name:
                # if you pass anything to icl you get stuck in a pager
                arg = ''
            else:
                arg = '--version'

            try:
                p, out, err = Popen_safe(compiler + [arg])
            except OSError as e:
                popen_exceptions[' '.join(compiler + [arg])] = e
                continue

            if 'ccrx' in compiler_name:
                out = err

            full_version = out.split('\n', 1)[0]
            version = search_version(out)

            guess_gcc_or_lcc = False
            if 'Free Software Foundation' in out or 'xt-' in out:
                guess_gcc_or_lcc = 'gcc'
            if 'e2k' in out and 'lcc' in out:
                guess_gcc_or_lcc = 'lcc'

            if guess_gcc_or_lcc:
                defines = self.get_gnu_compiler_defines(compiler)
                if not defines:
                    popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
                    continue

                if guess_gcc_or_lcc == 'lcc':
                    version = self.get_lcc_version_from_defines(defines)
                    cls = ElbrusCCompiler if lang == 'c' else ElbrusCPPCompiler
                else:
                    version = self.get_gnu_version_from_defines(defines)
                    cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler

                linker = self._guess_nix_linker(compiler, cls, for_machine)

                return cls(
                    ccache + compiler, version, for_machine, is_cross,
                    info, exe_wrap, defines, full_version=full_version,
                    linker=linker)

            if 'Emscripten' in out:
                cls = EmscriptenCCompiler if lang == 'c' else EmscriptenCPPCompiler
                self.coredata.add_lang_args(cls.language, cls, for_machine, self)
                return cls(
                    ccache + compiler, version, for_machine, is_cross, info,
                    exe_wrap, full_version=full_version)

            if 'armclang' in out:
                # The compiler version is not present in the first line of output,
                # instead it is present in second line, startswith 'Component:'.
                # So, searching for the 'Component' in out although we know it is
                # present in second line, as we are not sure about the
                # output format in future versions
                arm_ver_str = re.search('.*Component.*', out)
                if arm_ver_str is None:
                    popen_exceptions[' '.join(compiler)] = 'version string not found'
                    continue
                arm_ver_str = arm_ver_str.group(0)
                # Override previous values
                version = search_version(arm_ver_str)
                full_version = arm_ver_str
                cls = ArmclangCCompiler if lang == 'c' else ArmclangCPPCompiler
                linker = ArmClangDynamicLinker(for_machine, version=version)
                self.coredata.add_lang_args(cls.language, cls, for_machine, self)
                return cls(
                    ccache + compiler, version, for_machine, is_cross, info,
                    exe_wrap, full_version=full_version, linker=linker)
            if 'CL.EXE COMPATIBILITY' in out:
                # if this is clang-cl masquerading as cl, detect it as cl, not
                # clang
                arg = '--version'
                try:
                    p, out, err = Popen_safe(compiler + [arg])
                except OSError as e:
                    popen_exceptions[' '.join(compiler + [arg])] = e
                version = search_version(out)
                match = re.search('^Target: (.*?)-', out, re.MULTILINE)
                if match:
                    target = match.group(1)
                else:
                    target = 'unknown target'
                cls = ClangClCCompiler if lang == 'c' else ClangClCPPCompiler
                linker = self._guess_win_linker(['lld-link'], cls, for_machine)
                return cls(
                    compiler, version, for_machine, is_cross, info, exe_wrap,
                    target, linker=linker)
            if 'clang' in out:
                linker = None

                # Even if the for_machine is darwin, we could be using vanilla
                # clang.
                if 'Apple' in out:
                    cls = AppleClangCCompiler if lang == 'c' else AppleClangCPPCompiler
                else:
                    cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler

                if 'windows' in out or self.machines[for_machine].is_windows():
                    # If we're in a MINGW context this actually will use a gnu
                    # style ld, but for clang on "real" windows we'll use
                    # either link.exe or lld-link.exe
                    try:
                        linker = self._guess_win_linker(compiler, cls, for_machine)
                    except MesonException:
                        pass
                if linker is None:
                    linker = self._guess_nix_linker(compiler, cls, for_machine)

                return cls(
                    ccache + compiler, version, for_machine, is_cross, info,
                    exe_wrap, full_version=full_version, linker=linker)

            if 'Intel(R) C++ Intel(R)' in err:
                version = search_version(err)
                target = 'x86' if 'IA-32' in err else 'x86_64'
                cls = IntelClCCompiler if lang == 'c' else IntelClCPPCompiler
                self.coredata.add_lang_args(cls.language, cls, for_machine, self)
                linker = XilinkDynamicLinker(for_machine, [], version=version)
                return cls(
                    compiler, version, for_machine, is_cross, info=info,
                    exe_wrap=exe_wrap, target=target, linker=linker)
            if 'Microsoft' in out or 'Microsoft' in err:
                # Latest versions of Visual Studio print version
                # number to stderr but earlier ones print version
                # on stdout.  Why? Lord only knows.
                # Check both outputs to figure out version.
                for lookat in [err, out]:
                    version = search_version(lookat)
                    if version != 'unknown version':
                        break
                else:
                    m = 'Failed to detect MSVC compiler version: stderr was\n{!r}'
                    raise EnvironmentException(m.format(err))
                cl_signature = lookat.split('\n')[0]
                match = re.search('.*(x86|x64|ARM|ARM64)$', cl_signature)
                if match:
                    target = match.group(1)
                else:
                    m = 'Failed to detect MSVC compiler target architecture: \'cl /?\' output is\n{}'
                    raise EnvironmentException(m.format(cl_signature))
                cls = VisualStudioCCompiler if lang == 'c' else VisualStudioCPPCompiler
                linker = self._guess_win_linker(['link'], cls, for_machine)
                return cls(
                    compiler, version, for_machine, is_cross, info, exe_wrap,
                    target, linker=linker)
            if 'PGI Compilers' in out:
                cls = PGICCompiler if lang == 'c' else PGICPPCompiler
                self.coredata.add_lang_args(cls.language, cls, for_machine, self)
                linker = PGIDynamicLinker(compiler, for_machine, cls.LINKER_PREFIX, [], version=version)
                return cls(
                    ccache + compiler, version, for_machine, is_cross,
                    info, exe_wrap, linker=linker)
            if '(ICC)' in out:
                cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler
                l = self._guess_nix_linker(compiler, cls, for_machine)
                return cls(
                    ccache + compiler, version, for_machine, is_cross, info,
                    exe_wrap, full_version=full_version, linker=l)
            if 'ARM' in out:
                cls = ArmCCompiler if lang == 'c' else ArmCPPCompiler
                self.coredata.add_lang_args(cls.language, cls, for_machine, self)
                linker = ArmDynamicLinker(for_machine, version=version)
                return cls(
                    ccache + compiler, version, for_machine, is_cross,
                    info, exe_wrap, full_version=full_version, linker=linker)
            if 'RX Family' in out:
                cls = CcrxCCompiler if lang == 'c' else CcrxCPPCompiler
                self.coredata.add_lang_args(cls.language, cls, for_machine, self)
                linker = CcrxDynamicLinker(for_machine, version=version)
                return cls(
                    ccache + compiler, version, for_machine, is_cross, info,
                    exe_wrap, full_version=full_version, linker=linker)

        self._handle_exceptions(popen_exceptions, compilers)

    def detect_c_compiler(self, for_machine):
        return self._detect_c_or_cpp_compiler('c', for_machine)

    def detect_cpp_compiler(self, for_machine):
        return self._detect_c_or_cpp_compiler('cpp', for_machine)

    def detect_cuda_compiler(self, for_machine):
        popen_exceptions = {}
        is_cross = not self.machines.matches_build_machine(for_machine)
        compilers, ccache, exe_wrap = self._get_compilers('cuda', for_machine)
        info = self.machines[for_machine]
        for compiler in compilers:
            if isinstance(compiler, str):
                compiler = [compiler]
            else:
                raise EnvironmentException()
            arg = '--version'
            try:
                p, out, err = Popen_safe(compiler + [arg])
            except OSError as e:
                popen_exceptions[' '.join(compiler + [arg])] = e
                continue
            # Example nvcc printout:
            #
            #     nvcc: NVIDIA (R) Cuda compiler driver
            #     Copyright (c) 2005-2018 NVIDIA Corporation
            #     Built on Sat_Aug_25_21:08:01_CDT_2018
            #     Cuda compilation tools, release 10.0, V10.0.130
            #
            # search_version() first finds the "10.0" after "release",
            # rather than the more precise "10.0.130" after "V".
            # The patch version number is occasionally important; For
            # instance, on Linux,
            #    - CUDA Toolkit 8.0.44 requires NVIDIA Driver 367.48
            #    - CUDA Toolkit 8.0.61 requires NVIDIA Driver 375.26
            # Luckily, the "V" also makes it very simple to extract
            # the full version:
            version = out.strip().split('V')[-1]
            cpp_compiler = self.detect_cpp_compiler(for_machine)
            cls = CudaCompiler
            self.coredata.add_lang_args(cls.language, cls, for_machine, self)
            linker = CudaLinker(compiler, for_machine, 'nvlink', CudaCompiler.LINKER_PREFIX, [], version=CudaLinker.parse_version())
            return cls(ccache + compiler, version, for_machine, is_cross, exe_wrap, host_compiler=cpp_compiler, info=info, linker=linker)
        raise EnvironmentException('Could not find suitable CUDA compiler: "' + ' '.join(compilers) + '"')

    def detect_fortran_compiler(self, for_machine: MachineChoice):
        popen_exceptions = {}
        compilers, ccache, exe_wrap = self._get_compilers('fortran', for_machine)
        is_cross = not self.machines.matches_build_machine(for_machine)
        info = self.machines[for_machine]
        for compiler in compilers:
            if isinstance(compiler, str):
                compiler = [compiler]
            for arg in ['--version', '-V']:
                try:
                    p, out, err = Popen_safe(compiler + [arg])
                except OSError as e:
                    popen_exceptions[' '.join(compiler + [arg])] = e
                    continue

                version = search_version(out)
                full_version = out.split('\n', 1)[0]

                guess_gcc_or_lcc = False
                if 'GNU Fortran' in out:
                    guess_gcc_or_lcc = 'gcc'
                if 'e2k' in out and 'lcc' in out:
                    guess_gcc_or_lcc = 'lcc'

                if guess_gcc_or_lcc:
                    defines = self.get_gnu_compiler_defines(compiler)
                    if not defines:
                        popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
                        continue
                    if guess_gcc_or_lcc == 'lcc':
                        version = self.get_lcc_version_from_defines(defines)
                        cls = ElbrusFortranCompiler
                    else:
                        version = self.get_gnu_version_from_defines(defines)
                        cls = GnuFortranCompiler
                    linker = self._guess_nix_linker(
                        compiler, cls, for_machine)
                    return cls(
                        compiler, version, for_machine, is_cross, info,
                        exe_wrap, defines, full_version=full_version,
                        linker=linker)

                if 'G95' in out:
                    linker = self._guess_nix_linker(
                        compiler, cls, for_machine)
                    return G95FortranCompiler(
                        compiler, version, for_machine, is_cross, info,
                        exe_wrap, full_version=full_version, linker=linker)

                if 'Sun Fortran' in err:
                    version = search_version(err)
                    linker = self._guess_nix_linker(
                        compiler, cls, for_machine)
                    return SunFortranCompiler(
                        compiler, version, for_machine, is_cross, info,
                        exe_wrap, full_version=full_version, linker=linker)

                if 'Intel(R) Visual Fortran' in err:
                    version = search_version(err)
                    target = 'x86' if 'IA-32' in err else 'x86_64'
                    cls = IntelClFortranCompiler
                    self.coredata.add_lang_args(cls.language, cls, for_machine, self)
                    linker = XilinkDynamicLinker(for_machine, [], version=version)
                    return cls(
                        compiler, version, for_machine, is_cross, target,
                        info, exe_wrap, linker=linker)

                if 'ifort (IFORT)' in out:
                    linker = self._guess_nix_linker(compiler, IntelFortranCompiler, for_machine)
                    return IntelFortranCompiler(
                        compiler, version, for_machine, is_cross, info,
                        exe_wrap, full_version=full_version, linker=linker)

                if 'PathScale EKOPath(tm)' in err:
                    return PathScaleFortranCompiler(
                        compiler, version, for_machine, is_cross, info,
                        exe_wrap, full_version=full_version)

                if 'PGI Compilers' in out:
                    cls = PGIFortranCompiler
                    self.coredata.add_lang_args(cls.language, cls, for_machine, self)
                    linker = PGIDynamicLinker(compiler, for_machine,
                                              cls.LINKER_PREFIX, [], version=version)
                    return cls(
                        compiler, version, for_machine, is_cross, info, exe_wrap,
                        full_version=full_version, linker=linker)

                if 'flang' in out or 'clang' in out:
                    linker = self._guess_nix_linker(
                        compiler, FlangFortranCompiler, for_machine)
                    return FlangFortranCompiler(
                        compiler, version, for_machine, is_cross, info,
                        exe_wrap, full_version=full_version, linker=linker)

                if 'Open64 Compiler Suite' in err:
                    linker = self._guess_nix_linker(
                        compiler, Open64FortranCompiler, for_machine)
                    return Open64FortranCompiler(
                        compiler, version, for_machine, is_cross, info,
                        exe_wrap, full_version=full_version, linker=linker)

                if 'NAG Fortran' in err:
                    linker = self._guess_nix_linker(
                        compiler, NAGFortranCompiler, for_machine)
                    return NAGFortranCompiler(
                        compiler, version, for_machine, is_cross, info,
                        exe_wrap, full_version=full_version, linker=linker)

        self._handle_exceptions(popen_exceptions, compilers)

    def get_scratch_dir(self):
        return self.scratch_dir

    def detect_objc_compiler(self, for_machine: MachineInfo) -> 'Compiler':
        return self._detect_objc_or_objcpp_compiler(for_machine, True)

    def detect_objcpp_compiler(self, for_machine: MachineInfo) -> 'Compiler':
        return self._detect_objc_or_objcpp_compiler(for_machine, False)

    def _detect_objc_or_objcpp_compiler(self, for_machine: MachineInfo, objc: bool) -> 'Compiler':
        popen_exceptions = {}
        compilers, ccache, exe_wrap = self._get_compilers('objc' if objc else 'objcpp', for_machine)
        is_cross = not self.machines.matches_build_machine(for_machine)
        info = self.machines[for_machine]

        for compiler in compilers:
            if isinstance(compiler, str):
                compiler = [compiler]
            arg = ['--version']
            try:
                p, out, err = Popen_safe(compiler + arg)
            except OSError as e:
                popen_exceptions[' '.join(compiler + arg)] = e
                continue
            version = search_version(out)
            if 'Free Software Foundation' in out:
                defines = self.get_gnu_compiler_defines(compiler)
                if not defines:
                    popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
                    continue
                version = self.get_gnu_version_from_defines(defines)
                comp = GnuObjCCompiler if objc else GnuObjCPPCompiler
                linker = self._guess_nix_linker(compiler, comp, for_machine)
                return comp(
                    ccache + compiler, version, for_machine, is_cross, info,
                    exe_wrap, defines, linker=linker)
            if 'clang' in out:
                linker = None
                comp = ClangObjCCompiler if objc else ClangObjCPPCompiler
                if 'windows' in out or self.machines[for_machine].is_windows():
                    # If we're in a MINGW context this actually will use a gnu style ld
                    try:
                        linker = self._guess_win_linker(compiler, comp, for_machine)
                    except MesonException:
                        pass

                if not linker:
                    linker = self._guess_nix_linker(
                        compiler, comp, for_machine)
                return comp(
                    ccache + compiler, version, for_machine,
                    is_cross, info, exe_wrap, linker=linker)
        self._handle_exceptions(popen_exceptions, compilers)

    def detect_java_compiler(self, for_machine):
        exelist = self.binaries.host.lookup_entry('java')
        info = self.machines[for_machine]
        if exelist is None:
            # TODO support fallback
            exelist = [self.default_java[0]]

        try:
            p, out, err = Popen_safe(exelist + ['-version'])
        except OSError:
            raise EnvironmentException('Could not execute Java compiler "%s"' % ' '.join(exelist))
        if 'javac' in out or 'javac' in err:
            version = search_version(err if 'javac' in err else out)
            if not version or version == 'unknown version':
                parts = (err if 'javac' in err else out).split()
                if len(parts) > 1:
                    version = parts[1]
            comp_class = JavaCompiler
            self.coredata.add_lang_args(comp_class.language, comp_class, for_machine, self)
            return comp_class(exelist, version, for_machine, info)
        raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')

    def detect_cs_compiler(self, for_machine):
        compilers, ccache, exe_wrap = self._get_compilers('cs', for_machine)
        popen_exceptions = {}
        info = self.machines[for_machine]
        for comp in compilers:
            if not isinstance(comp, list):
                comp = [comp]
            try:
                p, out, err = Popen_safe(comp + ['--version'])
            except OSError as e:
                popen_exceptions[' '.join(comp + ['--version'])] = e
                continue

            version = search_version(out)
            if 'Mono' in out:
                cls = MonoCompiler
            elif "Visual C#" in out:
                cls = VisualStudioCsCompiler
            self.coredata.add_lang_args(cls.language, cls, for_machine, self)
            return cls(comp, version, for_machine, info)

        self._handle_exceptions(popen_exceptions, compilers)

    def detect_vala_compiler(self, for_machine):
        exelist = self.binaries.host.lookup_entry('vala')
        is_cross = not self.machines.matches_build_machine(for_machine)
        info = self.machines[for_machine]
        if exelist is None:
            # TODO support fallback
            exelist = [self.default_vala[0]]

        try:
            p, out = Popen_safe(exelist + ['--version'])[0:2]
        except OSError:
            raise EnvironmentException('Could not execute Vala compiler "%s"' % ' '.join(exelist))
        version = search_version(out)
        if 'Vala' in out:
            comp_class = ValaCompiler
            self.coredata.add_lang_args(comp_class.language, comp_class, for_machine, self)
            return comp_class(exelist, version, for_machine, info, is_cross)
        raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')

    def detect_rust_compiler(self, for_machine):
        popen_exceptions = {}
        compilers, ccache, exe_wrap = self._get_compilers('rust', for_machine)
        is_cross = not self.machines.matches_build_machine(for_machine)
        info = self.machines[for_machine]

        cc = self.detect_c_compiler(for_machine)
        is_link_exe = isinstance(cc.linker, VisualStudioLikeLinkerMixin)
        override = self.binaries[for_machine].lookup_entry('rust_ld')

        for compiler in compilers:
            if isinstance(compiler, str):
                compiler = [compiler]
            arg = ['--version']
            try:
                p, out = Popen_safe(compiler + arg)[0:2]
            except OSError as e:
                popen_exceptions[' '.join(compiler + arg)] = e
                continue

            version = search_version(out)

            if 'rustc' in out:
                # On Linux and mac rustc will invoke gcc (clang for mac
                # presumably) and it can do this windows, for dynamic linking.
                # this means the easiest way to C compiler for dynamic linking.
                # figure out what linker to use is to just get the value of the
                # C compiler and use that as the basis of the rust linker.
                # However, there are two things we need to change, if CC is not
                # the default use that, and second add the necessary arguments
                # to rust to use -fuse-ld

                if override is None:
                    extra_args = {}
                    always_args = []
                    if is_link_exe:
                        compiler.extend(['-C', 'linker={}'.format(cc.linker.exelist[0])])
                        extra_args['direct'] = True
                        extra_args['machine'] = cc.linker.machine
                    elif not ((info.is_darwin() and isinstance(cc, AppleClangCCompiler)) or
                              isinstance(cc, GnuCCompiler)):
                        c = cc.exelist[1] if cc.exelist[0].endswith('ccache') else cc.exelist[0]
                        compiler.extend(['-C', 'linker={}'.format(c)])

                    # This trickery with type() gets us the class of the linker
                    # so we can initialize a new copy for the Rust Compiler
                    if is_link_exe:
                        linker = type(cc.linker)(for_machine, always_args, exelist=cc.linker.exelist,
                                                 version=cc.linker.version, **extra_args)
                    else:
                        linker = type(cc.linker)(compiler, for_machine, cc.LINKER_PREFIX,
                                                 always_args=always_args, version=cc.linker.version,
                                                 **extra_args)
                elif 'link' in override[0]:
                    linker = self._guess_win_linker(
                        override, RustCompiler, for_machine, use_linker_prefix=False)
                    linker.direct = True
                else:
                    # We're creating a new type of "C" compiler, that has rust
                    # as it's language. This is gross, but I can't figure out
                    # another way to handle this, because rustc is actually
                    # invoking the c compiler as it's linker.
                    b = type('b', (type(cc), ), {})
                    b.language = RustCompiler.language
                    linker = self._guess_nix_linker(cc.exelist, b, for_machine)

                    # Of course, we're not going to use any of that, we just
                    # need it to get the proper arguments to pass to rustc
                    c = cc.exelist[1] if cc.exelist[0].endswith('ccache') else cc.exelist[0]
                    compiler.extend(['-C', 'linker={}'.format(c)])
                    compiler.extend(['-C', 'link-args={}'.format(' '.join(cc.use_linker_args(override[0])))])

                self.coredata.add_lang_args(RustCompiler.language, RustCompiler, for_machine, self)
                return RustCompiler(
                    compiler, version, for_machine, is_cross, info, exe_wrap,
                    linker=linker)

        self._handle_exceptions(popen_exceptions, compilers)

    def detect_d_compiler(self, for_machine: MachineChoice):
        info = self.machines[for_machine]

        # Detect the target architecture, required for proper architecture handling on Windows.
        # MSVC compiler is required for correct platform detection.
        c_compiler = {'c': self.detect_c_compiler(for_machine)}
        is_msvc = isinstance(c_compiler['c'], VisualStudioCCompiler)
        if not is_msvc:
            c_compiler = {}

        arch = detect_cpu_family(c_compiler)
        if is_msvc and arch == 'x86':
            arch = 'x86_mscoff'

        popen_exceptions = {}
        is_cross = not self.machines.matches_build_machine(for_machine)
        results, ccache, exe_wrap = self._get_compilers('d', for_machine)
        for exelist in results:
            # Search for a D compiler.
            # We prefer LDC over GDC unless overridden with the DC
            # environment variable because LDC has a much more
            # up to date language version at time (2016).
            if not isinstance(exelist, list):
                exelist = [exelist]
            if os.path.basename(exelist[-1]).startswith(('ldmd', 'gdmd')):
                raise EnvironmentException(
                    'Meson does not support {} as it is only a DMD frontend for another compiler.'
                    'Please provide a valid value for DC or unset it so that Meson can resolve the compiler by itself.'.format(exelist[-1]))
            try:
                p, out = Popen_safe(exelist + ['--version'])[0:2]
            except OSError as e:
                popen_exceptions[' '.join(exelist + ['--version'])] = e
                continue
            version = search_version(out)
            full_version = out.split('\n', 1)[0]

            if 'LLVM D compiler' in out:
                # LDC seems to require a file
                if info.is_windows() or info.is_cygwin():
                    # Getting LDC on windows to give useful linker output when
                    # not doing real work is painfully hard. It ships with a
                    # version of lld-link, so unless we think the user wants
                    # link.exe, just assume that we're going to use lld-link
                    # with it.
                    linker = self._guess_win_linker(
                        ['link' if is_msvc else 'lld-link'],
                        compilers.LLVMDCompiler, for_machine, use_linker_prefix=False)
                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, compilers.LLVMDCompiler, for_machine,
                            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)
            elif 'gdc' in out:
                linker = self._guess_nix_linker(exelist, compilers.GnuDCompiler, for_machine)
                return compilers.GnuDCompiler(
                    exelist, version, for_machine, info, arch, is_cross, exe_wrap,
                    full_version=full_version, linker=linker)
            elif 'The D Language Foundation' in out or 'Digital Mars' in out:
                # DMD seems to require a file
                if info.is_windows() or info.is_cygwin():
                    if is_msvc:
                        linker_cmd = ['link']
                    elif arch == 'x86':
                        linker_cmd = ['optlink']
                    else:
                        linker_cmd = ['lld-link']
                    linker = self._guess_win_linker(linker_cmd, compilers.DmdDCompiler, for_machine,
                                                    use_linker_prefix=False)
                else:
                    with tempfile.NamedTemporaryFile(suffix='.d') as f:
                        linker = self._guess_nix_linker(
                            exelist, compilers.DmdDCompiler, for_machine,
                            extra_args=[f.name])
                return compilers.DmdDCompiler(
                    exelist, version, for_machine, info, arch,
                    full_version=full_version, linker=linker)
            raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')

        self._handle_exceptions(popen_exceptions, compilers)

    def detect_swift_compiler(self, for_machine):
        exelist = self.binaries.host.lookup_entry('swift')
        is_cross = not self.machines.matches_build_machine(for_machine)
        info = self.machines[for_machine]
        if exelist is None:
            # TODO support fallback
            exelist = [self.default_swift[0]]

        try:
            p, _, err = Popen_safe(exelist + ['-v'])
        except OSError:
            raise EnvironmentException('Could not execute Swift compiler "%s"' % ' '.join(exelist))
        version = search_version(err)
        if 'Swift' in err:
            # As for 5.0.1 swiftc *requires* a file to check the linker:
            with tempfile.NamedTemporaryFile(suffix='.swift') as f:
                linker = self._guess_nix_linker(
                    exelist, compilers.SwiftCompiler, for_machine,
                    extra_args=[f.name])
            return compilers.SwiftCompiler(
                exelist, version, for_machine, info, is_cross, linker=linker)

        raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')

    def compiler_from_language(self, lang: str, for_machine: MachineChoice):
        if lang == 'c':
            comp = self.detect_c_compiler(for_machine)
        elif lang == 'cpp':
            comp = self.detect_cpp_compiler(for_machine)
        elif lang == 'objc':
            comp = self.detect_objc_compiler(for_machine)
        elif lang == 'cuda':
            comp = self.detect_cuda_compiler(for_machine)
        elif lang == 'objcpp':
            comp = self.detect_objcpp_compiler(for_machine)
        elif lang == 'java':
            comp = self.detect_java_compiler(for_machine)
        elif lang == 'cs':
            comp = self.detect_cs_compiler(for_machine)
        elif lang == 'vala':
            comp = self.detect_vala_compiler(for_machine)
        elif lang == 'd':
            comp = self.detect_d_compiler(for_machine)
        elif lang == 'rust':
            comp = self.detect_rust_compiler(for_machine)
        elif lang == 'fortran':
            comp = self.detect_fortran_compiler(for_machine)
        elif lang == 'swift':
            comp = self.detect_swift_compiler(for_machine)
        else:
            comp = None
        return comp

    def detect_compiler_for(self, lang: str, for_machine: MachineChoice):
        comp = self.compiler_from_language(lang, for_machine)
        if comp is not None:
            assert comp.for_machine == for_machine
            self.coredata.process_new_compiler(lang, comp, self)
        return comp

    def detect_static_linker(self, compiler):
        linker = self.binaries[compiler.for_machine].lookup_entry('ar')
        if linker is not None:
            linkers = [linker]
        else:
            evar = 'AR'
            defaults = [[l] for l in self.default_static_linker]
            if isinstance(compiler, compilers.CudaCompiler):
                linkers = [self.cuda_static_linker] + defaults
            elif evar in os.environ:
                linkers = [split_args(os.environ[evar])]
            elif isinstance(compiler, compilers.VisualStudioLikeCompiler):
                linkers = [self.vs_static_linker, self.clang_cl_static_linker]
            elif isinstance(compiler, compilers.GnuCompiler):
                # Use gcc-ar if available; needed for LTO
                linkers = [self.gcc_static_linker] + defaults
            elif isinstance(compiler, compilers.ClangCompiler):
                # Use llvm-ar if available; needed for LTO
                linkers = [self.clang_static_linker] + defaults
            elif isinstance(compiler, compilers.DCompiler):
                # Prefer static linkers over linkers used by D compilers
                if mesonlib.is_windows():
                    linkers = [self.vs_static_linker, self.clang_cl_static_linker, compiler.get_linker_exelist()]
                else:
                    linkers = defaults
            elif isinstance(compiler, IntelClCCompiler):
                # Intel has it's own linker that acts like microsoft's lib
                linkers = ['xilib']
            elif isinstance(compiler, (PGICCompiler, PGIFortranCompiler)) and mesonlib.is_windows():
                linkers = [['ar']]  # For PGI on Windows, "ar" is just a wrapper calling link/lib.
            else:
                linkers = defaults
        popen_exceptions = {}
        for linker in linkers:
            if not {'lib', 'lib.exe', 'llvm-lib', 'llvm-lib.exe', 'xilib', 'xilib.exe'}.isdisjoint(linker):
                arg = '/?'
            else:
                arg = '--version'
            try:
                p, out, err = Popen_safe(linker + [arg])
            except OSError as e:
                popen_exceptions[' '.join(linker + [arg])] = e
                continue
            if "xilib: executing 'lib'" in err:
                return IntelVisualStudioLinker(linker, getattr(compiler, 'machine', None))
            if '/OUT:' in out.upper() or '/OUT:' in err.upper():
                return VisualStudioLinker(linker, getattr(compiler, 'machine', None))
            if 'ar-Error-Unknown switch: --version' in err:
                return PGIStaticLinker(linker)
            if p.returncode == 0 and ('armar' in linker or 'armar.exe' in linker):
                return ArmarLinker(linker)
            if 'DMD32 D Compiler' in out or 'DMD64 D Compiler' in out:
                return DLinker(linker, compiler.arch)
            if 'LDC - the LLVM D compiler' in out:
                return DLinker(linker, compiler.arch)
            if 'GDC' in out and ' based on D ' in out:
                return DLinker(linker, compiler.arch)
            if err.startswith('Renesas') and ('rlink' in linker or 'rlink.exe' in linker):
                return CcrxLinker(linker)
            if p.returncode == 0:
                return ArLinker(linker)
            if p.returncode == 1 and err.startswith('usage'): # OSX
                return ArLinker(linker)
            if p.returncode == 1 and err.startswith('Usage'): # AIX
                return ArLinker(linker)
            if p.returncode == 1 and err.startswith('ar: bad option: --'): # Solaris
                return ArLinker(linker)
        self._handle_exceptions(popen_exceptions, linkers, 'linker')
        raise EnvironmentException('Unknown static linker "%s"' % ' '.join(linkers))

    def get_source_dir(self):
        return self.source_dir

    def get_build_dir(self):
        return self.build_dir

    def get_import_lib_dir(self) -> str:
        "Install dir for the import library (library used for linking)"
        return self.get_libdir()

    def get_shared_module_dir(self) -> str:
        "Install dir for shared modules that are loaded at runtime"
        return self.get_libdir()

    def get_shared_lib_dir(self) -> str:
        "Install dir for the shared library"
        m = self.machines.host
        # Windows has no RPATH or similar, so DLLs must be next to EXEs.
        if m.is_windows() or m.is_cygwin():
            return self.get_bindir()
        return self.get_libdir()

    def get_static_lib_dir(self) -> str:
        "Install dir for the static library"
        return self.get_libdir()

    def get_prefix(self) -> str:
        return self.coredata.get_builtin_option('prefix')

    def get_libdir(self) -> str:
        return self.coredata.get_builtin_option('libdir')

    def get_libexecdir(self) -> str:
        return self.coredata.get_builtin_option('libexecdir')

    def get_bindir(self) -> str:
        return self.coredata.get_builtin_option('bindir')

    def get_includedir(self) -> str:
        return self.coredata.get_builtin_option('includedir')

    def get_mandir(self) -> str:
        return self.coredata.get_builtin_option('mandir')

    def get_datadir(self) -> str:
        return self.coredata.get_builtin_option('datadir')

    def get_compiler_system_dirs(self, for_machine: MachineChoice):
        for comp in self.coredata.compilers[for_machine].values():
            if isinstance(comp, compilers.ClangCompiler):
                index = 1
                break
            elif isinstance(comp, compilers.GnuCompiler):
                index = 2
                break
        else:
            # This option is only supported by gcc and clang. If we don't get a
            # GCC or Clang compiler return and empty list.
            return []

        p, out, _ = Popen_safe(comp.get_exelist() + ['-print-search-dirs'])
        if p.returncode != 0:
            raise mesonlib.MesonException('Could not calculate system search dirs')
        out = out.split('\n')[index].lstrip('libraries: =').split(':')
        return [os.path.normpath(p) for p in out]

    def need_exe_wrapper(self, for_machine: MachineChoice = MachineChoice.HOST):
        value = self.properties[for_machine].get('needs_exe_wrapper', None)
        if value is not None:
            return value
        return not machine_info_can_run(self.machines[for_machine])

    def get_exe_wrapper(self):
        if not self.need_exe_wrapper():
            from .dependencies import EmptyExternalProgram
            return EmptyExternalProgram()
        return self.exe_wrapper
meson-0.53.2/mesonbuild/interpreter.py0000644000175000017500000062631713625260316021415 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2018 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import mparser
from . import environment
from . import coredata
from . import dependencies
from . import mlog
from . import build
from . import optinterpreter
from . import compilers
from .wrap import wrap, WrapMode
from . import mesonlib
from .mesonlib import FileMode, MachineChoice, Popen_safe, listify, extract_as_list, has_path_sep
from .dependencies import ExternalProgram
from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException
from .depfile import DepFile
from .interpreterbase import InterpreterBase
from .interpreterbase import check_stringlist, flatten, noPosargs, noKwargs, stringArgs, permittedKwargs, noArgsFlattening
from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler, disablerIfNotFound
from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs
from .interpreterbase import ObjectHolder
from .modules import ModuleReturnValue
from .cmake import CMakeInterpreter

from pathlib import Path, PurePath
import os, shutil, uuid
import re, shlex
import subprocess
import collections
from itertools import chain
import functools
import typing as T

import importlib

permitted_method_kwargs = {
    'partial_dependency': {'compile_args', 'link_args', 'links', 'includes',
                           'sources'},
}

def stringifyUserArguments(args):
    if isinstance(args, list):
        return '[%s]' % ', '.join([stringifyUserArguments(x) for x in args])
    elif isinstance(args, dict):
        return '{%s}' % ', '.join(['%s : %s' % (stringifyUserArguments(k), stringifyUserArguments(v)) for k, v in args.items()])
    elif isinstance(args, int):
        return str(args)
    elif isinstance(args, str):
        return "'%s'" % args
    raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')


class OverrideProgram(dependencies.ExternalProgram):
    pass


class FeatureOptionHolder(InterpreterObject, ObjectHolder):
    def __init__(self, env, name, option):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, option)
        if option.is_auto():
            self.held_object = env.coredata.builtins['auto_features']
        self.name = name
        self.methods.update({'enabled': self.enabled_method,
                             'disabled': self.disabled_method,
                             'auto': self.auto_method,
                             })

    @noPosargs
    @permittedKwargs({})
    def enabled_method(self, args, kwargs):
        return self.held_object.is_enabled()

    @noPosargs
    @permittedKwargs({})
    def disabled_method(self, args, kwargs):
        return self.held_object.is_disabled()

    @noPosargs
    @permittedKwargs({})
    def auto_method(self, args, kwargs):
        return self.held_object.is_auto()

def extract_required_kwarg(kwargs, subproject, feature_check=None, default=True):
    val = kwargs.get('required', default)
    disabled = False
    required = False
    feature = None
    if isinstance(val, FeatureOptionHolder):
        if not feature_check:
            feature_check = FeatureNew('User option "feature"', '0.47.0')
        feature_check.use(subproject)
        option = val.held_object
        feature = val.name
        if option.is_disabled():
            disabled = True
        elif option.is_enabled():
            required = True
    elif isinstance(val, bool):
        required = val
    else:
        raise InterpreterException('required keyword argument must be boolean or a feature option')

    # Keep boolean value in kwargs to simplify other places where this kwarg is
    # checked.
    kwargs['required'] = required

    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__()
        self.res = res
        self.methods.update({'returncode': self.returncode_method,
                             'compiled': self.compiled_method,
                             'stdout': self.stdout_method,
                             'stderr': self.stderr_method,
                             })

    @noPosargs
    @permittedKwargs({})
    def returncode_method(self, args, kwargs):
        return self.res.returncode

    @noPosargs
    @permittedKwargs({})
    def compiled_method(self, args, kwargs):
        return self.res.compiled

    @noPosargs
    @permittedKwargs({})
    def stdout_method(self, args, kwargs):
        return self.res.stdout

    @noPosargs
    @permittedKwargs({})
    def stderr_method(self, args, kwargs):
        return self.res.stderr

class RunProcess(InterpreterObject):

    def __init__(self, cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False, check=False, capture=True):
        super().__init__()
        if not isinstance(cmd, ExternalProgram):
            raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
        self.capture = capture
        pc, self.stdout, self.stderr = self.run_command(cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check)
        self.returncode = pc.returncode
        self.methods.update({'returncode': self.returncode_method,
                             'stdout': self.stdout_method,
                             'stderr': self.stderr_method,
                             })

    def run_command(self, cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check=False):
        command_array = cmd.get_command() + args
        menv = {'MESON_SOURCE_ROOT': source_dir,
                'MESON_BUILD_ROOT': build_dir,
                'MESON_SUBDIR': subdir,
                'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]),
                }
        if in_builddir:
            cwd = os.path.join(build_dir, subdir)
        else:
            cwd = os.path.join(source_dir, subdir)
        child_env = os.environ.copy()
        child_env.update(menv)
        child_env = env.get_env(child_env)
        stdout = subprocess.PIPE if self.capture else subprocess.DEVNULL
        mlog.debug('Running command:', ' '.join(command_array))
        try:
            p, o, e = Popen_safe(command_array, stdout=stdout, env=child_env, cwd=cwd)
            if self.capture:
                mlog.debug('--- stdout ---')
                mlog.debug(o)
            else:
                o = ''
                mlog.debug('--- stdout disabled ---')
            mlog.debug('--- stderr ---')
            mlog.debug(e)
            mlog.debug('')

            if check and p.returncode != 0:
                raise InterpreterException('Command "{}" failed with status {}.'.format(' '.join(command_array), p.returncode))

            return p, o, e
        except FileNotFoundError:
            raise InterpreterException('Could not execute command "%s".' % ' '.join(command_array))

    @noPosargs
    @permittedKwargs({})
    def returncode_method(self, args, kwargs):
        return self.returncode

    @noPosargs
    @permittedKwargs({})
    def stdout_method(self, args, kwargs):
        return self.stdout

    @noPosargs
    @permittedKwargs({})
    def stderr_method(self, args, kwargs):
        return self.stderr

class ConfigureFileHolder(InterpreterObject, ObjectHolder):

    def __init__(self, subdir, sourcename, targetname, configuration_data):
        InterpreterObject.__init__(self)
        obj = build.ConfigureFile(subdir, sourcename, targetname, configuration_data)
        ObjectHolder.__init__(self, obj)


class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
    def __init__(self, initial_values=None):
        MutableInterpreterObject.__init__(self)
        ObjectHolder.__init__(self, build.EnvironmentVariables())
        self.methods.update({'set': self.set_method,
                             'append': self.append_method,
                             'prepend': self.prepend_method,
                             })
        if isinstance(initial_values, dict):
            for k, v in initial_values.items():
                self.set_method([k, v], {})
        elif isinstance(initial_values, list):
            for e in initial_values:
                if '=' not in e:
                    raise InterpreterException('Env var definition must be of type key=val.')
                (k, val) = e.split('=', 1)
                k = k.strip()
                val = val.strip()
                if ' ' in k:
                    raise InterpreterException('Env var key must not have spaces in it.')
                self.set_method([k, val], {})
        elif initial_values:
            raise AssertionError('Unsupported EnvironmentVariablesHolder initial_values')

    def __repr__(self):
        repr_str = "<{0}: {1}>"
        return repr_str.format(self.__class__.__name__, self.held_object.envvars)

    def add_var(self, method, args, kwargs):
        if not isinstance(kwargs.get("separator", ""), str):
            raise InterpreterException("EnvironmentVariablesHolder methods 'separator'"
                                       " argument needs to be a string.")
        if len(args) < 2:
            raise InterpreterException("EnvironmentVariablesHolder methods require at least"
                                       "2 arguments, first is the name of the variable and"
                                       " following one are values")
        # Warn when someone tries to use append() or prepend() on an env var
        # which already has an operation set on it. People seem to think that
        # multiple append/prepend operations stack, but they don't.
        if method != self.held_object.set and self.held_object.has_name(args[0]):
            mlog.warning('Overriding previous value of environment variable {!r} with a new one'
                         .format(args[0]), location=self.current_node)
        self.held_object.add_var(method, args[0], args[1:], kwargs)

    @stringArgs
    @permittedKwargs({'separator'})
    def set_method(self, args, kwargs):
        self.add_var(self.held_object.set, args, kwargs)

    @stringArgs
    @permittedKwargs({'separator'})
    def append_method(self, args, kwargs):
        self.add_var(self.held_object.append, args, kwargs)

    @stringArgs
    @permittedKwargs({'separator'})
    def prepend_method(self, args, kwargs):
        self.add_var(self.held_object.prepend, args, kwargs)


class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
    def __init__(self, pv, initial_values=None):
        MutableInterpreterObject.__init__(self)
        self.used = False # These objects become immutable after use in configure_file.
        ObjectHolder.__init__(self, build.ConfigurationData(), pv)
        self.methods.update({'set': self.set_method,
                             'set10': self.set10_method,
                             'set_quoted': self.set_quoted_method,
                             'has': self.has_method,
                             'get': self.get_method,
                             'get_unquoted': self.get_unquoted_method,
                             'merge_from': self.merge_from_method,
                             })
        if isinstance(initial_values, dict):
            for k, v in initial_values.items():
                self.set_method([k, v], {})
        elif initial_values:
            raise AssertionError('Unsupported ConfigurationDataHolder initial_values')

    def is_used(self):
        return self.used

    def mark_used(self):
        self.used = True

    def validate_args(self, args, kwargs):
        if len(args) == 1 and isinstance(args[0], list) and len(args[0]) == 2:
            mlog.deprecation('Passing a list as the single argument to '
                             'configuration_data.set is deprecated. This will '
                             'become a hard error in the future.',
                             location=self.current_node)
            args = args[0]

        if len(args) != 2:
            raise InterpreterException("Configuration set requires 2 arguments.")
        if self.used:
            raise InterpreterException("Can not set values on configuration object that has been used.")
        name, val = args
        if not isinstance(val, (int, str)):
            msg = 'Setting a configuration data value to {!r} is invalid, ' \
                  'and will fail at configure_file(). If you are using it ' \
                  'just to store some values, please use a dict instead.'
            mlog.deprecation(msg.format(val), location=self.current_node)
        desc = kwargs.get('description', None)
        if not isinstance(name, str):
            raise InterpreterException("First argument to set must be a string.")
        if desc is not None and not isinstance(desc, str):
            raise InterpreterException('Description must be a string.')

        return name, val, desc

    @noArgsFlattening
    def set_method(self, args, kwargs):
        (name, val, desc) = self.validate_args(args, kwargs)
        self.held_object.values[name] = (val, desc)

    def set_quoted_method(self, args, kwargs):
        (name, val, desc) = self.validate_args(args, kwargs)
        if not isinstance(val, str):
            raise InterpreterException("Second argument to set_quoted must be a string.")
        escaped_val = '\\"'.join(val.split('"'))
        self.held_object.values[name] = ('"' + escaped_val + '"', desc)

    def set10_method(self, args, kwargs):
        (name, val, desc) = self.validate_args(args, kwargs)
        if val:
            self.held_object.values[name] = (1, desc)
        else:
            self.held_object.values[name] = (0, desc)

    def has_method(self, args, kwargs):
        return args[0] in self.held_object.values

    @FeatureNew('configuration_data.get()', '0.38.0')
    @noArgsFlattening
    def get_method(self, args, kwargs):
        if len(args) < 1 or len(args) > 2:
            raise InterpreterException('Get method takes one or two arguments.')
        name = args[0]
        if name in self.held_object:
            return self.held_object.get(name)[0]
        if len(args) > 1:
            return args[1]
        raise InterpreterException('Entry %s not in configuration data.' % name)

    @FeatureNew('configuration_data.get_unquoted()', '0.44.0')
    def get_unquoted_method(self, args, kwargs):
        if len(args) < 1 or len(args) > 2:
            raise InterpreterException('Get method takes one or two arguments.')
        name = args[0]
        if name in self.held_object:
            val = self.held_object.get(name)[0]
        elif len(args) > 1:
            val = args[1]
        else:
            raise InterpreterException('Entry %s not in configuration data.' % name)
        if val[0] == '"' and val[-1] == '"':
            return val[1:-1]
        return val

    def get(self, name):
        return self.held_object.values[name] # (val, desc)

    def keys(self):
        return self.held_object.values.keys()

    def merge_from_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Merge_from takes one positional argument.')
        from_object = args[0]
        if not isinstance(from_object, ConfigurationDataHolder):
            raise InterpreterException('Merge_from argument must be a configuration data object.')
        from_object = from_object.held_object
        for k, v in from_object.values.items():
            self.held_object.values[k] = v

# Interpreter objects can not be pickled so we must have
# these wrappers.

class DependencyHolder(InterpreterObject, ObjectHolder):
    def __init__(self, dep, pv):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, dep, pv)
        self.methods.update({'found': self.found_method,
                             'type_name': self.type_name_method,
                             'version': self.version_method,
                             'name': self.name_method,
                             'get_pkgconfig_variable': self.pkgconfig_method,
                             'get_configtool_variable': self.configtool_method,
                             'get_variable': self.variable_method,
                             'partial_dependency': self.partial_dependency_method,
                             'include_type': self.include_type_method,
                             'as_system': self.as_system_method,
                             })

    def found(self):
        return self.found_method([], {})

    @noPosargs
    @permittedKwargs({})
    def type_name_method(self, args, kwargs):
        return self.held_object.type_name

    @noPosargs
    @permittedKwargs({})
    def found_method(self, args, kwargs):
        if self.held_object.type_name == 'internal':
            return True
        return self.held_object.found()

    @noPosargs
    @permittedKwargs({})
    def version_method(self, args, kwargs):
        return self.held_object.get_version()

    @noPosargs
    @permittedKwargs({})
    def name_method(self, args, kwargs):
        return self.held_object.get_name()

    @permittedKwargs({'define_variable', 'default'})
    def pkgconfig_method(self, args, kwargs):
        args = listify(args)
        if len(args) != 1:
            raise InterpreterException('get_pkgconfig_variable takes exactly one argument.')
        varname = args[0]
        if not isinstance(varname, str):
            raise InterpreterException('Variable name must be a string.')
        return self.held_object.get_pkgconfig_variable(varname, kwargs)

    @FeatureNew('dep.get_configtool_variable', '0.44.0')
    @permittedKwargs({})
    def configtool_method(self, args, kwargs):
        args = listify(args)
        if len(args) != 1:
            raise InterpreterException('get_configtool_variable takes exactly one argument.')
        varname = args[0]
        if not isinstance(varname, str):
            raise InterpreterException('Variable name must be a string.')
        return self.held_object.get_configtool_variable(varname)

    @FeatureNew('dep.partial_dependency', '0.46.0')
    @noPosargs
    @permittedKwargs(permitted_method_kwargs['partial_dependency'])
    def partial_dependency_method(self, args, kwargs):
        pdep = self.held_object.get_partial_dependency(**kwargs)
        return DependencyHolder(pdep, self.subproject)

    @FeatureNew('dep.get_variable', '0.51.0')
    @noPosargs
    @permittedKwargs({'cmake', 'pkgconfig', 'configtool', 'default_value', 'pkgconfig_define'})
    def variable_method(self, args, kwargs):
        return self.held_object.get_variable(**kwargs)

    @FeatureNew('dep.include_type', '0.52.0')
    @noPosargs
    @permittedKwargs({})
    def include_type_method(self, args, kwargs):
        return self.held_object.get_include_type()

    @FeatureNew('dep.as_system', '0.52.0')
    @permittedKwargs({})
    def as_system_method(self, args, kwargs):
        args = listify(args)
        new_is_system = 'system'
        if len(args) > 1:
            raise InterpreterException('as_system takes only one optional value')
        if len(args) == 1:
            new_is_system = args[0]
        new_dep = self.held_object.generate_system_dependency(new_is_system)
        return DependencyHolder(new_dep, self.subproject)

class ExternalProgramHolder(InterpreterObject, ObjectHolder):
    def __init__(self, ep):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, ep)
        self.methods.update({'found': self.found_method,
                             'path': self.path_method})
        self.cached_version = None

    @noPosargs
    @permittedKwargs({})
    def found_method(self, args, kwargs):
        return self.found()

    @noPosargs
    @permittedKwargs({})
    def path_method(self, args, kwargs):
        return self.held_object.get_path()

    def found(self):
        return isinstance(self.held_object, build.Executable) or self.held_object.found()

    def get_command(self):
        return self.held_object.get_command()

    def get_name(self):
        return self.held_object.get_name()

    def get_version(self, interpreter):
        if not self.cached_version:
            raw_cmd = self.get_command() + ['--version']
            cmd = [self, '--version']
            res = interpreter.run_command_impl(interpreter.current_node, cmd, {}, True)
            if res.returncode != 0:
                m = 'Running {!r} failed'
                raise InterpreterException(m.format(raw_cmd))
            output = res.stdout.strip()
            if not output:
                output = res.stderr.strip()
            match = re.search(r'([0-9][0-9\.]+)', output)
            if not match:
                m = 'Could not find a version number in output of {!r}'
                raise InterpreterException(m.format(raw_cmd))
            self.cached_version = match.group(1)
        return self.cached_version

class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
    def __init__(self, el, pv):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, el, pv)
        self.methods.update({'found': self.found_method,
                             'type_name': self.type_name_method,
                             'partial_dependency': self.partial_dependency_method,
                             })

    def found(self):
        return self.held_object.found()

    @noPosargs
    @permittedKwargs({})
    def type_name_method(self, args, kwargs):
        return self.held_object.type_name

    @noPosargs
    @permittedKwargs({})
    def found_method(self, args, kwargs):
        return self.found()

    def get_name(self):
        return self.held_object.name

    def get_compile_args(self):
        return self.held_object.get_compile_args()

    def get_link_args(self):
        return self.held_object.get_link_args()

    def get_exe_args(self):
        return self.held_object.get_exe_args()

    @FeatureNew('dep.partial_dependency', '0.46.0')
    @noPosargs
    @permittedKwargs(permitted_method_kwargs['partial_dependency'])
    def partial_dependency_method(self, args, kwargs):
        pdep = self.held_object.get_partial_dependency(**kwargs)
        return DependencyHolder(pdep, self.subproject)

class GeneratorHolder(InterpreterObject, ObjectHolder):
    @FeatureNewKwargs('generator', '0.43.0', ['capture'])
    def __init__(self, interp, args, kwargs):
        self.interpreter = interp
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, build.Generator(args, kwargs), interp.subproject)
        self.methods.update({'process': self.process_method})

    @FeatureNewKwargs('generator.process', '0.45.0', ['preserve_path_from'])
    @permittedKwargs({'extra_args', 'preserve_path_from'})
    def process_method(self, args, kwargs):
        extras = mesonlib.stringlistify(kwargs.get('extra_args', []))
        if 'preserve_path_from' in kwargs:
            preserve_path_from = kwargs['preserve_path_from']
            if not isinstance(preserve_path_from, str):
                raise InvalidArguments('Preserve_path_from must be a string.')
            preserve_path_from = os.path.normpath(preserve_path_from)
            if not os.path.isabs(preserve_path_from):
                # This is a bit of a hack. Fix properly before merging.
                raise InvalidArguments('Preserve_path_from must be an absolute path for now. Sorry.')
        else:
            preserve_path_from = None
        gl = self.held_object.process_files('Generator', args, self.interpreter,
                                            preserve_path_from, extra_args=extras)
        return GeneratedListHolder(gl)


class GeneratedListHolder(InterpreterObject, ObjectHolder):
    def __init__(self, arg1, extra_args=None):
        InterpreterObject.__init__(self)
        if isinstance(arg1, GeneratorHolder):
            ObjectHolder.__init__(self, build.GeneratedList(arg1.held_object, extra_args if extra_args is not None else []))
        else:
            ObjectHolder.__init__(self, arg1)

    def __repr__(self):
        r = '<{}: {!r}>'
        return r.format(self.__class__.__name__, self.held_object.get_outputs())

    def add_file(self, a):
        self.held_object.add_file(a)

# A machine that's statically known from the cross file
class MachineHolder(InterpreterObject, ObjectHolder):
    def __init__(self, machine_info):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, machine_info)
        self.methods.update({'system': self.system_method,
                             'cpu': self.cpu_method,
                             'cpu_family': self.cpu_family_method,
                             'endian': self.endian_method,
                             })

    @noPosargs
    @permittedKwargs({})
    def cpu_family_method(self, args, kwargs):
        return self.held_object.cpu_family

    @noPosargs
    @permittedKwargs({})
    def cpu_method(self, args, kwargs):
        return self.held_object.cpu

    @noPosargs
    @permittedKwargs({})
    def system_method(self, args, kwargs):
        return self.held_object.system

    @noPosargs
    @permittedKwargs({})
    def endian_method(self, args, kwargs):
        return self.held_object.endian

class IncludeDirsHolder(InterpreterObject, ObjectHolder):
    def __init__(self, idobj):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, idobj)

class Headers(InterpreterObject):

    def __init__(self, sources, kwargs):
        InterpreterObject.__init__(self)
        self.sources = sources
        self.install_subdir = kwargs.get('subdir', '')
        if os.path.isabs(self.install_subdir):
            mlog.deprecation('Subdir keyword must not be an absolute path. This will be a hard error in the next release.')
        self.custom_install_dir = kwargs.get('install_dir', None)
        self.custom_install_mode = kwargs.get('install_mode', None)
        if self.custom_install_dir is not None:
            if not isinstance(self.custom_install_dir, str):
                raise InterpreterException('Custom_install_dir must be a string.')

    def set_install_subdir(self, subdir):
        self.install_subdir = subdir

    def get_install_subdir(self):
        return self.install_subdir

    def get_sources(self):
        return self.sources

    def get_custom_install_dir(self):
        return self.custom_install_dir

    def get_custom_install_mode(self):
        return self.custom_install_mode

class DataHolder(InterpreterObject, ObjectHolder):
    def __init__(self, data):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, data)

    def get_source_subdir(self):
        return self.held_object.source_subdir

    def get_sources(self):
        return self.held_object.sources

    def get_install_dir(self):
        return self.held_object.install_dir

class InstallDir(InterpreterObject):
    def __init__(self, src_subdir, inst_subdir, install_dir, install_mode, exclude, strip_directory):
        InterpreterObject.__init__(self)
        self.source_subdir = src_subdir
        self.installable_subdir = inst_subdir
        self.install_dir = install_dir
        self.install_mode = install_mode
        self.exclude = exclude
        self.strip_directory = strip_directory

class Man(InterpreterObject):

    def __init__(self, sources, kwargs):
        InterpreterObject.__init__(self)
        self.sources = sources
        self.validate_sources()
        self.custom_install_dir = kwargs.get('install_dir', None)
        self.custom_install_mode = kwargs.get('install_mode', None)
        if self.custom_install_dir is not None and not isinstance(self.custom_install_dir, str):
            raise InterpreterException('Custom_install_dir must be a string.')

    def validate_sources(self):
        for s in self.sources:
            try:
                num = int(s.split('.')[-1])
            except (IndexError, ValueError):
                num = 0
            if num < 1 or num > 8:
                raise InvalidArguments('Man file must have a file extension of a number between 1 and 8')

    def get_custom_install_dir(self):
        return self.custom_install_dir

    def get_custom_install_mode(self):
        return self.custom_install_mode

    def get_sources(self):
        return self.sources

class GeneratedObjectsHolder(InterpreterObject, ObjectHolder):
    def __init__(self, held_object):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, held_object)

class TargetHolder(InterpreterObject, ObjectHolder):
    def __init__(self, target, interp):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, target, interp.subproject)
        self.interpreter = interp

class BuildTargetHolder(TargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)
        self.methods.update({'extract_objects': self.extract_objects_method,
                             'extract_all_objects': self.extract_all_objects_method,
                             'get_id': self.get_id_method,
                             'outdir': self.outdir_method,
                             'full_path': self.full_path_method,
                             'private_dir_include': self.private_dir_include_method,
                             })

    def __repr__(self):
        r = '<{} {}: {}>'
        h = self.held_object
        return r.format(self.__class__.__name__, h.get_id(), h.filename)

    def is_cross(self):
        return not self.held_object.environment.machines.matches_build_machine(self.held_object.for_machine)

    @noPosargs
    @permittedKwargs({})
    def private_dir_include_method(self, args, kwargs):
        return IncludeDirsHolder(build.IncludeDirs('', [], False,
                                                   [self.interpreter.backend.get_target_private_dir(self.held_object)]))

    @noPosargs
    @permittedKwargs({})
    def full_path_method(self, args, kwargs):
        return self.interpreter.backend.get_target_filename_abs(self.held_object)

    @noPosargs
    @permittedKwargs({})
    def outdir_method(self, args, kwargs):
        return self.interpreter.backend.get_target_dir(self.held_object)

    @permittedKwargs({})
    def extract_objects_method(self, args, kwargs):
        gobjs = self.held_object.extract_objects(args)
        return GeneratedObjectsHolder(gobjs)

    @FeatureNewKwargs('extract_all_objects', '0.46.0', ['recursive'])
    @noPosargs
    @permittedKwargs({'recursive'})
    def extract_all_objects_method(self, args, kwargs):
        recursive = kwargs.get('recursive', False)
        gobjs = self.held_object.extract_all_objects(recursive)
        if gobjs.objlist and 'recursive' not in kwargs:
            mlog.warning('extract_all_objects called without setting recursive '
                         'keyword argument. Meson currently defaults to '
                         'non-recursive to maintain backward compatibility but '
                         'the default will be changed in the future.',
                         location=self.current_node)
        return GeneratedObjectsHolder(gobjs)

    @noPosargs
    @permittedKwargs({})
    def get_id_method(self, args, kwargs):
        return self.held_object.get_id()

class ExecutableHolder(BuildTargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)

class StaticLibraryHolder(BuildTargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)

class SharedLibraryHolder(BuildTargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)
        # Set to True only when called from self.func_shared_lib().
        target.shared_library_only = False

class BothLibrariesHolder(BuildTargetHolder):
    def __init__(self, shared_holder, static_holder, interp):
        # FIXME: This build target always represents the shared library, but
        # that should be configurable.
        super().__init__(shared_holder.held_object, interp)
        self.shared_holder = shared_holder
        self.static_holder = static_holder
        self.methods.update({'get_shared_lib': self.get_shared_lib_method,
                             'get_static_lib': self.get_static_lib_method,
                             })

    def __repr__(self):
        r = '<{} {}: {}, {}: {}>'
        h1 = self.shared_holder.held_object
        h2 = self.static_holder.held_object
        return r.format(self.__class__.__name__, h1.get_id(), h1.filename, h2.get_id(), h2.filename)

    @noPosargs
    @permittedKwargs({})
    def get_shared_lib_method(self, args, kwargs):
        return self.shared_holder

    @noPosargs
    @permittedKwargs({})
    def get_static_lib_method(self, args, kwargs):
        return self.static_holder

class SharedModuleHolder(BuildTargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)

class JarHolder(BuildTargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)

class CustomTargetIndexHolder(InterpreterObject, ObjectHolder):
    def __init__(self, object_to_hold):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, object_to_hold)

class CustomTargetHolder(TargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)
        self.methods.update({'full_path': self.full_path_method,
                             })

    def __repr__(self):
        r = '<{} {}: {}>'
        h = self.held_object
        return r.format(self.__class__.__name__, h.get_id(), h.command)

    @noPosargs
    @permittedKwargs({})
    def full_path_method(self, args, kwargs):
        return self.interpreter.backend.get_target_filename_abs(self.held_object)

    def __getitem__(self, index):
        return CustomTargetIndexHolder(self.held_object[index])

    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):  # lgtm[py/unexpected-raise-in-special-method]
        raise InterpreterException('Cannot delete a member of a CustomTarget')

    def outdir_include(self):
        return IncludeDirsHolder(build.IncludeDirs('', [], False,
                                                   [os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(self.held_object))]))

class RunTargetHolder(TargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)

    def __repr__(self):
        r = '<{} {}: {}>'
        h = self.held_object
        return r.format(self.__class__.__name__, h.get_id(), h.command)

class Test(InterpreterObject):
    def __init__(self, name: str, project: str, suite: T.List[str], exe: build.Executable,
                 depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]],
                 is_parallel: bool, cmd_args: T.List[str], env: build.EnvironmentVariables,
                 should_fail: bool, timeout: int, workdir: T.Optional[str], protocol: str,
                 priority: int):
        InterpreterObject.__init__(self)
        self.name = name
        self.suite = suite
        self.project_name = project
        self.exe = exe
        self.depends = depends
        self.is_parallel = is_parallel
        self.cmd_args = cmd_args
        self.env = env
        self.should_fail = should_fail
        self.timeout = timeout
        self.workdir = workdir
        self.protocol = protocol
        self.priority = priority

    def get_exe(self):
        return self.exe

    def get_name(self):
        return self.name

class SubprojectHolder(InterpreterObject, ObjectHolder):

    def __init__(self, subinterpreter, subproject_dir, name):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, subinterpreter)
        self.name = name
        self.subproject_dir = subproject_dir
        self.methods.update({'get_variable': self.get_variable_method,
                             'found': self.found_method,
                             })

    @noPosargs
    @permittedKwargs({})
    def found_method(self, args, kwargs):
        return self.found()

    def found(self):
        return self.held_object is not None

    @permittedKwargs({})
    @noArgsFlattening
    def get_variable_method(self, args, kwargs):
        if len(args) < 1 or len(args) > 2:
            raise InterpreterException('Get_variable takes one or two arguments.')
        if not self.found():
            raise InterpreterException('Subproject "%s/%s" disabled can\'t get_variable on it.' % (
                self.subproject_dir, self.name))
        varname = args[0]
        if not isinstance(varname, str):
            raise InterpreterException('Get_variable first argument must be a string.')
        try:
            return self.held_object.variables[varname]
        except KeyError:
            pass

        if len(args) == 2:
            return args[1]

        raise InvalidArguments('Requested variable "{0}" not found.'.format(varname))

header_permitted_kwargs = set([
    'required',
    'prefix',
    'no_builtin_args',
    'include_directories',
    'args',
    'dependencies',
])

find_library_permitted_kwargs = set([
    'has_headers',
    'required',
    'dirs',
    'static',
])

find_library_permitted_kwargs |= set(['header_' + k for k in header_permitted_kwargs])

class CompilerHolder(InterpreterObject):
    def __init__(self, compiler, env, subproject):
        InterpreterObject.__init__(self)
        self.compiler = compiler
        self.environment = env
        self.subproject = subproject
        self.methods.update({'compiles': self.compiles_method,
                             'links': self.links_method,
                             'get_id': self.get_id_method,
                             'get_linker_id': self.get_linker_id_method,
                             'compute_int': self.compute_int_method,
                             'sizeof': self.sizeof_method,
                             'get_define': self.get_define_method,
                             'check_header': self.check_header_method,
                             'has_header': self.has_header_method,
                             'has_header_symbol': self.has_header_symbol_method,
                             'run': self.run_method,
                             'has_function': self.has_function_method,
                             'has_member': self.has_member_method,
                             'has_members': self.has_members_method,
                             'has_type': self.has_type_method,
                             'alignment': self.alignment_method,
                             'version': self.version_method,
                             'cmd_array': self.cmd_array_method,
                             'find_library': self.find_library_method,
                             'has_argument': self.has_argument_method,
                             'has_function_attribute': self.has_func_attribute_method,
                             'get_supported_function_attributes': self.get_supported_function_attributes_method,
                             'has_multi_arguments': self.has_multi_arguments_method,
                             'get_supported_arguments': self.get_supported_arguments_method,
                             'first_supported_argument': self.first_supported_argument_method,
                             'has_link_argument': self.has_link_argument_method,
                             'has_multi_link_arguments': self.has_multi_link_arguments_method,
                             'get_supported_link_arguments': self.get_supported_link_arguments_method,
                             'first_supported_link_argument': self.first_supported_link_argument_method,
                             'unittest_args': self.unittest_args_method,
                             'symbols_have_underscore_prefix': self.symbols_have_underscore_prefix_method,
                             'get_argument_syntax': self.get_argument_syntax_method,
                             })

    def _dep_msg(self, deps, endl):
        msg_single = 'with dependency {}'
        msg_many = 'with dependencies {}'
        if not deps:
            return endl
        if endl is None:
            endl = ''
        tpl = msg_many if len(deps) > 1 else msg_single
        names = []
        for d in deps:
            if isinstance(d, dependencies.ExternalLibrary):
                name = '-l' + d.name
            else:
                name = d.name
            names.append(name)
        return tpl.format(', '.join(names)) + endl

    @noPosargs
    @permittedKwargs({})
    def version_method(self, args, kwargs):
        return self.compiler.version

    @noPosargs
    @permittedKwargs({})
    def cmd_array_method(self, args, kwargs):
        return self.compiler.exelist

    def determine_args(self, kwargs, mode='link'):
        nobuiltins = kwargs.get('no_builtin_args', False)
        if not isinstance(nobuiltins, bool):
            raise InterpreterException('Type of no_builtin_args not a boolean.')
        args = []
        incdirs = extract_as_list(kwargs, 'include_directories')
        for i in incdirs:
            if not isinstance(i, IncludeDirsHolder):
                raise InterpreterException('Include directories argument must be an include_directories object.')
            for idir in i.held_object.get_incdirs():
                idir = os.path.join(self.environment.get_source_dir(),
                                    i.held_object.get_curdir(), idir)
                args += self.compiler.get_include_args(idir, False)
        if not nobuiltins:
            for_machine = Interpreter.machine_from_native_kwarg(kwargs)
            opts = self.environment.coredata.compiler_options[for_machine]
            args += self.compiler.get_option_compile_args(opts)
            if mode == 'link':
                args += self.compiler.get_option_link_args(opts)
        args += mesonlib.stringlistify(kwargs.get('args', []))
        return args

    def determine_dependencies(self, kwargs, endl=':'):
        deps = kwargs.get('dependencies', None)
        if deps is not None:
            deps = listify(deps)
            final_deps = []
            for d in deps:
                try:
                    d = d.held_object
                except Exception:
                    pass
                if isinstance(d, InternalDependency) or not isinstance(d, Dependency):
                    raise InterpreterException('Dependencies must be external dependencies')
                final_deps.append(d)
            deps = final_deps
        return deps, self._dep_msg(deps, endl)

    @permittedKwargs({
        'prefix',
        'args',
        'dependencies',
    })
    def alignment_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Alignment method takes exactly one positional argument.')
        check_stringlist(args)
        typename = args[0]
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of alignment must be a string.')
        extra_args = mesonlib.stringlistify(kwargs.get('args', []))
        deps, msg = self.determine_dependencies(kwargs)
        result = self.compiler.alignment(typename, prefix, self.environment,
                                         extra_args=extra_args,
                                         dependencies=deps)
        mlog.log('Checking for alignment of', mlog.bold(typename, True), msg, result)
        return result

    @permittedKwargs({
        'name',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def run_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Run method takes exactly one positional argument.')
        code = args[0]
        if isinstance(code, mesonlib.File):
            code = mesonlib.File.from_absolute_file(
                code.rel_to_builddir(self.environment.source_dir))
        elif not isinstance(code, str):
            raise InvalidArguments('Argument must be string or file.')
        testname = kwargs.get('name', '')
        if not isinstance(testname, str):
            raise InterpreterException('Testname argument must be a string.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs, endl=None)
        result = self.compiler.run(code, self.environment, extra_args=extra_args,
                                   dependencies=deps)
        if len(testname) > 0:
            if not result.compiled:
                h = mlog.red('DID NOT COMPILE')
            elif result.returncode == 0:
                h = mlog.green('YES')
            else:
                h = mlog.red('NO (%d)' % result.returncode)
            mlog.log('Checking if', mlog.bold(testname, True), msg, 'runs:', h)
        return TryRunResultHolder(result)

    @noPosargs
    @permittedKwargs({})
    def get_id_method(self, args, kwargs):
        return self.compiler.get_id()

    @noPosargs
    @permittedKwargs({})
    @FeatureNew('compiler.get_linker_id', '0.53.0')
    def get_linker_id_method(self, args, kwargs):
        return self.compiler.get_linker_id()

    @noPosargs
    @permittedKwargs({})
    def symbols_have_underscore_prefix_method(self, args, kwargs):
        '''
        Check if the compiler prefixes _ (underscore) to global C symbols
        See: https://en.wikipedia.org/wiki/Name_mangling#C
        '''
        return self.compiler.symbols_have_underscore_prefix(self.environment)

    @noPosargs
    @permittedKwargs({})
    def unittest_args_method(self, args, kwargs):
        '''
        This function is deprecated and should not be used.
        It can be removed in a future version of Meson.
        '''
        if not hasattr(self.compiler, 'get_feature_args'):
            raise InterpreterException('This {} compiler has no feature arguments.'.format(self.compiler.get_display_language()))
        build_to_src = os.path.relpath(self.environment.get_source_dir(), self.environment.get_build_dir())
        return self.compiler.get_feature_args({'unittest': 'true'}, build_to_src)

    @permittedKwargs({
        'prefix',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def has_member_method(self, args, kwargs):
        if len(args) != 2:
            raise InterpreterException('Has_member takes exactly two arguments.')
        check_stringlist(args)
        typename, membername = args
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of has_member must be a string.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        had, cached = self.compiler.has_members(typename, [membername], prefix,
                                                self.environment,
                                                extra_args=extra_args,
                                                dependencies=deps)
        cached = mlog.blue('(cached)') if cached else ''
        if had:
            hadtxt = mlog.green('YES')
        else:
            hadtxt = mlog.red('NO')
        mlog.log('Checking whether type', mlog.bold(typename, True),
                 'has member', mlog.bold(membername, True), msg, hadtxt, cached)
        return had

    @permittedKwargs({
        'prefix',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def has_members_method(self, args, kwargs):
        if len(args) < 2:
            raise InterpreterException('Has_members needs at least two arguments.')
        check_stringlist(args)
        typename, *membernames = args
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of has_members must be a string.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        had, cached = self.compiler.has_members(typename, membernames, prefix,
                                                self.environment,
                                                extra_args=extra_args,
                                                dependencies=deps)
        cached = mlog.blue('(cached)') if cached else ''
        if had:
            hadtxt = mlog.green('YES')
        else:
            hadtxt = mlog.red('NO')
        members = mlog.bold(', '.join(['"{}"'.format(m) for m in membernames]))
        mlog.log('Checking whether type', mlog.bold(typename, True),
                 'has members', members, msg, hadtxt, cached)
        return had

    @permittedKwargs({
        'prefix',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def has_function_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Has_function takes exactly one argument.')
        check_stringlist(args)
        funcname = args[0]
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of has_function must be a string.')
        extra_args = self.determine_args(kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        had, cached = self.compiler.has_function(funcname, prefix, self.environment,
                                                 extra_args=extra_args,
                                                 dependencies=deps)
        cached = mlog.blue('(cached)') if cached else ''
        if had:
            hadtxt = mlog.green('YES')
        else:
            hadtxt = mlog.red('NO')
        mlog.log('Checking for function', mlog.bold(funcname, True), msg, hadtxt, cached)
        return had

    @permittedKwargs({
        'prefix',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def has_type_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Has_type takes exactly one argument.')
        check_stringlist(args)
        typename = args[0]
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of has_type must be a string.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        had, cached = self.compiler.has_type(typename, prefix, self.environment,
                                             extra_args=extra_args, dependencies=deps)
        cached = mlog.blue('(cached)') if cached else ''
        if had:
            hadtxt = mlog.green('YES')
        else:
            hadtxt = mlog.red('NO')
        mlog.log('Checking for type', mlog.bold(typename, True), msg, hadtxt, cached)
        return had

    @FeatureNew('compiler.compute_int', '0.40.0')
    @permittedKwargs({
        'prefix',
        'low',
        'high',
        'guess',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def compute_int_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Compute_int takes exactly one argument.')
        check_stringlist(args)
        expression = args[0]
        prefix = kwargs.get('prefix', '')
        low = kwargs.get('low', None)
        high = kwargs.get('high', None)
        guess = kwargs.get('guess', None)
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of compute_int must be a string.')
        if low is not None and not isinstance(low, int):
            raise InterpreterException('Low argument of compute_int must be an int.')
        if high is not None and not isinstance(high, int):
            raise InterpreterException('High argument of compute_int must be an int.')
        if guess is not None and not isinstance(guess, int):
            raise InterpreterException('Guess argument of compute_int must be an int.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        res = self.compiler.compute_int(expression, low, high, guess, prefix,
                                        self.environment, extra_args=extra_args,
                                        dependencies=deps)
        mlog.log('Computing int of', mlog.bold(expression, True), msg, res)
        return res

    @permittedKwargs({
        'prefix',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def sizeof_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Sizeof takes exactly one argument.')
        check_stringlist(args)
        element = args[0]
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of sizeof must be a string.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        esize = self.compiler.sizeof(element, prefix, self.environment,
                                     extra_args=extra_args, dependencies=deps)
        mlog.log('Checking for size of', mlog.bold(element, True), msg, esize)
        return esize

    @FeatureNew('compiler.get_define', '0.40.0')
    @permittedKwargs({
        'prefix',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def get_define_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('get_define() takes exactly one argument.')
        check_stringlist(args)
        element = args[0]
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of get_define() must be a string.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        value, cached = self.compiler.get_define(element, prefix, self.environment,
                                                 extra_args=extra_args,
                                                 dependencies=deps)
        cached = mlog.blue('(cached)') if cached else ''
        mlog.log('Fetching value of define', mlog.bold(element, True), msg, value, cached)
        return value

    @permittedKwargs({
        'name',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def compiles_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('compiles method takes exactly one argument.')
        code = args[0]
        if isinstance(code, mesonlib.File):
            code = mesonlib.File.from_absolute_file(
                code.rel_to_builddir(self.environment.source_dir))
        elif not isinstance(code, str):
            raise InvalidArguments('Argument must be string or file.')
        testname = kwargs.get('name', '')
        if not isinstance(testname, str):
            raise InterpreterException('Testname argument must be a string.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs, endl=None)
        result, cached = self.compiler.compiles(code, self.environment,
                                                extra_args=extra_args,
                                                dependencies=deps)
        if len(testname) > 0:
            if result:
                h = mlog.green('YES')
            else:
                h = mlog.red('NO')
            cached = mlog.blue('(cached)') if cached else ''
            mlog.log('Checking if', mlog.bold(testname, True), msg, 'compiles:', h, cached)
        return result

    @permittedKwargs({
        'name',
        'no_builtin_args',
        'include_directories',
        'args',
        'dependencies',
    })
    def links_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('links method takes exactly one argument.')
        code = args[0]
        if isinstance(code, mesonlib.File):
            code = mesonlib.File.from_absolute_file(
                code.rel_to_builddir(self.environment.source_dir))
        elif not isinstance(code, str):
            raise InvalidArguments('Argument must be string or file.')
        testname = kwargs.get('name', '')
        if not isinstance(testname, str):
            raise InterpreterException('Testname argument must be a string.')
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs, endl=None)
        result, cached = self.compiler.links(code, self.environment,
                                             extra_args=extra_args,
                                             dependencies=deps)
        cached = mlog.blue('(cached)') if cached else ''
        if len(testname) > 0:
            if result:
                h = mlog.green('YES')
            else:
                h = mlog.red('NO')
            mlog.log('Checking if', mlog.bold(testname, True), msg, 'links:', h, cached)
        return result

    @FeatureNew('compiler.check_header', '0.47.0')
    @FeatureNewKwargs('compiler.check_header', '0.50.0', ['required'])
    @permittedKwargs(header_permitted_kwargs)
    def check_header_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('check_header method takes exactly one argument.')
        check_stringlist(args)
        hname = args[0]
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of has_header must be a string.')
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            mlog.log('Check usable header', mlog.bold(hname, True), 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        haz, cached = self.compiler.check_header(hname, prefix, self.environment,
                                                 extra_args=extra_args,
                                                 dependencies=deps)
        cached = mlog.blue('(cached)') if cached else ''
        if required and not haz:
            raise InterpreterException('{} header {!r} not usable'.format(self.compiler.get_display_language(), hname))
        elif haz:
            h = mlog.green('YES')
        else:
            h = mlog.red('NO')
        mlog.log('Check usable header', mlog.bold(hname, True), msg, h, cached)
        return haz

    @FeatureNewKwargs('compiler.has_header', '0.50.0', ['required'])
    @permittedKwargs(header_permitted_kwargs)
    def has_header_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('has_header method takes exactly one argument.')
        check_stringlist(args)
        hname = args[0]
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of has_header must be a string.')
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            mlog.log('Has header', mlog.bold(hname, True), 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        haz, cached = self.compiler.has_header(hname, prefix, self.environment,
                                               extra_args=extra_args, dependencies=deps)
        cached = mlog.blue('(cached)') if cached else ''
        if required and not haz:
            raise InterpreterException('{} header {!r} not found'.format(self.compiler.get_display_language(), hname))
        elif haz:
            h = mlog.green('YES')
        else:
            h = mlog.red('NO')
        mlog.log('Has header', mlog.bold(hname, True), msg, h, cached)
        return haz

    @FeatureNewKwargs('compiler.has_header_symbol', '0.50.0', ['required'])
    @permittedKwargs(header_permitted_kwargs)
    def has_header_symbol_method(self, args, kwargs):
        if len(args) != 2:
            raise InterpreterException('has_header_symbol method takes exactly two arguments.')
        check_stringlist(args)
        hname, symbol = args
        prefix = kwargs.get('prefix', '')
        if not isinstance(prefix, str):
            raise InterpreterException('Prefix argument of has_header_symbol must be a string.')
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
        if disabled:
            mlog.log('Header <{0}> has symbol'.format(hname), mlog.bold(symbol, True), 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        extra_args = functools.partial(self.determine_args, kwargs)
        deps, msg = self.determine_dependencies(kwargs)
        haz, cached = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment,
                                                      extra_args=extra_args,
                                                      dependencies=deps)
        if required and not haz:
            raise InterpreterException('{} symbol {} not found in header {}'.format(self.compiler.get_display_language(), symbol, hname))
        elif haz:
            h = mlog.green('YES')
        else:
            h = mlog.red('NO')
        cached = mlog.blue('(cached)') if cached else ''
        mlog.log('Header <{0}> has symbol'.format(hname), mlog.bold(symbol, True), msg, h, cached)
        return haz

    def notfound_library(self, libname):
        lib = dependencies.ExternalLibrary(libname, None,
                                           self.environment,
                                           self.compiler.language,
                                           silent=True)
        return ExternalLibraryHolder(lib, self.subproject)

    @FeatureNewKwargs('compiler.find_library', '0.51.0', ['static'])
    @FeatureNewKwargs('compiler.find_library', '0.50.0', ['has_headers'])
    @FeatureNewKwargs('compiler.find_library', '0.49.0', ['disabler'])
    @disablerIfNotFound
    @permittedKwargs(find_library_permitted_kwargs)
    def find_library_method(self, args, kwargs):
        # TODO add dependencies support?
        if len(args) != 1:
            raise InterpreterException('find_library method takes one argument.')
        libname = args[0]
        if not isinstance(libname, str):
            raise InterpreterException('Library name not a string.')

        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            mlog.log('Library', mlog.bold(libname), 'skipped: feature', mlog.bold(feature), 'disabled')
            return self.notfound_library(libname)

        has_header_kwargs = {k[7:]: v for k, v in kwargs.items() if k.startswith('header_')}
        has_header_kwargs['required'] = required
        headers = mesonlib.stringlistify(kwargs.get('has_headers', []))
        for h in headers:
            if not self.has_header_method([h], has_header_kwargs):
                return self.notfound_library(libname)

        search_dirs = extract_search_dirs(kwargs)

        libtype = mesonlib.LibType.PREFER_SHARED
        if 'static' in kwargs:
            if not isinstance(kwargs['static'], bool):
                raise InterpreterException('static must be a boolean')
            libtype = mesonlib.LibType.STATIC if kwargs['static'] else mesonlib.LibType.SHARED
        linkargs = self.compiler.find_library(libname, self.environment, search_dirs, libtype)
        if required and not linkargs:
            raise InterpreterException(
                '{} library {!r} not found'.format(self.compiler.get_display_language(), libname))
        lib = dependencies.ExternalLibrary(libname, linkargs, self.environment,
                                           self.compiler.language)
        return ExternalLibraryHolder(lib, self.subproject)

    @permittedKwargs({})
    def has_argument_method(self, args, kwargs):
        args = mesonlib.stringlistify(args)
        if len(args) != 1:
            raise InterpreterException('has_argument takes exactly one argument.')
        return self.has_multi_arguments_method(args, kwargs)

    @permittedKwargs({})
    def has_multi_arguments_method(self, args, kwargs):
        args = mesonlib.stringlistify(args)
        result, cached = self.compiler.has_multi_arguments(args, self.environment)
        if result:
            h = mlog.green('YES')
        else:
            h = mlog.red('NO')
        cached = mlog.blue('(cached)') if cached else ''
        mlog.log(
            'Compiler for {} supports arguments {}:'.format(
                self.compiler.get_display_language(), ' '.join(args)),
            h, cached)
        return result

    @FeatureNew('compiler.get_supported_arguments', '0.43.0')
    @permittedKwargs({})
    def get_supported_arguments_method(self, args, kwargs):
        args = mesonlib.stringlistify(args)
        supported_args = []
        for arg in args:
            if self.has_argument_method(arg, kwargs):
                supported_args.append(arg)
        return supported_args

    @permittedKwargs({})
    def first_supported_argument_method(self, args, kwargs):
        for i in mesonlib.stringlistify(args):
            if self.has_argument_method(i, kwargs):
                mlog.log('First supported argument:', mlog.bold(i))
                return [i]
        mlog.log('First supported argument:', mlog.red('None'))
        return []

    @FeatureNew('compiler.has_link_argument', '0.46.0')
    @permittedKwargs({})
    def has_link_argument_method(self, args, kwargs):
        args = mesonlib.stringlistify(args)
        if len(args) != 1:
            raise InterpreterException('has_link_argument takes exactly one argument.')
        return self.has_multi_link_arguments_method(args, kwargs)

    @FeatureNew('compiler.has_multi_link_argument', '0.46.0')
    @permittedKwargs({})
    def has_multi_link_arguments_method(self, args, kwargs):
        args = mesonlib.stringlistify(args)
        result, cached = self.compiler.has_multi_link_arguments(args, self.environment)
        cached = mlog.blue('(cached)') if cached else ''
        if result:
            h = mlog.green('YES')
        else:
            h = mlog.red('NO')
        mlog.log(
            'Compiler for {} supports link arguments {}:'.format(
                self.compiler.get_display_language(), ' '.join(args)),
            h, cached)
        return result

    @FeatureNew('compiler.get_supported_link_arguments_method', '0.46.0')
    @permittedKwargs({})
    def get_supported_link_arguments_method(self, args, kwargs):
        args = mesonlib.stringlistify(args)
        supported_args = []
        for arg in args:
            if self.has_link_argument_method(arg, kwargs):
                supported_args.append(arg)
        return supported_args

    @FeatureNew('compiler.first_supported_link_argument_method', '0.46.0')
    @permittedKwargs({})
    def first_supported_link_argument_method(self, args, kwargs):
        for i in mesonlib.stringlistify(args):
            if self.has_link_argument_method(i, kwargs):
                mlog.log('First supported link argument:', mlog.bold(i))
                return [i]
        mlog.log('First supported link argument:', mlog.red('None'))
        return []

    @FeatureNew('compiler.has_function_attribute', '0.48.0')
    @permittedKwargs({})
    def has_func_attribute_method(self, args, kwargs):
        args = mesonlib.stringlistify(args)
        if len(args) != 1:
            raise InterpreterException('has_func_attribute takes exactly one argument.')
        result, cached = self.compiler.has_func_attribute(args[0], self.environment)
        cached = mlog.blue('(cached)') if cached else ''
        h = mlog.green('YES') if result else mlog.red('NO')
        mlog.log('Compiler for {} supports function attribute {}:'.format(self.compiler.get_display_language(), args[0]), h, cached)
        return result

    @FeatureNew('compiler.get_supported_function_attributes', '0.48.0')
    @permittedKwargs({})
    def get_supported_function_attributes_method(self, args, kwargs):
        args = mesonlib.stringlistify(args)
        return [a for a in args if self.has_func_attribute_method(a, kwargs)]

    @FeatureNew('compiler.get_argument_syntax_method', '0.49.0')
    @noPosargs
    @noKwargs
    def get_argument_syntax_method(self, args, kwargs):
        return self.compiler.get_argument_syntax()


ModuleState = collections.namedtuple('ModuleState', [
    'source_root', 'build_to_src', 'subproject', 'subdir', 'current_lineno', 'environment',
    'project_name', 'project_version', 'backend', 'targets',
    'data', 'headers', 'man', 'global_args', 'project_args', 'build_machine',
    'host_machine', 'target_machine', 'current_node'])

class ModuleHolder(InterpreterObject, ObjectHolder):
    def __init__(self, modname, module, interpreter):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, module)
        self.modname = modname
        self.interpreter = interpreter

    def method_call(self, method_name, args, kwargs):
        try:
            fn = getattr(self.held_object, method_name)
        except AttributeError:
            raise InvalidArguments('Module %s does not have method %s.' % (self.modname, method_name))
        if method_name.startswith('_'):
            raise InvalidArguments('Function {!r} in module {!r} is private.'.format(method_name, self.modname))
        if not getattr(fn, 'no-args-flattening', False):
            args = flatten(args)
        # This is not 100% reliable but we can't use hash()
        # because the Build object contains dicts and lists.
        num_targets = len(self.interpreter.build.targets)
        state = ModuleState(
            source_root = self.interpreter.environment.get_source_dir(),
            build_to_src=mesonlib.relpath(self.interpreter.environment.get_source_dir(),
                                          self.interpreter.environment.get_build_dir()),
            subproject=self.interpreter.subproject,
            subdir=self.interpreter.subdir,
            current_lineno=self.interpreter.current_lineno,
            environment=self.interpreter.environment,
            project_name=self.interpreter.build.project_name,
            project_version=self.interpreter.build.dep_manifest[self.interpreter.active_projectname],
            # The backend object is under-used right now, but we will need it:
            # https://github.com/mesonbuild/meson/issues/1419
            backend=self.interpreter.backend,
            targets=self.interpreter.build.targets,
            data=self.interpreter.build.data,
            headers=self.interpreter.build.get_headers(),
            man=self.interpreter.build.get_man(),
            #global_args_for_build = self.interpreter.build.global_args.build,
            global_args = self.interpreter.build.global_args.host,
            #project_args_for_build = self.interpreter.build.projects_args.build.get(self.interpreter.subproject, {}),
            project_args = self.interpreter.build.projects_args.host.get(self.interpreter.subproject, {}),
            build_machine=self.interpreter.builtin['build_machine'].held_object,
            host_machine=self.interpreter.builtin['host_machine'].held_object,
            target_machine=self.interpreter.builtin['target_machine'].held_object,
            current_node=self.current_node
        )
        if self.held_object.is_snippet(method_name):
            value = fn(self.interpreter, state, args, kwargs)
            return self.interpreter.holderify(value)
        else:
            value = fn(state, args, kwargs)
            if num_targets != len(self.interpreter.build.targets):
                raise InterpreterException('Extension module altered internal state illegally.')
            return self.interpreter.module_method_callback(value)


class Summary:
    def __init__(self, project_name, project_version):
        self.project_name = project_name
        self.project_version = project_version
        self.sections = collections.defaultdict(dict)
        self.max_key_len = 0

    def add_section(self, section, values, kwargs):
        bool_yn = kwargs.get('bool_yn', False)
        if not isinstance(bool_yn, bool):
            raise InterpreterException('bool_yn keyword argument must be boolean')
        for k, v in values.items():
            if k in self.sections[section]:
                raise InterpreterException('Summary section {!r} already have key {!r}'.format(section, k))
            formatted_values = []
            for i in listify(v):
                if not isinstance(i, (str, int)):
                    m = 'Summary value in section {!r}, key {!r}, must be string, integer or boolean'
                    raise InterpreterException(m.format(section, k))
                if bool_yn and isinstance(i, bool):
                    formatted_values.append(mlog.green('YES') if i else mlog.red('NO'))
                else:
                    formatted_values.append(i)
            if not formatted_values:
                formatted_values = ['']
            self.sections[section][k] = formatted_values
            self.max_key_len = max(self.max_key_len, len(k))

    def dump(self):
        mlog.log(self.project_name, mlog.normal_cyan(self.project_version))
        for section, values in self.sections.items():
            mlog.log('')  # newline
            if section:
                mlog.log(' ', mlog.bold(section))
            for k, v in values.items():
                indent = self.max_key_len - len(k) + 3
                mlog.log(' ' * indent, k + ':', v[0])
                indent = self.max_key_len + 5
                for i in v[1:]:
                    mlog.log(' ' * indent, i)
        mlog.log('')  # newline


class MesonMain(InterpreterObject):
    def __init__(self, build, interpreter):
        InterpreterObject.__init__(self)
        self.build = build
        self.interpreter = interpreter
        self._found_source_scripts = {}
        self.methods.update({'get_compiler': self.get_compiler_method,
                             'is_cross_build': self.is_cross_build_method,
                             'has_exe_wrapper': self.has_exe_wrapper_method,
                             'is_unity': self.is_unity_method,
                             'is_subproject': self.is_subproject_method,
                             'current_source_dir': self.current_source_dir_method,
                             'current_build_dir': self.current_build_dir_method,
                             'source_root': self.source_root_method,
                             'build_root': self.build_root_method,
                             'add_install_script': self.add_install_script_method,
                             'add_postconf_script': self.add_postconf_script_method,
                             'add_dist_script': self.add_dist_script_method,
                             'install_dependency_manifest': self.install_dependency_manifest_method,
                             'override_find_program': self.override_find_program_method,
                             'project_version': self.project_version_method,
                             'project_license': self.project_license_method,
                             'version': self.version_method,
                             'project_name': self.project_name_method,
                             'get_cross_property': self.get_cross_property_method,
                             'backend': self.backend_method,
                             })

    def _find_source_script(self, name, args):
        # Prefer scripts in the current source directory
        search_dir = os.path.join(self.interpreter.environment.source_dir,
                                  self.interpreter.subdir)
        key = (name, search_dir)
        if key in self._found_source_scripts:
            found = self._found_source_scripts[key]
        else:
            found = dependencies.ExternalProgram(name, search_dir=search_dir)
            if found.found():
                self._found_source_scripts[key] = found
            else:
                m = 'Script or command {!r} not found or not executable'
                raise InterpreterException(m.format(name))
        return build.RunScript(found.get_command(), args)

    @permittedKwargs({})
    def add_install_script_method(self, args, kwargs):
        if len(args) < 1:
            raise InterpreterException('add_install_script takes one or more arguments')
        check_stringlist(args, 'add_install_script args must be strings')
        script = self._find_source_script(args[0], args[1:])
        self.build.install_scripts.append(script)

    @permittedKwargs({})
    def add_postconf_script_method(self, args, kwargs):
        if len(args) < 1:
            raise InterpreterException('add_postconf_script takes one or more arguments')
        check_stringlist(args, 'add_postconf_script arguments must be strings')
        script = self._find_source_script(args[0], args[1:])
        self.build.postconf_scripts.append(script)

    @permittedKwargs({})
    def add_dist_script_method(self, args, kwargs):
        if len(args) < 1:
            raise InterpreterException('add_dist_script takes one or more arguments')
        if len(args) > 1:
            FeatureNew('Calling "add_dist_script" with multiple arguments', '0.49.0').use(self.interpreter.subproject)
        check_stringlist(args, 'add_dist_script argument must be a string')
        if self.interpreter.subproject != '':
            raise InterpreterException('add_dist_script may not be used in a subproject.')
        script = self._find_source_script(args[0], args[1:])
        self.build.dist_scripts.append(script)

    @noPosargs
    @permittedKwargs({})
    def current_source_dir_method(self, args, kwargs):
        src = self.interpreter.environment.source_dir
        sub = self.interpreter.subdir
        if sub == '':
            return src
        return os.path.join(src, sub)

    @noPosargs
    @permittedKwargs({})
    def current_build_dir_method(self, args, kwargs):
        src = self.interpreter.environment.build_dir
        sub = self.interpreter.subdir
        if sub == '':
            return src
        return os.path.join(src, sub)

    @noPosargs
    @permittedKwargs({})
    def backend_method(self, args, kwargs):
        return self.interpreter.backend.name

    @noPosargs
    @permittedKwargs({})
    def source_root_method(self, args, kwargs):
        return self.interpreter.environment.source_dir

    @noPosargs
    @permittedKwargs({})
    def build_root_method(self, args, kwargs):
        return self.interpreter.environment.build_dir

    @noPosargs
    @permittedKwargs({})
    def has_exe_wrapper_method(self, args, kwargs):
        if self.is_cross_build_method(None, None) and \
           self.build.environment.need_exe_wrapper():
            if self.build.environment.exe_wrapper is None:
                return False
        # We return True when exe_wrap is defined, when it's not needed, and
        # when we're compiling natively. The last two are semantically confusing.
        # Need to revisit this.
        return True

    @noPosargs
    @permittedKwargs({})
    def is_cross_build_method(self, args, kwargs):
        return self.build.environment.is_cross_build()

    @permittedKwargs({'native'})
    def get_compiler_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('get_compiler_method must have one and only one argument.')
        cname = args[0]
        for_machine = Interpreter.machine_from_native_kwarg(kwargs)
        clist = self.interpreter.coredata.compilers[for_machine]
        if cname in clist:
            return CompilerHolder(clist[cname], self.build.environment, self.interpreter.subproject)
        raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname)

    @noPosargs
    @permittedKwargs({})
    def is_unity_method(self, args, kwargs):
        optval = self.interpreter.environment.coredata.get_builtin_option('unity')
        if optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject()):
            return True
        return False

    @noPosargs
    @permittedKwargs({})
    def is_subproject_method(self, args, kwargs):
        return self.interpreter.is_subproject()

    @permittedKwargs({})
    def install_dependency_manifest_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Must specify manifest install file name')
        if not isinstance(args[0], str):
            raise InterpreterException('Argument must be a string.')
        self.build.dep_manifest_name = args[0]

    @FeatureNew('meson.override_find_program', '0.46.0')
    @permittedKwargs({})
    def override_find_program_method(self, args, kwargs):
        if len(args) != 2:
            raise InterpreterException('Override needs two arguments')
        name, exe = args
        if not isinstance(name, str):
            raise InterpreterException('First argument must be a string')
        if hasattr(exe, 'held_object'):
            exe = exe.held_object
        if isinstance(exe, mesonlib.File):
            abspath = exe.absolute_path(self.interpreter.environment.source_dir,
                                        self.interpreter.environment.build_dir)
            if not os.path.exists(abspath):
                raise InterpreterException('Tried to override %s with a file that does not exist.' % name)
            exe = OverrideProgram(abspath)
        if not isinstance(exe, (dependencies.ExternalProgram, build.Executable)):
            raise InterpreterException('Second argument must be an external program or executable.')
        self.interpreter.add_find_program_override(name, exe)

    @noPosargs
    @permittedKwargs({})
    def project_version_method(self, args, kwargs):
        return self.build.dep_manifest[self.interpreter.active_projectname]['version']

    @FeatureNew('meson.project_license()', '0.45.0')
    @noPosargs
    @permittedKwargs({})
    def project_license_method(self, args, kwargs):
        return self.build.dep_manifest[self.interpreter.active_projectname]['license']

    @noPosargs
    @permittedKwargs({})
    def version_method(self, args, kwargs):
        return coredata.version

    @noPosargs
    @permittedKwargs({})
    def project_name_method(self, args, kwargs):
        return self.interpreter.active_projectname

    @noArgsFlattening
    @permittedKwargs({})
    def get_cross_property_method(self, args, kwargs):
        if len(args) < 1 or len(args) > 2:
            raise InterpreterException('Must have one or two arguments.')
        propname = args[0]
        if not isinstance(propname, str):
            raise InterpreterException('Property name must be string.')
        try:
            props = self.interpreter.environment.properties.host
            return props[propname]
        except Exception:
            if len(args) == 2:
                return args[1]
            raise InterpreterException('Unknown cross property: %s.' % propname)


known_library_kwargs = (
    build.known_shlib_kwargs |
    build.known_stlib_kwargs
)

known_build_target_kwargs = (
    known_library_kwargs |
    build.known_exe_kwargs |
    build.known_jar_kwargs |
    {'target_type'}
)

_base_test_args = {'args', 'depends', 'env', 'should_fail', 'timeout', 'workdir', 'suite', 'priority', 'protocol'}

permitted_kwargs = {'add_global_arguments': {'language', 'native'},
                    'add_global_link_arguments': {'language', 'native'},
                    'add_languages': {'required'},
                    'add_project_link_arguments': {'language', 'native'},
                    'add_project_arguments': {'language', 'native'},
                    'add_test_setup': {'exe_wrapper', 'gdb', 'timeout_multiplier', 'env', 'is_default'},
                    'benchmark': _base_test_args,
                    'build_target': known_build_target_kwargs,
                    'configure_file': {'input',
                                       'output',
                                       'configuration',
                                       'command',
                                       'copy',
                                       'depfile',
                                       'install_dir',
                                       'install_mode',
                                       'capture',
                                       'install',
                                       'format',
                                       'output_format',
                                       'encoding'},
                    'custom_target': {'input',
                                      'output',
                                      'command',
                                      'install',
                                      'install_dir',
                                      'install_mode',
                                      'build_always',
                                      'capture',
                                      'depends',
                                      'depend_files',
                                      'depfile',
                                      'build_by_default',
                                      'build_always_stale',
                                      'console'},
                    'dependency': {'default_options',
                                   'embed',
                                   'fallback',
                                   'language',
                                   'main',
                                   'method',
                                   'modules',
                                   'cmake_module_path',
                                   'optional_modules',
                                   'native',
                                   'not_found_message',
                                   'required',
                                   'static',
                                   'version',
                                   'private_headers',
                                   'cmake_args',
                                   'include_type',
                                   },
                    'declare_dependency': {'include_directories',
                                           'link_with',
                                           'sources',
                                           'dependencies',
                                           'compile_args',
                                           'link_args',
                                           'link_whole',
                                           'version',
                                           },
                    'executable': build.known_exe_kwargs,
                    'find_program': {'required', 'native', 'version', 'dirs'},
                    'generator': {'arguments',
                                  'output',
                                  'depends',
                                  'depfile',
                                  'capture',
                                  'preserve_path_from'},
                    'include_directories': {'is_system'},
                    'install_data': {'install_dir', 'install_mode', 'rename', 'sources'},
                    'install_headers': {'install_dir', 'install_mode', 'subdir'},
                    'install_man': {'install_dir', 'install_mode'},
                    'install_subdir': {'exclude_files', 'exclude_directories', 'install_dir', 'install_mode', 'strip_directory'},
                    'jar': build.known_jar_kwargs,
                    'project': {'version', 'meson_version', 'default_options', 'license', 'subproject_dir'},
                    'run_command': {'check', 'capture', 'env'},
                    'run_target': {'command', 'depends'},
                    'shared_library': build.known_shlib_kwargs,
                    'shared_module': build.known_shmod_kwargs,
                    'static_library': build.known_stlib_kwargs,
                    'both_libraries': known_library_kwargs,
                    'library': known_library_kwargs,
                    'subdir': {'if_found'},
                    'subproject': {'version', 'default_options', 'required'},
                    'test': set.union(_base_test_args, {'is_parallel'}),
                    'vcs_tag': {'input', 'output', 'fallback', 'command', 'replace_string'},
                    }


class Interpreter(InterpreterBase):

    def __init__(self, build, backend=None, subproject='', subdir='', subproject_dir='subprojects',
                 modules = None, default_project_options=None, mock=False, ast=None):
        super().__init__(build.environment.get_source_dir(), subdir)
        self.an_unpicklable_object = mesonlib.an_unpicklable_object
        self.build = build
        self.environment = build.environment
        self.coredata = self.environment.get_coredata()
        self.backend = backend
        self.subproject = subproject
        self.summary = {}
        if modules is None:
            self.modules = {}
        else:
            self.modules = modules
        # Subproject directory is usually the name of the subproject, but can
        # be different for dependencies provided by wrap files.
        self.subproject_directory_name = subdir.split(os.path.sep)[-1]
        self.subproject_dir = subproject_dir
        self.option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt')
        if not mock and ast is None:
            self.load_root_meson_file()
            self.sanity_check_ast()
        elif ast is not None:
            self.ast = ast
            self.sanity_check_ast()
        self.builtin.update({'meson': MesonMain(build, self)})
        self.generators = []
        self.visited_subdirs = {}
        self.project_args_frozen = False
        self.global_args_frozen = False  # implies self.project_args_frozen
        self.subprojects = {}
        self.subproject_stack = []
        self.configure_file_outputs = {}
        # Passed from the outside, only used in subprojects.
        if default_project_options:
            self.default_project_options = default_project_options.copy()
        else:
            self.default_project_options = {}
        self.project_default_options = {}
        self.build_func_dict()
        # build_def_files needs to be defined before parse_project is called
        self.build_def_files = [os.path.join(self.subdir, environment.build_filename)]
        if not mock:
            self.parse_project()

        # Re-initialize machine descriptions. We can do a better job now because we
        # have the compilers needed to gain more knowledge, so wipe out old
        # inference and start over.
        machines = self.build.environment.machines.miss_defaulting()
        machines.build = environment.detect_machine_info(self.coredata.compilers.build)
        self.build.environment.machines = machines.default_missing()
        assert self.build.environment.machines.build.cpu is not None
        assert self.build.environment.machines.host.cpu is not None
        assert self.build.environment.machines.target.cpu is not None

        self.builtin['build_machine'] = \
            MachineHolder(self.build.environment.machines.build)
        self.builtin['host_machine'] = \
            MachineHolder(self.build.environment.machines.host)
        self.builtin['target_machine'] = \
            MachineHolder(self.build.environment.machines.target)

    def get_non_matching_default_options(self):
        env = self.environment
        for def_opt_name, def_opt_value in self.project_default_options.items():
            for opts in env.coredata.get_all_options():
                cur_opt_value = opts.get(def_opt_name)
                if cur_opt_value is not None:
                    def_opt_value = env.coredata.validate_option_value(def_opt_name, def_opt_value)
                    if def_opt_value != cur_opt_value.value:
                        yield (def_opt_name, def_opt_value, cur_opt_value)

    def build_func_dict(self):
        self.funcs.update({'add_global_arguments': self.func_add_global_arguments,
                           'add_project_arguments': self.func_add_project_arguments,
                           'add_global_link_arguments': self.func_add_global_link_arguments,
                           'add_project_link_arguments': self.func_add_project_link_arguments,
                           'add_test_setup': self.func_add_test_setup,
                           'add_languages': self.func_add_languages,
                           'alias_target': self.func_alias_target,
                           'assert': self.func_assert,
                           'benchmark': self.func_benchmark,
                           'build_target': self.func_build_target,
                           'configuration_data': self.func_configuration_data,
                           'configure_file': self.func_configure_file,
                           'custom_target': self.func_custom_target,
                           'declare_dependency': self.func_declare_dependency,
                           'dependency': self.func_dependency,
                           'disabler': self.func_disabler,
                           'environment': self.func_environment,
                           'error': self.func_error,
                           'executable': self.func_executable,
                           'generator': self.func_generator,
                           'gettext': self.func_gettext,
                           'get_option': self.func_get_option,
                           'get_variable': self.func_get_variable,
                           'files': self.func_files,
                           'find_library': self.func_find_library,
                           'find_program': self.func_find_program,
                           'include_directories': self.func_include_directories,
                           'import': self.func_import,
                           'install_data': self.func_install_data,
                           'install_headers': self.func_install_headers,
                           'install_man': self.func_install_man,
                           'install_subdir': self.func_install_subdir,
                           'is_disabler': self.func_is_disabler,
                           'is_variable': self.func_is_variable,
                           'jar': self.func_jar,
                           'join_paths': self.func_join_paths,
                           'library': self.func_library,
                           'message': self.func_message,
                           'warning': self.func_warning,
                           'option': self.func_option,
                           'project': self.func_project,
                           'run_target': self.func_run_target,
                           'run_command': self.func_run_command,
                           'set_variable': self.func_set_variable,
                           'subdir': self.func_subdir,
                           'subdir_done': self.func_subdir_done,
                           'subproject': self.func_subproject,
                           'summary': self.func_summary,
                           'shared_library': self.func_shared_lib,
                           'shared_module': self.func_shared_module,
                           'static_library': self.func_static_lib,
                           'both_libraries': self.func_both_lib,
                           'test': self.func_test,
                           'vcs_tag': self.func_vcs_tag
                           })
        if 'MESON_UNIT_TEST' in os.environ:
            self.funcs.update({'exception': self.func_exception})

    def holderify(self, item):
        if isinstance(item, list):
            return [self.holderify(x) for x in item]
        if isinstance(item, dict):
            return {k: self.holderify(v) for k, v in item.items()}

        if isinstance(item, build.CustomTarget):
            return CustomTargetHolder(item, self)
        elif isinstance(item, (int, str, bool)) or item is None:
            return item
        elif isinstance(item, build.Executable):
            return ExecutableHolder(item, self)
        elif isinstance(item, build.GeneratedList):
            return GeneratedListHolder(item)
        elif isinstance(item, build.RunTarget):
            raise RuntimeError('This is not a pipe.')
        elif isinstance(item, build.RunScript):
            raise RuntimeError('Do not do this.')
        elif isinstance(item, build.Data):
            return DataHolder(item)
        elif isinstance(item, dependencies.Dependency):
            return DependencyHolder(item, self.subproject)
        elif isinstance(item, dependencies.ExternalProgram):
            return ExternalProgramHolder(item)
        elif hasattr(item, 'held_object'):
            return item
        else:
            raise InterpreterException('Module returned a value of unknown type.')

    def process_new_values(self, invalues):
        invalues = listify(invalues)
        for v in invalues:
            if isinstance(v, (RunTargetHolder, CustomTargetHolder, BuildTargetHolder)):
                v = v.held_object

            if isinstance(v, (build.BuildTarget, build.CustomTarget, build.RunTarget)):
                self.add_target(v.name, v)
            elif isinstance(v, list):
                self.module_method_callback(v)
            elif isinstance(v, build.GeneratedList):
                pass
            elif isinstance(v, build.RunScript):
                self.build.install_scripts.append(v)
            elif isinstance(v, build.Data):
                self.build.data.append(v)
            elif isinstance(v, dependencies.ExternalProgram):
                return ExternalProgramHolder(v)
            elif isinstance(v, dependencies.InternalDependency):
                # FIXME: This is special cased and not ideal:
                # The first source is our new VapiTarget, the rest are deps
                self.process_new_values(v.sources[0])
            elif hasattr(v, 'held_object'):
                pass
            elif isinstance(v, (int, str, bool)):
                pass
            else:
                raise InterpreterException('Module returned a value of unknown type.')

    def module_method_callback(self, return_object):
        if not isinstance(return_object, ModuleReturnValue):
            raise InterpreterException('Bug in module, it returned an invalid object')
        invalues = return_object.new_objects
        self.process_new_values(invalues)
        return self.holderify(return_object.return_value)

    def get_build_def_files(self):
        return self.build_def_files

    def add_build_def_file(self, f):
        # Use relative path for files within source directory, and absolute path
        # for system files. Skip files within build directory. Also skip not regular
        # files (e.g. /dev/stdout) Normalize the path to avoid duplicates, this
        # is especially important to convert '/' to '\' on Windows.
        if isinstance(f, mesonlib.File):
            if f.is_built:
                return
            f = os.path.normpath(f.relative_name())
        elif os.path.isfile(f) and not f.startswith('/dev'):
            srcdir = self.environment.get_source_dir()
            builddir = self.environment.get_build_dir()
            f = os.path.normpath(f)
            rel_path = mesonlib.relpath(f, start=srcdir)
            if not rel_path.startswith('..'):
                f = rel_path
            elif not mesonlib.relpath(f, start=builddir).startswith('..'):
                return
        else:
            return
        if f not in self.build_def_files:
            self.build_def_files.append(f)

    def get_variables(self):
        return self.variables

    def check_stdlibs(self):
        for for_machine in MachineChoice:
            props = self.build.environment.properties[for_machine]
            for l in self.coredata.compilers[for_machine].keys():
                try:
                    di = mesonlib.stringlistify(props.get_stdlib(l))
                    if len(di) != 2:
                        raise InterpreterException('Stdlib definition for %s should have exactly two elements.'
                                                   % l)
                    projname, depname = di
                    subproj = self.do_subproject(projname, 'meson', {})
                    self.build.stdlibs.host[l] = subproj.get_variable_method([depname], {})
                except KeyError:
                    pass
                except InvalidArguments:
                    pass

    @stringArgs
    @noKwargs
    def func_import(self, node, args, kwargs):
        if len(args) != 1:
            raise InvalidCode('Import takes one argument.')
        modname = args[0]
        if modname.startswith('unstable-'):
            plainname = modname.split('-', 1)[1]
            mlog.warning('Module %s has no backwards or forwards compatibility and might not exist in future releases.' % modname, location=node)
            modname = 'unstable_' + plainname
        if modname not in self.modules:
            try:
                module = importlib.import_module('mesonbuild.modules.' + modname)
            except ImportError:
                raise InvalidArguments('Module "%s" does not exist' % (modname, ))
            self.modules[modname] = module.initialize(self)
        return ModuleHolder(modname, self.modules[modname], self)

    @stringArgs
    @noKwargs
    def func_files(self, node, args, kwargs):
        return [mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, fname) for fname in args]

    @FeatureNewKwargs('declare_dependency', '0.46.0', ['link_whole'])
    @permittedKwargs(permitted_kwargs['declare_dependency'])
    @noPosargs
    def func_declare_dependency(self, node, args, kwargs):
        version = kwargs.get('version', self.project_version)
        if not isinstance(version, str):
            raise InterpreterException('Version must be a string.')
        incs = self.extract_incdirs(kwargs)
        libs = extract_as_list(kwargs, 'link_with', unholder=True)
        libs_whole = extract_as_list(kwargs, 'link_whole', unholder=True)
        sources = extract_as_list(kwargs, 'sources')
        sources = listify(self.source_strings_to_files(sources), unholder=True)
        deps = extract_as_list(kwargs, 'dependencies', unholder=True)
        compile_args = mesonlib.stringlistify(kwargs.get('compile_args', []))
        link_args = mesonlib.stringlistify(kwargs.get('link_args', []))
        final_deps = []
        for d in deps:
            try:
                d = d.held_object
            except Exception:
                pass
            if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)):
                raise InterpreterException('Dependencies must be external deps')
            final_deps.append(d)
        for l in libs:
            if isinstance(l, dependencies.Dependency):
                raise InterpreterException('''Entries in "link_with" may only be self-built targets,
external dependencies (including libraries) must go to "dependencies".''')
        dep = dependencies.InternalDependency(version, incs, compile_args,
                                              link_args, libs, libs_whole, sources, final_deps)
        return DependencyHolder(dep, self.subproject)

    @noKwargs
    def func_assert(self, node, args, kwargs):
        if len(args) == 1:
            FeatureNew('assert function without message argument', '0.53.0').use(self.subproject)
            value = args[0]
            message = None
        elif len(args) == 2:
            value, message = args
            if not isinstance(message, str):
                raise InterpreterException('Assert message not a string.')
        else:
            raise InterpreterException('Assert takes between one and two arguments')
        if not isinstance(value, bool):
            raise InterpreterException('Assert value not bool.')
        if not value:
            if message is None:
                from .ast import AstPrinter
                printer = AstPrinter()
                node.args.arguments[0].accept(printer)
                message = printer.result
            raise InterpreterException('Assert failed: ' + message)

    def validate_arguments(self, args, argcount, arg_types):
        if argcount is not None:
            if argcount != len(args):
                raise InvalidArguments('Expected %d arguments, got %d.' %
                                       (argcount, len(args)))
        for actual, wanted in zip(args, arg_types):
            if wanted is not None:
                if not isinstance(actual, wanted):
                    raise InvalidArguments('Incorrect argument type.')

    @FeatureNewKwargs('run_command', '0.50.0', ['env'])
    @FeatureNewKwargs('run_command', '0.47.0', ['check', 'capture'])
    @permittedKwargs(permitted_kwargs['run_command'])
    def func_run_command(self, node, args, kwargs):
        return self.run_command_impl(node, args, kwargs)

    def run_command_impl(self, node, args, kwargs, in_builddir=False):
        if len(args) < 1:
            raise InterpreterException('Not enough arguments')
        cmd, *cargs = args
        capture = kwargs.get('capture', True)
        srcdir = self.environment.get_source_dir()
        builddir = self.environment.get_build_dir()

        check = kwargs.get('check', False)
        if not isinstance(check, bool):
            raise InterpreterException('Check must be boolean.')

        env = self.unpack_env_kwarg(kwargs)

        m = 'must be a string, or the output of find_program(), files() '\
            'or configure_file(), or a compiler object; not {!r}'
        expanded_args = []
        if isinstance(cmd, ExternalProgramHolder):
            cmd = cmd.held_object
            if isinstance(cmd, build.Executable):
                progname = node.args.arguments[0].value
                msg = 'Program {!r} was overridden with the compiled executable {!r}'\
                      ' and therefore cannot be used during configuration'
                raise InterpreterException(msg.format(progname, cmd.description()))
            if not cmd.found():
                raise InterpreterException('command {!r} not found or not executable'.format(cmd))
        elif isinstance(cmd, CompilerHolder):
            exelist = cmd.compiler.get_exelist()
            cmd = exelist[0]
            prog = ExternalProgram(cmd, silent=True)
            if not prog.found():
                raise InterpreterException('Program {!r} not found '
                                           'or not executable'.format(cmd))
            cmd = prog
            expanded_args = exelist[1:]
        else:
            if isinstance(cmd, mesonlib.File):
                cmd = cmd.absolute_path(srcdir, builddir)
            elif not isinstance(cmd, str):
                raise InterpreterException('First argument ' + m.format(cmd))
            # Prefer scripts in the current source directory
            search_dir = os.path.join(srcdir, self.subdir)
            prog = ExternalProgram(cmd, silent=True, search_dir=search_dir)
            if not prog.found():
                raise InterpreterException('Program or command {!r} not found '
                                           'or not executable'.format(cmd))
            cmd = prog
        for a in listify(cargs):
            if isinstance(a, str):
                expanded_args.append(a)
            elif isinstance(a, mesonlib.File):
                expanded_args.append(a.absolute_path(srcdir, builddir))
            elif isinstance(a, ExternalProgramHolder):
                expanded_args.append(a.held_object.get_path())
            else:
                raise InterpreterException('Arguments ' + m.format(a))
        # If any file that was used as an argument to the command
        # changes, we must re-run the configuration step.
        self.add_build_def_file(cmd.get_path())
        for a in expanded_args:
            if not os.path.isabs(a):
                a = os.path.join(builddir if in_builddir else srcdir, self.subdir, a)
            self.add_build_def_file(a)
        return RunProcess(cmd, expanded_args, env, srcdir, builddir, self.subdir,
                          self.environment.get_build_command() + ['introspect'],
                          in_builddir=in_builddir, check=check, capture=capture)

    @stringArgs
    def func_gettext(self, nodes, args, kwargs):
        raise InterpreterException('Gettext() function has been moved to module i18n. Import it and use i18n.gettext() instead')

    def func_option(self, nodes, args, kwargs):
        raise InterpreterException('Tried to call option() in build description file. All options must be in the option file.')

    @FeatureNewKwargs('subproject', '0.38.0', ['default_options'])
    @permittedKwargs(permitted_kwargs['subproject'])
    @stringArgs
    def func_subproject(self, nodes, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Subproject takes exactly one argument')
        dirname = args[0]
        return self.do_subproject(dirname, 'meson', kwargs)

    def disabled_subproject(self, dirname, feature=None):
        sub = SubprojectHolder(None, self.subproject_dir, dirname)
        if feature:
            sub.disabled_feature = feature
        self.subprojects[dirname] = sub
        return sub

    def do_subproject(self, dirname: str, method: str, kwargs):
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            mlog.log('Subproject', mlog.bold(dirname), ':', 'skipped: feature', mlog.bold(feature), 'disabled')
            return self.disabled_subproject(dirname, feature)

        default_options = mesonlib.stringlistify(kwargs.get('default_options', []))
        default_options = coredata.create_options_dict(default_options)
        if dirname == '':
            raise InterpreterException('Subproject dir name must not be empty.')
        if dirname[0] == '.':
            raise InterpreterException('Subproject dir name must not start with a period.')
        if '..' in dirname:
            raise InterpreterException('Subproject name must not contain a ".." path segment.')
        if os.path.isabs(dirname):
            raise InterpreterException('Subproject name must not be an absolute path.')
        if has_path_sep(dirname):
            mlog.warning('Subproject name has a path separator. This may cause unexpected behaviour.',
                         location=self.current_node)
        if dirname in self.subproject_stack:
            fullstack = self.subproject_stack + [dirname]
            incpath = ' => '.join(fullstack)
            raise InvalidCode('Recursive include of subprojects: %s.' % incpath)
        if dirname in self.subprojects:
            subproject = self.subprojects[dirname]
            if required and not subproject.found():
                raise InterpreterException('Subproject "%s/%s" required but not found.' % (
                                           self.subproject_dir, dirname))
            return subproject

        subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
        r = wrap.Resolver(subproject_dir_abs, self.coredata.get_builtin_option('wrap_mode'))
        try:
            resolved = r.resolve(dirname, method)
        except wrap.WrapException as e:
            subprojdir = os.path.join(self.subproject_dir, r.directory)
            if isinstance(e, wrap.WrapNotFoundException):
                # if the reason subproject execution failed was because
                # the directory doesn't exist, try to give some helpful
                # advice if it's a nested subproject that needs
                # promotion...
                self.print_nested_info(dirname)
            if not required:
                mlog.log(e)
                mlog.log('Subproject ', mlog.bold(subprojdir), 'is buildable:', mlog.red('NO'), '(disabling)')
                return self.disabled_subproject(dirname)
            raise e

        subdir = os.path.join(self.subproject_dir, resolved)
        subdir_abs = os.path.join(subproject_dir_abs, resolved)
        os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
        self.global_args_frozen = True

        mlog.log()
        with mlog.nested():
            mlog.log('Executing subproject', mlog.bold(dirname), 'method', mlog.bold(method), '\n')
        try:
            if method == 'meson':
                return self._do_subproject_meson(dirname, subdir, default_options, kwargs)
            elif method == 'cmake':
                return self._do_subproject_cmake(dirname, subdir, subdir_abs, default_options, kwargs)
            else:
                raise InterpreterException('The method {} is invalid for the subproject {}'.format(method, dirname))
        # Invalid code is always an error
        except InvalidCode:
            raise
        except Exception as e:
            if not required:
                with mlog.nested():
                    # Suppress the 'ERROR:' prefix because this exception is not
                    # fatal and VS CI treat any logs with "ERROR:" as fatal.
                    mlog.exception(e, prefix=mlog.yellow('Exception:'))
                mlog.log('\nSubproject', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)')
                return self.disabled_subproject(dirname)
            raise e

    def _do_subproject_meson(self, dirname, subdir, default_options, kwargs, ast=None, build_def_files=None):
        with mlog.nested():
            new_build = self.build.copy()
            subi = Interpreter(new_build, self.backend, dirname, subdir, self.subproject_dir,
                               self.modules, default_options, ast=ast)
            subi.subprojects = self.subprojects

            subi.subproject_stack = self.subproject_stack + [dirname]
            current_active = self.active_projectname
            subi.run()
            mlog.log('Subproject', mlog.bold(dirname), 'finished.')

        mlog.log()

        if 'version' in kwargs:
            pv = subi.project_version
            wanted = kwargs['version']
            if pv == 'undefined' or not mesonlib.version_compare_many(pv, wanted)[0]:
                raise InterpreterException('Subproject %s version is %s but %s required.' % (dirname, pv, wanted))
        self.active_projectname = current_active
        self.subprojects.update(subi.subprojects)
        self.subprojects[dirname] = SubprojectHolder(subi, self.subproject_dir, dirname)
        # Duplicates are possible when subproject uses files from project root
        if build_def_files:
            self.build_def_files = list(set(self.build_def_files + build_def_files))
        else:
            self.build_def_files = list(set(self.build_def_files + subi.build_def_files))
        self.build.merge(subi.build)
        self.build.subprojects[dirname] = subi.project_version
        self.summary.update(subi.summary)
        return self.subprojects[dirname]

    def _do_subproject_cmake(self, dirname, subdir, subdir_abs, default_options, kwargs):
        with mlog.nested():
            new_build = self.build.copy()
            prefix = self.coredata.builtins['prefix'].value
            cmake_options = mesonlib.stringlistify(kwargs.get('cmake_options', []))
            cm_int = CMakeInterpreter(new_build, subdir, subdir_abs, prefix, new_build.environment, self.backend)
            cm_int.initialise(cmake_options)
            cm_int.analyse()

            # Generate a meson ast and execute it with the normal do_subproject_meson
            ast = cm_int.pretend_to_be_meson()

            mlog.log()
            with mlog.nested():
                mlog.log('Processing generated meson AST')

                # Debug print the generated meson file
                from .ast import AstIndentationGenerator, AstPrinter
                printer = AstPrinter()
                ast.accept(AstIndentationGenerator())
                ast.accept(printer)
                printer.post_process()
                meson_filename = os.path.join(self.build.environment.get_build_dir(), subdir, 'meson.build')
                with open(meson_filename, "w") as f:
                    f.write(printer.result)

                mlog.log('Build file:', meson_filename)
                mlog.cmd_ci_include(meson_filename)
                mlog.log()

            result = self._do_subproject_meson(dirname, subdir, default_options, kwargs, ast, cm_int.bs_files)
            result.cm_interpreter = cm_int

        mlog.log()
        return result

    def get_option_internal(self, optname):
        for opts in chain(
                [self.coredata.base_options, compilers.base_options, self.coredata.builtins],
                self.coredata.get_prefixed_options_per_machine(self.coredata.builtins_per_machine),
                self.coredata.get_prefixed_options_per_machine(self.coredata.compiler_options),
        ):
            v = opts.get(optname)
            if v is not None:
                return v

        raw_optname = optname
        if self.is_subproject():
            optname = self.subproject + ':' + optname

        try:
            opt = self.coredata.user_options[optname]
            if opt.yielding and ':' in optname and raw_optname in self.coredata.user_options:
                popt = self.coredata.user_options[raw_optname]
                if type(opt) is type(popt):
                    opt = popt
                else:
                    # Get class name, then option type as a string
                    opt_type = opt.__class__.__name__[4:][:-6].lower()
                    popt_type = popt.__class__.__name__[4:][:-6].lower()
                    # This is not a hard error to avoid dependency hell, the workaround
                    # when this happens is to simply set the subproject's option directly.
                    mlog.warning('Option {0!r} of type {1!r} in subproject {2!r} cannot yield '
                                 'to parent option of type {3!r}, ignoring parent value. '
                                 'Use -D{2}:{0}=value to set the value for this option manually'
                                 '.'.format(raw_optname, opt_type, self.subproject, popt_type),
                                 location=self.current_node)
            return opt
        except KeyError:
            pass

        raise InterpreterException('Tried to access unknown option "%s".' % optname)

    @stringArgs
    @noKwargs
    def func_get_option(self, nodes, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Argument required for get_option.')
        optname = args[0]
        if ':' in optname:
            raise InterpreterException('Having a colon in option name is forbidden, '
                                       'projects are not allowed to directly access '
                                       'options of other subprojects.')
        opt = self.get_option_internal(optname)
        if isinstance(opt, coredata.UserFeatureOption):
            return FeatureOptionHolder(self.environment, optname, opt)
        elif isinstance(opt, coredata.UserOption):
            return opt.value
        return opt

    @noKwargs
    def func_configuration_data(self, node, args, kwargs):
        if len(args) > 1:
            raise InterpreterException('configuration_data takes only one optional positional arguments')
        elif len(args) == 1:
            FeatureNew('configuration_data dictionary', '0.49.0').use(self.subproject)
            initial_values = args[0]
            if not isinstance(initial_values, dict):
                raise InterpreterException('configuration_data first argument must be a dictionary')
        else:
            initial_values = {}
        return ConfigurationDataHolder(self.subproject, initial_values)

    def set_backend(self):
        # The backend is already set when parsing subprojects
        if self.backend is not None:
            return
        backend = self.coredata.get_builtin_option('backend')
        from .backend import backends
        self.backend = backends.get_backend_from_name(backend, self.build)

        if self.backend is None:
            raise InterpreterException('Unknown backend "%s".' % backend)
        if backend != self.backend.name:
            if self.backend.name.startswith('vs'):
                mlog.log('Auto detected Visual Studio backend:', mlog.bold(self.backend.name))
            self.coredata.set_builtin_option('backend', self.backend.name)

        # Only init backend options on first invocation otherwise it would
        # override values previously set from command line.
        if self.environment.first_invocation:
            self.coredata.init_backend_options(backend)

        options = {k: v for k, v in self.environment.cmd_line_options.items() if k.startswith('backend_')}
        self.coredata.set_options(options)

    @stringArgs
    @permittedKwargs(permitted_kwargs['project'])
    def func_project(self, node, args, kwargs):
        if len(args) < 1:
            raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.')
        proj_name, *proj_langs = args
        if ':' in proj_name:
            raise InvalidArguments("Project name {!r} must not contain ':'".format(proj_name))

        if 'meson_version' in kwargs:
            cv = coredata.version
            pv = kwargs['meson_version']
            if not mesonlib.version_compare(cv, pv):
                raise InterpreterException('Meson version is %s but project requires %s' % (cv, pv))

        if os.path.exists(self.option_file):
            oi = optinterpreter.OptionInterpreter(self.subproject)
            oi.process(self.option_file)
            self.coredata.merge_user_options(oi.options)

        # Do not set default_options on reconfigure otherwise it would override
        # values previously set from command line. That means that changing
        # default_options in a project will trigger a reconfigure but won't
        # have any effect.
        self.project_default_options = mesonlib.stringlistify(kwargs.get('default_options', []))
        self.project_default_options = coredata.create_options_dict(self.project_default_options)
        if self.environment.first_invocation:
            default_options = self.project_default_options
            default_options.update(self.default_project_options)
        else:
            default_options = {}
        self.coredata.set_default_options(default_options, self.subproject, self.environment)

        if not self.is_subproject():
            self.build.project_name = proj_name
        self.active_projectname = proj_name
        self.project_version = kwargs.get('version', 'undefined')
        if self.build.project_version is None:
            self.build.project_version = self.project_version
        proj_license = mesonlib.stringlistify(kwargs.get('license', 'unknown'))
        self.build.dep_manifest[proj_name] = {'version': self.project_version,
                                              'license': proj_license}
        if self.subproject in self.build.projects:
            raise InvalidCode('Second call to project().')
        if not self.is_subproject() and 'subproject_dir' in kwargs:
            spdirname = kwargs['subproject_dir']
            if not isinstance(spdirname, str):
                raise InterpreterException('Subproject_dir must be a string')
            if os.path.isabs(spdirname):
                raise InterpreterException('Subproject_dir must not be an absolute path.')
            if spdirname.startswith('.'):
                raise InterpreterException('Subproject_dir must not begin with a period.')
            if '..' in spdirname:
                raise InterpreterException('Subproject_dir must not contain a ".." segment.')
            self.subproject_dir = spdirname

        self.build.subproject_dir = self.subproject_dir

        mesonlib.project_meson_versions[self.subproject] = ''
        if 'meson_version' in kwargs:
            mesonlib.project_meson_versions[self.subproject] = kwargs['meson_version']

        self.build.projects[self.subproject] = proj_name
        mlog.log('Project name:', mlog.bold(proj_name))
        mlog.log('Project version:', mlog.bold(self.project_version))
        self.add_languages(proj_langs, True)
        self.set_backend()
        if not self.is_subproject():
            self.check_stdlibs()

    @permittedKwargs(permitted_kwargs['add_languages'])
    @stringArgs
    def func_add_languages(self, node, args, kwargs):
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            for lang in sorted(args, key=compilers.sort_clink):
                mlog.log('Compiler for language', mlog.bold(lang), 'skipped: feature', mlog.bold(feature), 'disabled')
            return False
        return self.add_languages(args, required)

    def get_message_string_arg(self, node):
        # reduce arguments again to avoid flattening posargs
        (posargs, _) = self.reduce_arguments(node.args)
        if len(posargs) != 1:
            raise InvalidArguments('Expected 1 argument, got %d' % len(posargs))

        arg = posargs[0]
        if isinstance(arg, list):
            argstr = stringifyUserArguments(arg)
        elif isinstance(arg, dict):
            argstr = stringifyUserArguments(arg)
        elif isinstance(arg, str):
            argstr = arg
        elif isinstance(arg, int):
            argstr = str(arg)
        else:
            raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')

        return argstr

    @noKwargs
    def func_message(self, node, args, kwargs):
        argstr = self.get_message_string_arg(node)
        self.message_impl(argstr)

    def message_impl(self, argstr):
        mlog.log(mlog.bold('Message:'), argstr)

    @noArgsFlattening
    @permittedKwargs({'section', 'bool_yn'})
    @FeatureNew('summary', '0.53.0')
    def func_summary(self, node, args, kwargs):
        if len(args) == 1:
            if not isinstance(args[0], dict):
                raise InterpreterException('Summary first argument must be dictionary.')
            values = args[0]
        elif len(args) == 2:
            if not isinstance(args[0], str):
                raise InterpreterException('Summary first argument must be string.')
            values = {args[0]: args[1]}
        else:
            raise InterpreterException('Summary accepts at most 2 arguments.')
        section = kwargs.get('section', '')
        if not isinstance(section, str):
            raise InterpreterException('Summary\'s section keyword argument must be string.')
        self.summary_impl(section, values, kwargs)

    def summary_impl(self, section, values, kwargs):
        if self.subproject not in self.summary:
            self.summary[self.subproject] = Summary(self.active_projectname, self.project_version)
        self.summary[self.subproject].add_section(section, values, kwargs)

    def _print_summary(self):
        # Add automatic 'Supbrojects' section in main project.
        all_subprojects = collections.OrderedDict()
        for name, subp in sorted(self.subprojects.items()):
            value = subp.found()
            if not value and hasattr(subp, 'disabled_feature'):
                value = 'Feature {!r} disabled'.format(subp.disabled_feature)
            all_subprojects[name] = value
        if all_subprojects:
            self.summary_impl('Subprojects', all_subprojects, {'bool_yn': True})
        # Print all summaries, main project last.
        mlog.log('')  # newline
        main_summary = self.summary.pop('', None)
        for _, summary in sorted(self.summary.items()):
            summary.dump()
        if main_summary:
            main_summary.dump()

    @FeatureNew('warning', '0.44.0')
    @noKwargs
    def func_warning(self, node, args, kwargs):
        argstr = self.get_message_string_arg(node)
        mlog.warning(argstr, location=node)

    @noKwargs
    def func_error(self, node, args, kwargs):
        self.validate_arguments(args, 1, [str])
        raise InterpreterException('Problem encountered: ' + args[0])

    @noKwargs
    def func_exception(self, node, args, kwargs):
        self.validate_arguments(args, 0, [])
        raise Exception()

    def add_languages(self, args: T.Sequence[str], required: bool) -> bool:
        success = self.add_languages_for(args, required, MachineChoice.BUILD)
        success &= self.add_languages_for(args, required, MachineChoice.HOST)
        if not self.coredata.is_cross_build():
            self.coredata.copy_build_options_from_regular_ones()
        return success

    def add_languages_for(self, args, required, for_machine: MachineChoice):
        success = True
        for lang in sorted(args, key=compilers.sort_clink):
            lang = lang.lower()
            clist = self.coredata.compilers[for_machine]
            machine_name = for_machine.get_lower_case_name()
            if lang in clist:
                comp = clist[lang]
            else:
                try:
                    comp = self.environment.detect_compiler_for(lang, for_machine)
                    if comp is None:
                        raise InvalidArguments('Tried to use unknown language "%s".' % lang)
                    comp.sanity_check(self.environment.get_scratch_dir(), self.environment)
                except Exception:
                    if not required:
                        mlog.log('Compiler for language',
                                 mlog.bold(lang), 'for the', machine_name,
                                 'machine not found.')
                        success = False
                        continue
                    else:
                        raise

            if for_machine == MachineChoice.HOST or self.environment.is_cross_build():
                logger_fun = mlog.log
            else:
                logger_fun = mlog.debug
            logger_fun(comp.get_display_language(), 'compiler for the', machine_name, 'machine:',
                       mlog.bold(' '.join(comp.get_exelist())), comp.get_version_string())
            if comp.linker is not None:
                logger_fun(comp.get_display_language(), 'linker for the', machine_name, 'machine:',
                           mlog.bold(' '.join(comp.linker.get_exelist())), comp.linker.id, comp.linker.version)
            self.build.ensure_static_linker(comp)

        langs = self.coredata.compilers[for_machine].keys()
        if 'vala' in langs:
            if 'c' not in langs:
                raise InterpreterException('Compiling Vala requires C. Add C to your project languages and rerun Meson.')

        return success

    def program_from_file_for(self, for_machine, prognames, silent):
        bins = self.environment.binaries[for_machine]
        for p in prognames:
            if hasattr(p, 'held_object'):
                p = p.held_object
            if isinstance(p, mesonlib.File):
                continue # Always points to a local (i.e. self generated) file.
            if not isinstance(p, str):
                raise InterpreterException('Executable name must be a string')
            prog = ExternalProgram.from_bin_list(bins, p)
            if prog.found():
                return ExternalProgramHolder(prog)
        return None

    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.
        source_dir = os.path.join(self.environment.get_source_dir(), self.subdir)
        for exename in args:
            if isinstance(exename, mesonlib.File):
                if exename.is_built:
                    search_dir = os.path.join(self.environment.get_build_dir(),
                                              exename.subdir)
                else:
                    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():
                return progobj

    def program_from_overrides(self, command_names, silent=False):
        for name in command_names:
            if not isinstance(name, str):
                continue
            if name in self.build.find_overrides:
                exe = self.build.find_overrides[name]
                if not silent:
                    mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
                             '(overridden: %s)' % exe.description())
                return ExternalProgramHolder(exe)
        return None

    def store_name_lookups(self, command_names):
        for name in command_names:
            if isinstance(name, str):
                self.build.searched_programs.add(name)

    def add_find_program_override(self, name, exe):
        if name in self.build.searched_programs:
            raise InterpreterException('Tried to override finding of executable "%s" which has already been found.'
                                       % name)
        if name in self.build.find_overrides:
            raise InterpreterException('Tried to override executable "%s" which has already been overridden.'
                                       % name)
        self.build.find_overrides[name] = exe

    # 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='', search_dirs=None):
        if not isinstance(args, list):
            args = [args]

        progobj = self.program_from_overrides(args, silent=silent)
        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, 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)
        if required and (progobj is None or not progobj.found()):
            raise InvalidArguments('Program(s) {!r} not found or not executable'.format(args))
        if progobj is None:
            return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
        # Only store successful lookups
        self.store_name_lookups(args)
        if wanted:
            version = progobj.get_version(self)
            is_found, not_found, found = mesonlib.version_compare_many(version, wanted)
            if not is_found:
                mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'),
                         'found {!r} but need:'.format(version),
                         ', '.join(["'{}'".format(e) for e in not_found]))
                if required:
                    m = 'Invalid version of program, need {!r} {!r} found {!r}.'
                    raise InvalidArguments(m.format(progobj.get_name(), not_found, version))
                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
    @permittedKwargs(permitted_kwargs['find_program'])
    def func_find_program(self, node, args, kwargs):
        if not args:
            raise InterpreterException('No program name specified.')

        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            mlog.log('Program', mlog.bold(' '.join(args)), 'skipped: feature', mlog.bold(feature), 'disabled')
            return ExternalProgramHolder(dependencies.NonExistingExternalProgram())

        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,
                                      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'
                          'Look here for documentation: http://mesonbuild.com/Reference-manual.html#compiler-object\n'
                          'Look here for example: http://mesonbuild.com/howtox.html#add-math-library-lm-portably\n'
                          )

    def _find_cached_dep(self, name, kwargs):
        # Check if we want this as a build-time / build machine or runt-time /
        # host machine dep.
        for_machine = self.machine_from_native_kwarg(kwargs)

        identifier = dependencies.get_dep_identifier(name, kwargs)
        cached_dep = self.coredata.deps[for_machine].get(identifier)
        if cached_dep:
            if not cached_dep.found():
                mlog.log('Dependency', mlog.bold(name),
                         'found:', mlog.red('NO'), mlog.blue('(cached)'))
                return identifier, cached_dep

            # Verify the cached dep version match
            wanted_vers = mesonlib.stringlistify(kwargs.get('version', []))
            found_vers = cached_dep.get_version()
            if not wanted_vers or mesonlib.version_compare_many(found_vers, wanted_vers)[0]:
                info = [mlog.blue('(cached)')]
                if found_vers:
                    info = [mlog.normal_cyan(found_vers), *info]
                mlog.log('Dependency', mlog.bold(name),
                         'found:', mlog.green('YES'), *info)
                return identifier, cached_dep

        return identifier, None

    @staticmethod
    def check_subproject_version(wanted, found):
        if not wanted:
            return True
        if found == 'undefined' or not mesonlib.version_compare_many(found, wanted)[0]:
            return False
        return True

    def notfound_dependency(self):
        return DependencyHolder(NotFoundDependency(self.environment), self.subproject)

    def get_subproject_dep(self, display_name, dirname, varname, kwargs):
        dep = self.notfound_dependency()
        try:
            subproject = self.subprojects[dirname]
            if subproject.found():
                dep = self.subprojects[dirname].get_variable_method([varname], {})
        except InvalidArguments:
            pass

        if not isinstance(dep, DependencyHolder):
            raise InvalidCode('Fetched variable {!r} in the subproject {!r} is '
                              'not a dependency object.'.format(varname, dirname))

        required = kwargs.get('required', True)
        wanted = mesonlib.stringlistify(kwargs.get('version', []))
        subproj_path = os.path.join(self.subproject_dir, dirname)

        if not dep.found():
            if required:
                raise DependencyException('Could not find dependency {} in subproject {}'
                                          ''.format(varname, dirname))
            # If the dependency is not required, don't raise an exception
            mlog.log('Dependency', mlog.bold(display_name), 'from subproject',
                     mlog.bold(subproj_path), 'found:', mlog.red('NO'))
            return dep

        found = dep.held_object.get_version()
        if not self.check_subproject_version(wanted, found):
            if required:
                raise DependencyException('Version {} of subproject dependency {} already '
                                          'cached, requested incompatible version {} for '
                                          'dep {}'.format(found, dirname, wanted, display_name))

            mlog.log('Dependency', mlog.bold(display_name), 'from subproject',
                     mlog.bold(subproj_path), 'found:', mlog.red('NO'),
                     'found', mlog.normal_cyan(found), 'but need:',
                     mlog.bold(', '.join(["'{}'".format(e) for e in wanted])))
            return self.notfound_dependency()

        found = mlog.normal_cyan(found) if found else None
        mlog.log('Dependency', mlog.bold(display_name), 'from subproject',
                 mlog.bold(subproj_path), 'found:', mlog.green('YES'), found)
        return dep

    def _handle_featurenew_dependencies(self, name):
        'Do a feature check on dependencies used by this subproject'
        if name == 'mpi':
            FeatureNew('MPI Dependency', '0.42.0').use(self.subproject)
        elif name == 'pcap':
            FeatureNew('Pcap Dependency', '0.42.0').use(self.subproject)
        elif name == 'vulkan':
            FeatureNew('Vulkan Dependency', '0.42.0').use(self.subproject)
        elif name == 'libwmf':
            FeatureNew('LibWMF Dependency', '0.44.0').use(self.subproject)
        elif name == 'openmp':
            FeatureNew('OpenMP Dependency', '0.46.0').use(self.subproject)

    @FeatureNewKwargs('dependency', '0.52.0', ['include_type'])
    @FeatureNewKwargs('dependency', '0.50.0', ['not_found_message', 'cmake_module_path', 'cmake_args'])
    @FeatureNewKwargs('dependency', '0.49.0', ['disabler'])
    @FeatureNewKwargs('dependency', '0.40.0', ['method'])
    @FeatureNewKwargs('dependency', '0.38.0', ['default_options'])
    @disablerIfNotFound
    @permittedKwargs(permitted_kwargs['dependency'])
    def func_dependency(self, node, args, kwargs):
        self.validate_arguments(args, 1, [str])
        name = args[0]
        display_name = name if name else '(anonymous)'
        not_found_message = kwargs.get('not_found_message', '')
        if not isinstance(not_found_message, str):
            raise InvalidArguments('The not_found_message must be a string.')
        try:
            d = self.dependency_impl(name, display_name, kwargs)
        except Exception:
            if not_found_message:
                self.message_impl(not_found_message)
            raise
        if not d.found() and not_found_message:
            self.message_impl(not_found_message)
        return d

    def dependency_impl(self, name, display_name, kwargs):
        disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
        if disabled:
            mlog.log('Dependency', mlog.bold(display_name), 'skipped: feature', mlog.bold(feature), 'disabled')
            return self.notfound_dependency()

        has_fallback = 'fallback' in kwargs
        if 'default_options' in kwargs and not has_fallback:
            mlog.warning('The "default_options" keyworg argument does nothing without a "fallback" keyword argument.',
                         location=self.current_node)

        # writing just "dependency('')" is an error, because it can only fail
        if name == '' and required and not has_fallback:
            raise InvalidArguments('Dependency is both required and not-found')

        if '<' in name or '>' in name or '=' in name:
            raise InvalidArguments('Characters <, > and = are forbidden in dependency names. To specify'
                                   'version\n requirements use the \'version\' keyword argument instead.')

        identifier, cached_dep = self._find_cached_dep(name, kwargs)
        if cached_dep:
            if required and not cached_dep.found():
                m = 'Dependency {!r} was already checked and was not found'
                raise DependencyException(m.format(display_name))
            return DependencyHolder(cached_dep, self.subproject)

        # If the dependency has already been configured, possibly by
        # a higher level project, try to use it first.
        if has_fallback:
            dirname, varname = self.get_subproject_infos(kwargs)
            if dirname in self.subprojects:
                return self.get_subproject_dep(name, dirname, varname, kwargs)

        wrap_mode = self.coredata.get_builtin_option('wrap_mode')
        forcefallback = wrap_mode == WrapMode.forcefallback and has_fallback
        if name != '' and not forcefallback:
            self._handle_featurenew_dependencies(name)
            kwargs['required'] = required and not has_fallback
            dep = dependencies.find_external_dependency(name, self.environment, kwargs)

            kwargs['required'] = required
            # Only store found-deps in the cache
            # Never add fallback deps to self.coredata.deps since we
            # cannot cache them. They must always be evaluated else
            # we won't actually read all the build files.
            if dep.found():
                for_machine = self.machine_from_native_kwarg(kwargs)
                self.coredata.deps[for_machine].put(identifier, dep)
                return DependencyHolder(dep, self.subproject)

        if has_fallback:
            return self.dependency_fallback(display_name, kwargs)

        return self.notfound_dependency()

    @FeatureNew('disabler', '0.44.0')
    @noKwargs
    @noPosargs
    def func_disabler(self, node, args, kwargs):
        return Disabler()

    def print_nested_info(self, dependency_name):
        message = ['Dependency', mlog.bold(dependency_name), 'not found but it is available in a sub-subproject.\n' +
                   'To use it in the current project, promote it by going in the project source\n'
                   'root and issuing']
        sprojs = mesonlib.detect_subprojects('subprojects', self.source_root)
        if dependency_name not in sprojs:
            return
        found = sprojs[dependency_name]
        if len(found) > 1:
            message.append('one of the following commands:')
        else:
            message.append('the following command:')
        command_templ = '\nmeson wrap promote {}'
        for l in found:
            message.append(mlog.bold(command_templ.format(l[len(self.source_root) + 1:])))
        mlog.warning(*message, location=self.current_node)

    def get_subproject_infos(self, kwargs):
        fbinfo = kwargs['fallback']
        check_stringlist(fbinfo)
        if len(fbinfo) != 2:
            raise InterpreterException('Fallback info must have exactly two items.')
        return fbinfo

    def dependency_fallback(self, display_name, kwargs):
        if self.coredata.get_builtin_option('wrap_mode') == WrapMode.nofallback:
            mlog.log('Not looking for a fallback subproject for the dependency',
                     mlog.bold(display_name), 'because:\nUse of fallback'
                     'dependencies is disabled.')
            return self.notfound_dependency()
        elif self.coredata.get_builtin_option('wrap_mode') == WrapMode.forcefallback:
            mlog.log('Looking for a fallback subproject for the dependency',
                     mlog.bold(display_name), 'because:\nUse of fallback dependencies is forced.')
        else:
            mlog.log('Looking for a fallback subproject for the dependency',
                     mlog.bold(display_name))
        dirname, varname = self.get_subproject_infos(kwargs)
        sp_kwargs = {
            'default_options': kwargs.get('default_options', []),
            'required': kwargs.get('required', True),
        }
        self.do_subproject(dirname, 'meson', sp_kwargs)
        return self.get_subproject_dep(display_name, dirname, varname, kwargs)

    @FeatureNewKwargs('executable', '0.42.0', ['implib'])
    @permittedKwargs(permitted_kwargs['executable'])
    def func_executable(self, node, args, kwargs):
        return self.build_target(node, args, kwargs, ExecutableHolder)

    @permittedKwargs(permitted_kwargs['static_library'])
    def func_static_lib(self, node, args, kwargs):
        return self.build_target(node, args, kwargs, StaticLibraryHolder)

    @permittedKwargs(permitted_kwargs['shared_library'])
    def func_shared_lib(self, node, args, kwargs):
        holder = self.build_target(node, args, kwargs, SharedLibraryHolder)
        holder.held_object.shared_library_only = True
        return holder

    @permittedKwargs(permitted_kwargs['both_libraries'])
    def func_both_lib(self, node, args, kwargs):
        return self.build_both_libraries(node, args, kwargs)

    @FeatureNew('shared_module', '0.37.0')
    @permittedKwargs(permitted_kwargs['shared_module'])
    def func_shared_module(self, node, args, kwargs):
        return self.build_target(node, args, kwargs, SharedModuleHolder)

    @permittedKwargs(permitted_kwargs['library'])
    def func_library(self, node, args, kwargs):
        return self.build_library(node, args, kwargs)

    @permittedKwargs(permitted_kwargs['jar'])
    def func_jar(self, node, args, kwargs):
        return self.build_target(node, args, kwargs, JarHolder)

    @FeatureNewKwargs('build_target', '0.40.0', ['link_whole', 'override_options'])
    @permittedKwargs(permitted_kwargs['build_target'])
    def func_build_target(self, node, args, kwargs):
        if 'target_type' not in kwargs:
            raise InterpreterException('Missing target_type keyword argument')
        target_type = kwargs.pop('target_type')
        if target_type == 'executable':
            return self.build_target(node, args, kwargs, ExecutableHolder)
        elif target_type == 'shared_library':
            return self.build_target(node, args, kwargs, SharedLibraryHolder)
        elif target_type == 'shared_module':
            FeatureNew('build_target(target_type: \'shared_module\')',
                       '0.51.0').use(self.subproject)
            return self.build_target(node, args, kwargs, SharedModuleHolder)
        elif target_type == 'static_library':
            return self.build_target(node, args, kwargs, StaticLibraryHolder)
        elif target_type == 'both_libraries':
            return self.build_both_libraries(node, args, kwargs)
        elif target_type == 'library':
            return self.build_library(node, args, kwargs)
        elif target_type == 'jar':
            return self.build_target(node, args, kwargs, JarHolder)
        else:
            raise InterpreterException('Unknown target_type.')

    @permittedKwargs(permitted_kwargs['vcs_tag'])
    def func_vcs_tag(self, node, args, kwargs):
        if 'input' not in kwargs or 'output' not in kwargs:
            raise InterpreterException('Keyword arguments input and output must exist')
        if 'fallback' not in kwargs:
            FeatureNew('T.Optional fallback in vcs_tag', '0.41.0').use(self.subproject)
        fallback = kwargs.pop('fallback', self.project_version)
        if not isinstance(fallback, str):
            raise InterpreterException('Keyword argument fallback must be a string.')
        replace_string = kwargs.pop('replace_string', '@VCS_TAG@')
        regex_selector = '(.*)' # default regex selector for custom command: use complete output
        vcs_cmd = kwargs.get('command', None)
        if vcs_cmd and not isinstance(vcs_cmd, list):
            vcs_cmd = [vcs_cmd]
        source_dir = os.path.normpath(os.path.join(self.environment.get_source_dir(), self.subdir))
        if vcs_cmd:
            # Is the command an executable in path or maybe a script in the source tree?
            vcs_cmd[0] = shutil.which(vcs_cmd[0]) or os.path.join(source_dir, vcs_cmd[0])
        else:
            vcs = mesonlib.detect_vcs(source_dir)
            if vcs:
                mlog.log('Found %s repository at %s' % (vcs['name'], vcs['wc_dir']))
                vcs_cmd = vcs['get_rev'].split()
                regex_selector = vcs['rev_regex']
            else:
                vcs_cmd = [' '] # executing this cmd will fail in vcstagger.py and force to use the fallback string
        # vcstagger.py parameters: infile, outfile, fallback, source_dir, replace_string, regex_selector, command...
        kwargs['command'] = self.environment.get_build_command() + \
            ['--internal',
             'vcstagger',
             '@INPUT0@',
             '@OUTPUT0@',
             fallback,
             source_dir,
             replace_string,
             regex_selector] + vcs_cmd
        kwargs.setdefault('build_by_default', True)
        kwargs.setdefault('build_always_stale', True)
        return self._func_custom_target_impl(node, [kwargs['output']], kwargs)

    @FeatureNew('subdir_done', '0.46.0')
    @stringArgs
    def func_subdir_done(self, node, args, kwargs):
        if len(kwargs) > 0:
            raise InterpreterException('exit does not take named arguments')
        if len(args) > 0:
            raise InterpreterException('exit does not take any arguments')
        raise SubdirDoneRequest()

    @stringArgs
    @FeatureNewKwargs('custom_target', '0.48.0', ['console'])
    @FeatureNewKwargs('custom_target', '0.47.0', ['install_mode', 'build_always_stale'])
    @FeatureNewKwargs('custom_target', '0.40.0', ['build_by_default'])
    @permittedKwargs(permitted_kwargs['custom_target'])
    def func_custom_target(self, node, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('custom_target: Only one positional argument is allowed, and it must be a string name')
        if 'depfile' in kwargs and ('@BASENAME@' in kwargs['depfile'] or '@PLAINNAME@' in kwargs['depfile']):
            FeatureNew('substitutions in custom_target depfile', '0.47.0').use(self.subproject)
        return self._func_custom_target_impl(node, args, kwargs)

    def _func_custom_target_impl(self, node, args, kwargs):
        'Implementation-only, without FeatureNew checks, for internal use'
        name = args[0]
        kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs)
        if 'input' in kwargs:
            try:
                kwargs['input'] = self.source_strings_to_files(extract_as_list(kwargs, 'input'))
            except mesonlib.MesonException:
                mlog.warning('''Custom target input \'%s\' can\'t be converted to File object(s).
This will become a hard error in the future.''' % kwargs['input'], location=self.current_node)
        tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, self.subproject, kwargs, backend=self.backend), self)
        self.add_target(name, tg.held_object)
        return tg

    @permittedKwargs(permitted_kwargs['run_target'])
    def func_run_target(self, node, args, kwargs):
        if len(args) > 1:
            raise InvalidCode('Run_target takes only one positional argument: the target name.')
        elif len(args) == 1:
            if 'command' not in kwargs:
                raise InterpreterException('Missing "command" keyword argument')
            all_args = extract_as_list(kwargs, 'command')
            deps = extract_as_list(kwargs, 'depends', unholder=True)
        else:
            raise InterpreterException('Run_target needs at least one positional argument.')

        cleaned_args = []
        for i in listify(all_args, unholder=True):
            if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)):
                mlog.debug('Wrong type:', str(i))
                raise InterpreterException('Invalid argument to run_target.')
            if isinstance(i, dependencies.ExternalProgram) and not i.found():
                raise InterpreterException('Tried to use non-existing executable {!r}'.format(i.name))
            cleaned_args.append(i)
        name = args[0]
        if not isinstance(name, str):
            raise InterpreterException('First argument must be a string.')
        cleaned_deps = []
        for d in deps:
            if not isinstance(d, (build.BuildTarget, build.CustomTarget)):
                raise InterpreterException('Depends items must be build targets.')
            cleaned_deps.append(d)
        command, *cmd_args = cleaned_args
        tg = RunTargetHolder(build.RunTarget(name, command, cmd_args, cleaned_deps, self.subdir, self.subproject), self)
        self.add_target(name, tg.held_object)
        full_name = (self.subproject, name)
        assert(full_name not in self.build.run_target_names)
        self.build.run_target_names.add(full_name)
        return tg

    @FeatureNew('alias_target', '0.52.0')
    @noKwargs
    def func_alias_target(self, node, args, kwargs):
        if len(args) < 2:
            raise InvalidCode('alias_target takes at least 2 arguments.')
        name = args[0]
        if not isinstance(name, str):
            raise InterpreterException('First argument must be a string.')
        deps = listify(args[1:], unholder=True)
        for d in deps:
            if not isinstance(d, (build.BuildTarget, build.CustomTarget)):
                raise InterpreterException('Depends items must be build targets.')
        tg = RunTargetHolder(build.AliasTarget(name, deps, self.subdir, self.subproject), self)
        self.add_target(name, tg.held_object)
        return tg

    @permittedKwargs(permitted_kwargs['generator'])
    def func_generator(self, node, args, kwargs):
        gen = GeneratorHolder(self, args, kwargs)
        self.generators.append(gen)
        return gen

    @FeatureNewKwargs('benchmark', '0.46.0', ['depends'])
    @FeatureNewKwargs('benchmark', '0.52.0', ['priority'])
    @permittedKwargs(permitted_kwargs['benchmark'])
    def func_benchmark(self, node, args, kwargs):
        # is_parallel isn't valid here, so make sure it isn't passed
        if 'is_parallel' in kwargs:
            del kwargs['is_parallel']
        self.add_test(node, args, kwargs, False)

    @FeatureNewKwargs('test', '0.46.0', ['depends'])
    @FeatureNewKwargs('test', '0.52.0', ['priority'])
    @permittedKwargs(permitted_kwargs['test'])
    def func_test(self, node, args, kwargs):
        self.add_test(node, args, kwargs, True)

    def unpack_env_kwarg(self, kwargs) -> build.EnvironmentVariables:
        envlist = kwargs.get('env', EnvironmentVariablesHolder())
        if isinstance(envlist, EnvironmentVariablesHolder):
            env = envlist.held_object
        elif isinstance(envlist, dict):
            FeatureNew('environment dictionary', '0.52.0').use(self.subproject)
            env = EnvironmentVariablesHolder(envlist)
            env = env.held_object
        else:
            envlist = listify(envlist)
            # Convert from array to environment object
            env = EnvironmentVariablesHolder(envlist)
            env = env.held_object
        return env

    def add_test(self, node, args, kwargs, is_base_test):
        if len(args) != 2:
            raise InterpreterException('Incorrect number of arguments')
        if not isinstance(args[0], str):
            raise InterpreterException('First argument of test must be a string.')
        exe = args[1]
        if not isinstance(exe, (ExecutableHolder, JarHolder, ExternalProgramHolder)):
            if isinstance(exe, mesonlib.File):
                exe = self.func_find_program(node, args[1], {})
            else:
                raise InterpreterException('Second argument must be executable.')
        par = kwargs.get('is_parallel', True)
        if not isinstance(par, bool):
            raise InterpreterException('Keyword argument is_parallel must be a boolean.')
        cmd_args = extract_as_list(kwargs, 'args', unholder=True)
        for i in cmd_args:
            if not isinstance(i, (str, mesonlib.File, build.Target)):
                raise InterpreterException('Command line arguments must be strings, files or targets.')
        env = self.unpack_env_kwarg(kwargs)
        should_fail = kwargs.get('should_fail', False)
        if not isinstance(should_fail, bool):
            raise InterpreterException('Keyword argument should_fail must be a boolean.')
        timeout = kwargs.get('timeout', 30)
        if 'workdir' in kwargs:
            workdir = kwargs['workdir']
            if not isinstance(workdir, str):
                raise InterpreterException('Workdir keyword argument must be a string.')
            if not os.path.isabs(workdir):
                raise InterpreterException('Workdir keyword argument must be an absolute path.')
        else:
            workdir = None
        if not isinstance(timeout, int):
            raise InterpreterException('Timeout must be an integer.')
        protocol = kwargs.get('protocol', 'exitcode')
        if protocol not in ('exitcode', 'tap'):
            raise InterpreterException('Protocol must be "exitcode" or "tap".')
        suite = []
        prj = self.subproject if self.is_subproject() else self.build.project_name
        for s in mesonlib.stringlistify(kwargs.get('suite', '')):
            if len(s) > 0:
                s = ':' + s
            suite.append(prj.replace(' ', '_').replace(':', '_') + s)
        depends = extract_as_list(kwargs, 'depends', unholder=True)
        for dep in depends:
            if not isinstance(dep, (build.CustomTarget, build.BuildTarget)):
                raise InterpreterException('Depends items must be build targets.')
        priority = kwargs.get('priority', 0)
        if not isinstance(priority, int):
            raise InterpreterException('Keyword argument priority must be an integer.')
        t = Test(args[0], prj, suite, exe.held_object, depends, par, cmd_args,
                 env, should_fail, timeout, workdir, protocol, priority)
        if is_base_test:
            self.build.tests.append(t)
            mlog.debug('Adding test', mlog.bold(args[0], True))
        else:
            self.build.benchmarks.append(t)
            mlog.debug('Adding benchmark', mlog.bold(args[0], True))

    @FeatureNewKwargs('install_headers', '0.47.0', ['install_mode'])
    @permittedKwargs(permitted_kwargs['install_headers'])
    def func_install_headers(self, node, args, kwargs):
        source_files = self.source_strings_to_files(args)
        kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs)
        h = Headers(source_files, kwargs)
        self.build.headers.append(h)
        return h

    @FeatureNewKwargs('install_man', '0.47.0', ['install_mode'])
    @permittedKwargs(permitted_kwargs['install_man'])
    def func_install_man(self, node, args, kwargs):
        fargs = self.source_strings_to_files(args)
        kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs)
        m = Man(fargs, kwargs)
        self.build.man.append(m)
        return m

    @FeatureNewKwargs('subdir', '0.44.0', ['if_found'])
    @permittedKwargs(permitted_kwargs['subdir'])
    def func_subdir(self, node, args, kwargs):
        self.validate_arguments(args, 1, [str])
        mesonlib.check_direntry_issues(args)
        if '..' in args[0]:
            raise InvalidArguments('Subdir contains ..')
        if self.subdir == '' and args[0] == self.subproject_dir:
            raise InvalidArguments('Must not go into subprojects dir with subdir(), use subproject() instead.')
        if self.subdir == '' and args[0].startswith('meson-'):
            raise InvalidArguments('The "meson-" prefix is reserved and cannot be used for top-level subdir().')
        for i in mesonlib.extract_as_list(kwargs, 'if_found'):
            if not hasattr(i, 'found_method'):
                raise InterpreterException('Object used in if_found does not have a found method.')
            if not i.found_method([], {}):
                return
        prev_subdir = self.subdir
        subdir = os.path.join(prev_subdir, args[0])
        if os.path.isabs(subdir):
            raise InvalidArguments('Subdir argument must be a relative path.')
        absdir = os.path.join(self.environment.get_source_dir(), subdir)
        symlinkless_dir = os.path.realpath(absdir)
        if symlinkless_dir in self.visited_subdirs:
            raise InvalidArguments('Tried to enter directory "%s", which has already been visited.'
                                   % subdir)
        self.visited_subdirs[symlinkless_dir] = True
        self.subdir = subdir
        os.makedirs(os.path.join(self.environment.build_dir, subdir), exist_ok=True)
        buildfilename = os.path.join(self.subdir, environment.build_filename)
        self.build_def_files.append(buildfilename)
        absname = os.path.join(self.environment.get_source_dir(), buildfilename)
        if not os.path.isfile(absname):
            self.subdir = prev_subdir
            raise InterpreterException('Non-existent build file {!r}'.format(buildfilename))
        with open(absname, encoding='utf8') as f:
            code = f.read()
        assert(isinstance(code, str))
        try:
            codeblock = mparser.Parser(code, self.subdir).parse()
        except mesonlib.MesonException as me:
            me.file = buildfilename
            raise me
        try:
            self.evaluate_codeblock(codeblock)
        except SubdirDoneRequest:
            pass
        self.subdir = prev_subdir

    def _get_kwarg_install_mode(self, kwargs):
        if kwargs.get('install_mode', None) is None:
            return None
        install_mode = []
        mode = mesonlib.typeslistify(kwargs.get('install_mode', []), (str, int))
        for m in mode:
            # We skip any arguments that are set to `false`
            if m is False:
                m = None
            install_mode.append(m)
        if len(install_mode) > 3:
            raise InvalidArguments('Keyword argument install_mode takes at '
                                   'most 3 arguments.')
        if len(install_mode) > 0 and install_mode[0] is not None and \
           not isinstance(install_mode[0], str):
            raise InvalidArguments('Keyword argument install_mode requires the '
                                   'permissions arg to be a string or false')
        return FileMode(*install_mode)

    @FeatureNewKwargs('install_data', '0.46.0', ['rename'])
    @FeatureNewKwargs('install_data', '0.38.0', ['install_mode'])
    @permittedKwargs(permitted_kwargs['install_data'])
    def func_install_data(self, node, args, kwargs):
        kwsource = mesonlib.stringlistify(kwargs.get('sources', []))
        raw_sources = args + kwsource
        sources = []
        source_strings = []
        for s in raw_sources:
            if isinstance(s, mesonlib.File):
                sources.append(s)
            elif isinstance(s, str):
                source_strings.append(s)
            else:
                raise InvalidArguments('Argument {!r} must be string or file.'.format(s))
        sources += self.source_strings_to_files(source_strings)
        install_dir = kwargs.get('install_dir', None)
        if not isinstance(install_dir, (str, type(None))):
            raise InvalidArguments('Keyword argument install_dir not a string.')
        install_mode = self._get_kwarg_install_mode(kwargs)
        rename = kwargs.get('rename', None)
        data = DataHolder(build.Data(sources, install_dir, install_mode, rename))
        self.build.data.append(data.held_object)
        return data

    @FeatureNewKwargs('install_subdir', '0.42.0', ['exclude_files', 'exclude_directories'])
    @FeatureNewKwargs('install_subdir', '0.38.0', ['install_mode'])
    @permittedKwargs(permitted_kwargs['install_subdir'])
    @stringArgs
    def func_install_subdir(self, node, args, kwargs):
        if len(args) != 1:
            raise InvalidArguments('Install_subdir requires exactly one argument.')
        subdir = args[0]
        if 'install_dir' not in kwargs:
            raise InvalidArguments('Missing keyword argument install_dir')
        install_dir = kwargs['install_dir']
        if not isinstance(install_dir, str):
            raise InvalidArguments('Keyword argument install_dir not a string.')
        if 'strip_directory' in kwargs:
            if not isinstance(kwargs['strip_directory'], bool):
                raise InterpreterException('"strip_directory" keyword must be a boolean.')
            strip_directory = kwargs['strip_directory']
        else:
            strip_directory = False
        if 'exclude_files' in kwargs:
            exclude = extract_as_list(kwargs, 'exclude_files')
            for f in exclude:
                if not isinstance(f, str):
                    raise InvalidArguments('Exclude argument not a string.')
                elif os.path.isabs(f):
                    raise InvalidArguments('Exclude argument cannot be absolute.')
            exclude_files = set(exclude)
        else:
            exclude_files = set()
        if 'exclude_directories' in kwargs:
            exclude = extract_as_list(kwargs, 'exclude_directories')
            for d in exclude:
                if not isinstance(d, str):
                    raise InvalidArguments('Exclude argument not a string.')
                elif os.path.isabs(d):
                    raise InvalidArguments('Exclude argument cannot be absolute.')
            exclude_directories = set(exclude)
        else:
            exclude_directories = set()
        exclude = (exclude_files, exclude_directories)
        install_mode = self._get_kwarg_install_mode(kwargs)
        idir = InstallDir(self.subdir, subdir, install_dir, install_mode, exclude, strip_directory)
        self.build.install_dirs.append(idir)
        return idir

    @FeatureNewKwargs('configure_file', '0.47.0', ['copy', 'output_format', 'install_mode', 'encoding'])
    @FeatureNewKwargs('configure_file', '0.46.0', ['format'])
    @FeatureNewKwargs('configure_file', '0.41.0', ['capture'])
    @FeatureNewKwargs('configure_file', '0.50.0', ['install'])
    @FeatureNewKwargs('configure_file', '0.52.0', ['depfile'])
    @permittedKwargs(permitted_kwargs['configure_file'])
    def func_configure_file(self, node, args, kwargs):
        if len(args) > 0:
            raise InterpreterException("configure_file takes only keyword arguments.")
        if 'output' not in kwargs:
            raise InterpreterException('Required keyword argument "output" not defined.')
        actions = set(['configuration', 'command', 'copy']).intersection(kwargs.keys())
        if len(actions) == 0:
            raise InterpreterException('Must specify an action with one of these '
                                       'keyword arguments: \'configuration\', '
                                       '\'command\', or \'copy\'.')
        elif len(actions) == 2:
            raise InterpreterException('Must not specify both {!r} and {!r} '
                                       'keyword arguments since they are '
                                       'mutually exclusive.'.format(*actions))
        elif len(actions) == 3:
            raise InterpreterException('Must specify one of {!r}, {!r}, and '
                                       '{!r} keyword arguments since they are '
                                       'mutually exclusive.'.format(*actions))
        if 'capture' in kwargs:
            if not isinstance(kwargs['capture'], bool):
                raise InterpreterException('"capture" keyword must be a boolean.')
            if 'command' not in kwargs:
                raise InterpreterException('"capture" keyword requires "command" keyword.')

        if 'format' in kwargs:
            fmt = kwargs['format']
            if not isinstance(fmt, str):
                raise InterpreterException('"format" keyword must be a string.')
        else:
            fmt = 'meson'

        if fmt not in ('meson', 'cmake', 'cmake@'):
            raise InterpreterException('"format" possible values are "meson", "cmake" or "cmake@".')

        if 'output_format' in kwargs:
            output_format = kwargs['output_format']
            if not isinstance(output_format, str):
                raise InterpreterException('"output_format" keyword must be a string.')
        else:
            output_format = 'c'

        if output_format not in ('c', 'nasm'):
            raise InterpreterException('"format" possible values are "c" or "nasm".')

        if 'depfile' in kwargs:
            depfile = kwargs['depfile']
            if not isinstance(depfile, str):
                raise InterpreterException('depfile file name must be a string')
        else:
            depfile = None

        # Validate input
        inputs = self.source_strings_to_files(extract_as_list(kwargs, 'input'))
        inputs_abs = []
        for f in inputs:
            if isinstance(f, mesonlib.File):
                inputs_abs.append(f.absolute_path(self.environment.source_dir,
                                                  self.environment.build_dir))
                self.add_build_def_file(f)
            else:
                raise InterpreterException('Inputs can only be strings or file objects')
        # Validate output
        output = kwargs['output']
        if not isinstance(output, str):
            raise InterpreterException('Output file name must be a string')
        if inputs_abs:
            values = mesonlib.get_filenames_templates_dict(inputs_abs, None)
            outputs = mesonlib.substitute_values([output], values)
            output = outputs[0]
            if depfile:
                depfile = mesonlib.substitute_values([depfile], values)[0]
        ofile_rpath = os.path.join(self.subdir, output)
        if ofile_rpath in self.configure_file_outputs:
            mesonbuildfile = os.path.join(self.subdir, 'meson.build')
            current_call = "{}:{}".format(mesonbuildfile, self.current_lineno)
            first_call = "{}:{}".format(mesonbuildfile, self.configure_file_outputs[ofile_rpath])
            mlog.warning('Output file', mlog.bold(ofile_rpath, True), 'for configure_file() at', current_call, 'overwrites configure_file() output at', first_call)
        else:
            self.configure_file_outputs[ofile_rpath] = self.current_lineno
        if os.path.dirname(output) != '':
            raise InterpreterException('Output file name must not contain a subdirectory.')
        (ofile_path, ofile_fname) = os.path.split(os.path.join(self.subdir, output))
        ofile_abs = os.path.join(self.environment.build_dir, ofile_path, ofile_fname)
        # Perform the appropriate action
        if 'configuration' in kwargs:
            conf = kwargs['configuration']
            if isinstance(conf, dict):
                FeatureNew('configure_file.configuration dictionary', '0.49.0').use(self.subproject)
                conf = ConfigurationDataHolder(self.subproject, conf)
            elif not isinstance(conf, ConfigurationDataHolder):
                raise InterpreterException('Argument "configuration" is not of type configuration_data')
            mlog.log('Configuring', mlog.bold(output), 'using configuration')
            if len(inputs) > 1:
                raise InterpreterException('At most one input file can given in configuration mode')
            if inputs:
                os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True)
                file_encoding = kwargs.setdefault('encoding', 'utf-8')
                missing_variables, confdata_useless = \
                    mesonlib.do_conf_file(inputs_abs[0], ofile_abs, conf.held_object,
                                          fmt, file_encoding)
                if missing_variables:
                    var_list = ", ".join(map(repr, sorted(missing_variables)))
                    mlog.warning(
                        "The variable(s) %s in the input file '%s' are not "
                        "present in the given configuration data." % (
                            var_list, inputs[0]), location=node)
                if confdata_useless:
                    ifbase = os.path.basename(inputs_abs[0])
                    mlog.warning('Got an empty configuration_data() object and found no '
                                 'substitutions in the input file {!r}. If you want to '
                                 'copy a file to the build dir, use the \'copy:\' keyword '
                                 'argument added in 0.47.0'.format(ifbase), location=node)
            else:
                mesonlib.dump_conf_header(ofile_abs, conf.held_object, output_format)
            conf.mark_used()
        elif 'command' in kwargs:
            if len(inputs) > 1:
                FeatureNew('multiple inputs in configure_file()', '0.52.0').use(self.subproject)
            # We use absolute paths for input and output here because the cwd
            # that the command is run from is 'unspecified', so it could change.
            # Currently it's builddir/subdir for in_builddir else srcdir/subdir.
            values = mesonlib.get_filenames_templates_dict(inputs_abs, [ofile_abs])
            if depfile:
                depfile = os.path.join(self.environment.get_scratch_dir(), depfile)
                values['@DEPFILE@'] = depfile
            # Substitute @INPUT@, @OUTPUT@, etc here.
            cmd = mesonlib.substitute_values(kwargs['command'], values)
            mlog.log('Configuring', mlog.bold(output), 'with command')
            res = self.run_command_impl(node, cmd,  {}, True)
            if res.returncode != 0:
                raise InterpreterException('Running configure command failed.\n%s\n%s' %
                                           (res.stdout, res.stderr))
            if 'capture' in kwargs and kwargs['capture']:
                dst_tmp = ofile_abs + '~'
                file_encoding = kwargs.setdefault('encoding', 'utf-8')
                with open(dst_tmp, 'w', encoding=file_encoding) as f:
                    f.writelines(res.stdout)
                if inputs_abs:
                    shutil.copymode(inputs_abs[0], dst_tmp)
                mesonlib.replace_if_different(ofile_abs, dst_tmp)
            if depfile:
                mlog.log('Reading depfile:', mlog.bold(depfile))
                with open(depfile, 'r') as f:
                    df = DepFile(f.readlines())
                    deps = df.get_all_dependencies(ofile_fname)
                    for dep in deps:
                        self.add_build_def_file(dep)

        elif 'copy' in kwargs:
            if len(inputs_abs) != 1:
                raise InterpreterException('Exactly one input file must be given in copy mode')
            os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True)
            shutil.copyfile(inputs_abs[0], ofile_abs)
            shutil.copystat(inputs_abs[0], ofile_abs)
        else:
            # Not reachable
            raise AssertionError
        # Install file if requested, we check for the empty string
        # for backwards compatibility. That was the behaviour before
        # 0.45.0 so preserve it.
        idir = kwargs.get('install_dir', '')
        if idir is False:
            idir = ''
            mlog.deprecation('Please use the new `install:` kwarg instead of passing '
                             '`false` to `install_dir:`', location=node)
        if not isinstance(idir, str):
            if isinstance(idir, list) and len(idir) == 0:
                mlog.deprecation('install_dir: kwarg must be a string and not an empty array. '
                                 'Please use the install: kwarg to enable or disable installation. '
                                 'This will be a hard error in the next release.')
            else:
                raise InterpreterException('"install_dir" must be a string')
        install = kwargs.get('install', idir != '')
        if not isinstance(install, bool):
            raise InterpreterException('"install" must be a boolean')
        if install:
            if not idir:
                raise InterpreterException('"install_dir" must be specified '
                                           'when "install" in a configure_file '
                                           'is true')
            cfile = mesonlib.File.from_built_file(ofile_path, ofile_fname)
            install_mode = self._get_kwarg_install_mode(kwargs)
            self.build.data.append(build.Data([cfile], idir, install_mode))
        return mesonlib.File.from_built_file(self.subdir, output)

    def extract_incdirs(self, kwargs):
        prospectives = listify(kwargs.get('include_directories', []), unholder=True)
        result = []
        for p in prospectives:
            if isinstance(p, build.IncludeDirs):
                result.append(p)
            elif isinstance(p, str):
                result.append(self.build_incdir_object([p]).held_object)
            else:
                raise InterpreterException('Include directory objects can only be created from strings or include directories.')
        return result

    @permittedKwargs(permitted_kwargs['include_directories'])
    @stringArgs
    def func_include_directories(self, node, args, kwargs):
        return self.build_incdir_object(args, kwargs.get('is_system', False))

    def build_incdir_object(self, incdir_strings, is_system=False):
        if not isinstance(is_system, bool):
            raise InvalidArguments('Is_system must be boolean.')
        src_root = self.environment.get_source_dir()
        build_root = self.environment.get_build_dir()
        absbase_src = os.path.join(src_root, self.subdir)
        absbase_build = os.path.join(build_root, self.subdir)

        for a in incdir_strings:
            if a.startswith(src_root):
                raise InvalidArguments('''Tried to form an absolute path to a source dir. You should not do that but use
relative paths instead.

To get include path to any directory relative to the current dir do

incdir = include_directories(dirname)

After this incdir will contain both the current source dir as well as the
corresponding build dir. It can then be used in any subdirectory and
Meson will take care of all the busywork to make paths work.

Dirname can even be '.' to mark the current directory. Though you should
remember that the current source and build directories are always
put in the include directories by default so you only need to do
include_directories('.') if you intend to use the result in a
different subdirectory.
''')
            absdir_src = os.path.join(absbase_src, a)
            absdir_build = os.path.join(absbase_build, a)
            if not os.path.isdir(absdir_src) and not os.path.isdir(absdir_build):
                raise InvalidArguments('Include dir %s does not exist.' % a)
        i = IncludeDirsHolder(build.IncludeDirs(self.subdir, incdir_strings, is_system))
        return i

    @permittedKwargs(permitted_kwargs['add_test_setup'])
    @stringArgs
    def func_add_test_setup(self, node, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Add_test_setup needs one argument for the setup name.')
        setup_name = args[0]
        if re.fullmatch('([_a-zA-Z][_0-9a-zA-Z]*:)?[_a-zA-Z][_0-9a-zA-Z]*', setup_name) is None:
            raise InterpreterException('Setup name may only contain alphanumeric characters.')
        if ":" not in setup_name:
            setup_name = (self.subproject if self.subproject else self.build.project_name) + ":" + setup_name
        try:
            inp = extract_as_list(kwargs, 'exe_wrapper', unholder=True)
            exe_wrapper = []
            for i in inp:
                if isinstance(i, str):
                    exe_wrapper.append(i)
                elif isinstance(i, dependencies.ExternalProgram):
                    if not i.found():
                        raise InterpreterException('Tried to use non-found executable.')
                    exe_wrapper += i.get_command()
                else:
                    raise InterpreterException('Exe wrapper can only contain strings or external binaries.')
        except KeyError:
            exe_wrapper = None
        gdb = kwargs.get('gdb', False)
        if not isinstance(gdb, bool):
            raise InterpreterException('Gdb option must be a boolean')
        timeout_multiplier = kwargs.get('timeout_multiplier', 1)
        if not isinstance(timeout_multiplier, int):
            raise InterpreterException('Timeout multiplier must be a number.')
        is_default = kwargs.get('is_default', False)
        if not isinstance(is_default, bool):
            raise InterpreterException('is_default option must be a boolean')
        if is_default:
            if self.build.test_setup_default_name is not None:
                raise InterpreterException('\'%s\' is already set as default. '
                                           'is_default can be set to true only once' % self.build.test_setup_default_name)
            self.build.test_setup_default_name = setup_name
        env = self.unpack_env_kwarg(kwargs)
        self.build.test_setups[setup_name] = build.TestSetup(exe_wrapper, gdb, timeout_multiplier, env)

    @permittedKwargs(permitted_kwargs['add_global_arguments'])
    @stringArgs
    def func_add_global_arguments(self, node, args, kwargs):
        for_machine = self.machine_from_native_kwarg(kwargs)
        self.add_global_arguments(node, self.build.global_args[for_machine], args, kwargs)

    @permittedKwargs(permitted_kwargs['add_global_link_arguments'])
    @stringArgs
    def func_add_global_link_arguments(self, node, args, kwargs):
        for_machine = self.machine_from_native_kwarg(kwargs)
        self.add_global_arguments(node, self.build.global_link_args[for_machine], args, kwargs)

    @permittedKwargs(permitted_kwargs['add_project_arguments'])
    @stringArgs
    def func_add_project_arguments(self, node, args, kwargs):
        for_machine = self.machine_from_native_kwarg(kwargs)
        self.add_project_arguments(node, self.build.projects_args[for_machine], args, kwargs)

    @permittedKwargs(permitted_kwargs['add_project_link_arguments'])
    @stringArgs
    def func_add_project_link_arguments(self, node, args, kwargs):
        for_machine = self.machine_from_native_kwarg(kwargs)
        self.add_project_arguments(node, self.build.projects_link_args[for_machine], args, kwargs)

    def warn_about_builtin_args(self, args):
        warnargs = ('/W1', '/W2', '/W3', '/W4', '/Wall', '-Wall', '-Wextra', '-Wpedantic')
        optargs = ('-O0', '-O2', '-O3', '-Os', '/O1', '/O2', '/Os')
        for arg in args:
            if arg in warnargs:
                mlog.warning('Consider using the built-in warning_level option instead of using "{}".'.format(arg),
                             location=self.current_node)
            elif arg in optargs:
                mlog.warning('Consider using the built-in optimization level instead of using "{}".'.format(arg),
                             location=self.current_node)
            elif arg == '-g':
                mlog.warning('Consider using the built-in debug option instead of using "{}".'.format(arg),
                             location=self.current_node)
            elif arg == '-pipe':
                mlog.warning("You don't need to add -pipe, Meson will use it automatically when it is available.",
                             location=self.current_node)
            elif arg.startswith('-fsanitize'):
                mlog.warning('Consider using the built-in option for sanitizers instead of using "{}".'.format(arg),
                             location=self.current_node)
            elif arg.startswith('-std=') or arg.startswith('/std:'):
                mlog.warning('Consider using the built-in option for language standard version instead of using "{}".'.format(arg),
                             location=self.current_node)

    def add_global_arguments(self, node, argsdict, args, kwargs):
        if self.is_subproject():
            msg = 'Function \'{}\' cannot be used in subprojects because ' \
                  'there is no way to make that reliable.\nPlease only call ' \
                  'this if is_subproject() returns false. Alternatively, ' \
                  'define a variable that\ncontains your language-specific ' \
                  'arguments and add it to the appropriate *_args kwarg ' \
                  'in each target.'.format(node.func_name)
            raise InvalidCode(msg)
        frozen = self.project_args_frozen or self.global_args_frozen
        self.add_arguments(node, argsdict, frozen, args, kwargs)

    def add_project_arguments(self, node, argsdict, args, kwargs):
        if self.subproject not in argsdict:
            argsdict[self.subproject] = {}
        self.add_arguments(node, argsdict[self.subproject],
                           self.project_args_frozen, args, kwargs)

    def add_arguments(self, node, argsdict, args_frozen, args, kwargs):
        if args_frozen:
            msg = 'Tried to use \'{}\' after a build target has been declared.\n' \
                  'This is not permitted. Please declare all ' \
                  'arguments before your targets.'.format(node.func_name)
            raise InvalidCode(msg)

        if 'language' not in kwargs:
            raise InvalidCode('Missing language definition in {}'.format(node.func_name))

        self.warn_about_builtin_args(args)

        for lang in mesonlib.stringlistify(kwargs['language']):
            lang = lang.lower()
            argsdict[lang] = argsdict.get(lang, []) + args

    @noKwargs
    @noArgsFlattening
    def func_environment(self, node, args, kwargs):
        if len(args) > 1:
            raise InterpreterException('environment takes only one optional positional arguments')
        elif len(args) == 1:
            FeatureNew('environment positional arguments', '0.52.0').use(self.subproject)
            initial_values = args[0]
            if not isinstance(initial_values, dict) and not isinstance(initial_values, list):
                raise InterpreterException('environment first argument must be a dictionary or a list')
        else:
            initial_values = {}
        return EnvironmentVariablesHolder(initial_values)

    @stringArgs
    @noKwargs
    def func_join_paths(self, node, args, kwargs):
        return self.join_path_strings(args)

    def run(self):
        super().run()
        mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets))))
        FeatureNew.report(self.subproject)
        FeatureDeprecated.report(self.subproject)
        if not self.is_subproject():
            self.print_extra_warnings()
        if self.subproject == '':
            self._print_summary()

    def print_extra_warnings(self):
        # TODO cross compilation
        for c in self.coredata.compilers.host.values():
            if c.get_id() == 'clang':
                self.check_clang_asan_lundef()
                break

    def check_clang_asan_lundef(self):
        if 'b_lundef' not in self.coredata.base_options:
            return
        if 'b_sanitize' not in self.coredata.base_options:
            return
        if (self.coredata.base_options['b_lundef'].value and
                self.coredata.base_options['b_sanitize'].value != 'none'):
            mlog.warning('''Trying to use {} sanitizer on Clang with b_lundef.
This will probably not work.
Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_sanitize'].value),
                         location=self.current_node)

    def evaluate_subproject_info(self, path_from_source_root, subproject_dirname):
        depth = 0
        subproj_name = ''
        segs = PurePath(path_from_source_root).parts
        segs_spd = PurePath(subproject_dirname).parts
        while segs and segs[0] == segs_spd[0]:
            if len(segs_spd) == 1:
                subproj_name = segs[1]
                segs = segs[2:]
                depth += 1
            else:
                segs_spd = segs_spd[1:]
                segs = segs[1:]
        return (depth, subproj_name)

    # Check that the indicated file is within the same subproject
    # as we currently are. This is to stop people doing
    # nasty things like:
    #
    # f = files('../../master_src/file.c')
    #
    # Note that this is validated only when the file
    # object is generated. The result can be used in a different
    # subproject than it is defined in (due to e.g. a
    # declare_dependency).
    def validate_within_subproject(self, subdir, fname):
        norm = os.path.normpath(os.path.join(subdir, fname))
        if os.path.isabs(norm):
            if not norm.startswith(self.environment.source_dir):
                # Grabbing files outside the source tree is ok.
                # This is for vendor stuff like:
                #
                # /opt/vendorsdk/src/file_with_license_restrictions.c
                return
            norm = os.path.relpath(norm, self.environment.source_dir)
            assert(not os.path.isabs(norm))
        (num_sps, sproj_name) = self.evaluate_subproject_info(norm, self.subproject_dir)
        plain_filename = os.path.basename(norm)
        if num_sps == 0:
            if not self.is_subproject():
                return
            raise InterpreterException('Sandbox violation: Tried to grab file %s from a different subproject.' % plain_filename)
        if num_sps > 1:
            raise InterpreterException('Sandbox violation: Tried to grab file %s from a nested subproject.' % plain_filename)
        if sproj_name != self.subproject_directory_name:
            raise InterpreterException('Sandbox violation: Tried to grab file %s from a different subproject.' % plain_filename)

    def source_strings_to_files(self, sources):
        results = []
        mesonlib.check_direntry_issues(sources)
        if not isinstance(sources, list):
            sources = [sources]
        for s in sources:
            if isinstance(s, (mesonlib.File, GeneratedListHolder,
                              TargetHolder, CustomTargetIndexHolder,
                              GeneratedObjectsHolder)):
                pass
            elif isinstance(s, str):
                self.validate_within_subproject(self.subdir, s)
                s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s)
            else:
                raise InterpreterException('Source item is {!r} instead of '
                                           'string or File-type object'.format(s))
            results.append(s)
        return results

    def add_target(self, name, tobj):
        if name == '':
            raise InterpreterException('Target name must not be empty.')
        if name.strip() == '':
            raise InterpreterException('Target name must not consist only of whitespace.')
        if name.startswith('meson-'):
            raise InvalidArguments("Target names starting with 'meson-' are reserved "
                                   "for Meson's internal use. Please rename.")
        if name in coredata.forbidden_target_names:
            raise InvalidArguments("Target name '%s' is reserved for Meson's "
                                   "internal use. Please rename." % name)
        # To permit an executable and a shared library to have the
        # same name, such as "foo.exe" and "libfoo.a".
        idname = tobj.get_id()
        if idname in self.build.targets:
            raise InvalidCode('Tried to create target "%s", but a target of that name already exists.' % name)
        self.build.targets[idname] = tobj
        if idname not in self.coredata.target_guids:
            self.coredata.target_guids[idname] = str(uuid.uuid4()).upper()

    @FeatureNew('both_libraries', '0.46.0')
    def build_both_libraries(self, node, args, kwargs):
        shared_holder = self.build_target(node, args, kwargs, SharedLibraryHolder)

        # Check if user forces non-PIC static library.
        pic = True
        if 'pic' in kwargs:
            pic = kwargs['pic']
        elif 'b_staticpic' in self.environment.coredata.base_options:
            pic = self.environment.coredata.base_options['b_staticpic'].value

        if pic:
            # Exclude sources from args and kwargs to avoid building them twice
            static_args = [args[0]]
            static_kwargs = kwargs.copy()
            static_kwargs['sources'] = []
            static_kwargs['objects'] = shared_holder.held_object.extract_all_objects()
        else:
            static_args = args
            static_kwargs = kwargs

        static_holder = self.build_target(node, static_args, static_kwargs, StaticLibraryHolder)

        return BothLibrariesHolder(shared_holder, static_holder, self)

    def build_library(self, node, args, kwargs):
        default_library = self.coredata.get_builtin_option('default_library')
        if default_library == 'shared':
            return self.build_target(node, args, kwargs, SharedLibraryHolder)
        elif default_library == 'static':
            return self.build_target(node, args, kwargs, StaticLibraryHolder)
        elif default_library == 'both':
            return self.build_both_libraries(node, args, kwargs)
        else:
            raise InterpreterException('Unknown default_library value: %s.', default_library)

    def build_target(self, node, args, kwargs, targetholder):
        @FeatureNewKwargs('build target', '0.42.0', ['rust_crate_type', 'build_rpath', 'implicit_include_directories'])
        @FeatureNewKwargs('build target', '0.41.0', ['rust_args'])
        @FeatureNewKwargs('build target', '0.40.0', ['build_by_default'])
        @FeatureNewKwargs('build target', '0.48.0', ['gnu_symbol_visibility'])
        def build_target_decorator_caller(self, node, args, kwargs):
            return True

        build_target_decorator_caller(self, node, args, kwargs)

        if not args:
            raise InterpreterException('Target does not have a name.')
        name, *sources = args
        for_machine = self.machine_from_native_kwarg(kwargs)
        if 'sources' in kwargs:
            sources += listify(kwargs['sources'])
        sources = self.source_strings_to_files(sources)
        objs = extract_as_list(kwargs, 'objects')
        kwargs['dependencies'] = extract_as_list(kwargs, 'dependencies')
        kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs)
        if 'extra_files' in kwargs:
            ef = extract_as_list(kwargs, 'extra_files')
            kwargs['extra_files'] = self.source_strings_to_files(ef)
        self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources)
        if targetholder is ExecutableHolder:
            targetclass = build.Executable
        elif targetholder is SharedLibraryHolder:
            targetclass = build.SharedLibrary
        elif targetholder is SharedModuleHolder:
            targetclass = build.SharedModule
        elif targetholder is StaticLibraryHolder:
            targetclass = build.StaticLibrary
        elif targetholder is JarHolder:
            targetclass = build.Jar
        else:
            mlog.debug('Unknown target type:', str(targetholder))
            raise RuntimeError('Unreachable code')
        self.kwarg_strings_to_includedirs(kwargs)

        # Filter out kwargs from other target types. For example 'soversion'
        # passed to library() when default_library == 'static'.
        kwargs = {k: v for k, v in kwargs.items() if k in targetclass.known_kwargs}

        kwargs['include_directories'] = self.extract_incdirs(kwargs)
        target = targetclass(name, self.subdir, self.subproject, for_machine, sources, objs, self.environment, kwargs)

        if not self.environment.machines.matches_build_machine(for_machine):
            self.add_cross_stdlib_info(target)
        l = targetholder(target, self)
        self.add_target(name, l.held_object)
        self.project_args_frozen = True
        return l

    def kwarg_strings_to_includedirs(self, kwargs):
        if 'd_import_dirs' in kwargs:
            items = mesonlib.extract_as_list(kwargs, 'd_import_dirs')
            cleaned_items = []
            for i in items:
                if isinstance(i, str):
                    # BW compatibility. This was permitted so we must support it
                    # for a few releases so people can transition to "correct"
                    # path declarations.
                    if os.path.normpath(i).startswith(self.environment.get_source_dir()):
                        mlog.warning('''Building a path to the source dir is not supported. Use a relative path instead.
This will become a hard error in the future.''', location=self.current_node)
                        i = os.path.relpath(i, os.path.join(self.environment.get_source_dir(), self.subdir))
                        i = self.build_incdir_object([i])
                cleaned_items.append(i)
            kwargs['d_import_dirs'] = cleaned_items

    def get_used_languages(self, target):
        result = {}
        for i in target.sources:
            # TODO other platforms
            for lang, c in self.coredata.compilers.host.items():
                if c.can_compile(i):
                    result[lang] = True
                    break
        return result

    def add_cross_stdlib_info(self, target):
        if target.for_machine != MachineChoice.HOST:
            return
        for l in self.get_used_languages(target):
            props = self.environment.properties.host
            if props.has_stdlib(l) \
                    and self.subproject != props.get_stdlib(l)[0]:
                target.add_deps(self.build.stdlibs.host[l])

    def check_sources_exist(self, subdir, sources):
        for s in sources:
            if not isinstance(s, str):
                continue # This means a generated source and they always exist.
            fname = os.path.join(subdir, s)
            if not os.path.isfile(fname):
                raise InterpreterException('Tried to add non-existing source file %s.' % s)

    # Only permit object extraction from the same subproject
    def validate_extraction(self, buildtarget):
        if not self.subdir.startswith(self.subproject_dir):
            if buildtarget.subdir.startswith(self.subproject_dir):
                raise InterpreterException('Tried to extract objects from a subproject target.')
        else:
            if not buildtarget.subdir.startswith(self.subproject_dir):
                raise InterpreterException('Tried to extract objects from the main project from a subproject.')
            if self.subdir.split('/')[1] != buildtarget.subdir.split('/')[1]:
                raise InterpreterException('Tried to extract objects from a different subproject.')

    def check_contains(self, obj, args):
        if len(args) != 1:
            raise InterpreterException('Contains method takes exactly one argument.')
        item = args[0]
        for element in obj:
            if isinstance(element, list):
                found = self.check_contains(element, args)
                if found:
                    return True
            if element == item:
                return True
        return False

    def is_subproject(self):
        return self.subproject != ''

    @noKwargs
    @noArgsFlattening
    def func_set_variable(self, node, args, kwargs):
        if len(args) != 2:
            raise InvalidCode('Set_variable takes two arguments.')
        varname, value = args
        self.set_variable(varname, value)

    @noKwargs
    @noArgsFlattening
    def func_get_variable(self, node, args, kwargs):
        if len(args) < 1 or len(args) > 2:
            raise InvalidCode('Get_variable takes one or two arguments.')
        varname = args[0]
        if not isinstance(varname, str):
            raise InterpreterException('First argument must be a string.')
        try:
            return self.variables[varname]
        except KeyError:
            pass
        if len(args) == 2:
            return args[1]
        raise InterpreterException('Tried to get unknown variable "%s".' % varname)

    @stringArgs
    @noKwargs
    def func_is_variable(self, node, args, kwargs):
        if len(args) != 1:
            raise InvalidCode('Is_variable takes two arguments.')
        varname = args[0]
        return varname in self.variables

    @staticmethod
    def machine_from_native_kwarg(kwargs: T.Dict[str, T.Any]) -> MachineChoice:
        native = kwargs.get('native', False)
        if not isinstance(native, bool):
            raise InvalidArguments('Argument to "native" must be a boolean.')
        return MachineChoice.BUILD if native else MachineChoice.HOST

    @FeatureNew('is_disabler', '0.52.0')
    @noKwargs
    def func_is_disabler(self, node, args, kwargs):
        if len(args) != 1:
            raise InvalidCode('Is_disabler takes one argument.')
        varname = args[0]
        return isinstance(varname, Disabler)
meson-0.53.2/mesonbuild/interpreterbase.py0000644000175000017500000012612213602226377022241 0ustar  jpakkanejpakkane00000000000000# Copyright 2016-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This class contains the basic functionality needed to run any interpreter
# or an interpreter-based tool.

from . import mparser, mesonlib, mlog
from . import environment, dependencies

import os, copy, re
from functools import wraps

class ObjectHolder:
    def __init__(self, obj, subproject=None):
        self.held_object = obj
        self.subproject = subproject

    def __repr__(self):
        return ''.format(self.held_object)

# Decorators for method calls.

def check_stringlist(a, msg='Arguments must be strings.'):
    if not isinstance(a, list):
        mlog.debug('Not a list:', str(a))
        raise InvalidArguments('Argument not a list.')
    if not all(isinstance(s, str) for s in a):
        mlog.debug('Element not a string:', str(a))
        raise InvalidArguments(msg)

def _get_callee_args(wrapped_args, want_subproject=False):
    s = wrapped_args[0]
    n = len(wrapped_args)
    # Raise an error if the codepaths are not there
    subproject = None
    if want_subproject and n == 2:
        if hasattr(s, 'subproject'):
            # Interpreter base types have 2 args: self, node
            node = wrapped_args[1]
            # args and kwargs are inside the node
            args = None
            kwargs = None
            subproject = s.subproject
        elif hasattr(wrapped_args[1], 'subproject'):
            # Module objects have 2 args: self, interpreter
            node = wrapped_args[1].current_node
            # args and kwargs are inside the node
            args = None
            kwargs = None
            subproject = wrapped_args[1].subproject
        else:
            raise AssertionError('Unknown args: {!r}'.format(wrapped_args))
    elif n == 3:
        # Methods on objects (*Holder, MesonMain, etc) have 3 args: self, args, kwargs
        node = s.current_node
        args = wrapped_args[1]
        kwargs = wrapped_args[2]
        if want_subproject:
            if hasattr(s, 'subproject'):
                subproject = s.subproject
            elif hasattr(s, 'interpreter'):
                subproject = s.interpreter.subproject
    elif n == 4:
        # Meson functions have 4 args: self, node, args, kwargs
        # Module functions have 4 args: self, state, args, kwargs
        if isinstance(s, InterpreterBase):
            node = wrapped_args[1]
        else:
            node = wrapped_args[1].current_node
        args = wrapped_args[2]
        kwargs = wrapped_args[3]
        if want_subproject:
            if isinstance(s, InterpreterBase):
                subproject = s.subproject
            else:
                subproject = wrapped_args[1].subproject
    elif n == 5:
        # Module snippets have 5 args: self, interpreter, state, args, kwargs
        node = wrapped_args[2].current_node
        args = wrapped_args[3]
        kwargs = wrapped_args[4]
        if want_subproject:
            subproject = wrapped_args[2].subproject
    else:
        raise AssertionError('Unknown args: {!r}'.format(wrapped_args))
    # Sometimes interpreter methods are called internally with None instead of
    # empty list/dict
    args = args if args is not None else []
    kwargs = kwargs if kwargs is not None else {}
    return s, node, args, kwargs, subproject

def flatten(args):
    if isinstance(args, mparser.StringNode):
        return args.value
    if isinstance(args, (int, str, mesonlib.File, InterpreterObject)):
        return args
    result = []
    for a in args:
        if isinstance(a, list):
            rest = flatten(a)
            result = result + rest
        elif isinstance(a, mparser.StringNode):
            result.append(a.value)
        else:
            result.append(a)
    return result

def noPosargs(f):
    @wraps(f)
    def wrapped(*wrapped_args, **wrapped_kwargs):
        args = _get_callee_args(wrapped_args)[2]
        if args:
            raise InvalidArguments('Function does not take positional arguments.')
        return f(*wrapped_args, **wrapped_kwargs)
    return wrapped

def noKwargs(f):
    @wraps(f)
    def wrapped(*wrapped_args, **wrapped_kwargs):
        kwargs = _get_callee_args(wrapped_args)[3]
        if kwargs:
            raise InvalidArguments('Function does not take keyword arguments.')
        return f(*wrapped_args, **wrapped_kwargs)
    return wrapped

def stringArgs(f):
    @wraps(f)
    def wrapped(*wrapped_args, **wrapped_kwargs):
        args = _get_callee_args(wrapped_args)[2]
        assert(isinstance(args, list))
        check_stringlist(args)
        return f(*wrapped_args, **wrapped_kwargs)
    return wrapped

def noArgsFlattening(f):
    setattr(f, 'no-args-flattening', True)  # noqa: B010
    return f

def disablerIfNotFound(f):
    @wraps(f)
    def wrapped(*wrapped_args, **wrapped_kwargs):
        kwargs = _get_callee_args(wrapped_args)[3]
        disabler = kwargs.pop('disabler', False)
        ret = f(*wrapped_args, **wrapped_kwargs)
        if disabler and not ret.held_object.found():
            return Disabler()
        return ret
    return wrapped

class permittedKwargs:

    def __init__(self, permitted):
        self.permitted = permitted

    def __call__(self, f):
        @wraps(f)
        def wrapped(*wrapped_args, **wrapped_kwargs):
            s, node, args, kwargs, _ = _get_callee_args(wrapped_args)
            for k in kwargs:
                if k not in self.permitted:
                    mlog.warning('''Passed invalid keyword argument "{}".'''.format(k), location=node)
                    mlog.warning('This will become a hard error in the future.')
            return f(*wrapped_args, **wrapped_kwargs)
        return wrapped


class FeatureCheckBase:
    "Base class for feature version checks"

    def __init__(self, feature_name, version):
        self.feature_name = feature_name
        self.feature_version = version

    @staticmethod
    def get_target_version(subproject):
        # Don't do any checks if project() has not been parsed yet
        if subproject not in mesonlib.project_meson_versions:
            return ''
        return mesonlib.project_meson_versions[subproject]

    def use(self, subproject):
        tv = self.get_target_version(subproject)
        # No target version
        if tv == '':
            return
        # Target version is new enough
        if mesonlib.version_compare_condition_with_min(tv, self.feature_version):
            return
        # Feature is too new for target version, register it
        if subproject not in self.feature_registry:
            self.feature_registry[subproject] = {self.feature_version: set()}
        register = self.feature_registry[subproject]
        if self.feature_version not in register:
            register[self.feature_version] = set()
        if self.feature_name in register[self.feature_version]:
            # Don't warn about the same feature multiple times
            # FIXME: This is needed to prevent duplicate warnings, but also
            # means we won't warn about a feature used in multiple places.
            return
        register[self.feature_version].add(self.feature_name)
        self.log_usage_warning(tv)

    @classmethod
    def report(cls, subproject):
        if subproject not in cls.feature_registry:
            return
        warning_str = cls.get_warning_str_prefix(cls.get_target_version(subproject))
        fv = cls.feature_registry[subproject]
        for version in sorted(fv.keys()):
            warning_str += '\n * {}: {}'.format(version, fv[version])
        mlog.warning(warning_str)

    def __call__(self, f):
        @wraps(f)
        def wrapped(*wrapped_args, **wrapped_kwargs):
            subproject = _get_callee_args(wrapped_args, want_subproject=True)[4]
            if subproject is None:
                raise AssertionError('{!r}'.format(wrapped_args))
            self.use(subproject)
            return f(*wrapped_args, **wrapped_kwargs)
        return wrapped

class FeatureNew(FeatureCheckBase):
    """Checks for new features"""
    # Class variable, shared across all instances
    #
    # Format: {subproject: {feature_version: set(feature_names)}}
    feature_registry = {}

    @staticmethod
    def get_warning_str_prefix(tv):
        return 'Project specifies a minimum meson_version \'{}\' but uses features which were added in newer versions:'.format(tv)

    def log_usage_warning(self, tv):
        mlog.warning('Project targeting \'{}\' but tried to use feature introduced '
                     'in \'{}\': {}'.format(tv, self.feature_version, self.feature_name))

class FeatureDeprecated(FeatureCheckBase):
    """Checks for deprecated features"""
    # Class variable, shared across all instances
    #
    # Format: {subproject: {feature_version: set(feature_names)}}
    feature_registry = {}

    @staticmethod
    def get_warning_str_prefix(tv):
        return 'Deprecated features used:'

    def log_usage_warning(self, tv):
        mlog.deprecation('Project targeting \'{}\' but tried to use feature '
                         'deprecated since \'{}\': {}'
                         ''.format(tv, self.feature_version, self.feature_name))


class FeatureCheckKwargsBase:
    def __init__(self, feature_name, feature_version, kwargs):
        self.feature_name = feature_name
        self.feature_version = feature_version
        self.kwargs = kwargs

    def __call__(self, f):
        @wraps(f)
        def wrapped(*wrapped_args, **wrapped_kwargs):
            # Which FeatureCheck class to invoke
            FeatureCheckClass = self.feature_check_class
            kwargs, subproject = _get_callee_args(wrapped_args, want_subproject=True)[3:5]
            if subproject is None:
                raise AssertionError('{!r}'.format(wrapped_args))
            for arg in self.kwargs:
                if arg not in kwargs:
                    continue
                name = arg + ' arg in ' + self.feature_name
                FeatureCheckClass(name, self.feature_version).use(subproject)
            return f(*wrapped_args, **wrapped_kwargs)
        return wrapped

class FeatureNewKwargs(FeatureCheckKwargsBase):
    feature_check_class = FeatureNew

class FeatureDeprecatedKwargs(FeatureCheckKwargsBase):
    feature_check_class = FeatureDeprecated


class InterpreterException(mesonlib.MesonException):
    pass

class InvalidCode(InterpreterException):
    pass

class InvalidArguments(InterpreterException):
    pass

class SubdirDoneRequest(BaseException):
    pass

class ContinueRequest(BaseException):
    pass

class BreakRequest(BaseException):
    pass

class InterpreterObject:
    def __init__(self):
        self.methods = {}
        # Current node set during a method call. This can be used as location
        # when printing a warning message during a method call.
        self.current_node = None

    def method_call(self, method_name, args, kwargs):
        if method_name in self.methods:
            method = self.methods[method_name]
            if not getattr(method, 'no-args-flattening', False):
                args = flatten(args)
            return method(args, kwargs)
        raise InvalidCode('Unknown method "%s" in object.' % method_name)

class MutableInterpreterObject(InterpreterObject):
    def __init__(self):
        super().__init__()

class Disabler(InterpreterObject):
    def __init__(self):
        super().__init__()
        self.methods.update({'found': self.found_method})

    def found_method(self, args, kwargs):
        return False

def is_disabler(i) -> bool:
    return isinstance(i, Disabler)

def is_arg_disabled(arg) -> bool:
    if is_disabler(arg):
        return True
    if isinstance(arg, list):
        for i in arg:
            if is_arg_disabled(i):
                return True
    return False

def is_disabled(args, kwargs) -> bool:
    for i in args:
        if is_arg_disabled(i):
            return True
    for i in kwargs.values():
        if is_arg_disabled(i):
            return True
    return False

class InterpreterBase:
    def __init__(self, source_root, subdir):
        self.source_root = source_root
        self.funcs = {}
        self.builtin = {}
        self.subdir = subdir
        self.variables = {}
        self.argument_depth = 0
        self.current_lineno = -1
        # Current node set during a function call. This can be used as location
        # when printing a warning message during a method call.
        self.current_node = None

    def load_root_meson_file(self):
        mesonfile = os.path.join(self.source_root, self.subdir, environment.build_filename)
        if not os.path.isfile(mesonfile):
            raise InvalidArguments('Missing Meson file in %s' % mesonfile)
        with open(mesonfile, encoding='utf8') as mf:
            code = mf.read()
        if code.isspace():
            raise InvalidCode('Builder file is empty.')
        assert(isinstance(code, str))
        try:
            self.ast = mparser.Parser(code, self.subdir).parse()
        except mesonlib.MesonException as me:
            me.file = mesonfile
            raise me

    def join_path_strings(self, args):
        return os.path.join(*args).replace('\\', '/')

    def parse_project(self):
        """
        Parses project() and initializes languages, compilers etc. Do this
        early because we need this before we parse the rest of the AST.
        """
        self.evaluate_codeblock(self.ast, end=1)

    def sanity_check_ast(self):
        if not isinstance(self.ast, mparser.CodeBlockNode):
            raise InvalidCode('AST is of invalid type. Possibly a bug in the parser.')
        if not self.ast.lines:
            raise InvalidCode('No statements in code.')
        first = self.ast.lines[0]
        if not isinstance(first, mparser.FunctionNode) or first.func_name != 'project':
            raise InvalidCode('First statement must be a call to project')

    def run(self):
        # Evaluate everything after the first line, which is project() because
        # we already parsed that in self.parse_project()
        try:
            self.evaluate_codeblock(self.ast, start=1)
        except SubdirDoneRequest:
            pass

    def evaluate_codeblock(self, node, start=0, end=None):
        if node is None:
            return
        if not isinstance(node, mparser.CodeBlockNode):
            e = InvalidCode('Tried to execute a non-codeblock. Possibly a bug in the parser.')
            e.lineno = node.lineno
            e.colno = node.colno
            raise e
        statements = node.lines[start:end]
        i = 0
        while i < len(statements):
            cur = statements[i]
            try:
                self.current_lineno = cur.lineno
                self.evaluate_statement(cur)
            except Exception as e:
                if not hasattr(e, 'lineno'):
                    e.lineno = cur.lineno
                    e.colno = cur.colno
                    e.file = os.path.join(self.subdir, 'meson.build')
                raise e
            i += 1 # In THE FUTURE jump over blocks and stuff.

    def evaluate_statement(self, cur):
        if isinstance(cur, mparser.FunctionNode):
            return self.function_call(cur)
        elif isinstance(cur, mparser.AssignmentNode):
            return self.assignment(cur)
        elif isinstance(cur, mparser.MethodNode):
            return self.method_call(cur)
        elif isinstance(cur, mparser.StringNode):
            return cur.value
        elif isinstance(cur, mparser.BooleanNode):
            return cur.value
        elif isinstance(cur, mparser.IfClauseNode):
            return self.evaluate_if(cur)
        elif isinstance(cur, mparser.IdNode):
            return self.get_variable(cur.value)
        elif isinstance(cur, mparser.ComparisonNode):
            return self.evaluate_comparison(cur)
        elif isinstance(cur, mparser.ArrayNode):
            return self.evaluate_arraystatement(cur)
        elif isinstance(cur, mparser.DictNode):
            return self.evaluate_dictstatement(cur)
        elif isinstance(cur, mparser.NumberNode):
            return cur.value
        elif isinstance(cur, mparser.AndNode):
            return self.evaluate_andstatement(cur)
        elif isinstance(cur, mparser.OrNode):
            return self.evaluate_orstatement(cur)
        elif isinstance(cur, mparser.NotNode):
            return self.evaluate_notstatement(cur)
        elif isinstance(cur, mparser.UMinusNode):
            return self.evaluate_uminusstatement(cur)
        elif isinstance(cur, mparser.ArithmeticNode):
            return self.evaluate_arithmeticstatement(cur)
        elif isinstance(cur, mparser.ForeachClauseNode):
            return self.evaluate_foreach(cur)
        elif isinstance(cur, mparser.PlusAssignmentNode):
            return self.evaluate_plusassign(cur)
        elif isinstance(cur, mparser.IndexNode):
            return self.evaluate_indexing(cur)
        elif isinstance(cur, mparser.TernaryNode):
            return self.evaluate_ternary(cur)
        elif isinstance(cur, mparser.ContinueNode):
            raise ContinueRequest()
        elif isinstance(cur, mparser.BreakNode):
            raise BreakRequest()
        elif self.is_elementary_type(cur):
            return cur
        else:
            raise InvalidCode("Unknown statement.")

    def evaluate_arraystatement(self, cur):
        (arguments, kwargs) = self.reduce_arguments(cur.args)
        if len(kwargs) > 0:
            raise InvalidCode('Keyword arguments are invalid in array construction.')
        return arguments

    @FeatureNew('dict', '0.47.0')
    def evaluate_dictstatement(self, cur):
        (arguments, kwargs) = self.reduce_arguments(cur.args)
        assert (not arguments)
        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)
        if is_disabler(v):
            return v
        if not isinstance(v, bool):
            raise InterpreterException('Argument to "not" is not a boolean.')
        return not v

    def evaluate_if(self, node):
        assert(isinstance(node, mparser.IfClauseNode))
        for i in node.ifs:
            result = self.evaluate_statement(i.condition)
            if is_disabler(result):
                return result
            if not(isinstance(result, bool)):
                raise InvalidCode('If clause {!r} does not evaluate to true or false.'.format(result))
            if result:
                self.evaluate_codeblock(i.block)
                return
        if not isinstance(node.elseblock, mparser.EmptyNode):
            self.evaluate_codeblock(node.elseblock)

    def validate_comparison_types(self, val1, val2):
        if type(val1) != type(val2):
            return False
        return True

    def evaluate_in(self, val1, val2):
        if not isinstance(val1, (str, int, float, ObjectHolder)):
            raise InvalidArguments('lvalue of "in" operator must be a string, integer, float, or object')
        if not isinstance(val2, (list, dict)):
            raise InvalidArguments('rvalue of "in" operator must be an array or a dict')
        return val1 in val2

    def evaluate_comparison(self, node):
        val1 = self.evaluate_statement(node.left)
        if is_disabler(val1):
            return val1
        val2 = self.evaluate_statement(node.right)
        if is_disabler(val2):
            return val2
        if node.ctype == 'in':
            return self.evaluate_in(val1, val2)
        elif node.ctype == 'notin':
            return not self.evaluate_in(val1, val2)
        valid = self.validate_comparison_types(val1, val2)
        # Ordering comparisons of different types isn't allowed since PR #1810
        # (0.41.0).  Since PR #2884 we also warn about equality comparisons of
        # different types, which will one day become an error.
        if not valid and (node.ctype == '==' or node.ctype == '!='):
            mlog.warning('''Trying to compare values of different types ({}, {}) using {}.
The result of this is undefined and will become a hard error in a future Meson release.'''
                         .format(type(val1).__name__, type(val2).__name__, node.ctype), location=node)
        if node.ctype == '==':
            return val1 == val2
        elif node.ctype == '!=':
            return val1 != val2
        elif not valid:
            raise InterpreterException(
                'Values of different types ({}, {}) cannot be compared using {}.'.format(type(val1).__name__,
                                                                                         type(val2).__name__,
                                                                                         node.ctype))
        elif not self.is_elementary_type(val1):
            raise InterpreterException('{} can only be compared for equality.'.format(node.left.value))
        elif not self.is_elementary_type(val2):
            raise InterpreterException('{} can only be compared for equality.'.format(node.right.value))
        elif node.ctype == '<':
            return val1 < val2
        elif node.ctype == '<=':
            return val1 <= val2
        elif node.ctype == '>':
            return val1 > val2
        elif node.ctype == '>=':
            return val1 >= val2
        else:
            raise InvalidCode('You broke my compare eval.')

    def evaluate_andstatement(self, cur):
        l = self.evaluate_statement(cur.left)
        if is_disabler(l):
            return l
        if not isinstance(l, bool):
            raise InterpreterException('First argument to "and" is not a boolean.')
        if not l:
            return False
        r = self.evaluate_statement(cur.right)
        if is_disabler(r):
            return r
        if not isinstance(r, bool):
            raise InterpreterException('Second argument to "and" is not a boolean.')
        return r

    def evaluate_orstatement(self, cur):
        l = self.evaluate_statement(cur.left)
        if is_disabler(l):
            return l
        if not isinstance(l, bool):
            raise InterpreterException('First argument to "or" is not a boolean.')
        if l:
            return True
        r = self.evaluate_statement(cur.right)
        if is_disabler(r):
            return r
        if not isinstance(r, bool):
            raise InterpreterException('Second argument to "or" is not a boolean.')
        return r

    def evaluate_uminusstatement(self, cur):
        v = self.evaluate_statement(cur.value)
        if is_disabler(v):
            return v
        if not isinstance(v, int):
            raise InterpreterException('Argument to negation is not an integer.')
        return -v

    @FeatureNew('/ with string arguments', '0.49.0')
    def evaluate_path_join(self, l, r):
        if not isinstance(l, str):
            raise InvalidCode('The division operator can only append to a string.')
        if not isinstance(r, str):
            raise InvalidCode('The division operator can only append a string.')
        return self.join_path_strings((l, r))

    def evaluate_division(self, l, r):
        if isinstance(l, str) or isinstance(r, str):
            return self.evaluate_path_join(l, r)
        if isinstance(l, int) and isinstance(r, int):
            if r == 0:
                raise InvalidCode('Division by zero.')
            return l // r
        raise InvalidCode('Division works only with strings or integers.')

    def evaluate_arithmeticstatement(self, cur):
        l = self.evaluate_statement(cur.left)
        if is_disabler(l):
            return l
        r = self.evaluate_statement(cur.right)
        if is_disabler(r):
            return r

        if cur.operation == 'add':
            if isinstance(l, dict) and isinstance(r, dict):
                return {**l, **r}
            try:
                return l + r
            except Exception as e:
                raise InvalidCode('Invalid use of addition: ' + str(e))
        elif cur.operation == 'sub':
            if not isinstance(l, int) or not isinstance(r, int):
                raise InvalidCode('Subtraction works only with integers.')
            return l - r
        elif cur.operation == 'mul':
            if not isinstance(l, int) or not isinstance(r, int):
                raise InvalidCode('Multiplication works only with integers.')
            return l * r
        elif cur.operation == 'div':
            return self.evaluate_division(l, r)
        elif cur.operation == 'mod':
            if not isinstance(l, int) or not isinstance(r, int):
                raise InvalidCode('Modulo works only with integers.')
            return l % r
        else:
            raise InvalidCode('You broke me.')

    def evaluate_ternary(self, node):
        assert(isinstance(node, mparser.TernaryNode))
        result = self.evaluate_statement(node.condition)
        if is_disabler(result):
            return result
        if not isinstance(result, bool):
            raise InterpreterException('Ternary condition is not boolean.')
        if result:
            return self.evaluate_statement(node.trueblock)
        else:
            return self.evaluate_statement(node.falseblock)

    def evaluate_foreach(self, node):
        assert(isinstance(node, mparser.ForeachClauseNode))
        items = self.evaluate_statement(node.items)

        if isinstance(items, list):
            if len(node.varnames) != 1:
                raise InvalidArguments('Foreach on array does not unpack')
            varname = node.varnames[0].value
            for item in items:
                self.set_variable(varname, item)
                try:
                    self.evaluate_codeblock(node.block)
                except ContinueRequest:
                    continue
                except BreakRequest:
                    break
        elif isinstance(items, dict):
            if len(node.varnames) != 2:
                raise InvalidArguments('Foreach on dict unpacks key and value')
            for key, value in items.items():
                self.set_variable(node.varnames[0].value, key)
                self.set_variable(node.varnames[1].value, value)
                try:
                    self.evaluate_codeblock(node.block)
                except ContinueRequest:
                    continue
                except BreakRequest:
                    break
        else:
            raise InvalidArguments('Items of foreach loop must be an array or a dict')

    def evaluate_plusassign(self, node):
        assert(isinstance(node, mparser.PlusAssignmentNode))
        varname = node.var_name
        addition = self.evaluate_statement(node.value)
        if is_disabler(addition):
            self.set_variable(varname, addition)
            return
        # Remember that all variables are immutable. We must always create a
        # full new variable and then assign it.
        old_variable = self.get_variable(varname)
        if isinstance(old_variable, str):
            if not isinstance(addition, str):
                raise InvalidArguments('The += operator requires a string on the right hand side if the variable on the left is a string')
            new_value = old_variable + addition
        elif isinstance(old_variable, int):
            if not isinstance(addition, int):
                raise InvalidArguments('The += operator requires an int on the right hand side if the variable on the left is an int')
            new_value = old_variable + addition
        elif isinstance(old_variable, list):
            if isinstance(addition, list):
                new_value = old_variable + addition
            else:
                new_value = old_variable + [addition]
        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_value = {**old_variable, **addition}
        # Add other data types here.
        else:
            raise InvalidArguments('The += operator currently only works with arrays, dicts, strings or ints ')
        self.set_variable(varname, new_value)

    def evaluate_indexing(self, node):
        assert(isinstance(node, mparser.IndexNode))
        iobject = self.evaluate_statement(node.iobject)
        if is_disabler(iobject):
            return iobject
        if not hasattr(iobject, '__getitem__'):
            raise InterpreterException(
                'Tried to index an object that doesn\'t support indexing.')
        index = self.evaluate_statement(node.index)

        if isinstance(iobject, dict):
            if not isinstance(index, str):
                raise InterpreterException('Key is not a string')
            try:
                return iobject[index]
            except KeyError:
                raise InterpreterException('Key %s is not in dict' % index)
        else:
            if not isinstance(index, int):
                raise InterpreterException('Index value is not an integer.')
            try:
                return iobject[index]
            except IndexError:
                raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject)))

    def function_call(self, node):
        func_name = node.func_name
        (posargs, kwargs) = self.reduce_arguments(node.args)
        if is_disabled(posargs, kwargs) and func_name != 'set_variable' and func_name != 'is_disabler':
            return Disabler()
        if func_name in self.funcs:
            func = self.funcs[func_name]
            if not getattr(func, 'no-args-flattening', False):
                posargs = flatten(posargs)

            self.current_node = node
            return func(node, posargs, kwargs)
        else:
            self.unknown_function_called(func_name)

    def method_call(self, node):
        invokable = node.source_object
        if isinstance(invokable, mparser.IdNode):
            object_name = invokable.value
            obj = self.get_variable(object_name)
        else:
            obj = self.evaluate_statement(invokable)
        method_name = node.name
        args = node.args
        if isinstance(obj, str):
            return self.string_method_call(obj, method_name, args)
        if isinstance(obj, bool):
            return self.bool_method_call(obj, method_name, args)
        if isinstance(obj, int):
            return self.int_method_call(obj, method_name, args)
        if isinstance(obj, list):
            return self.array_method_call(obj, method_name, args)
        if isinstance(obj, dict):
            return self.dict_method_call(obj, method_name, args)
        if isinstance(obj, mesonlib.File):
            raise InvalidArguments('File object "%s" is not callable.' % obj)
        if not isinstance(obj, InterpreterObject):
            raise InvalidArguments('Variable "%s" is not callable.' % object_name)
        (args, kwargs) = self.reduce_arguments(args)
        # Special case. This is the only thing you can do with a disabler
        # object. Every other use immediately returns the disabler object.
        if isinstance(obj, Disabler):
            if method_name == 'found':
                return False
            else:
                return Disabler()
        if is_disabled(args, kwargs):
            return Disabler()
        if method_name == 'extract_objects':
            self.validate_extraction(obj.held_object)
        obj.current_node = node
        return obj.method_call(method_name, args, kwargs)

    def bool_method_call(self, obj, method_name, args):
        (posargs, kwargs) = self.reduce_arguments(args)
        if is_disabled(posargs, kwargs):
            return Disabler()
        if method_name == 'to_string':
            if not posargs:
                if obj:
                    return 'true'
                else:
                    return 'false'
            elif len(posargs) == 2 and isinstance(posargs[0], str) and isinstance(posargs[1], str):
                if obj:
                    return posargs[0]
                else:
                    return posargs[1]
            else:
                raise InterpreterException('bool.to_string() must have either no arguments or exactly two string arguments that signify what values to return for true and false.')
        elif method_name == 'to_int':
            if obj:
                return 1
            else:
                return 0
        else:
            raise InterpreterException('Unknown method "%s" for a boolean.' % method_name)

    def int_method_call(self, obj, method_name, args):
        (posargs, kwargs) = self.reduce_arguments(args)
        if is_disabled(posargs, kwargs):
            return Disabler()
        if method_name == 'is_even':
            if not posargs:
                return obj % 2 == 0
            else:
                raise InterpreterException('int.is_even() must have no arguments.')
        elif method_name == 'is_odd':
            if not posargs:
                return obj % 2 != 0
            else:
                raise InterpreterException('int.is_odd() must have no arguments.')
        elif method_name == 'to_string':
            if not posargs:
                return str(obj)
            else:
                raise InterpreterException('int.to_string() must have no arguments.')
        else:
            raise InterpreterException('Unknown method "%s" for an integer.' % method_name)

    @staticmethod
    def _get_one_string_posarg(posargs, method_name):
        if len(posargs) > 1:
            m = '{}() must have zero or one arguments'
            raise InterpreterException(m.format(method_name))
        elif len(posargs) == 1:
            s = posargs[0]
            if not isinstance(s, str):
                m = '{}() argument must be a string'
                raise InterpreterException(m.format(method_name))
            return s
        return None

    def string_method_call(self, obj, method_name, args):
        (posargs, kwargs) = self.reduce_arguments(args)
        if is_disabled(posargs, kwargs):
            return Disabler()
        if method_name == 'strip':
            s = self._get_one_string_posarg(posargs, 'strip')
            if s is not None:
                return obj.strip(s)
            return obj.strip()
        elif method_name == 'format':
            return self.format_string(obj, args)
        elif method_name == 'to_upper':
            return obj.upper()
        elif method_name == 'to_lower':
            return obj.lower()
        elif method_name == 'underscorify':
            return re.sub(r'[^a-zA-Z0-9]', '_', obj)
        elif method_name == 'split':
            s = self._get_one_string_posarg(posargs, 'split')
            if s is not None:
                return obj.split(s)
            return obj.split()
        elif method_name == 'startswith' or method_name == 'contains' or method_name == 'endswith':
            s = posargs[0]
            if not isinstance(s, str):
                raise InterpreterException('Argument must be a string.')
            if method_name == 'startswith':
                return obj.startswith(s)
            elif method_name == 'contains':
                return obj.find(s) >= 0
            return obj.endswith(s)
        elif method_name == 'to_int':
            try:
                return int(obj)
            except Exception:
                raise InterpreterException('String {!r} cannot be converted to int'.format(obj))
        elif method_name == 'join':
            if len(posargs) != 1:
                raise InterpreterException('Join() takes exactly one argument.')
            strlist = posargs[0]
            check_stringlist(strlist)
            return obj.join(strlist)
        elif method_name == 'version_compare':
            if len(posargs) != 1:
                raise InterpreterException('Version_compare() takes exactly one argument.')
            cmpr = posargs[0]
            if not isinstance(cmpr, str):
                raise InterpreterException('Version_compare() argument must be a string.')
            return mesonlib.version_compare(obj, cmpr)
        raise InterpreterException('Unknown method "%s" for a string.' % method_name)

    def format_string(self, templ, args):
        if isinstance(args, mparser.ArgumentNode):
            args = args.arguments
        arg_strings = []
        for arg in args:
            arg = self.evaluate_statement(arg)
            if isinstance(arg, bool): # Python boolean is upper case.
                arg = str(arg).lower()
            arg_strings.append(str(arg))

        def arg_replace(match):
            idx = int(match.group(1))
            if idx >= len(arg_strings):
                raise InterpreterException('Format placeholder @{}@ out of range.'.format(idx))
            return arg_strings[idx]

        return re.sub(r'@(\d+)@', arg_replace, templ)

    def unknown_function_called(self, func_name):
        raise InvalidCode('Unknown function "%s".' % func_name)

    def array_method_call(self, obj, method_name, args):
        (posargs, kwargs) = self.reduce_arguments(args)
        if is_disabled(posargs, kwargs):
            return Disabler()
        if method_name == 'contains':
            return self.check_contains(obj, posargs)
        elif method_name == 'length':
            return len(obj)
        elif method_name == 'get':
            index = posargs[0]
            fallback = None
            if len(posargs) == 2:
                fallback = posargs[1]
            elif len(posargs) > 2:
                m = 'Array method \'get()\' only takes two arguments: the ' \
                    'index and an optional fallback value if the index is ' \
                    'out of range.'
                raise InvalidArguments(m)
            if not isinstance(index, int):
                raise InvalidArguments('Array index must be a number.')
            if index < -len(obj) or index >= len(obj):
                if fallback is None:
                    m = 'Array index {!r} is out of bounds for array of size {!r}.'
                    raise InvalidArguments(m.format(index, len(obj)))
                return fallback
            return obj[index]
        m = 'Arrays do not have a method called {!r}.'
        raise InterpreterException(m.format(method_name))

    def dict_method_call(self, obj, method_name, args):
        (posargs, kwargs) = self.reduce_arguments(args)
        if is_disabled(posargs, kwargs):
            return Disabler()

        if method_name in ('has_key', 'get'):
            if method_name == 'has_key':
                if len(posargs) != 1:
                    raise InterpreterException('has_key() takes exactly one argument.')
            else:
                if len(posargs) not in (1, 2):
                    raise InterpreterException('get() takes one or two arguments.')

            key = posargs[0]
            if not isinstance(key, (str)):
                raise InvalidArguments('Dictionary key must be a string.')

            has_key = key in obj

            if method_name == 'has_key':
                return has_key

            if has_key:
                return obj[key]

            if len(posargs) == 2:
                return posargs[1]

            raise InterpreterException('Key {!r} is not in the dictionary.'.format(key))

        if method_name == 'keys':
            if len(posargs) != 0:
                raise InterpreterException('keys() takes no arguments.')
            return list(obj.keys())

        raise InterpreterException('Dictionaries do not have a method called "%s".' % method_name)

    def reduce_arguments(self, args):
        assert(isinstance(args, mparser.ArgumentNode))
        if args.incorrect_order():
            raise InvalidArguments('All keyword arguments must be after positional arguments.')
        self.argument_depth += 1
        reduced_pos = [self.evaluate_statement(arg) for arg in args.arguments]
        reduced_kw = {}
        for key in args.kwargs.keys():
            a = args.kwargs[key]
            reduced_kw[key] = self.evaluate_statement(a)
        self.argument_depth -= 1
        final_kw = self.expand_default_kwargs(reduced_kw)
        return reduced_pos, final_kw

    def expand_default_kwargs(self, kwargs):
        if 'kwargs' not in kwargs:
            return kwargs
        to_expand = kwargs.pop('kwargs')
        if not isinstance(to_expand, dict):
            raise InterpreterException('Value of "kwargs" must be dictionary.')
        if 'kwargs' in to_expand:
            raise InterpreterException('Kwargs argument must not contain a "kwargs" entry. Points for thinking meta, though. :P')
        for k, v in to_expand.items():
            if k in kwargs:
                raise InterpreterException('Entry "{}" defined both as a keyword argument and in a "kwarg" entry.'.format(k))
            kwargs[k] = v
        return kwargs

    def assignment(self, node):
        assert(isinstance(node, mparser.AssignmentNode))
        if self.argument_depth != 0:
            raise InvalidArguments('''Tried to assign values inside an argument list.
To specify a keyword argument, use : instead of =.''')
        var_name = node.var_name
        if not isinstance(var_name, str):
            raise InvalidArguments('Tried to assign value to a non-variable.')
        value = self.evaluate_statement(node.value)
        if not self.is_assignable(value):
            raise InvalidCode('Tried to assign an invalid value to variable.')
        # For mutable objects we need to make a copy on assignment
        if isinstance(value, MutableInterpreterObject):
            value = copy.deepcopy(value)
        self.set_variable(var_name, value)
        return None

    def set_variable(self, varname, variable):
        if variable is None:
            raise InvalidCode('Can not assign None to variable.')
        if not isinstance(varname, str):
            raise InvalidCode('First argument to set_variable must be a string.')
        if not self.is_assignable(variable):
            raise InvalidCode('Assigned value not of assignable type.')
        if re.match('[_a-zA-Z][_0-9a-zA-Z]*$', varname) is None:
            raise InvalidCode('Invalid variable name: ' + varname)
        if varname in self.builtin:
            raise InvalidCode('Tried to overwrite internal variable "%s"' % varname)
        self.variables[varname] = variable

    def get_variable(self, varname):
        if varname in self.builtin:
            return self.builtin[varname]
        if varname in self.variables:
            return self.variables[varname]
        raise InvalidCode('Unknown variable "%s".' % varname)

    def is_assignable(self, value):
        return isinstance(value, (InterpreterObject, dependencies.Dependency,
                                  str, int, list, dict, mesonlib.File))

    def is_elementary_type(self, v):
        return isinstance(v, (int, float, str, bool, list))
meson-0.53.2/mesonbuild/linkers.py0000644000175000017500000010644313625260316020512 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import abc
import os
import typing as T

from . import mesonlib

if T.TYPE_CHECKING:
    from .coredata import OptionDictType
    from .environment import Environment


class StaticLinker:

    def __init__(self, exelist: T.List[str]):
        self.exelist = exelist

    def can_linker_accept_rsp(self) -> bool:
        """
        Determines whether the linker can accept arguments using the @rsp syntax.
        """
        return mesonlib.is_windows()

    def get_base_link_args(self, options: 'OptionDictType') -> T.List[str]:
        """Like compilers.get_base_link_args, but for the static linker."""
        return []

    def get_exelist(self) -> T.List[str]:
        return self.exelist.copy()

    def get_std_link_args(self) -> T.List[str]:
        return []

    def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]:
        return []

    def get_output_args(self, target: str) -> T.List[str]:
        return[]

    def get_coverage_link_args(self) -> T.List[str]:
        return []

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: str, build_rpath: str,
                         install_rpath: str) -> T.List[str]:
        return []

    def thread_link_flags(self, env: 'Environment') -> T.List[str]:
        return []

    def openmp_flags(self) -> T.List[str]:
        return []

    def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]:
        return []

    @classmethod
    def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]:
        return args[:]

    @classmethod
    def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
        return args[:]

    def get_link_debugfile_args(self, targetfile: str) -> T.List[str]:
        # Static libraries do not have PDB files
        return []

    def get_always_args(self) -> T.List[str]:
        return []

    def get_linker_always_args(self) -> T.List[str]:
        return []


class VisualStudioLikeLinker:
    always_args = ['/NOLOGO']

    def __init__(self, machine: str):
        self.machine = machine

    def get_always_args(self) -> T.List[str]:
        return self.always_args.copy()

    def get_linker_always_args(self) -> T.List[str]:
        return self.always_args.copy()

    def get_output_args(self, target: str) -> T.List[str]:
        args = []  # type: T.List[str]
        if self.machine:
            args += ['/MACHINE:' + self.machine]
        args += ['/OUT:' + target]
        return args

    @classmethod
    def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]:
        from .compilers import VisualStudioCCompiler
        return VisualStudioCCompiler.unix_args_to_native(args)

    @classmethod
    def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
        from .compilers import VisualStudioCCompiler
        return VisualStudioCCompiler.native_args_to_unix(args)


class VisualStudioLinker(VisualStudioLikeLinker, StaticLinker):

    """Microsoft's lib static linker."""

    def __init__(self, exelist: T.List[str], machine: str):
        StaticLinker.__init__(self, exelist)
        VisualStudioLikeLinker.__init__(self, machine)


class IntelVisualStudioLinker(VisualStudioLikeLinker, StaticLinker):

    """Intel's xilib static linker."""

    def __init__(self, exelist: T.List[str], machine: str):
        StaticLinker.__init__(self, exelist)
        VisualStudioLikeLinker.__init__(self, machine)


class ArLinker(StaticLinker):

    def __init__(self, exelist: T.List[str]):
        super().__init__(exelist)
        self.id = 'ar'
        pc, stdo = mesonlib.Popen_safe(self.exelist + ['-h'])[0:2]
        # Enable deterministic builds if they are available.
        if '[D]' in stdo:
            self.std_args = ['csrD']
        else:
            self.std_args = ['csr']

    def get_std_link_args(self) -> T.List[str]:
        return self.std_args

    def get_output_args(self, target: str) -> T.List[str]:
        return [target]


class ArmarLinker(ArLinker):  # lgtm [py/missing-call-to-init]

    def __init__(self, exelist: T.List[str]):
        StaticLinker.__init__(self, exelist)
        self.id = 'armar'
        self.std_args = ['-csr']

    def can_linker_accept_rsp(self) -> bool:
        # armar can't accept arguments using the @rsp syntax
        return False


class DLinker(StaticLinker):
    def __init__(self, exelist: T.List[str], arch: str):
        super().__init__(exelist)
        self.id = exelist[0]
        self.arch = arch

    def get_std_link_args(self) -> T.List[str]:
        return ['-lib']

    def get_output_args(self, target: str) -> T.List[str]:
        return ['-of=' + target]

    def get_linker_always_args(self) -> T.List[str]:
        if mesonlib.is_windows():
            if self.arch == 'x86_64':
                return ['-m64']
            elif self.arch == 'x86_mscoff' and self.id == 'dmd':
                return ['-m32mscoff']
            return ['-m32']
        return []


class CcrxLinker(StaticLinker):

    def __init__(self, exelist: T.List[str]):
        super().__init__(exelist)
        self.id = 'rlink'

    def can_linker_accept_rsp(self) -> bool:
        return False

    def get_output_args(self, target: str) -> T.List[str]:
        return ['-output=%s' % target]

    def get_linker_always_args(self) -> T.List[str]:
        return ['-nologo', '-form=library']


def prepare_rpaths(raw_rpaths: str, build_dir: str, from_dir: str) -> T.List[str]:
    # The rpaths we write must be relative if they point to the build dir,
    # because otherwise they have different length depending on the build
    # directory. This breaks reproducible builds.
    internal_format_rpaths = [evaluate_rpath(p, build_dir, from_dir) for p in raw_rpaths]
    ordered_rpaths = order_rpaths(internal_format_rpaths)
    return ordered_rpaths


def order_rpaths(rpath_list: T.List[str]) -> T.List[str]:
    # We want rpaths that point inside our build dir to always override
    # those pointing to other places in the file system. This is so built
    # binaries prefer our libraries to the ones that may lie somewhere
    # in the file system, such as /lib/x86_64-linux-gnu.
    #
    # The correct thing to do here would be C++'s std::stable_partition.
    # Python standard library does not have it, so replicate it with
    # sort, which is guaranteed to be stable.
    return sorted(rpath_list, key=os.path.isabs)


def evaluate_rpath(p: str, build_dir: str, from_dir: str) -> str:
    if p == from_dir:
        return '' # relpath errors out in this case
    elif os.path.isabs(p):
        return p # These can be outside of build dir.
    else:
        return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir))


class DynamicLinker(metaclass=abc.ABCMeta):

    """Base class for dynamic linkers."""

    _BUILDTYPE_ARGS = {
        'plain': [],
        'debug': [],
        'debugoptimized': [],
        'release': [],
        'minsize': [],
        'custom': [],
    }  # type: T.Dict[str, T.List[str]]

    def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]:
        args = [arg] if isinstance(arg, str) else arg
        if self.prefix_arg is None:
            return args
        elif isinstance(self.prefix_arg, str):
            return [self.prefix_arg + arg for arg in args]
        ret = []
        for arg in args:
            ret += self.prefix_arg + [arg]
        return ret

    def __init__(self, id_: str, exelist: T.List[str],
                 for_machine: mesonlib.MachineChoice, prefix_arg: T.Union[str, T.List[str]],
                 always_args: T.List[str], *, version: str = 'unknown version'):
        self.exelist = exelist
        self.for_machine = for_machine
        self.version = version
        self.id = id_
        self.prefix_arg = prefix_arg
        self.always_args = always_args

    def __repr__(self) -> str:
        return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist))

    def get_id(self) -> str:
        return self.id

    def get_version_string(self) -> str:
        return '({} {})'.format(self.id, self.version)

    def get_exelist(self) -> T.List[str]:
        return self.exelist.copy()

    def get_accepts_rsp(self) -> bool:
        # rsp files are only used when building on Windows because we want to
        # avoid issues with quoting and max argument length
        return mesonlib.is_windows()

    def get_always_args(self) -> T.List[str]:
        return self.always_args.copy()

    def get_lib_prefix(self) -> str:
        return ''

    # XXX: is use_ldflags a compiler or a linker attribute?

    def get_args_from_envvars(self) -> T.List[str]:
        flags = os.environ.get('LDFLAGS')
        if not flags:
            return []
        return mesonlib.split_args(flags)

    def get_option_args(self, options: 'OptionDictType') -> T.List[str]:
        return []

    def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]:
        m = 'Language {} does not support has_multi_link_arguments.'
        raise mesonlib.EnvironmentException(m.format(self.id))

    def get_debugfile_args(self, targetfile: str) -> T.List[str]:
        """Some compilers (MSVC) write debug into a separate file.

        This method takes the target object path and returns a list of
        commands to append to the linker invocation to control where that
        file is written.
        """
        return []

    def get_std_shared_lib_args(self) -> T.List[str]:
        return []

    def get_std_shared_module_args(self, options: 'OptionDictType') -> T.List[str]:
        return self.get_std_shared_lib_args()

    def get_pie_args(self) -> T.List[str]:
        # TODO: this really needs to take a boolean and return the args to
        # disable pie, otherwise it only acts to enable pie if pie *isn't* the
        # default.
        m = 'Linker {} does not support position-independent executable'
        raise mesonlib.EnvironmentException(m.format(self.id))

    def get_lto_args(self) -> T.List[str]:
        return []

    def sanitizer_args(self, value: str) -> T.List[str]:
        return []

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        # We can override these in children by just overriding the
        # _BUILDTYPE_ARGS value.
        return self._BUILDTYPE_ARGS[buildtype]

    def get_asneeded_args(self) -> T.List[str]:
        return []

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        raise mesonlib.EnvironmentException(
            'Linker {} does not support link_whole'.format(self.id))

    def get_allow_undefined_args(self) -> T.List[str]:
        raise mesonlib.EnvironmentException(
            'Linker {} does not support allow undefined'.format(self.id))

    @abc.abstractmethod
    def get_output_args(self, outname: str) -> T.List[str]:
        pass

    def get_coverage_args(self) -> T.List[str]:
        m = "Linker {} doesn't implement coverage data generation.".format(self.id)
        raise mesonlib.EnvironmentException(m)

    @abc.abstractmethod
    def get_search_args(self, dirname: str) -> T.List[str]:
        pass

    def export_dynamic_args(self, env: 'Environment') -> T.List[str]:
        return []

    def import_library_args(self, implibname: str) -> T.List[str]:
        """The name of the outputted import library.

        This implementation is used only on Windows by compilers that use GNU ld
        """
        return []

    def thread_flags(self, env: 'Environment') -> T.List[str]:
        return []

    def no_undefined_args(self) -> T.List[str]:
        """Arguments to error if there are any undefined symbols at link time.

        This is the inverse of get_allow_undefined_args().

        TODO: A future cleanup might merge this and
              get_allow_undefined_args() into a single method taking a
              boolean
        """
        return []

    def fatal_warnings(self) -> T.List[str]:
        """Arguments to make all warnings errors."""
        return []

    def bitcode_args(self) -> T.List[str]:
        raise mesonlib.MesonException('This linker does not support bitcode bundles')

    def get_debug_crt_args(self) -> T.List[str]:
        return []

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: str, build_rpath: str,
                         install_rpath: str) -> T.List[str]:
        return []

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        return []


class PosixDynamicLinkerMixin:

    """Mixin class for POSIX-ish linkers.

    This is obviously a pretty small subset of the linker interface, but
    enough dynamic linkers that meson supports are POSIX-like but not
    GNU-like that it makes sense to split this out.
    """

    def get_output_args(self, outname: str) -> T.List[str]:
        return ['-o', outname]

    def get_std_shared_lib_args(self) -> T.List[str]:
        return ['-shared']

    def get_search_args(self, dirname: str) -> T.List[str]:
        return ['-L' + dirname]


class GnuLikeDynamicLinkerMixin:

    """Mixin class for dynamic linkers that provides gnu-like interface.

    This acts as a base for the GNU linkers (bfd and gold), LLVM's lld, and
    other linkers like GNU-ld.
    """

    _BUILDTYPE_ARGS = {
        'plain': [],
        'debug': [],
        'debugoptimized': [],
        'release': ['-O1'],
        'minsize': [],
        'custom': [],
    }  # type: T.Dict[str, T.List[str]]

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        # We can override these in children by just overriding the
        # _BUILDTYPE_ARGS value.
        return mesonlib.listify([self._apply_prefix(a) for a in self._BUILDTYPE_ARGS[buildtype]])

    def get_pie_args(self) -> T.List[str]:
        return ['-pie']

    def get_asneeded_args(self) -> T.List[str]:
        return self._apply_prefix('--as-needed')

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        if not args:
            return args
        return self._apply_prefix('--whole-archive') + args + self._apply_prefix('--no-whole-archive')

    def get_allow_undefined_args(self) -> T.List[str]:
        return self._apply_prefix('--allow-shlib-undefined')

    def get_lto_args(self) -> T.List[str]:
        return ['-flto']

    def sanitizer_args(self, value: str) -> T.List[str]:
        if value == 'none':
            return []
        return ['-fsanitize=' + value]

    def get_coverage_args(self) -> T.List[str]:
        return ['--coverage']

    def export_dynamic_args(self, env: 'Environment') -> T.List[str]:
        m = env.machines[self.for_machine]
        if m.is_windows() or m.is_cygwin():
            return self._apply_prefix('--export-all-symbols')
        return self._apply_prefix('-export-dynamic')

    def import_library_args(self, implibname: str) -> T.List[str]:
        return self._apply_prefix('--out-implib=' + implibname)

    def thread_flags(self, env: 'Environment') -> T.List[str]:
        if env.machines[self.for_machine].is_haiku():
            return []
        return ['-pthread']

    def no_undefined_args(self) -> T.List[str]:
        return self._apply_prefix('--no-undefined')

    def fatal_warnings(self) -> T.List[str]:
        return self._apply_prefix('--fatal-warnings')

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        m = env.machines[self.for_machine]
        if m.is_windows() or m.is_cygwin():
            # For PE/COFF the soname argument has no effect
            return []
        sostr = '' if soversion is None else '.' + soversion
        return self._apply_prefix('-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr))

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: str, build_rpath: str,
                         install_rpath: str) -> T.List[str]:
        m = env.machines[self.for_machine]
        if m.is_windows() or m.is_cygwin():
            return []
        if not rpath_paths and not install_rpath and not build_rpath:
            return []
        args = []
        origin_placeholder = '$ORIGIN'
        processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
        # Need to deduplicate rpaths, as macOS's install_name_tool
        # is *very* allergic to duplicate -delete_rpath arguments
        # when calling depfixer on installation.
        all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
        # Build_rpath is used as-is (it is usually absolute).
        if build_rpath != '':
            all_paths.add(build_rpath)

        # TODO: should this actually be "for (dragonfly|open)bsd"?
        if mesonlib.is_dragonflybsd() or mesonlib.is_openbsd():
            # This argument instructs the compiler to record the value of
            # ORIGIN in the .dynamic section of the elf. On Linux this is done
            # by default, but is not on dragonfly/openbsd for some reason. Without this
            # $ORIGIN in the runtime path will be undefined and any binaries
            # linked against local libraries will fail to resolve them.
            args.extend(self._apply_prefix('-z,origin'))

        # In order to avoid relinking for RPATH removal, the binary needs to contain just
        # enough space in the ELF header to hold the final installation RPATH.
        paths = ':'.join(all_paths)
        if len(paths) < len(install_rpath):
            padding = 'X' * (len(install_rpath) - len(paths))
            if not paths:
                paths = padding
            else:
                paths = paths + ':' + padding
        args.extend(self._apply_prefix('-rpath,' + paths))

        # TODO: should this actually be "for solaris/sunos"?
        if mesonlib.is_sunos():
            return args

        # Rpaths to use while linking must be absolute. These are not
        # written to the binary. Needed only with GNU ld:
        # https://sourceware.org/bugzilla/show_bug.cgi?id=16936
        # Not needed on Windows or other platforms that don't use RPATH
        # https://github.com/mesonbuild/meson/issues/1897
        #
        # In addition, this linker option tends to be quite long and some
        # compilers have trouble dealing with it. That's why we will include
        # one option per folder, like this:
        #
        #   -Wl,-rpath-link,/path/to/folder1 -Wl,-rpath,/path/to/folder2 ...
        #
        # ...instead of just one single looooong option, like this:
        #
        #   -Wl,-rpath-link,/path/to/folder1:/path/to/folder2:...
        for p in rpath_paths:
            args.extend(self._apply_prefix('-rpath-link,' + os.path.join(build_dir, p)))

        return args


class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """Apple's ld implementation."""

    def __init__(self, *args, **kwargs):
        super().__init__('ld64', *args, **kwargs)

    def get_asneeded_args(self) -> T.List[str]:
        return self._apply_prefix('-dead_strip_dylibs')

    def get_allow_undefined_args(self) -> T.List[str]:
        return self._apply_prefix('-undefined,dynamic_lookup')

    def get_std_shared_module_args(self, options: 'OptionDictType') -> T.List[str]:
        return ['-bundle'] + self._apply_prefix('-undefined,dynamic_lookup')

    def get_pie_args(self) -> T.List[str]:
        return ['-pie']

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        result = []  # type: T.List[str]
        for a in args:
            result.extend(self._apply_prefix('-force_load'))
            result.append(a)
        return result

    def get_coverage_args(self) -> T.List[str]:
        return ['--coverage']

    def sanitizer_args(self, value: str) -> T.List[str]:
        if value == 'none':
            return []
        return ['-fsanitize=' + value]

    def no_undefined_args(self) -> T.List[str]:
        return self._apply_prefix('-undefined,error')

    def get_always_args(self) -> T.List[str]:
        return self._apply_prefix('-headerpad_max_install_names') + super().get_always_args()

    def bitcode_args(self) -> T.List[str]:
        return self._apply_prefix('-bitcode_bundle')

    def fatal_warnings(self) -> T.List[str]:
        return self._apply_prefix('-fatal_warnings')

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        if is_shared_module:
            return []
        install_name = ['@rpath/', prefix, shlib_name]
        if soversion is not None:
            install_name.append('.' + soversion)
        install_name.append('.dylib')
        args = ['-install_name', ''.join(install_name)]
        if darwin_versions:
            args.extend(['-compatibility_version', darwin_versions[0],
                         '-current_version', darwin_versions[1]])
        return args

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: str, build_rpath: str,
                         install_rpath: str) -> T.List[str]:
        if not rpath_paths and not install_rpath and not build_rpath:
            return []
        # Ensure that there is enough space for install_name_tool in-place
        # editing of large RPATHs
        args = self._apply_prefix('-headerpad_max_install_names')
        # @loader_path is the equivalent of $ORIGIN on macOS
        # https://stackoverflow.com/q/26280738
        origin_placeholder = '@loader_path'
        processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
        all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
        if build_rpath != '':
            all_paths.add(build_rpath)
        for rp in all_paths:
            args.extend(self._apply_prefix('-rpath,' + rp))

        return args


class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):

    """Representation of GNU ld.bfd and ld.gold."""


class GnuGoldDynamicLinker(GnuDynamicLinker):

    def __init__(self, *args, **kwargs):
        super().__init__('ld.gold', *args, **kwargs)


class GnuBFDDynamicLinker(GnuDynamicLinker):

    def __init__(self, *args, **kwargs):
        super().__init__('ld.bfd', *args, **kwargs)


class LLVMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):

    """Representation of LLVM's ld.lld linker.

    This is only the gnu-like linker, not the apple like or link.exe like
    linkers.
    """

    def __init__(self, *args, **kwargs):
        super().__init__('ld.lld', *args, **kwargs)


class CcrxDynamicLinker(DynamicLinker):

    """Linker for Renesis CCrx compiler."""

    def __init__(self, for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        super().__init__('rlink', ['rlink.exe'], for_machine, '', [],
                         version=version)

    def get_accepts_rsp(self) -> bool:
        return False

    def get_lib_prefix(self) -> str:
        return '-lib='

    def get_std_shared_lib_args(self) -> T.List[str]:
        return []

    def get_output_args(self, outputname: str) -> T.List[str]:
        return ['-output=%s' % outputname]

    def get_search_args(self, dirname: str) -> 'T.NoReturn':
        raise EnvironmentError('rlink.exe does not have a search dir argument')

    def get_allow_undefined_args(self) -> T.List[str]:
        return []

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        return []


class ArmDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """Linker for the ARM compiler."""

    def __init__(self, for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        super().__init__('armlink', ['armlink'], for_machine, '', [],
                         version=version)

    def get_accepts_rsp(self) -> bool:
        return False

    def get_std_shared_lib_args(self) -> 'T.NoReturn':
        raise mesonlib.MesonException('The Arm Linkers do not support shared libraries')

    def get_allow_undefined_args(self) -> T.List[str]:
        return []


class ArmClangDynamicLinker(ArmDynamicLinker):

    """Linker used with ARM's clang fork.

    The interface is similar enough to the old ARM ld that it inherits and
    extends a few things as needed.
    """

    def export_dynamic_args(self, env: 'Environment') -> T.List[str]:
        return ['--export_dynamic']

    def import_library_args(self, implibname: str) -> T.List[str]:
        return ['--symdefs=' + implibname]


class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """PGI linker."""

    def __init__(self, *args, **kwargs):
        super().__init__('pgi', *args, **kwargs)

    def get_allow_undefined_args(self) -> T.List[str]:
        return []

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        return []

    def get_std_shared_lib_args(self) -> T.List[str]:
        # PGI -shared is Linux only.
        if mesonlib.is_windows():
            return ['-Bdynamic', '-Mmakedll']
        elif mesonlib.is_linux():
            return ['-shared']
        return []

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: str, build_rpath: str,
                         install_rpath: str) -> T.List[str]:
        if not env.machines[self.for_machine].is_windows():
            return ['-R' + os.path.join(build_dir, p) for p in rpath_paths]
        return []


class PGIStaticLinker(StaticLinker):
    def __init__(self, exelist: T.List[str]):
        super().__init__(exelist)
        self.id = 'ar'
        self.std_args = ['-r']

    def get_std_link_args(self) -> T.List[str]:
        return self.std_args

    def get_output_args(self, target: str) -> T.List[str]:
        return [target]


class VisualStudioLikeLinkerMixin:

    _BUILDTYPE_ARGS = {
        'plain': [],
        'debug': [],
        'debugoptimized': [],
        # The otherwise implicit REF and ICF linker optimisations are disabled by
        # /DEBUG. REF implies ICF.
        'release': ['/OPT:REF'],
        'minsize': ['/INCREMENTAL:NO', '/OPT:REF'],
        'custom': [],
    }  # type: T.Dict[str, T.List[str]]

    def __init__(self, *args, direct: bool = True, machine: str = 'x86', **kwargs):
        super().__init__(*args, **kwargs)
        self.machine = machine

    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
        return mesonlib.listify([self._apply_prefix(a) for a in self._BUILDTYPE_ARGS[buildtype]])

    def invoked_by_compiler(self) -> bool:
        return not self.direct

    def get_debug_crt_args(self) -> T.List[str]:
        """Arguments needed to select a debug crt for the linker.

        Sometimes we need to manually select the CRT (C runtime) to use with
        MSVC. One example is when trying to link with static libraries since
        MSVC won't auto-select a CRT for us in that case and will error out
        asking us to select one.
        """
        return self._apply_prefix('/MDd')

    def get_output_args(self, outputname: str) -> T.List[str]:
        return self._apply_prefix(['/MACHINE:' + self.machine, '/OUT:' + outputname])

    def get_always_args(self) -> T.List[str]:
        return self._apply_prefix('/nologo') + super().get_always_args()

    def get_search_args(self, dirname: str) -> T.List[str]:
        return self._apply_prefix('/LIBPATH:' + dirname)

    def get_std_shared_lib_args(self) -> T.List[str]:
        return self._apply_prefix('/DLL')

    def get_debugfile_args(self, targetfile: str) -> T.List[str]:
        pdbarr = targetfile.split('.')[:-1]
        pdbarr += ['pdb']
        return self._apply_prefix(['/DEBUG', '/PDB:' + '.'.join(pdbarr)])

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        # Only since VS2015
        args = mesonlib.listify(args)
        l = []  # T.List[str]
        for a in args:
            l.extend(self._apply_prefix('/WHOLEARCHIVE:' + a))
        return l

    def get_allow_undefined_args(self) -> T.List[str]:
        return []

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        return []


class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):

    """Microsoft's Link.exe."""

    def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *,
                 exelist: T.Optional[T.List[str]] = None,
                 prefix: T.Union[str, T.List[str]] = '',
                 machine: str = 'x86', version: str = 'unknown version',
                 direct: bool = True):
        super().__init__('link', exelist or ['link.exe'], for_machine,
                         prefix, always_args, machine=machine, version=version, direct=direct)

    def get_always_args(self) -> T.List[str]:
        return self._apply_prefix(['/nologo', '/release']) + super().get_always_args()


class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):

    """Clang's lld-link.exe."""

    def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *,
                 exelist: T.Optional[T.List[str]] = None,
                 prefix: T.Union[str, T.List[str]] = '',
                 machine: str = 'x86', version: str = 'unknown version',
                 direct: bool = True):
        super().__init__('lld-link', exelist or ['lld-link.exe'], for_machine,
                         prefix, always_args, machine=machine, version=version, direct=direct)


class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):

    """Intel's Xilink.exe."""

    def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str],
                 *, version: str = 'unknown version'):
        super().__init__('xilink', ['xilink.exe'], for_machine, '', always_args, version=version)


class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):

    """Sys-V derived linker used on Solaris and OpenSolaris."""

    def __init__(self, *args, **kwargs):
        super().__init__('ld.solaris', *args, **kwargs)

    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
        if not args:
            return args
        return self._apply_prefix('--whole-archive') + args + self._apply_prefix('--no-whole-archive')

    def no_undefined_args(self) -> T.List[str]:
        return ['-z', 'defs']

    def get_allow_undefined_args(self) -> T.List[str]:
        return ['-z', 'nodefs']

    def fatal_warnings(self) -> T.List[str]:
        return ['-z', 'fatal-warnings']

    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
                         rpath_paths: str, build_rpath: str,
                         install_rpath: str) -> T.List[str]:
        if not rpath_paths and not install_rpath and not build_rpath:
            return []
        processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
        all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths])
        if build_rpath != '':
            all_paths.add(build_rpath)

        # In order to avoid relinking for RPATH removal, the binary needs to contain just
        # enough space in the ELF header to hold the final installation RPATH.
        paths = ':'.join(all_paths)
        if len(paths) < len(install_rpath):
            padding = 'X' * (len(install_rpath) - len(paths))
            if not paths:
                paths = padding
            else:
                paths = paths + ':' + padding
        return self._apply_prefix('-rpath,{}'.format(paths))

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        sostr = '' if soversion is None else '.' + soversion
        return self._apply_prefix('-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr))


class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):

    """Digital Mars dynamic linker for windows."""

    def __init__(self, for_machine: mesonlib.MachineChoice,
                 *, version: str = 'unknown version'):
        # Use optlink instead of link so we don't interfer with other link.exe
        # implementations.
        super().__init__('optlink', ['optlink.exe'], for_machine, '', [], version=version)

    def get_allow_undefined_args(self) -> T.List[str]:
        return []


class CudaLinker(PosixDynamicLinkerMixin, DynamicLinker):
    """Cuda linker (nvlink)"""

    def __init__(self, *args, **kwargs):
        super().__init__('nvlink', *args, **kwargs)

    @staticmethod
    def parse_version():
        version_cmd = ['nvlink', '--version']
        try:
            _, out, _ = mesonlib.Popen_safe(version_cmd)
        except OSError:
            return 'unknown version'
        # Output example:
        # nvlink: NVIDIA (R) Cuda linker
        # Copyright (c) 2005-2018 NVIDIA Corporation
        # Built on Sun_Sep_30_21:09:22_CDT_2018
        # Cuda compilation tools, release 10.0, V10.0.166
        # we need the most verbose version output. Luckily starting with V
        return out.strip().split('V')[-1]

    def get_accepts_rsp(self) -> bool:
        # nvcc does not support response files
        return False

    def get_lib_prefix(self) -> str:
        if not mesonlib.is_windows():
            return ''
        # nvcc doesn't recognize Meson's default .a extension for static libraries on
        # Windows and passes it to cl as an object file, resulting in 'warning D9024 :
        # unrecognized source file type 'xxx.a', object file assumed'.
        #
        # nvcc's --library= option doesn't help: it takes the library name without the
        # extension and assumes that the extension on Windows is .lib; prefixing the
        # library with -Xlinker= seems to work.
        from .compilers import CudaCompiler
        return CudaCompiler.LINKER_PREFIX

    def fatal_warnings(self) -> T.List[str]:
        return ['--warning-as-error']

    def get_allow_undefined_args(self) -> T.List[str]:
        return []

    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
                        suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
                        is_shared_module: bool) -> T.List[str]:
        return []
meson-0.53.2/mesonbuild/mconf.py0000644000175000017500000002722513571777336020164 0ustar  jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
from . import coredata, environment, mesonlib, build, mintro, mlog
from .ast import AstIDGenerator

def add_arguments(parser):
    coredata.register_builtin_arguments(parser)
    parser.add_argument('builddir', nargs='?', default='.')
    parser.add_argument('--clearcache', action='store_true', default=False,
                        help='Clear cached state (e.g. found dependencies)')


def make_lower_case(val):
    if isinstance(val, bool):
        return str(val).lower()
    elif isinstance(val, list):
        return [make_lower_case(i) for i in val]
    else:
        return str(val)


class ConfException(mesonlib.MesonException):
    pass


class Conf:
    def __init__(self, build_dir):
        self.build_dir = os.path.abspath(os.path.realpath(build_dir))
        if 'meson.build' in [os.path.basename(self.build_dir), self.build_dir]:
            self.build_dir = os.path.dirname(self.build_dir)
        self.build = None
        self.max_choices_line_length = 60
        self.name_col = []
        self.value_col = []
        self.choices_col = []
        self.descr_col = []
        self.has_choices = False
        self.all_subprojects = set()
        self.yielding_options = set()

        if os.path.isdir(os.path.join(self.build_dir, 'meson-private')):
            self.build = build.load(self.build_dir)
            self.source_dir = self.build.environment.get_source_dir()
            self.coredata = coredata.load(self.build_dir)
            self.default_values_only = False
        elif os.path.isfile(os.path.join(self.build_dir, environment.build_filename)):
            # Make sure that log entries in other parts of meson don't interfere with the JSON output
            mlog.disable()
            self.source_dir = os.path.abspath(os.path.realpath(self.build_dir))
            intr = mintro.IntrospectionInterpreter(self.source_dir, '', 'ninja', visitors = [AstIDGenerator()])
            intr.analyze()
            # Re-enable logging just in case
            mlog.enable()
            self.coredata = intr.coredata
            self.default_values_only = True
        else:
            raise ConfException('Directory {} is neither a Meson build directory nor a project source directory.'.format(build_dir))

    def clear_cache(self):
        self.coredata.deps.host.clear()
        self.coredata.deps.build.clear()

    def set_options(self, options):
        self.coredata.set_options(options)

    def save(self):
        # Do nothing when using introspection
        if self.default_values_only:
            return
        # Only called if something has changed so overwrite unconditionally.
        coredata.save(self.coredata, self.build_dir)
        # We don't write the build file because any changes to it
        # are erased when Meson is executed the next time, i.e. when
        # Ninja is run.

    def print_aligned(self):
        col_widths = (max([len(i) for i in self.name_col], default=0),
                      max([len(i) for i in self.value_col], default=0),
                      max([len(i) for i in self.choices_col], default=0))

        for line in zip(self.name_col, self.value_col, self.choices_col, self.descr_col):
            if self.has_choices:
                print('{0:{width[0]}} {1:{width[1]}} {2:{width[2]}} {3}'.format(*line, width=col_widths))
            else:
                print('{0:{width[0]}} {1:{width[1]}} {3}'.format(*line, width=col_widths))

    def split_options_per_subproject(self, options):
        result = {}
        for k, o in options.items():
            subproject = ''
            if ':' in k:
                subproject, optname = k.split(':')
                if o.yielding and optname in options:
                    self.yielding_options.add(k)
                self.all_subprojects.add(subproject)
            result.setdefault(subproject, {})[k] = o
        return result

    def _add_line(self, name, value, choices, descr):
        self.name_col.append(' ' * self.print_margin + name)
        self.value_col.append(value)
        self.choices_col.append(choices)
        self.descr_col.append(descr)

    def add_option(self, name, descr, value, choices):
        if isinstance(value, list):
            value = '[{0}]'.format(', '.join(make_lower_case(value)))
        else:
            value = make_lower_case(value)

        if choices:
            self.has_choices = True
            if isinstance(choices, list):
                choices_list = make_lower_case(choices)
                current = '['
                while choices_list:
                    i = choices_list.pop(0)
                    if len(current) + len(i) >= self.max_choices_line_length:
                        self._add_line(name, value, current + ',', descr)
                        name = ''
                        value = ''
                        descr = ''
                        current = ' '
                    if len(current) > 1:
                        current += ', '
                    current += i
                choices = current + ']'
            else:
                choices = make_lower_case(choices)
        else:
            choices = ''

        self._add_line(name, value, choices, descr)

    def add_title(self, title):
        titles = {'descr': 'Description', 'value': 'Current Value', 'choices': 'Possible Values'}
        if self.default_values_only:
            titles['value'] = 'Default Value'
        self._add_line('', '', '', '')
        self._add_line(title, titles['value'], titles['choices'], titles['descr'])
        self._add_line('-' * len(title), '-' * len(titles['value']), '-' * len(titles['choices']), '-' * len(titles['descr']))

    def add_section(self, section):
        self.print_margin = 0
        self._add_line('', '', '', '')
        self._add_line(section + ':', '', '', '')
        self.print_margin = 2

    def print_options(self, title, options):
        if not options:
            return
        if title:
            self.add_title(title)
        for k, o in sorted(options.items()):
            printable_value = o.printable_value()
            if k in self.yielding_options:
                printable_value = ''
            self.add_option(k, o.description, printable_value, o.choices)

    def print_conf(self):
        def print_default_values_warning():
            mlog.warning('The source directory instead of the build directory was specified.')
            mlog.warning('Only the default values for the project are printed, and all command line parameters are ignored.')

        if self.default_values_only:
            print_default_values_warning()
            print('')

        print('Core properties:')
        print('  Source dir', self.source_dir)
        if not self.default_values_only:
            print('  Build dir ', self.build_dir)

        dir_option_names = ['bindir',
                            'datadir',
                            'includedir',
                            'infodir',
                            'libdir',
                            'libexecdir',
                            'localedir',
                            'localstatedir',
                            'mandir',
                            'prefix',
                            'sbindir',
                            'sharedstatedir',
                            'sysconfdir']
        test_option_names = ['errorlogs',
                             'stdsplit']
        core_option_names = [k for k in self.coredata.builtins if k not in dir_option_names + test_option_names]

        dir_options = {k: o for k, o in self.coredata.builtins.items() if k in dir_option_names}
        test_options = {k: o for k, o in self.coredata.builtins.items() if k in test_option_names}
        core_options = {k: o for k, o in self.coredata.builtins.items() if k in core_option_names}

        def insert_build_prefix(k):
            idx = k.find(':')
            if idx < 0:
                return 'build.' + k
            return k[:idx + 1] + 'build.' + k[idx + 1:]

        core_options = self.split_options_per_subproject(core_options)
        host_compiler_options = self.split_options_per_subproject(self.coredata.compiler_options.host)
        build_compiler_options = self.split_options_per_subproject({insert_build_prefix(k): o for k, o in self.coredata.compiler_options.build.items()})
        project_options = self.split_options_per_subproject(self.coredata.user_options)
        show_build_options = self.default_values_only or self.build.environment.is_cross_build()

        self.add_section('Main project options')
        self.print_options('Core options', core_options[''])
        self.print_options('', self.coredata.builtins_per_machine.host)
        if show_build_options:
            self.print_options('', {insert_build_prefix(k): o for k, o in self.coredata.builtins_per_machine.build.items()})
        self.print_options('Backend options', self.coredata.backend_options)
        self.print_options('Base options', self.coredata.base_options)
        self.print_options('Compiler options', host_compiler_options.get('', {}))
        if show_build_options:
            self.print_options('', build_compiler_options.get('', {}))
        self.print_options('Directories', dir_options)
        self.print_options('Testing options', test_options)
        self.print_options('Project options', project_options.get('', {}))
        for subproject in sorted(self.all_subprojects):
            if subproject == '':
                continue
            self.add_section('Subproject ' + subproject)
            if subproject in core_options:
                self.print_options('Core options', core_options[subproject])
            if subproject in host_compiler_options:
                self.print_options('Compiler options', host_compiler_options[subproject])
            if subproject in build_compiler_options and show_build_options:
                self.print_options('', build_compiler_options[subproject])
            if subproject in project_options:
                self.print_options('Project options', project_options[subproject])
        self.print_aligned()

        # Print the warning twice so that the user shouldn't be able to miss it
        if self.default_values_only:
            print('')
            print_default_values_warning()

def run(options):
    coredata.parse_cmd_line_options(options)
    builddir = os.path.abspath(os.path.realpath(options.builddir))
    c = None
    try:
        c = Conf(builddir)
        if c.default_values_only:
            c.print_conf()
            return 0

        save = False
        if len(options.cmd_line_options) > 0:
            c.set_options(options.cmd_line_options)
            coredata.update_cmd_line_file(builddir, options)
            save = True
        elif options.clearcache:
            c.clear_cache()
            save = True
        else:
            c.print_conf()
        if save:
            c.save()
            mintro.update_build_options(c.coredata, c.build.environment.info_dir)
            mintro.write_meson_info_file(c.build, [])
    except ConfException as e:
        print('Meson configurator encountered an error:')
        if c is not None and c.build is not None:
            mintro.write_meson_info_file(c.build, [e])
        raise e
    return 0
meson-0.53.2/mesonbuild/mdist.py0000644000175000017500000002401513612417061020152 0ustar  jpakkanejpakkane00000000000000# Copyright 2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import gzip
import os
import sys
import shutil
import subprocess
import hashlib
import json
from glob import glob
from pathlib import Path
from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import windows_proof_rmtree, MesonException
from mesonbuild.wrap import wrap
from mesonbuild import mlog, build

archive_choices = ['gztar', 'xztar', 'zip']
archive_extension = {'gztar': '.tar.gz',
                     'xztar': '.tar.xz',
                     'zip': '.zip'}

def add_arguments(parser):
    parser.add_argument('-C', default='.', dest='wd',
                        help='directory to cd into before running')
    parser.add_argument('--formats', default='xztar',
                        help='Comma separated list of archive types to create.')
    parser.add_argument('--include-subprojects', action='store_true',
                        help='Include source code of subprojects that have been used for the build.')


def create_hash(fname):
    hashname = fname + '.sha256sum'
    m = hashlib.sha256()
    m.update(open(fname, 'rb').read())
    with open(hashname, 'w') as f:
        f.write('%s %s\n' % (m.hexdigest(), os.path.basename(fname)))


def del_gitfiles(dirname):
    for f in glob(os.path.join(dirname, '.git*')):
        if os.path.isdir(f) and not os.path.islink(f):
            windows_proof_rmtree(f)
        else:
            os.unlink(f)

def process_submodules(dirname):
    module_file = os.path.join(dirname, '.gitmodules')
    if not os.path.exists(module_file):
        return
    subprocess.check_call(['git', 'submodule', 'update', '--init', '--recursive'], cwd=dirname)
    for line in open(module_file):
        line = line.strip()
        if '=' not in line:
            continue
        k, v = line.split('=', 1)
        k = k.strip()
        v = v.strip()
        if k != 'path':
            continue
        del_gitfiles(os.path.join(dirname, v))


def run_dist_scripts(dist_root, dist_scripts):
    assert(os.path.isabs(dist_root))
    env = os.environ.copy()
    env['MESON_DIST_ROOT'] = dist_root
    for d in dist_scripts:
        script = d['exe']
        args = d['args']
        name = ' '.join(script + args)
        print('Running custom dist script {!r}'.format(name))
        try:
            rc = subprocess.call(script + args, env=env)
            if rc != 0:
                sys.exit('Dist script errored out')
        except OSError:
            print('Failed to run dist script {!r}'.format(name))
            sys.exit(1)

def is_git(src_root):
    _git = os.path.join(src_root, '.git')
    return os.path.isdir(_git) or os.path.isfile(_git)

def git_have_dirty_index(src_root):
    '''Check whether there are uncommitted changes in git'''
    ret = subprocess.call(['git', '-C', src_root, 'diff-index', '--quiet', 'HEAD'])
    return ret == 1

def git_clone(src_root, distdir):
    if git_have_dirty_index(src_root):
        mlog.warning('Repository has uncommitted changes that will not be included in the dist tarball')
    if os.path.exists(distdir):
        shutil.rmtree(distdir)
    os.makedirs(distdir)
    subprocess.check_call(['git', 'clone', '--shared', src_root, distdir])
    process_submodules(distdir)
    del_gitfiles(distdir)

def create_dist_git(dist_name, archives, src_root, bld_root, dist_sub, dist_scripts, subprojects):
    distdir = os.path.join(dist_sub, dist_name)
    git_clone(src_root, distdir)
    for path in subprojects:
        sub_src_root = os.path.join(src_root, path)
        sub_distdir = os.path.join(distdir, path)
        if os.path.exists(sub_distdir):
            continue
        if is_git(sub_src_root):
            git_clone(sub_src_root, sub_distdir)
        else:
            shutil.copytree(sub_src_root, sub_distdir)
    run_dist_scripts(distdir, dist_scripts)
    output_names = []
    for a in archives:
        compressed_name = distdir + archive_extension[a]
        shutil.make_archive(distdir, a, root_dir=dist_sub, base_dir=dist_name)
        output_names.append(compressed_name)
    shutil.rmtree(distdir)
    return output_names

def is_hg(src_root):
    return os.path.isdir(os.path.join(src_root, '.hg'))

def hg_have_dirty_index(src_root):
    '''Check whether there are uncommitted changes in hg'''
    out = subprocess.check_output(['hg', '-R', src_root, 'summary'])
    return b'commit: (clean)' not in out

def create_dist_hg(dist_name, archives, src_root, bld_root, dist_sub, dist_scripts):
    if hg_have_dirty_index(src_root):
        mlog.warning('Repository has uncommitted changes that will not be included in the dist tarball')

    os.makedirs(dist_sub, exist_ok=True)
    tarname = os.path.join(dist_sub, dist_name + '.tar')
    xzname = tarname + '.xz'
    gzname = tarname + '.gz'
    zipname = os.path.join(dist_sub, dist_name + '.zip')
    subprocess.check_call(['hg', 'archive', '-R', src_root, '-S', '-t', 'tar', tarname])
    output_names = []
    if dist_scripts:
        mlog.warning('dist scripts are not supported in Mercurial projects')
    if 'xztar' in archives:
        import lzma
        with lzma.open(xzname, 'wb') as xf, open(tarname, 'rb') as tf:
            shutil.copyfileobj(tf, xf)
        output_names.append(xzname)
    if 'gztar' in archives:
        with gzip.open(gzname, 'wb') as zf, open(tarname, 'rb') as tf:
            shutil.copyfileobj(tf, zf)
        output_names.append(gzname)
    os.unlink(tarname)
    if 'zip' in archives:
        subprocess.check_call(['hg', 'archive', '-R', src_root, '-S', '-t', 'zip', zipname])
        output_names.append(zipname)
    return output_names


def check_dist(packagename, meson_command, extra_meson_args, bld_root, privdir):
    print('Testing distribution package %s' % packagename)
    unpackdir = os.path.join(privdir, 'dist-unpack')
    builddir = os.path.join(privdir, 'dist-build')
    installdir = os.path.join(privdir, 'dist-install')
    for p in (unpackdir, builddir, installdir):
        if os.path.exists(p):
            shutil.rmtree(p)
        os.mkdir(p)
    ninja_bin = detect_ninja()
    try:
        shutil.unpack_archive(packagename, unpackdir)
        unpacked_files = glob(os.path.join(unpackdir, '*'))
        assert(len(unpacked_files) == 1)
        unpacked_src_dir = unpacked_files[0]
        with open(os.path.join(bld_root, 'meson-info', 'intro-buildoptions.json')) as boptions:
            meson_command += ['-D{name}={value}'.format(**o) for o in json.load(boptions)
                              if o['name'] not in ['backend', 'install_umask']]
        meson_command += extra_meson_args
        if subprocess.call(meson_command + ['--backend=ninja', unpacked_src_dir, builddir]) != 0:
            print('Running Meson on distribution package failed')
            return 1
        if subprocess.call([ninja_bin], cwd=builddir) != 0:
            print('Compiling the distribution package failed')
            return 1
        if subprocess.call([ninja_bin, 'test'], cwd=builddir) != 0:
            print('Running unit tests on the distribution package failed')
            return 1
        myenv = os.environ.copy()
        myenv['DESTDIR'] = installdir
        if subprocess.call([ninja_bin, 'install'], cwd=builddir, env=myenv) != 0:
            print('Installing the distribution package failed')
            return 1
    finally:
        shutil.rmtree(unpackdir)
        shutil.rmtree(builddir)
        shutil.rmtree(installdir)
    print('Distribution package %s tested' % packagename)
    return 0

def determine_archives_to_generate(options):
    result = []
    for i in options.formats.split(','):
        if i not in archive_choices:
            sys.exit('Value "{}" not one of permitted values {}.'.format(i, archive_choices))
        result.append(i)
    if len(i) == 0:
        sys.exit('No archive types specified.')
    return result

def run(options):
    options.wd = os.path.abspath(options.wd)
    buildfile = Path(options.wd) / 'meson-private' / 'build.dat'
    if not buildfile.is_file():
        raise MesonException('Directory {!r} does not seem to be a Meson build directory.'.format(options.wd))
    b = build.load(options.wd)
    # This import must be load delayed, otherwise it will get the default
    # value of None.
    from mesonbuild.mesonlib import meson_command
    src_root = b.environment.source_dir
    bld_root = b.environment.build_dir
    priv_dir = os.path.join(bld_root, 'meson-private')
    dist_sub = os.path.join(bld_root, 'meson-dist')

    dist_name = b.project_name + '-' + b.project_version

    archives = determine_archives_to_generate(options)

    subprojects = []
    extra_meson_args = []
    if options.include_subprojects:
        subproject_dir = os.path.join(src_root, b.subproject_dir)
        for sub in b.subprojects:
            _, directory = wrap.get_directory(subproject_dir, sub)
            subprojects.append(os.path.join(b.subproject_dir, directory))
        extra_meson_args.append('-Dwrap_mode=nodownload')

    if is_git(src_root):
        names = create_dist_git(dist_name, archives, src_root, bld_root, dist_sub, b.dist_scripts, subprojects)
    elif is_hg(src_root):
        if subprojects:
            print('--include-subprojects option currently not supported with Mercurial')
            return 1
        names = create_dist_hg(dist_name, archives, src_root, bld_root, dist_sub, b.dist_scripts)
    else:
        print('Dist currently only works with Git or Mercurial repos')
        return 1
    if names is None:
        return 1
    # Check only one.
    rc = check_dist(names[0], meson_command, extra_meson_args, bld_root, priv_dir)
    if rc == 0:
        for name in names:
            create_hash(name)
    return rc
meson-0.53.2/mesonbuild/mesonlib.py0000644000175000017500000015446013625260316020655 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A library of random helper functionality."""
from pathlib import Path
import sys
import stat
import time
import platform, subprocess, operator, os, shlex, shutil, re
import collections
from enum import Enum
from functools import lru_cache, update_wrapper
from itertools import tee, filterfalse
import typing as T
import uuid

from mesonbuild import mlog

_T = T.TypeVar('_T')
_U = T.TypeVar('_U')

have_fcntl = False
have_msvcrt = False
# {subproject: project_meson_version}
project_meson_versions = {}

try:
    import fcntl
    have_fcntl = True
except Exception:
    pass

try:
    import msvcrt
    have_msvcrt = True
except Exception:
    pass

from glob import glob

if os.path.basename(sys.executable) == 'meson.exe':
    # In Windows and using the MSI installed executable.
    python_command = [sys.executable, 'runpython']
else:
    python_command = [sys.executable]
meson_command = None

GIT = shutil.which('git')
def git(cmd: T.List[str], workingdir: str, **kwargs) -> subprocess.CompletedProcess:
    pc = subprocess.run([GIT, '-C', workingdir] + cmd,
                        # Redirect stdin to DEVNULL otherwise git messes up the
                        # console and ANSI colors stop working on Windows.
                        stdin=subprocess.DEVNULL, **kwargs)
    # Sometimes git calls git recursively, such as `git submodule update
    # --recursive` which will be without the above workaround, so set the
    # console mode again just in case.
    mlog.setup_console()
    return pc


def set_meson_command(mainfile):
    global python_command
    global meson_command
    # On UNIX-like systems `meson` is a Python script
    # On Windows `meson` and `meson.exe` are wrapper exes
    if not mainfile.endswith('.py'):
        meson_command = [mainfile]
    elif os.path.isabs(mainfile) and mainfile.endswith('mesonmain.py'):
        # Can't actually run meson with an absolute path to mesonmain.py, it must be run as -m mesonbuild.mesonmain
        meson_command = python_command + ['-m', 'mesonbuild.mesonmain']
    else:
        # Either run uninstalled, or full path to meson-script.py
        meson_command = python_command + [mainfile]
    # We print this value for unit tests.
    if 'MESON_COMMAND_TESTS' in os.environ:
        mlog.log('meson_command is {!r}'.format(meson_command))

def is_ascii_string(astring) -> bool:
    try:
        if isinstance(astring, str):
            astring.encode('ascii')
        elif isinstance(astring, bytes):
            astring.decode('ascii')
    except UnicodeDecodeError:
        return False
    return True

def check_direntry_issues(direntry_array):
    import locale
    # Warn if the locale is not UTF-8. This can cause various unfixable issues
    # such as os.stat not being able to decode filenames with unicode in them.
    # There is no way to reset both the preferred encoding and the filesystem
    # encoding, so we can just warn about it.
    e = locale.getpreferredencoding()
    if e.upper() != 'UTF-8' and not is_windows():
        if not isinstance(direntry_array, list):
            direntry_array = [direntry_array]
        for de in direntry_array:
            if is_ascii_string(de):
                continue
            mlog.warning('''You are using {!r} which is not a Unicode-compatible '
locale but you are trying to access a file system entry called {!r} which is
not pure ASCII. This may cause problems.
'''.format(e, de), file=sys.stderr)

# Put this in objects that should not get dumped to pickle files
# by accident.
import threading
an_unpicklable_object = threading.Lock()

class MesonException(Exception):
    '''Exceptions thrown by Meson'''

    def get_msg_with_context(self):
        s = ''
        if hasattr(self, 'lineno') and hasattr(self, 'file'):
            s = get_error_location_string(self.file, self.lineno) + ' '
        s += str(self)
        return s

class EnvironmentException(MesonException):
    '''Exceptions thrown while processing and creating the build environment'''

class FileMode:
    # The first triad is for owner permissions, the second for group permissions,
    # and the third for others (everyone else).
    # For the 1st character:
    #  'r' means can read
    #  '-' means not allowed
    # For the 2nd character:
    #  'w' means can write
    #  '-' means not allowed
    # For the 3rd character:
    #  'x' means can execute
    #  's' means can execute and setuid/setgid is set (owner/group triads only)
    #  'S' means cannot execute and setuid/setgid is set (owner/group triads only)
    #  't' means can execute and sticky bit is set ("others" triads only)
    #  'T' means cannot execute and sticky bit is set ("others" triads only)
    #  '-' means none of these are allowed
    #
    # The meanings of 'rwx' perms is not obvious for directories; see:
    # https://www.hackinglinuxexposed.com/articles/20030424.html
    #
    # For information on this notation such as setuid/setgid/sticky bits, see:
    # https://en.wikipedia.org/wiki/File_system_permissions#Symbolic_notation
    symbolic_perms_regex = re.compile('[r-][w-][xsS-]' # Owner perms
                                      '[r-][w-][xsS-]' # Group perms
                                      '[r-][w-][xtT-]') # Others perms

    def __init__(self, perms=None, owner=None, group=None):
        self.perms_s = perms
        self.perms = self.perms_s_to_bits(perms)
        self.owner = owner
        self.group = group

    def __repr__(self):
        ret = ' str:
        return self.relative_name()

    def __repr__(self) -> str:
        ret = ' str:
        if self.is_built:
            return self.relative_name()
        else:
            return os.path.join(build_to_src, self.subdir, self.fname)

    @lru_cache(maxsize=None)
    def absolute_path(self, srcdir: str, builddir: str) -> str:
        absdir = srcdir
        if self.is_built:
            absdir = builddir
        return os.path.join(absdir, self.relative_name())

    def endswith(self, ending: str) -> bool:
        return self.fname.endswith(ending)

    def split(self, s: str) -> T.List[str]:
        return self.fname.split(s)

    def __eq__(self, other) -> bool:
        return (self.fname, self.subdir, self.is_built) == (other.fname, other.subdir, other.is_built)

    def __hash__(self) -> int:
        return hash((self.fname, self.subdir, self.is_built))

    @lru_cache(maxsize=None)
    def relative_name(self) -> str:
        return os.path.join(self.subdir, self.fname)


def get_compiler_for_source(compilers, src):
    for comp in compilers:
        if comp.can_compile(src):
            return comp
    raise MesonException('No specified compiler can handle file {!s}'.format(src))

def classify_unity_sources(compilers, sources):
    compsrclist = {}
    for src in sources:
        comp = get_compiler_for_source(compilers, src)
        if comp not in compsrclist:
            compsrclist[comp] = [src]
        else:
            compsrclist[comp].append(src)
    return compsrclist

class OrderedEnum(Enum):
    """
    An Enum which additionally offers homogeneous ordered comparison.
    """
    def __ge__(self, other):
        if self.__class__ is other.__class__:
            return self.value >= other.value
        return NotImplemented

    def __gt__(self, other):
        if self.__class__ is other.__class__:
            return self.value > other.value
        return NotImplemented

    def __le__(self, other):
        if self.__class__ is other.__class__:
            return self.value <= other.value
        return NotImplemented

    def __lt__(self, other):
        if self.__class__ is other.__class__:
            return self.value < other.value
        return NotImplemented


class MachineChoice(OrderedEnum):

    """Enum class representing one of the two abstract machine names used in
    most places: the build, and host, machines.
    """

    BUILD = 0
    HOST = 1

    def get_lower_case_name(self):
        return PerMachine('build', 'host')[self]

    def get_prefix(self):
        return PerMachine('build.', '')[self]


class PerMachine(T.Generic[_T]):
    def __init__(self, build: _T, host: _T):
        self.build = build
        self.host = host

    def __getitem__(self, machine: MachineChoice) -> _T:
        return {
            MachineChoice.BUILD:  self.build,
            MachineChoice.HOST:   self.host,
        }[machine]

    def __setitem__(self, machine: MachineChoice, val: _T) -> None:
        setattr(self, machine.get_lower_case_name(), val)

    def miss_defaulting(self) -> "PerMachineDefaultable[T.Optional[_T]]":
        """Unset definition duplicated from their previous to None

        This is the inverse of ''default_missing''. By removing defaulted
        machines, we can elaborate the original and then redefault them and thus
        avoid repeating the elaboration explicitly.
        """
        unfreeze = PerMachineDefaultable() # type: PerMachineDefaultable[T.Optional[_T]]
        unfreeze.build = self.build
        unfreeze.host = self.host
        if unfreeze.host == unfreeze.build:
            unfreeze.host = None
        return unfreeze


class PerThreeMachine(PerMachine[_T]):
    """Like `PerMachine` but includes `target` too.

    It turns out just one thing do we need track the target machine. There's no
    need to computer the `target` field so we don't bother overriding the
    `__getitem__`/`__setitem__` methods.
    """
    def __init__(self, build: _T, host: _T, target: _T):
        super().__init__(build, host)
        self.target = target

    def miss_defaulting(self) -> "PerThreeMachineDefaultable[T.Optional[_T]]":
        """Unset definition duplicated from their previous to None

        This is the inverse of ''default_missing''. By removing defaulted
        machines, we can elaborate the original and then redefault them and thus
        avoid repeating the elaboration explicitly.
        """
        unfreeze = PerThreeMachineDefaultable() # type: PerThreeMachineDefaultable[T.Optional[_T]]
        unfreeze.build = self.build
        unfreeze.host = self.host
        unfreeze.target = self.target
        if unfreeze.target == unfreeze.host:
            unfreeze.target = None
        if unfreeze.host == unfreeze.build:
            unfreeze.host = None
        return unfreeze

    def matches_build_machine(self, machine: MachineChoice) -> bool:
        return self.build == self[machine]

class PerMachineDefaultable(PerMachine[T.Optional[_T]]):
    """Extends `PerMachine` with the ability to default from `None`s.
    """
    def __init__(self) -> None:
        super().__init__(None, None)

    def default_missing(self) -> "PerMachine[T.Optional[_T]]":
        """Default host to build

        This allows just specifying nothing in the native case, and just host in the
        cross non-compiler case.
        """
        freeze = PerMachine(self.build, self.host)
        if freeze.host is None:
            freeze.host = freeze.build
        return freeze


class PerThreeMachineDefaultable(PerMachineDefaultable, PerThreeMachine[T.Optional[_T]]):
    """Extends `PerThreeMachine` with the ability to default from `None`s.
    """
    def __init__(self) -> None:
        PerThreeMachine.__init__(self, None, None, None)

    def default_missing(self) -> "PerThreeMachine[T.Optional[_T]]":
        """Default host to build and target to host.

        This allows just specifying nothing in the native case, just host in the
        cross non-compiler case, and just target in the native-built
        cross-compiler case.
        """
        freeze = PerThreeMachine(self.build, self.host, self.target)
        if freeze.host is None:
            freeze.host = freeze.build
        if freeze.target is None:
            freeze.target = freeze.host
        return freeze


def is_sunos() -> bool:
    return platform.system().lower() == 'sunos'

def is_osx() -> bool:
    return platform.system().lower() == 'darwin'

def is_linux() -> bool:
    return platform.system().lower() == 'linux'

def is_android() -> bool:
    return platform.system().lower() == 'android'

def is_haiku() -> bool:
    return platform.system().lower() == 'haiku'

def is_openbsd() -> bool:
    return platform.system().lower() == 'openbsd'

def is_windows() -> bool:
    platname = platform.system().lower()
    return platname == 'windows' or 'mingw' in platname

def is_cygwin() -> bool:
    return platform.system().lower().startswith('cygwin')

def is_debianlike() -> bool:
    return os.path.isfile('/etc/debian_version')

def is_dragonflybsd() -> bool:
    return platform.system().lower() == 'dragonfly'

def is_netbsd() -> bool:
    return platform.system().lower() == 'netbsd'

def is_freebsd() -> bool:
    return platform.system().lower() == 'freebsd'

def exe_exists(arglist: T.List[str]) -> bool:
    try:
        if subprocess.run(arglist, timeout=10).returncode == 0:
            return True
    except (FileNotFoundError, subprocess.TimeoutExpired):
        pass
    return False

@lru_cache(maxsize=None)
def darwin_get_object_archs(objpath):
    '''
    For a specific object (executable, static library, dylib, etc), run `lipo`
    to fetch the list of archs supported by it. Supports both thin objects and
    'fat' objects.
    '''
    _, stdo, stderr = Popen_safe(['lipo', '-info', objpath])
    if not stdo:
        mlog.debug('lipo {}: {}'.format(objpath, stderr))
        return None
    stdo = stdo.rsplit(': ', 1)[1]
    # Convert from lipo-style archs to meson-style CPUs
    stdo = stdo.replace('i386', 'x86')
    stdo = stdo.replace('arm64', 'aarch64')
    # Add generic name for armv7 and armv7s
    if 'armv7' in stdo:
        stdo += ' arm'
    return stdo.split()

def detect_vcs(source_dir):
    vcs_systems = [
        dict(name = 'git',        cmd = 'git', repo_dir = '.git', get_rev = 'git describe --dirty=+', rev_regex = '(.*)', dep = '.git/logs/HEAD'),
        dict(name = 'mercurial',  cmd = 'hg',  repo_dir = '.hg',  get_rev = 'hg id -i',               rev_regex = '(.*)', dep = '.hg/dirstate'),
        dict(name = 'subversion', cmd = 'svn', repo_dir = '.svn', get_rev = 'svn info',               rev_regex = 'Revision: (.*)', dep = '.svn/wc.db'),
        dict(name = 'bazaar',     cmd = 'bzr', repo_dir = '.bzr', get_rev = 'bzr revno',              rev_regex = '(.*)', dep = '.bzr'),
    ]
    # FIXME: this is much cleaner with pathlib.Path
    segs = source_dir.replace('\\', '/').split('/')
    for i in range(len(segs), -1, -1):
        curdir = '/'.join(segs[:i])
        for vcs in vcs_systems:
            if os.path.isdir(os.path.join(curdir, vcs['repo_dir'])) and shutil.which(vcs['cmd']):
                vcs['wc_dir'] = curdir
                return vcs
    return None

# a helper class which implements the same version ordering as RPM
class Version:
    def __init__(self, s):
        self._s = s

        # split into numeric, alphabetic and non-alphanumeric sequences
        sequences = re.finditer(r'(\d+|[a-zA-Z]+|[^a-zA-Z\d]+)', s)
        # non-alphanumeric separators are discarded
        sequences = [m for m in sequences if not re.match(r'[^a-zA-Z\d]+', m.group(1))]
        # numeric sequences are converted from strings to ints
        sequences = [int(m.group(1)) if m.group(1).isdigit() else m.group(1) for m in sequences]

        self._v = sequences

    def __str__(self):
        return '%s (V=%s)' % (self._s, str(self._v))

    def __repr__(self):
        return ''.format(self._s)

    def __lt__(self, other):
        if isinstance(other, Version):
            return self.__cmp(other, operator.lt)
        return NotImplemented

    def __gt__(self, other):
        if isinstance(other, Version):
            return self.__cmp(other, operator.gt)
        return NotImplemented

    def __le__(self, other):
        if isinstance(other, Version):
            return self.__cmp(other, operator.le)
        return NotImplemented

    def __ge__(self, other):
        if isinstance(other, Version):
            return self.__cmp(other, operator.ge)
        return NotImplemented

    def __eq__(self, other):
        if isinstance(other, Version):
            return self._v == other._v
        return NotImplemented

    def __ne__(self, other):
        if isinstance(other, Version):
            return self._v != other._v
        return NotImplemented

    def __cmp(self, other, comparator):
        # compare each sequence in order
        for ours, theirs in zip(self._v, other._v):
            # sort a non-digit sequence before a digit sequence
            ours_is_int = isinstance(ours, int)
            theirs_is_int = isinstance(theirs, int)
            if ours_is_int != theirs_is_int:
                return comparator(ours_is_int, theirs_is_int)

            if ours != theirs:
                return comparator(ours, theirs)

        # if equal length, all components have matched, so equal
        # otherwise, the version with a suffix remaining is greater
        return comparator(len(self._v), len(other._v))

def _version_extract_cmpop(vstr2: str) -> T.Tuple[T.Callable[[T.Any, T.Any], bool], str]:
    if vstr2.startswith('>='):
        cmpop = operator.ge
        vstr2 = vstr2[2:]
    elif vstr2.startswith('<='):
        cmpop = operator.le
        vstr2 = vstr2[2:]
    elif vstr2.startswith('!='):
        cmpop = operator.ne
        vstr2 = vstr2[2:]
    elif vstr2.startswith('=='):
        cmpop = operator.eq
        vstr2 = vstr2[2:]
    elif vstr2.startswith('='):
        cmpop = operator.eq
        vstr2 = vstr2[1:]
    elif vstr2.startswith('>'):
        cmpop = operator.gt
        vstr2 = vstr2[1:]
    elif vstr2.startswith('<'):
        cmpop = operator.lt
        vstr2 = vstr2[1:]
    else:
        cmpop = operator.eq

    return (cmpop, vstr2)

def version_compare(vstr1: str, vstr2: str) -> bool:
    (cmpop, vstr2) = _version_extract_cmpop(vstr2)
    return cmpop(Version(vstr1), Version(vstr2))

def version_compare_many(vstr1, conditions):
    if not isinstance(conditions, (list, tuple, frozenset)):
        conditions = [conditions]
    found = []
    not_found = []
    for req in conditions:
        if not version_compare(vstr1, req):
            not_found.append(req)
        else:
            found.append(req)
    return not_found == [], not_found, found

# determine if the minimum version satisfying the condition |condition| exceeds
# the minimum version for a feature |minimum|
def version_compare_condition_with_min(condition: str, minimum: str) -> bool:
    if condition.startswith('>='):
        cmpop = operator.le
        condition = condition[2:]
    elif condition.startswith('<='):
        return False
    elif condition.startswith('!='):
        return False
    elif condition.startswith('=='):
        cmpop = operator.le
        condition = condition[2:]
    elif condition.startswith('='):
        cmpop = operator.le
        condition = condition[1:]
    elif condition.startswith('>'):
        cmpop = operator.lt
        condition = condition[1:]
    elif condition.startswith('<'):
        return False
    else:
        cmpop = operator.le

    # Declaring a project(meson_version: '>=0.46') and then using features in
    # 0.46.0 is valid, because (knowing the meson versioning scheme) '0.46.0' is
    # the lowest version which satisfies the constraint '>=0.46'.
    #
    # But this will fail here, because the minimum version required by the
    # version constraint ('0.46') is strictly less (in our version comparison)
    # than the minimum version needed for the feature ('0.46.0').
    #
    # Map versions in the constraint of the form '0.46' to '0.46.0', to embed
    # this knowledge of the meson versioning scheme.
    condition = condition.strip()
    if re.match(r'^\d+.\d+$', condition):
        condition += '.0'

    return cmpop(Version(minimum), Version(condition))

def default_libdir():
    if is_debianlike():
        try:
            pc = subprocess.Popen(['dpkg-architecture', '-qDEB_HOST_MULTIARCH'],
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.DEVNULL)
            (stdo, _) = pc.communicate()
            if pc.returncode == 0:
                archpath = stdo.decode().strip()
                return 'lib/' + archpath
        except Exception:
            pass
    if is_freebsd():
        return 'lib'
    if os.path.isdir('/usr/lib64') and not os.path.islink('/usr/lib64'):
        return 'lib64'
    return 'lib'

def default_libexecdir():
    # There is no way to auto-detect this, so it must be set at build time
    return 'libexec'

def default_prefix():
    return 'c:/' if is_windows() else '/usr/local'

def get_library_dirs() -> T.List[str]:
    if is_windows():
        return ['C:/mingw/lib'] # TODO: get programmatically
    if is_osx():
        return ['/usr/lib'] # TODO: get programmatically
    # The following is probably Debian/Ubuntu specific.
    # /usr/local/lib is first because it contains stuff
    # installed by the sysadmin and is probably more up-to-date
    # than /usr/lib. If you feel that this search order is
    # problematic, please raise the issue on the mailing list.
    unixdirs = ['/usr/local/lib', '/usr/lib', '/lib']

    if is_freebsd():
        return unixdirs
    # FIXME: this needs to be further genericized for aarch64 etc.
    machine = platform.machine()
    if machine in ('i386', 'i486', 'i586', 'i686'):
        plat = 'i386'
    elif machine.startswith('arm'):
        plat = 'arm'
    else:
        plat = ''

    # Solaris puts 32-bit libraries in the main /lib & /usr/lib directories
    # and 64-bit libraries in platform specific subdirectories.
    if is_sunos():
        if machine == 'i86pc':
            plat = 'amd64'
        elif machine.startswith('sun4'):
            plat = 'sparcv9'

    usr_platdir = Path('/usr/lib/') / plat
    if usr_platdir.is_dir():
        unixdirs += [str(x) for x in (usr_platdir).iterdir() if x.is_dir()]
    if os.path.exists('/usr/lib64'):
        unixdirs.append('/usr/lib64')

    lib_platdir = Path('/lib/') / plat
    if lib_platdir.is_dir():
        unixdirs += [str(x) for x in (lib_platdir).iterdir() if x.is_dir()]
    if os.path.exists('/lib64'):
        unixdirs.append('/lib64')

    return unixdirs

def has_path_sep(name, sep='/\\'):
    'Checks if any of the specified @sep path separators are in @name'
    for each in sep:
        if each in name:
            return True
    return False


if is_windows():
    # shlex.split is not suitable for splitting command line on Window (https://bugs.python.org/issue1724822);
    # shlex.quote is similarly problematic. Below are "proper" implementations of these functions according to
    # https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and
    # https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/

    _whitespace = ' \t\n\r'
    _find_unsafe_char = re.compile(r'[{}"]'.format(_whitespace)).search

    def quote_arg(arg):
        if arg and not _find_unsafe_char(arg):
            return arg

        result = '"'
        num_backslashes = 0
        for c in arg:
            if c == '\\':
                num_backslashes += 1
            else:
                if c == '"':
                    # Escape all backslashes and the following double quotation mark
                    num_backslashes = num_backslashes * 2 + 1

                result += num_backslashes * '\\' + c
                num_backslashes = 0

        # Escape all backslashes, but let the terminating double quotation
        # mark we add below be interpreted as a metacharacter
        result += (num_backslashes * 2) * '\\' + '"'
        return result

    def split_args(cmd: T.Sequence[str]) -> T.List[str]:
        result = []
        arg = ''
        num_backslashes = 0
        num_quotes = 0
        in_quotes = False
        for c in cmd:
            if c == '\\':
                num_backslashes += 1
            else:
                if c == '"' and not (num_backslashes % 2):
                    # unescaped quote, eat it
                    arg += (num_backslashes // 2) * '\\'
                    num_quotes += 1
                    in_quotes = not in_quotes
                elif c in _whitespace and not in_quotes:
                    if arg or num_quotes:
                        # reached the end of the argument
                        result.append(arg)
                        arg = ''
                        num_quotes = 0
                else:
                    if c == '"':
                        # escaped quote
                        num_backslashes = (num_backslashes - 1) // 2

                    arg += num_backslashes * '\\' + c

                num_backslashes = 0

        if arg or num_quotes:
            result.append(arg)

        return result
else:
    def quote_arg(arg):
        return shlex.quote(arg)

    def split_args(cmd):
        return shlex.split(cmd)


def join_args(args):
    return ' '.join([quote_arg(x) for x in args])


def do_replacement(regex, line, variable_format, confdata):
    missing_variables = set()
    start_tag = '@'
    backslash_tag = '\\@'
    if variable_format == 'cmake':
        start_tag = '${'
        backslash_tag = '\\${'

    def variable_replace(match):
        # Pairs of escape characters before '@' or '\@'
        if match.group(0).endswith('\\'):
            num_escapes = match.end(0) - match.start(0)
            return '\\' * (num_escapes // 2)
        # Single escape character and '@'
        elif match.group(0) == backslash_tag:
            return start_tag
        # Template variable to be replaced
        else:
            varname = match.group(1)
            if varname in confdata:
                (var, desc) = confdata.get(varname)
                if isinstance(var, str):
                    pass
                elif isinstance(var, int):
                    var = str(var)
                else:
                    msg = 'Tried to replace variable {!r} value with ' \
                          'something other than a string or int: {!r}'
                    raise MesonException(msg.format(varname, var))
            else:
                missing_variables.add(varname)
                var = ''
            return var
    return re.sub(regex, variable_replace, line), missing_variables

def do_mesondefine(line, confdata):
    arr = line.split()
    if len(arr) != 2:
        raise MesonException('#mesondefine does not contain exactly two tokens: %s' % line.strip())
    varname = arr[1]
    try:
        (v, desc) = confdata.get(varname)
    except KeyError:
        return '/* #undef %s */\n' % varname
    if isinstance(v, bool):
        if v:
            return '#define %s\n' % varname
        else:
            return '#undef %s\n' % varname
    elif isinstance(v, int):
        return '#define %s %d\n' % (varname, v)
    elif isinstance(v, str):
        return '#define %s %s\n' % (varname, v)
    else:
        raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname)


def do_conf_file(src, dst, confdata, variable_format, encoding='utf-8'):
    try:
        with open(src, encoding=encoding, newline='') as f:
            data = f.readlines()
    except Exception as e:
        raise MesonException('Could not read input file %s: %s' % (src, str(e)))
    # Only allow (a-z, A-Z, 0-9, _, -) as valid characters for a define
    # Also allow escaping '@' with '\@'
    if variable_format in ['meson', 'cmake@']:
        regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@')
    elif variable_format == 'cmake':
        regex = re.compile(r'(?:\\\\)+(?=\\?\$)|\\\${|\${([-a-zA-Z0-9_]+)}')
    else:
        raise MesonException('Format "{}" not handled'.format(variable_format))

    search_token = '#mesondefine'
    if variable_format != 'meson':
        search_token = '#cmakedefine'

    result = []
    missing_variables = set()
    # Detect when the configuration data is empty and no tokens were found
    # during substitution so we can warn the user to use the `copy:` kwarg.
    confdata_useless = not confdata.keys()
    for line in data:
        if line.startswith(search_token):
            confdata_useless = False
            line = do_mesondefine(line, confdata)
        else:
            line, missing = do_replacement(regex, line, variable_format, confdata)
            missing_variables.update(missing)
            if missing:
                confdata_useless = False
        result.append(line)
    dst_tmp = dst + '~'
    try:
        with open(dst_tmp, 'w', encoding=encoding, newline='') as f:
            f.writelines(result)
    except Exception as e:
        raise MesonException('Could not write output file %s: %s' % (dst, str(e)))
    shutil.copymode(src, dst_tmp)
    replace_if_different(dst, dst_tmp)
    return missing_variables, confdata_useless

CONF_C_PRELUDE = '''/*
 * Autogenerated by the Meson build system.
 * Do not edit, your changes will be lost.
 */

#pragma once

'''

CONF_NASM_PRELUDE = '''; Autogenerated by the Meson build system.
; Do not edit, your changes will be lost.

'''

def dump_conf_header(ofilename, cdata, output_format):
    if output_format == 'c':
        prelude = CONF_C_PRELUDE
        prefix = '#'
    elif output_format == 'nasm':
        prelude = CONF_NASM_PRELUDE
        prefix = '%'

    ofilename_tmp = ofilename + '~'
    with open(ofilename_tmp, 'w', encoding='utf-8') as ofile:
        ofile.write(prelude)
        for k in sorted(cdata.keys()):
            (v, desc) = cdata.get(k)
            if desc:
                if output_format == 'c':
                    ofile.write('/* %s */\n' % desc)
                elif output_format == 'nasm':
                    for line in desc.split('\n'):
                        ofile.write('; %s\n' % line)
            if isinstance(v, bool):
                if v:
                    ofile.write('%sdefine %s\n\n' % (prefix, k))
                else:
                    ofile.write('%sundef %s\n\n' % (prefix, k))
            elif isinstance(v, (int, str)):
                ofile.write('%sdefine %s %s\n\n' % (prefix, k, v))
            else:
                raise MesonException('Unknown data type in configuration file entry: ' + k)
    replace_if_different(ofilename, ofilename_tmp)

def replace_if_different(dst, dst_tmp):
    # If contents are identical, don't touch the file to prevent
    # unnecessary rebuilds.
    different = True
    try:
        with open(dst, 'rb') as f1, open(dst_tmp, 'rb') as f2:
            if f1.read() == f2.read():
                different = False
    except FileNotFoundError:
        pass
    if different:
        os.replace(dst_tmp, dst)
    else:
        os.unlink(dst_tmp)

def listify(item: T.Any,
            flatten: bool = True,
            unholder: bool = False) -> T.List[T.Any]:
    '''
    Returns a list with all args embedded in a list if they are not a list.
    This function preserves order.
    @flatten: Convert lists of lists to a flat list
    @unholder: Replace each item with the object it holds, if required

    Note: unholding only works recursively when flattening
    '''
    if not isinstance(item, list):
        if unholder and hasattr(item, 'held_object'):
            item = item.held_object
        return [item]
    result = []
    for i in item:
        if unholder and hasattr(i, 'held_object'):
            i = i.held_object
        if flatten and isinstance(i, list):
            result += listify(i, flatten=True, unholder=unholder)
        else:
            result.append(i)
    return result


def extract_as_list(dict_object, *keys, pop=False, **kwargs):
    '''
    Extracts all values from given dict_object and listifies them.
    '''
    result = []
    fetch = dict_object.get
    if pop:
        fetch = dict_object.pop
    # If there's only one key, we don't return a list with one element
    if len(keys) == 1:
        return listify(fetch(keys[0], []), **kwargs)
    # Return a list of values corresponding to *keys
    for key in keys:
        result.append(listify(fetch(key, []), **kwargs))
    return result

def typeslistify(item: 'T.Union[_T, T.List[_T]]',
                 types: 'T.Union[T.Type[_T], T.Tuple[T.Type[_T]]]') -> T.List[_T]:
    '''
    Ensure that type(@item) is one of @types or a
    list of items all of which are of type @types
    '''
    if isinstance(item, types):
        item = T.cast(T.List[_T], [item])
    if not isinstance(item, list):
        raise MesonException('Item must be a list or one of {!r}'.format(types))
    for i in item:
        if i is not None and not isinstance(i, types):
            raise MesonException('List item must be one of {!r}'.format(types))
    return item

def stringlistify(item: T.Union[str, T.List[str]]) -> T.List[str]:
    return typeslistify(item, str)

def expand_arguments(args):
    expended_args = []
    for arg in args:
        if not arg.startswith('@'):
            expended_args.append(arg)
            continue

        args_file = arg[1:]
        try:
            with open(args_file) as f:
                extended_args = f.read().split()
            expended_args += extended_args
        except Exception as e:
            print('Error expanding command line arguments, %s not found' % args_file)
            print(e)
            return None
    return expended_args

def partition(pred, iterable):
    'Use a predicate to partition entries into false entries and true entries'
    # partition(is_odd, range(10)) --> 0 2 4 6 8   and  1 3 5 7 9
    t1, t2 = tee(iterable)
    return filterfalse(pred, t1), filter(pred, t2)

def Popen_safe(args: T.List[str], write: T.Optional[str] = None,
               stdout: T.Union[T.BinaryIO, int] = subprocess.PIPE,
               stderr: T.Union[T.BinaryIO, int] = subprocess.PIPE,
               **kwargs: T.Any) -> T.Tuple[subprocess.Popen, str, str]:
    import locale
    encoding = locale.getpreferredencoding()
    # Redirect stdin to DEVNULL otherwise the command run by us here might mess
    # up the console and ANSI colors will stop working on Windows.
    if 'stdin' not in kwargs:
        kwargs['stdin'] = subprocess.DEVNULL
    if sys.version_info < (3, 6) or not sys.stdout.encoding or encoding.upper() != 'UTF-8':
        p, o, e = Popen_safe_legacy(args, write=write, stdout=stdout, stderr=stderr, **kwargs)
    else:
        p = subprocess.Popen(args, universal_newlines=True, close_fds=False,
                             stdout=stdout, stderr=stderr, **kwargs)
        o, e = p.communicate(write)
    # Sometimes the command that we run will call another command which will be
    # without the above stdin workaround, so set the console mode again just in
    # case.
    mlog.setup_console()
    return p, o, e

def Popen_safe_legacy(args: T.List[str], write: T.Optional[str] = None,
                      stdout: T.Union[T.BinaryIO, int] = subprocess.PIPE,
                      stderr: T.Union[T.BinaryIO, int] = subprocess.PIPE,
                      **kwargs: T.Any) -> T.Tuple[subprocess.Popen, str, str]:
    p = subprocess.Popen(args, universal_newlines=False, close_fds=False,
                         stdout=stdout, stderr=stderr, **kwargs)
    input_ = None  # type: T.Optional[bytes]
    if write is not None:
        input_ = write.encode('utf-8')
    o, e = p.communicate(input_)
    if o is not None:
        if sys.stdout.encoding:
            o = o.decode(encoding=sys.stdout.encoding, errors='replace').replace('\r\n', '\n')
        else:
            o = o.decode(errors='replace').replace('\r\n', '\n')
    if e is not None:
        if sys.stderr.encoding:
            e = e.decode(encoding=sys.stderr.encoding, errors='replace').replace('\r\n', '\n')
        else:
            e = e.decode(errors='replace').replace('\r\n', '\n')
    return p, o, e

def iter_regexin_iter(regexiter, initer):
    '''
    Takes each regular expression in @regexiter and tries to search for it in
    every item in @initer. If there is a match, returns that match.
    Else returns False.
    '''
    for regex in regexiter:
        for ii in initer:
            if not isinstance(ii, str):
                continue
            match = re.search(regex, ii)
            if match:
                return match.group()
    return False

def _substitute_values_check_errors(command, values):
    # Error checking
    inregex = ('@INPUT([0-9]+)?@', '@PLAINNAME@', '@BASENAME@')
    outregex = ('@OUTPUT([0-9]+)?@', '@OUTDIR@')
    if '@INPUT@' not in values:
        # Error out if any input-derived templates are present in the command
        match = iter_regexin_iter(inregex, command)
        if match:
            m = 'Command cannot have {!r}, since no input files were specified'
            raise MesonException(m.format(match))
    else:
        if len(values['@INPUT@']) > 1:
            # Error out if @PLAINNAME@ or @BASENAME@ is present in the command
            match = iter_regexin_iter(inregex[1:], command)
            if match:
                raise MesonException('Command cannot have {!r} when there is '
                                     'more than one input file'.format(match))
        # Error out if an invalid @INPUTnn@ template was specified
        for each in command:
            if not isinstance(each, str):
                continue
            match = re.search(inregex[0], each)
            if match and match.group() not in values:
                m = 'Command cannot have {!r} since there are only {!r} inputs'
                raise MesonException(m.format(match.group(), len(values['@INPUT@'])))
    if '@OUTPUT@' not in values:
        # Error out if any output-derived templates are present in the command
        match = iter_regexin_iter(outregex, command)
        if match:
            m = 'Command cannot have {!r} since there are no outputs'
            raise MesonException(m.format(match))
    else:
        # Error out if an invalid @OUTPUTnn@ template was specified
        for each in command:
            if not isinstance(each, str):
                continue
            match = re.search(outregex[0], each)
            if match and match.group() not in values:
                m = 'Command cannot have {!r} since there are only {!r} outputs'
                raise MesonException(m.format(match.group(), len(values['@OUTPUT@'])))

def substitute_values(command, values):
    '''
    Substitute the template strings in the @values dict into the list of
    strings @command and return a new list. For a full list of the templates,
    see get_filenames_templates_dict()

    If multiple inputs/outputs are given in the @values dictionary, we
    substitute @INPUT@ and @OUTPUT@ only if they are the entire string, not
    just a part of it, and in that case we substitute *all* of them.
    '''
    # Error checking
    _substitute_values_check_errors(command, values)
    # Substitution
    outcmd = []
    rx_keys = [re.escape(key) for key in values if key not in ('@INPUT@', '@OUTPUT@')]
    value_rx = re.compile('|'.join(rx_keys)) if rx_keys else None
    for vv in command:
        if not isinstance(vv, str):
            outcmd.append(vv)
        elif '@INPUT@' in vv:
            inputs = values['@INPUT@']
            if vv == '@INPUT@':
                outcmd += inputs
            elif len(inputs) == 1:
                outcmd.append(vv.replace('@INPUT@', inputs[0]))
            else:
                raise MesonException("Command has '@INPUT@' as part of a "
                                     "string and more than one input file")
        elif '@OUTPUT@' in vv:
            outputs = values['@OUTPUT@']
            if vv == '@OUTPUT@':
                outcmd += outputs
            elif len(outputs) == 1:
                outcmd.append(vv.replace('@OUTPUT@', outputs[0]))
            else:
                raise MesonException("Command has '@OUTPUT@' as part of a "
                                     "string and more than one output file")
        # Append values that are exactly a template string.
        # This is faster than a string replace.
        elif vv in values:
            outcmd.append(values[vv])
        # Substitute everything else with replacement
        elif value_rx:
            outcmd.append(value_rx.sub(lambda m: values[m.group(0)], vv))
        else:
            outcmd.append(vv)
    return outcmd

def get_filenames_templates_dict(inputs, outputs):
    '''
    Create a dictionary with template strings as keys and values as values for
    the following templates:

    @INPUT@  - the full path to one or more input files, from @inputs
    @OUTPUT@ - the full path to one or more output files, from @outputs
    @OUTDIR@ - the full path to the directory containing the output files

    If there is only one input file, the following keys are also created:

    @PLAINNAME@ - the filename of the input file
    @BASENAME@ - the filename of the input file with the extension removed

    If there is more than one input file, the following keys are also created:

    @INPUT0@, @INPUT1@, ... one for each input file

    If there is more than one output file, the following keys are also created:

    @OUTPUT0@, @OUTPUT1@, ... one for each output file
    '''
    values = {}
    # Gather values derived from the input
    if inputs:
        # We want to substitute all the inputs.
        values['@INPUT@'] = inputs
        for (ii, vv) in enumerate(inputs):
            # Write out @INPUT0@, @INPUT1@, ...
            values['@INPUT{}@'.format(ii)] = vv
        if len(inputs) == 1:
            # Just one value, substitute @PLAINNAME@ and @BASENAME@
            values['@PLAINNAME@'] = plain = os.path.basename(inputs[0])
            values['@BASENAME@'] = os.path.splitext(plain)[0]
    if outputs:
        # Gather values derived from the outputs, similar to above.
        values['@OUTPUT@'] = outputs
        for (ii, vv) in enumerate(outputs):
            values['@OUTPUT{}@'.format(ii)] = vv
        # Outdir should be the same for all outputs
        values['@OUTDIR@'] = os.path.dirname(outputs[0])
        # Many external programs fail on empty arguments.
        if values['@OUTDIR@'] == '':
            values['@OUTDIR@'] = '.'
    return values


def _make_tree_writable(topdir):
    # Ensure all files and directories under topdir are writable
    # (and readable) by owner.
    for d, _, files in os.walk(topdir):
        os.chmod(d, os.stat(d).st_mode | stat.S_IWRITE | stat.S_IREAD)
        for fname in files:
            fpath = os.path.join(d, fname)
            if os.path.isfile(fpath):
                os.chmod(fpath, os.stat(fpath).st_mode | stat.S_IWRITE | stat.S_IREAD)


def windows_proof_rmtree(f):
    # On Windows if anyone is holding a file open you can't
    # delete it. As an example an anti virus scanner might
    # be scanning files you are trying to delete. The only
    # way to fix this is to try again and again.
    delays = [0.1, 0.1, 0.2, 0.2, 0.2, 0.5, 0.5, 1, 1, 1, 1, 2]
    # Start by making the tree wriable.
    _make_tree_writable(f)
    for d in delays:
        try:
            shutil.rmtree(f)
            return
        except FileNotFoundError:
            return
        except OSError:
            time.sleep(d)
    # Try one last time and throw if it fails.
    shutil.rmtree(f)


def windows_proof_rm(fpath):
    """Like windows_proof_rmtree, but for a single file."""
    if os.path.isfile(fpath):
        os.chmod(fpath, os.stat(fpath).st_mode | stat.S_IWRITE | stat.S_IREAD)
    delays = [0.1, 0.1, 0.2, 0.2, 0.2, 0.5, 0.5, 1, 1, 1, 1, 2]
    for d in delays:
        try:
            os.unlink(fpath)
            return
        except FileNotFoundError:
            return
        except OSError:
            time.sleep(d)
    os.unlink(fpath)


def detect_subprojects(spdir_name, current_dir='', result=None):
    if result is None:
        result = {}
    spdir = os.path.join(current_dir, spdir_name)
    if not os.path.exists(spdir):
        return result
    for trial in glob(os.path.join(spdir, '*')):
        basename = os.path.basename(trial)
        if trial == 'packagecache':
            continue
        append_this = True
        if os.path.isdir(trial):
            detect_subprojects(spdir_name, trial, result)
        elif trial.endswith('.wrap') and os.path.isfile(trial):
            basename = os.path.splitext(basename)[0]
        else:
            append_this = False
        if append_this:
            if basename in result:
                result[basename].append(trial)
            else:
                result[basename] = [trial]
    return result

# This isn't strictly correct. What we really want here is something like:
# class StringProtocol(typing_extensions.Protocol):
#
#      def __str__(self) -> str: ...
#
# This would more accurately embody what this funcitonc an handle, but we
# don't have that yet, so instead we'll do some casting to work around it
def get_error_location_string(fname: str, lineno: str) -> str:
    return '{}:{}:'.format(fname, lineno)

def substring_is_in_list(substr: str, strlist: T.List[str]) -> bool:
    for s in strlist:
        if substr in s:
            return True
    return False

class OrderedSet(collections.abc.MutableSet):
    """A set that preserves the order in which items are added, by first
    insertion.
    """
    def __init__(self, iterable=None):
        self.__container = collections.OrderedDict()
        if iterable:
            self.update(iterable)

    def __contains__(self, value):
        return value in self.__container

    def __iter__(self):
        return iter(self.__container.keys())

    def __len__(self):
        return len(self.__container)

    def __repr__(self):
        # Don't print 'OrderedSet("")' for an empty set.
        if self.__container:
            return 'OrderedSet("{}")'.format(
                '", "'.join(repr(e) for e in self.__container.keys()))
        return 'OrderedSet()'

    def __reversed__(self):
        return reversed(self.__container)

    def add(self, value):
        self.__container[value] = None

    def discard(self, value):
        if value in self.__container:
            del self.__container[value]

    def update(self, iterable):
        for item in iterable:
            self.__container[item] = None

    def difference(self, set_):
        return type(self)(e for e in self if e not in set_)

class BuildDirLock:

    def __init__(self, builddir):
        self.lockfilename = os.path.join(builddir, 'meson-private/meson.lock')

    def __enter__(self):
        self.lockfile = open(self.lockfilename, 'w')
        try:
            if have_fcntl:
                fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
            elif have_msvcrt:
                msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1)
        except (BlockingIOError, PermissionError):
            self.lockfile.close()
            raise MesonException('Some other Meson process is already using this build directory. Exiting.')

    def __exit__(self, *args):
        if have_fcntl:
            fcntl.flock(self.lockfile, fcntl.LOCK_UN)
        elif have_msvcrt:
            msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)
        self.lockfile.close()

def relpath(path: str, start: str) -> str:
    # On Windows a relative path can't be evaluated for paths on two different
    # drives (i.e. c:\foo and f:\bar).  The only thing left to do is to use the
    # original absolute path.
    try:
        return os.path.relpath(path, start)
    except (TypeError, ValueError):
        return path


class LibType(Enum):

    """Enumeration for library types."""

    SHARED = 0
    STATIC = 1
    PREFER_SHARED = 2
    PREFER_STATIC = 3


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)
            return
        self.total = total
        self.done = 0
        self.printed_dots = 0
        if self.total and bar_type == 'download':
            print('Download size:', self.total)
        if desc:
            print('{}: '.format(desc), end='')

    # Pretend to be an iterator when called as one and don't print any
    # progress
    def __iter__(self):
        return self.iterable

    def __next__(self):
        return next(self.iterable)

    def print_dot(self):
        print('.', end='')
        sys.stdout.flush()
        self.printed_dots += 1

    def update(self, progress):
        self.done += progress
        if not self.total:
            # Just print one dot per call if we don't have a total length
            self.print_dot()
            return
        ratio = int(self.done / self.total * 10)
        while self.printed_dots < ratio:
            self.print_dot()

    def close(self):
        print('')

try:
    from tqdm import tqdm

    class ProgressBar(tqdm):
        def __init__(self, *args, bar_type=None, **kwargs):
            if bar_type == 'download':
                kwargs.update({'unit': 'bytes', 'leave': True})
            else:
                kwargs.update({'leave': False})
            kwargs['ncols'] = 100
            super().__init__(*args, **kwargs)
except ImportError:
    ProgressBar = ProgressBarFallback


def get_wine_shortpath(winecmd, wine_paths):

    """ Get A short version of @wine_paths to avoid
    reaching WINEPATH number of char limit.
    """

    seen = set()
    wine_paths = [p for p in wine_paths if not (p in seen or seen.add(p))]

    getShortPathScript = '%s.bat' % str(uuid.uuid4()).lower()[:5]
    with open(getShortPathScript, mode='w') as f:
        f.write("@ECHO OFF\nfor %%x in (%*) do (\n echo|set /p=;%~sx\n)\n")
        f.flush()
    try:
        with open(os.devnull, 'w') as stderr:
            wine_path = subprocess.check_output(
                winecmd +
                ['cmd', '/C', getShortPathScript] + wine_paths,
                stderr=stderr).decode('utf-8')
    except subprocess.CalledProcessError as e:
        print("Could not get short paths: %s" % e)
        wine_path = ';'.join(wine_paths)
    finally:
        os.remove(getShortPathScript)
    if len(wine_path) > 2048:
        raise MesonException(
            'WINEPATH size {} > 2048'
            ' this will cause random failure.'.format(
                len(wine_path)))

    return wine_path.strip(';')

def run_once(func):
    ret = []

    def wrapper(*args, **kwargs):
        if ret:
            return ret[0]

        val = func(*args, **kwargs)
        ret.append(val)
        return val

    return update_wrapper(wrapper, func)


class OptionProxy:
    def __init__(self, value):
        self.value = value

class OptionOverrideProxy:
    '''Mimic an option list but transparently override
    selected option values.'''
    def __init__(self, overrides, *options):
        self.overrides = overrides
        self.options = options

    def __getitem__(self, option_name):
        for opts in self.options:
            if option_name in opts:
                return self._get_override(option_name, opts[option_name])
        raise KeyError('Option not found', option_name)

    def _get_override(self, option_name, base_opt):
        if option_name in self.overrides:
            return OptionProxy(base_opt.validate_value(self.overrides[option_name]))
        return base_opt

    def copy(self):
        result = {}
        for opts in self.options:
            for option_name in opts:
                result[option_name] = self._get_override(option_name, opts[option_name])
        return result
meson-0.53.2/mesonbuild/mesonmain.py0000644000175000017500000002257513571777336021053 0ustar  jpakkanejpakkane00000000000000# Copyright 2012-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys
import os.path
import importlib
import traceback
import argparse
import codecs
import shutil

from . import mesonlib
from . import mlog
from . import mconf, mdist, minit, minstall, mintro, msetup, mtest, rewriter, msubprojects, munstable_coredata
from .mesonlib import MesonException
from .environment import detect_msys2_arch
from .wrap import wraptool


# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
class CommandLineParser:
    def __init__(self):
        self.term_width = shutil.get_terminal_size().columns
        self.formatter = lambda prog: argparse.HelpFormatter(prog, max_help_position=int(self.term_width / 2), width=self.term_width)

        self.commands = {}
        self.hidden_commands = []
        self.parser = argparse.ArgumentParser(prog='meson', formatter_class=self.formatter)
        self.subparsers = self.parser.add_subparsers(title='Commands',
                                                     description='If no command is specified it defaults to setup command.')
        self.add_command('setup', msetup.add_arguments, msetup.run,
                         help_msg='Configure the project')
        self.add_command('configure', mconf.add_arguments, mconf.run,
                         help_msg='Change project options',)
        self.add_command('dist', mdist.add_arguments, mdist.run,
                         help_msg='Generate release archive',)
        self.add_command('install', minstall.add_arguments, minstall.run,
                         help_msg='Install the project')
        self.add_command('introspect', mintro.add_arguments, mintro.run,
                         help_msg='Introspect project')
        self.add_command('init', minit.add_arguments, minit.run,
                         help_msg='Create a new project')
        self.add_command('test', mtest.add_arguments, mtest.run,
                         help_msg='Run tests')
        self.add_command('wrap', wraptool.add_arguments, wraptool.run,
                         help_msg='Wrap tools')
        self.add_command('subprojects', msubprojects.add_arguments, msubprojects.run,
                         help_msg='Manage subprojects')
        self.add_command('help', self.add_help_arguments, self.run_help_command,
                         help_msg='Print help of a subcommand')
        self.add_command('rewrite', lambda parser: rewriter.add_arguments(parser, self.formatter), rewriter.run,
                         help_msg='Modify the project definition')

        # Hidden commands
        self.add_command('runpython', self.add_runpython_arguments, self.run_runpython_command,
                         help_msg=argparse.SUPPRESS)
        self.add_command('unstable-coredata', munstable_coredata.add_arguments, munstable_coredata.run,
                         help_msg=argparse.SUPPRESS)

    def add_command(self, name, add_arguments_func, run_func, help_msg, aliases=None):
        aliases = aliases or []
        # FIXME: Cannot have hidden subparser:
        # https://bugs.python.org/issue22848
        if help_msg == argparse.SUPPRESS:
            p = argparse.ArgumentParser(prog='meson ' + name, formatter_class=self.formatter)
            self.hidden_commands.append(name)
        else:
            p = self.subparsers.add_parser(name, help=help_msg, aliases=aliases, formatter_class=self.formatter)
        add_arguments_func(p)
        p.set_defaults(run_func=run_func)
        for i in [name] + aliases:
            self.commands[i] = p

    def add_runpython_arguments(self, parser):
        parser.add_argument('-c', action='store_true', dest='eval_arg', default=False)
        parser.add_argument('script_file')
        parser.add_argument('script_args', nargs=argparse.REMAINDER)

    def run_runpython_command(self, options):
        import runpy
        if options.eval_arg:
            exec(options.script_file)
        else:
            sys.argv[1:] = options.script_args
            sys.path.insert(0, os.path.dirname(options.script_file))
            runpy.run_path(options.script_file, run_name='__main__')
        return 0

    def add_help_arguments(self, parser):
        parser.add_argument('command', nargs='?')

    def run_help_command(self, options):
        if options.command:
            self.commands[options.command].print_help()
        else:
            self.parser.print_help()
        return 0

    def run(self, args):
        # If first arg is not a known command, assume user wants to run the setup
        # command.
        known_commands = list(self.commands.keys()) + ['-h', '--help']
        if not args or args[0] not in known_commands:
            args = ['setup'] + args

        # Hidden commands have their own parser instead of using the global one
        if args[0] in self.hidden_commands:
            parser = self.commands[args[0]]
            args = args[1:]
        else:
            parser = self.parser

        args = mesonlib.expand_arguments(args)
        options = parser.parse_args(args)

        try:
            return options.run_func(options)
        except MesonException as e:
            mlog.exception(e)
            logfile = mlog.shutdown()
            if logfile is not None:
                mlog.log("\nA full log can be found at", mlog.bold(logfile))
            if os.environ.get('MESON_FORCE_BACKTRACE'):
                raise
            return 1
        except Exception:
            if os.environ.get('MESON_FORCE_BACKTRACE'):
                raise
            traceback.print_exc()
            return 2
        finally:
            mlog.shutdown()

def run_script_command(script_name, script_args):
    # Map script name to module name for those that doesn't match
    script_map = {'exe': 'meson_exe',
                  'install': 'meson_install',
                  'delsuffix': 'delwithsuffix',
                  'gtkdoc': 'gtkdochelper',
                  'hotdoc': 'hotdochelper',
                  'regencheck': 'regen_checker'}
    module_name = script_map.get(script_name, script_name)

    try:
        module = importlib.import_module('mesonbuild.scripts.' + module_name)
    except ModuleNotFoundError as e:
        mlog.exception(e)
        return 1

    try:
        return module.run(script_args)
    except MesonException as e:
        mlog.error('Error in {} helper script:'.format(script_name))
        mlog.exception(e)
        return 1

def ensure_stdout_accepts_unicode():
    if sys.stdout.encoding and not sys.stdout.encoding.upper().startswith('UTF-'):
        if sys.version_info >= (3, 7):
            sys.stdout.reconfigure(errors='surrogateescape')
        else:
            sys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach(),
                                                   errors='surrogateescape')
            sys.stdout.encoding = 'UTF-8'
            if not hasattr(sys.stdout, 'buffer'):
                sys.stdout.buffer = sys.stdout.raw if hasattr(sys.stdout, 'raw') else sys.stdout

def run(original_args, mainfile):
    if sys.version_info < (3, 5):
        print('Meson works correctly only with python 3.5+.')
        print('You have python %s.' % sys.version)
        print('Please update your environment')
        return 1

    # Meson gets confused if stdout can't output Unicode, if the
    # locale isn't Unicode, just force stdout to accept it. This tries
    # to emulate enough of PEP 540 to work elsewhere.
    ensure_stdout_accepts_unicode()

    # https://github.com/mesonbuild/meson/issues/3653
    if sys.platform.lower() == 'msys':
        mlog.error('This python3 seems to be msys/python on MSYS2 Windows, which is known to have path semantics incompatible with Meson')
        msys2_arch = detect_msys2_arch()
        if msys2_arch:
            mlog.error('Please install and use mingw-w64-i686-python3 and/or mingw-w64-x86_64-python3 with Pacman')
        else:
            mlog.error('Please download and use Python as detailed at: https://mesonbuild.com/Getting-meson.html')
        return 2

    # Set the meson command that will be used to run scripts and so on
    mesonlib.set_meson_command(mainfile)

    args = original_args[:]

    # Special handling of internal commands called from backends, they don't
    # need to go through argparse.
    if len(args) >= 2 and args[0] == '--internal':
        if args[1] == 'regenerate':
            # Rewrite "meson --internal regenerate" command line to
            # "meson --reconfigure"
            args = ['--reconfigure'] + args[2:]
        else:
            return run_script_command(args[1], args[2:])

    return CommandLineParser().run(args)

def main():
    # Always resolve the command path so Ninja can find it for regen, tests, etc.
    if 'meson.exe' in sys.executable:
        assert(os.path.isabs(sys.executable))
        launcher = sys.executable
    else:
        launcher = os.path.realpath(sys.argv[0])
    return run(sys.argv[1:], launcher)

if __name__ == '__main__':
    sys.exit(main())
meson-0.53.2/mesonbuild/minit.py0000644000175000017500000002317213571777336020177 0ustar  jpakkanejpakkane00000000000000# Copyright 2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Code that creates simple startup projects."""

from pathlib import Path
import re, shutil, subprocess
from glob import glob
from mesonbuild import mesonlib
from mesonbuild.environment import detect_ninja

from mesonbuild.templates.ctemplates import (create_exe_c_sample, create_lib_c_sample)
from mesonbuild.templates.cpptemplates import (create_exe_cpp_sample, create_lib_cpp_sample)
from mesonbuild.templates.objctemplates import (create_exe_objc_sample, create_lib_objc_sample)
from mesonbuild.templates.dlangtemplates import (create_exe_d_sample, create_lib_d_sample)
from mesonbuild.templates.fortrantemplates import (create_exe_fortran_sample, create_lib_fortran_sample)
from mesonbuild.templates.rusttemplates import (create_exe_rust_sample, create_lib_rust_sample)

FORTRAN_SUFFIXES = ['.f', '.for', '.F', '.f90', '.F90']

info_message = '''Sample project created. To build it run the
following commands:

meson builddir
ninja -C builddir
'''

def create_sample(options):
    if options.language == 'c':
        if options.type == 'executable':
            create_exe_c_sample(options.name, options.version)
        elif options.type == 'library':
            create_lib_c_sample(options.name, options.version)
        else:
            raise RuntimeError('Unreachable code')
    elif options.language == 'cpp':
        if options.type == 'executable':
            create_exe_cpp_sample(options.name, options.version)
        elif options.type == 'library':
            create_lib_cpp_sample(options.name, options.version)
        else:
            raise RuntimeError('Unreachable code')
    elif options.language == 'd':
        if options.type == 'executable':
            create_exe_d_sample(options.name, options.version)
        elif options.type == 'library':
            create_lib_d_sample(options.name, options.version)
        else:
            raise RuntimeError('Unreachable code')
    elif options.language == 'fortran':
        if options.type == 'executable':
            create_exe_fortran_sample(options.name, options.version)
        elif options.type == 'library':
            create_lib_fortran_sample(options.name, options.version)
        else:
            raise RuntimeError('Unreachable code')
    elif options.language == 'rust':
        if options.type == 'executable':
            create_exe_rust_sample(options.name, options.version)
        elif options.type == 'library':
            create_lib_rust_sample(options.name, options.version)
        else:
            raise RuntimeError('Unreachable code')
    elif options.language == 'objc':
        if options.type == 'executable':
            create_exe_objc_sample(options.name, options.version)
        elif options.type == 'library':
            create_lib_objc_sample(options.name, options.version)
        else:
            raise RuntimeError('Unreachable code')
    else:
        raise RuntimeError('Unreachable code')
    print(info_message)

def autodetect_options(options, sample: bool = False):
    if not options.name:
        options.name = Path().resolve().stem
        if not re.match('[a-zA-Z_][a-zA-Z0-9]*', options.name) and sample:
            raise SystemExit('Name of current directory "{}" is not usable as a sample project name.\n'
                             'Specify a project name with --name.'.format(options.name))
        print('Using "{}" (name of current directory) as project name.'
              .format(options.name))
    if not options.executable:
        options.executable = options.name
        print('Using "{}" (project name) as name of executable to build.'
              .format(options.executable))
    if sample:
        # The rest of the autodetection is not applicable to generating sample projects.
        return
    if not options.srcfiles:
        srcfiles = []
        for f in (f for f in Path().iterdir() if f.is_file()):
            if f.suffix in (['.cc', '.cpp', '.c', '.d', '.m', '.rs'] + FORTRAN_SUFFIXES):
                srcfiles.append(f)
        if not srcfiles:
            raise SystemExit('No recognizable source files found.\n'
                             'Run meson init in an empty directory to create a sample project.')
        options.srcfiles = srcfiles
        print("Detected source files: " + ' '.join(map(str, srcfiles)))
    options.srcfiles = [Path(f) for f in options.srcfiles]
    if not options.language:
        for f in options.srcfiles:
            if f.suffix in ('.cc', '.cpp'):
                options.language = 'cpp'
                break
            if f.suffix == '.c':
                options.language = 'c'
                break
            if f.suffix == '.d':
                options.language = 'd'
                break
            if f.suffix in FORTRAN_SUFFIXES:
                options.language = 'fortran'
                break
            if f.suffix == '.rs':
                options.language = 'rust'
                break
            if f.suffix == '.m':
                options.language = 'objc'
                break
        if not options.language:
            raise SystemExit("Can't autodetect language, please specify it with -l.")
        print("Detected language: " + options.language)


meson_executable_template = '''project('{project_name}', '{language}',
  version : '{version}',
  default_options : [{default_options}])

executable('{executable}',
           {sourcespec},{depspec}
           install : true)
'''

def create_meson_build(options):
    if options.type != 'executable':
        raise SystemExit('\nGenerating a meson.build file from existing sources is\n'
                         'supported only for project type "executable".\n'
                         'Run meson init in an empty directory to create a sample project.')
    default_options = ['warning_level=3']
    if options.language == 'cpp':
        # This shows how to set this very common option.
        default_options += ['cpp_std=c++14']
    # If we get a meson.build autoformatter one day, this code could
    # be simplified quite a bit.
    formatted_default_options = ', '.join("'{}'".format(x) for x in default_options)
    sourcespec = ',\n           '.join("'{}'".format(x) for x in options.srcfiles)
    depspec = ''
    if options.deps:
        depspec = '\n           dependencies : [\n              '
        depspec += ',\n              '.join("dependency('{}')".format(x)
                                            for x in options.deps.split(','))
        depspec += '],'
    content = meson_executable_template.format(project_name=options.name,
                                               language=options.language,
                                               version=options.version,
                                               executable=options.executable,
                                               sourcespec=sourcespec,
                                               depspec=depspec,
                                               default_options=formatted_default_options)
    open('meson.build', 'w').write(content)
    print('Generated meson.build file:\n\n' + content)

def add_arguments(parser):
    parser.add_argument("srcfiles", metavar="sourcefile", nargs="*",
                        help="source files. default: all recognized files in current directory")
    parser.add_argument("-n", "--name", help="project name. default: name of current directory")
    parser.add_argument("-e", "--executable", help="executable name. default: project name")
    parser.add_argument("-d", "--deps", help="dependencies, comma-separated")
    parser.add_argument("-l", "--language", choices=['c', 'cpp', 'd', 'fortran', 'rust', 'objc'],
                        help="project language. default: autodetected based on source files")
    parser.add_argument("-b", "--build", help="build after generation", action='store_true')
    parser.add_argument("--builddir", help="directory for build", default='build')
    parser.add_argument("-f", "--force", action="store_true",
                        help="force overwrite of existing files and directories.")
    parser.add_argument('--type', default='executable',
                        choices=['executable', 'library'])
    parser.add_argument('--version', default='0.1')

def run(options) -> int:
    if not glob('*'):
        autodetect_options(options, sample=True)
        if not options.language:
            print('Defaulting to generating a C language project.')
            options.language = 'c'
        create_sample(options)
    else:
        autodetect_options(options)
        if Path('meson.build').is_file() and not options.force:
            raise SystemExit('meson.build already exists. Use --force to overwrite.')
        create_meson_build(options)
    if options.build:
        if Path(options.builddir).is_dir() and options.force:
            print('Build directory already exists, deleting it.')
            shutil.rmtree(options.builddir)
        print('Building...')
        cmd = mesonlib.meson_command + [options.builddir]
        ret = subprocess.run(cmd)
        if ret.returncode:
            raise SystemExit
        cmd = [detect_ninja(), '-C', options.builddir]
        ret = subprocess.run(cmd)
        if ret.returncode:
            raise SystemExit
    return 0
meson-0.53.2/mesonbuild/minstall.py0000644000175000017500000005370013602226377020667 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2014 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys, pickle, os, shutil, subprocess, errno
import shlex
from glob import glob
from .scripts import depfixer
from .scripts import destdir_join
from .mesonlib import is_windows, Popen_safe
from .mtest import rebuild_all
try:
    from __main__ import __file__ as main_file
except ImportError:
    # Happens when running as meson.exe which is native Windows.
    # This is only used for pkexec which is not, so this is fine.
    main_file = None

symlink_warning = '''Warning: trying to copy a symlink that points to a file. This will copy the file,
but this will be changed in a future version of Meson to copy the symlink as is. Please update your
build definitions so that it will not break when the change happens.'''

selinux_updates = []

def add_arguments(parser):
    parser.add_argument('-C', default='.', dest='wd',
                        help='directory to cd into before running')
    parser.add_argument('--no-rebuild', default=False, action='store_true',
                        help='Do not rebuild before installing.')
    parser.add_argument('--only-changed', default=False, action='store_true',
                        help='Only overwrite files that are older than the copied file.')

class DirMaker:
    def __init__(self, lf):
        self.lf = lf
        self.dirs = []

    def makedirs(self, path, exist_ok=False):
        dirname = os.path.normpath(path)
        dirs = []
        while dirname != os.path.dirname(dirname):
            if not os.path.exists(dirname):
                dirs.append(dirname)
            dirname = os.path.dirname(dirname)
        os.makedirs(path, exist_ok=exist_ok)

        # store the directories in creation order, with the parent directory
        # before the child directories. Future calls of makedir() will not
        # create the parent directories, so the last element in the list is
        # the last one to be created. That is the first one to be removed on
        # __exit__
        dirs.reverse()
        self.dirs += dirs

    def __enter__(self):
        return self

    def __exit__(self, exception_type, value, traceback):
        self.dirs.reverse()
        for d in self.dirs:
            append_to_log(self.lf, d)

def is_executable(path, follow_symlinks=False):
    '''Checks whether any of the "x" bits are set in the source file mode.'''
    return bool(os.stat(path, follow_symlinks=follow_symlinks).st_mode & 0o111)

def append_to_log(lf, line):
    lf.write(line)
    if not line.endswith('\n'):
        lf.write('\n')
    lf.flush()

def set_chown(path, user=None, group=None, dir_fd=None, follow_symlinks=True):
    # shutil.chown will call os.chown without passing all the parameters
    # and particularly follow_symlinks, thus we replace it temporary
    # with a lambda with all the parameters so that follow_symlinks will
    # be actually passed properly.
    # Not nice, but better than actually rewriting shutil.chown until
    # this python bug is fixed: https://bugs.python.org/issue18108
    real_os_chown = os.chown
    try:
        os.chown = lambda p, u, g: real_os_chown(p, u, g,
                                                 dir_fd=dir_fd,
                                                 follow_symlinks=follow_symlinks)
        shutil.chown(path, user, group)
    except Exception:
        raise
    finally:
        os.chown = real_os_chown

def set_chmod(path, mode, dir_fd=None, follow_symlinks=True):
    try:
        os.chmod(path, mode, dir_fd=dir_fd, follow_symlinks=follow_symlinks)
    except (NotImplementedError, OSError, SystemError):
        if not os.path.islink(path):
            os.chmod(path, mode, dir_fd=dir_fd)

def sanitize_permissions(path, umask):
    if umask == 'preserve':
        return
    new_perms = 0o777 if is_executable(path, follow_symlinks=False) else 0o666
    new_perms &= ~umask
    try:
        set_chmod(path, new_perms, follow_symlinks=False)
    except PermissionError as e:
        msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...'
        print(msg.format(path, new_perms, e.strerror))

def set_mode(path, mode, default_umask):
    if mode is None or (mode.perms_s or mode.owner or mode.group) is None:
        # Just sanitize permissions with the default umask
        sanitize_permissions(path, default_umask)
        return
    # No chown() on Windows, and must set one of owner/group
    if not is_windows() and (mode.owner or mode.group) is not None:
        try:
            set_chown(path, mode.owner, mode.group, follow_symlinks=False)
        except PermissionError as e:
            msg = '{!r}: Unable to set owner {!r} and group {!r}: {}, ignoring...'
            print(msg.format(path, mode.owner, mode.group, e.strerror))
        except LookupError:
            msg = '{!r}: Non-existent owner {!r} or group {!r}: ignoring...'
            print(msg.format(path, mode.owner, mode.group))
        except OSError as e:
            if e.errno == errno.EINVAL:
                msg = '{!r}: Non-existent numeric owner {!r} or group {!r}: ignoring...'
                print(msg.format(path, mode.owner, mode.group))
            else:
                raise
    # Must set permissions *after* setting owner/group otherwise the
    # setuid/setgid bits will get wiped by chmod
    # NOTE: On Windows you can set read/write perms; the rest are ignored
    if mode.perms_s is not None:
        try:
            set_chmod(path, mode.perms, follow_symlinks=False)
        except PermissionError as e:
            msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...'
            print(msg.format(path, mode.perms_s, e.strerror))
    else:
        sanitize_permissions(path, default_umask)

def restore_selinux_contexts():
    '''
    Restores the SELinux context for files in @selinux_updates

    If $DESTDIR is set, do not warn if the call fails.
    '''
    try:
        subprocess.check_call(['selinuxenabled'])
    except (FileNotFoundError, NotADirectoryError, PermissionError, subprocess.CalledProcessError):
        # If we don't have selinux or selinuxenabled returned 1, failure
        # is ignored quietly.
        return

    if not shutil.which('restorecon'):
        # If we don't have restorecon, failure is ignored quietly.
        return

    with subprocess.Popen(['restorecon', '-F', '-f-', '-0'],
                          stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc:
        out, err = proc.communicate(input=b'\0'.join(os.fsencode(f) for f in selinux_updates) + b'\0')
        if proc.returncode != 0 and not os.environ.get('DESTDIR'):
            print('Failed to restore SELinux context of installed files...',
                  'Standard output:', out.decode(),
                  'Standard error:', err.decode(), sep='\n')


def get_destdir_path(d, path):
    if os.path.isabs(path):
        output = destdir_join(d.destdir, path)
    else:
        output = os.path.join(d.fullprefix, path)
    return output


def check_for_stampfile(fname):
    '''Some languages e.g. Rust have output files
    whose names are not known at configure time.
    Check if this is the case and return the real
    file instead.'''
    if fname.endswith('.so') or fname.endswith('.dll'):
        if os.stat(fname).st_size == 0:
            (base, suffix) = os.path.splitext(fname)
            files = glob(base + '-*' + suffix)
            if len(files) > 1:
                print("Stale dynamic library files in build dir. Can't install.")
                sys.exit(1)
            if len(files) == 1:
                return files[0]
    elif fname.endswith('.a') or fname.endswith('.lib'):
        if os.stat(fname).st_size == 0:
            (base, suffix) = os.path.splitext(fname)
            files = glob(base + '-*' + '.rlib')
            if len(files) > 1:
                print("Stale static library files in build dir. Can't install.")
                sys.exit(1)
            if len(files) == 1:
                return files[0]
    return fname

class Installer:

    def __init__(self, options, lf):
        self.did_install_something = False
        self.options = options
        self.lf = lf

    def should_preserve_existing_file(self, from_file, to_file):
        if not self.options.only_changed:
            return False
        # Always replace danging symlinks
        if os.path.islink(from_file) and not os.path.isfile(from_file):
            return False
        from_time = os.stat(from_file).st_mtime
        to_time = os.stat(to_file).st_mtime
        return from_time <= to_time

    def do_copyfile(self, from_file, to_file):
        outdir = os.path.split(to_file)[0]
        if not os.path.isfile(from_file) and not os.path.islink(from_file):
            raise RuntimeError('Tried to install something that isn\'t a file:'
                               '{!r}'.format(from_file))
        # copyfile fails if the target file already exists, so remove it to
        # allow overwriting a previous install. If the target is not a file, we
        # want to give a readable error.
        if os.path.exists(to_file):
            if not os.path.isfile(to_file):
                raise RuntimeError('Destination {!r} already exists and is not '
                                   'a file'.format(to_file))
            if self.should_preserve_existing_file(from_file, to_file):
                append_to_log(self.lf, '# Preserving old file %s\n' % to_file)
                print('Preserving existing file %s' % to_file)
                return False
            os.remove(to_file)
        print('Installing %s to %s' % (from_file, outdir))
        if os.path.islink(from_file):
            if not os.path.exists(from_file):
                # Dangling symlink. Replicate as is.
                shutil.copy(from_file, outdir, follow_symlinks=False)
            else:
                # Remove this entire branch when changing the behaviour to duplicate
                # symlinks rather than copying what they point to.
                print(symlink_warning)
                shutil.copyfile(from_file, to_file)
                shutil.copystat(from_file, to_file)
        else:
            shutil.copyfile(from_file, to_file)
            shutil.copystat(from_file, to_file)
        selinux_updates.append(to_file)
        append_to_log(self.lf, to_file)
        return True

    def do_copydir(self, data, src_dir, dst_dir, exclude, install_mode):
        '''
        Copies the contents of directory @src_dir into @dst_dir.

        For directory
            /foo/
              bar/
                excluded
                foobar
              file
        do_copydir(..., '/foo', '/dst/dir', {'bar/excluded'}) creates
            /dst/
              dir/
                bar/
                  foobar
                file

        Args:
            src_dir: str, absolute path to the source directory
            dst_dir: str, absolute path to the destination directory
            exclude: (set(str), set(str)), tuple of (exclude_files, exclude_dirs),
                     each element of the set is a path relative to src_dir.
        '''
        if not os.path.isabs(src_dir):
            raise ValueError('src_dir must be absolute, got %s' % src_dir)
        if not os.path.isabs(dst_dir):
            raise ValueError('dst_dir must be absolute, got %s' % dst_dir)
        if exclude is not None:
            exclude_files, exclude_dirs = exclude
        else:
            exclude_files = exclude_dirs = set()
        for root, dirs, files in os.walk(src_dir):
            assert os.path.isabs(root)
            for d in dirs[:]:
                abs_src = os.path.join(root, d)
                filepart = os.path.relpath(abs_src, start=src_dir)
                abs_dst = os.path.join(dst_dir, filepart)
                # Remove these so they aren't visited by os.walk at all.
                if filepart in exclude_dirs:
                    dirs.remove(d)
                    continue
                if os.path.isdir(abs_dst):
                    continue
                if os.path.exists(abs_dst):
                    print('Tried to copy directory %s but a file of that name already exists.' % abs_dst)
                    sys.exit(1)
                data.dirmaker.makedirs(abs_dst)
                shutil.copystat(abs_src, abs_dst)
                sanitize_permissions(abs_dst, data.install_umask)
            for f in files:
                abs_src = os.path.join(root, f)
                filepart = os.path.relpath(abs_src, start=src_dir)
                if filepart in exclude_files:
                    continue
                abs_dst = os.path.join(dst_dir, filepart)
                if os.path.isdir(abs_dst):
                    print('Tried to copy file %s but a directory of that name already exists.' % abs_dst)
                parent_dir = os.path.dirname(abs_dst)
                if not os.path.isdir(parent_dir):
                    os.mkdir(parent_dir)
                    shutil.copystat(os.path.dirname(abs_src), parent_dir)
                # FIXME: what about symlinks?
                self.do_copyfile(abs_src, abs_dst)
                set_mode(abs_dst, install_mode, data.install_umask)

    def do_install(self, datafilename):
        with open(datafilename, 'rb') as ifile:
            d = pickle.load(ifile)
        d.destdir = os.environ.get('DESTDIR', '')
        d.fullprefix = destdir_join(d.destdir, d.prefix)

        if d.install_umask != 'preserve':
            os.umask(d.install_umask)

        self.did_install_something = False
        try:
            d.dirmaker = DirMaker(self.lf)
            with d.dirmaker:
                self.install_subdirs(d) # Must be first, because it needs to delete the old subtree.
                self.install_targets(d)
                self.install_headers(d)
                self.install_man(d)
                self.install_data(d)
                restore_selinux_contexts()
                self.run_install_script(d)
                if not self.did_install_something:
                    print('Nothing to install.')
        except PermissionError:
            if shutil.which('pkexec') is not None and 'PKEXEC_UID' not in os.environ:
                print('Installation failed due to insufficient permissions.')
                print('Attempting to use polkit to gain elevated privileges...')
                os.execlp('pkexec', 'pkexec', sys.executable, main_file, *sys.argv[1:],
                          '-C', os.getcwd())
            else:
                raise

    def install_subdirs(self, d):
        for (src_dir, dst_dir, mode, exclude) in d.install_subdirs:
            self.did_install_something = True
            full_dst_dir = get_destdir_path(d, dst_dir)
            print('Installing subdir %s to %s' % (src_dir, full_dst_dir))
            d.dirmaker.makedirs(full_dst_dir, exist_ok=True)
            self.do_copydir(d, src_dir, full_dst_dir, exclude, mode)

    def install_data(self, d):
        for i in d.data:
            self.did_install_something = True
            fullfilename = i[0]
            outfilename = get_destdir_path(d, i[1])
            mode = i[2]
            outdir = os.path.dirname(outfilename)
            d.dirmaker.makedirs(outdir, exist_ok=True)
            self.do_copyfile(fullfilename, outfilename)
            set_mode(outfilename, mode, d.install_umask)

    def install_man(self, d):
        for m in d.man:
            self.did_install_something = True
            full_source_filename = m[0]
            outfilename = get_destdir_path(d, m[1])
            outdir = os.path.dirname(outfilename)
            d.dirmaker.makedirs(outdir, exist_ok=True)
            install_mode = m[2]
            self.do_copyfile(full_source_filename, outfilename)
            set_mode(outfilename, install_mode, d.install_umask)

    def install_headers(self, d):
        for t in d.headers:
            self.did_install_something = True
            fullfilename = t[0]
            fname = os.path.basename(fullfilename)
            outdir = get_destdir_path(d, t[1])
            outfilename = os.path.join(outdir, fname)
            install_mode = t[2]
            d.dirmaker.makedirs(outdir, exist_ok=True)
            self.do_copyfile(fullfilename, outfilename)
            set_mode(outfilename, install_mode, d.install_umask)

    def run_install_script(self, d):
        env = {'MESON_SOURCE_ROOT': d.source_dir,
               'MESON_BUILD_ROOT': d.build_dir,
               'MESON_INSTALL_PREFIX': d.prefix,
               'MESON_INSTALL_DESTDIR_PREFIX': d.fullprefix,
               'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in d.mesonintrospect]),
               }

        child_env = os.environ.copy()
        child_env.update(env)

        for i in d.install_scripts:
            self.did_install_something = True  # Custom script must report itself if it does nothing.
            script = i['exe']
            args = i['args']
            name = ' '.join(script + args)
            print('Running custom install script {!r}'.format(name))
            try:
                rc = subprocess.call(script + args, env=child_env)
                if rc != 0:
                    sys.exit(rc)
            except OSError:
                print('Failed to run install script {!r}'.format(name))
                sys.exit(1)

    def install_targets(self, d):
        for t in d.targets:
            self.did_install_something = True
            if not os.path.exists(t.fname):
                # For example, import libraries of shared modules are optional
                if t.optional:
                    print('File {!r} not found, skipping'.format(t.fname))
                    continue
                else:
                    raise RuntimeError('File {!r} could not be found'.format(t.fname))
            fname = check_for_stampfile(t.fname)
            outdir = get_destdir_path(d, t.outdir)
            outname = os.path.join(outdir, os.path.basename(fname))
            final_path = os.path.join(d.prefix, t.outdir, os.path.basename(fname))
            aliases = t.aliases
            should_strip = t.strip
            install_rpath = t.install_rpath
            install_name_mappings = t.install_name_mappings
            install_mode = t.install_mode
            d.dirmaker.makedirs(outdir, exist_ok=True)
            if not os.path.exists(fname):
                raise RuntimeError('File {!r} could not be found'.format(fname))
            elif os.path.isfile(fname):
                self.do_copyfile(fname, outname)
                set_mode(outname, install_mode, d.install_umask)
                if should_strip and d.strip_bin is not None:
                    if fname.endswith('.jar'):
                        print('Not stripping jar target:', os.path.basename(fname))
                        continue
                    print('Stripping target {!r} using {}.'.format(fname, d.strip_bin[0]))
                    ps, stdo, stde = Popen_safe(d.strip_bin + [outname])
                    if ps.returncode != 0:
                        print('Could not strip file.\n')
                        print('Stdout:\n%s\n' % stdo)
                        print('Stderr:\n%s\n' % stde)
                        sys.exit(1)
                if fname.endswith('.js'):
                    # Emscripten outputs js files and optionally a wasm file.
                    # If one was generated, install it as well.
                    wasm_source = os.path.splitext(fname)[0] + '.wasm'
                    if os.path.exists(wasm_source):
                        wasm_output = os.path.splitext(outname)[0] + '.wasm'
                        self.do_copyfile(wasm_source, wasm_output)
            elif os.path.isdir(fname):
                fname = os.path.join(d.build_dir, fname.rstrip('/'))
                outname = os.path.join(outdir, os.path.basename(fname))
                self.do_copydir(d, fname, outname, None, install_mode)
            else:
                raise RuntimeError('Unknown file type for {!r}'.format(fname))
            printed_symlink_error = False
            for alias, to in aliases.items():
                try:
                    symlinkfilename = os.path.join(outdir, alias)
                    try:
                        os.remove(symlinkfilename)
                    except FileNotFoundError:
                        pass
                    os.symlink(to, symlinkfilename)
                    append_to_log(self.lf, symlinkfilename)
                except (NotImplementedError, OSError):
                    if not printed_symlink_error:
                        print("Symlink creation does not work on this platform. "
                              "Skipping all symlinking.")
                        printed_symlink_error = True
            if os.path.isfile(outname):
                try:
                    depfixer.fix_rpath(outname, install_rpath, final_path,
                                       install_name_mappings, verbose=False)
                except SystemExit as e:
                    if isinstance(e.code, int) and e.code == 0:
                        pass
                    else:
                        raise

def run(opts):
    datafilename = 'meson-private/install.dat'
    private_dir = os.path.dirname(datafilename)
    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.')
    if not opts.no_rebuild:
        if not rebuild_all(opts.wd):
            sys.exit(-1)
    os.chdir(opts.wd)
    with open(os.path.join(log_dir, 'install-log.txt'), 'w') as lf:
        installer = Installer(opts, lf)
        append_to_log(lf, '# List of files installed by Meson')
        append_to_log(lf, '# Does not contain files installed by custom scripts.')
        installer.do_install(datafilename)
    return 0
meson-0.53.2/mesonbuild/mintro.py0000644000175000017500000005340413612313307020344 0ustar  jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This is a helper script for IDE developers. It allows you to
extract information such as list of targets, files, compiler flags,
tests and so on. All output is in JSON for simple parsing.

Currently only works for the Ninja backend. Others use generated
project files and don't need this info."""

import json
from . import build, coredata as cdata
from . import mesonlib
from .ast import IntrospectionInterpreter, build_target_functions, AstConditionLevel, AstIDGenerator, AstIndentationGenerator
from . import mlog
from .backend import backends
from .mparser import FunctionNode, ArrayNode, ArgumentNode, StringNode
import typing as T
import os
import pathlib

def get_meson_info_file(info_dir: str) -> str:
    return os.path.join(info_dir, 'meson-info.json')

def get_meson_introspection_version() -> str:
    return '1.0.0'

def get_meson_introspection_required_version() -> T.List[str]:
    return ['>=1.0', '<2.0']

class IntroCommand:
    def __init__(self,
                 desc: str,
                 func: T.Optional[T.Callable[[], T.Union[dict, list]]] = None,
                 no_bd: T.Optional[T.Callable[[IntrospectionInterpreter], T.Union[dict, list]]] = None) -> None:
        self.desc = desc + '.'
        self.func = func
        self.no_bd = no_bd

def get_meson_introspection_types(coredata: T.Optional[cdata.CoreData] = None,
                                  builddata: T.Optional[build.Build] = None,
                                  backend: T.Optional[backends.Backend] = None,
                                  sourcedir: T.Optional[str] = None) -> T.Dict[str, IntroCommand]:
    if backend and builddata:
        benchmarkdata = backend.create_test_serialisation(builddata.get_benchmarks())
        testdata = backend.create_test_serialisation(builddata.get_tests())
        installdata = backend.create_install_data()
    else:
        benchmarkdata = testdata = installdata = None

    return {
        'benchmarks': IntroCommand('T.List all benchmarks', func=lambda: list_benchmarks(benchmarkdata)),
        'buildoptions': IntroCommand('T.List all build options', func=lambda: list_buildoptions(coredata), no_bd=list_buildoptions_from_source),
        'buildsystem_files': IntroCommand('T.List files that make up the build system', func=lambda: list_buildsystem_files(builddata)),
        'dependencies': IntroCommand('T.List external dependencies', func=lambda: list_deps(coredata), no_bd=list_deps_from_source),
        'scan_dependencies': IntroCommand('Scan for dependencies used in the meson.build file', no_bd=list_deps_from_source),
        'installed': IntroCommand('T.List all installed files and directories', func=lambda: list_installed(installdata)),
        'projectinfo': IntroCommand('Information about projects', func=lambda: list_projinfo(builddata), no_bd=list_projinfo_from_source),
        'targets': IntroCommand('T.List top level targets', func=lambda: list_targets(builddata, installdata, backend), no_bd=list_targets_from_source),
        'tests': IntroCommand('T.List all unit tests', func=lambda: list_tests(testdata)),
    }

def add_arguments(parser):
    intro_types = get_meson_introspection_types()
    for key, val in intro_types.items():
        flag = '--' + key.replace('_', '-')
        parser.add_argument(flag, action='store_true', dest=key, default=False, help=val.desc)

    parser.add_argument('--backend', choices=cdata.backendlist, dest='backend', default='ninja',
                        help='The backend to use for the --buildoptions introspection.')
    parser.add_argument('-a', '--all', action='store_true', dest='all', default=False,
                        help='Print all available information.')
    parser.add_argument('-i', '--indent', action='store_true', dest='indent', default=False,
                        help='Enable pretty printed JSON.')
    parser.add_argument('-f', '--force-object-output', action='store_true', dest='force_dict', default=False,
                        help='Always use the new JSON format for multiple entries (even for 0 and 1 introspection commands)')
    parser.add_argument('builddir', nargs='?', default='.', help='The build directory')

def list_installed(installdata):
    res = {}
    if installdata is not None:
        for t in installdata.targets:
            res[os.path.join(installdata.build_dir, t.fname)] = \
                os.path.join(installdata.prefix, t.outdir, os.path.basename(t.fname))
        for path, installpath, _ in installdata.data:
            res[path] = os.path.join(installdata.prefix, installpath)
        for path, installdir, _ in installdata.headers:
            res[path] = os.path.join(installdata.prefix, installdir, os.path.basename(path))
        for path, installpath, _ in installdata.man:
            res[path] = os.path.join(installdata.prefix, installpath)
        for path, installpath, _, _ in installdata.install_subdirs:
            res[path] = os.path.join(installdata.prefix, installpath)
    return res

def list_targets_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]:
    tlist = []  # type: T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]
    for i in intr.targets:
        sources = []  # type: T.List[str]
        for n in i['sources']:
            args = []  # type: T.List[T.Union[str, StringNode]]
            if isinstance(n, FunctionNode):
                args = list(n.args.arguments)
                if n.func_name in build_target_functions:
                    args.pop(0)
            elif isinstance(n, ArrayNode):
                args = n.args.arguments
            elif isinstance(n, ArgumentNode):
                args = n.arguments
            for j in args:
                if isinstance(j, StringNode):
                    sources += [j.value]
                elif isinstance(j, str):
                    sources += [j]

        tlist += [{
            'name': i['name'],
            'id': i['id'],
            'type': i['type'],
            'defined_in': i['defined_in'],
            'filename': [os.path.join(i['subdir'], x) for x in i['outputs']],
            'build_by_default': i['build_by_default'],
            'target_sources': [{
                'language': 'unknown',
                'compiler': [],
                'parameters': [],
                'sources': [os.path.normpath(os.path.join(os.path.abspath(intr.source_root), i['subdir'], x)) for x in sources],
                'generated_sources': []
            }],
            'subproject': None, # Subprojects are not supported
            'installed': i['installed']
        }]

    return tlist

def list_targets(builddata: build.Build, installdata, backend: backends.Backend) -> T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]:
    tlist = []  # type: T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]
    build_dir = builddata.environment.get_build_dir()
    src_dir = builddata.environment.get_source_dir()

    # Fast lookup table for installation files
    install_lookuptable = {}
    for i in installdata.targets:
        outname = os.path.join(installdata.prefix, i.outdir, os.path.basename(i.fname))
        install_lookuptable[os.path.basename(i.fname)] = str(pathlib.PurePath(outname))

    for (idname, target) in builddata.get_targets().items():
        if not isinstance(target, build.Target):
            raise RuntimeError('The target object in `builddata.get_targets()` is not of type `build.Target`. Please file a bug with this error message.')

        t = {
            'name': target.get_basename(),
            'id': idname,
            'type': target.get_typename(),
            'defined_in': os.path.normpath(os.path.join(src_dir, target.subdir, 'meson.build')),
            'filename': [os.path.join(build_dir, target.subdir, x) for x in target.get_outputs()],
            'build_by_default': target.build_by_default,
            'target_sources': backend.get_introspection_data(idname, target),
            'subproject': target.subproject or None
        }

        if installdata and target.should_install():
            t['installed'] = True
            t['install_filename'] = [install_lookuptable.get(x, None) for x in target.get_outputs()]
        else:
            t['installed'] = False
        tlist.append(t)
    return tlist

def list_buildoptions_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
    return list_buildoptions(intr.coredata)

def list_buildoptions(coredata: cdata.CoreData) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
    optlist = []  # type: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]

    dir_option_names = ['bindir',
                        'datadir',
                        'includedir',
                        'infodir',
                        'libdir',
                        'libexecdir',
                        'localedir',
                        'localstatedir',
                        'mandir',
                        'prefix',
                        'sbindir',
                        'sharedstatedir',
                        'sysconfdir']
    test_option_names = ['errorlogs',
                         'stdsplit']
    core_option_names = [k for k in coredata.builtins if k not in dir_option_names + test_option_names]

    dir_options = {k: o for k, o in coredata.builtins.items() if k in dir_option_names}
    test_options = {k: o for k, o in coredata.builtins.items() if k in test_option_names}
    core_options = {k: o for k, o in coredata.builtins.items() if k in core_option_names}

    def add_keys(options: T.Dict[str, cdata.UserOption], section: str, machine: str = 'any') -> None:
        for key in sorted(options.keys()):
            opt = options[key]
            optdict = {'name': key, 'value': opt.value, 'section': section, 'machine': machine}
            if isinstance(opt, cdata.UserStringOption):
                typestr = 'string'
            elif isinstance(opt, cdata.UserBooleanOption):
                typestr = 'boolean'
            elif isinstance(opt, cdata.UserComboOption):
                optdict['choices'] = opt.choices
                typestr = 'combo'
            elif isinstance(opt, cdata.UserIntegerOption):
                typestr = 'integer'
            elif isinstance(opt, cdata.UserArrayOption):
                typestr = 'array'
            else:
                raise RuntimeError("Unknown option type")
            optdict['type'] = typestr
            optdict['description'] = opt.description
            optlist.append(optdict)

    add_keys(core_options, 'core')
    add_keys(coredata.builtins_per_machine.host, 'core', machine='host')
    add_keys(
        {'build.' + k: o for k, o in coredata.builtins_per_machine.build.items()},
        'core',
        machine='build',
    )
    add_keys(coredata.backend_options, 'backend')
    add_keys(coredata.base_options, 'base')
    add_keys(coredata.compiler_options.host, 'compiler', machine='host')
    add_keys(
        {'build.' + k: o for k, o in coredata.compiler_options.build.items()},
        'compiler',
        machine='build',
    )
    add_keys(dir_options, 'directory')
    add_keys(coredata.user_options, 'user')
    add_keys(test_options, 'test')
    return optlist

def find_buildsystem_files_list(src_dir) -> T.List[str]:
    # I feel dirty about this. But only slightly.
    filelist = []  # type: T.List[str]
    for root, _, files in os.walk(src_dir):
        for f in files:
            if f == 'meson.build' or f == 'meson_options.txt':
                filelist.append(os.path.relpath(os.path.join(root, f), src_dir))
    return filelist

def list_buildsystem_files(builddata: build.Build) -> T.List[str]:
    src_dir = builddata.environment.get_source_dir()
    filelist = find_buildsystem_files_list(src_dir)
    filelist = [os.path.join(src_dir, x) for x in filelist]
    return filelist

def list_deps_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[str, bool]]]:
    result = []  # type: T.List[T.Dict[str, T.Union[str, bool]]]
    for i in intr.dependencies:
        keys = [
            'name',
            'required',
            'version',
            'has_fallback',
            'conditional',
        ]
        result += [{k: v for k, v in i.items() if k in keys}]
    return result

def list_deps(coredata: cdata.CoreData) -> T.List[T.Dict[str, T.Union[str, T.List[str]]]]:
    result = []  # type: T.List[T.Dict[str, T.Union[str, T.List[str]]]]
    for d in coredata.deps.host.values():
        if d.found():
            result += [{'name': d.name,
                        'version': d.get_version(),
                        'compile_args': d.get_compile_args(),
                        'link_args': d.get_link_args()}]
    return result

def get_test_list(testdata) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]:
    result = []  # type: T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]
    for t in testdata:
        to = {}
        if isinstance(t.fname, str):
            fname = [t.fname]
        else:
            fname = t.fname
        to['cmd'] = fname + t.cmd_args
        if isinstance(t.env, build.EnvironmentVariables):
            to['env'] = t.env.get_env({})
        else:
            to['env'] = t.env
        to['name'] = t.name
        to['workdir'] = t.workdir
        to['timeout'] = t.timeout
        to['suite'] = t.suite
        to['is_parallel'] = t.is_parallel
        to['priority'] = t.priority
        to['protocol'] = t.protocol
        result.append(to)
    return result

def list_tests(testdata) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]:
    return get_test_list(testdata)

def list_benchmarks(benchdata) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]:
    return get_test_list(benchdata)

def list_projinfo(builddata: build.Build) -> T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]]:
    result = {'version': builddata.project_version,
              'descriptive_name': builddata.project_name,
              'subproject_dir': builddata.subproject_dir}
    subprojects = []
    for k, v in builddata.subprojects.items():
        c = {'name': k,
             'version': v,
             'descriptive_name': builddata.projects.get(k)}
        subprojects.append(c)
    result['subprojects'] = subprojects
    return result

def list_projinfo_from_source(intr: IntrospectionInterpreter) -> T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]]:
    sourcedir = intr.source_root
    files = find_buildsystem_files_list(sourcedir)
    files = [os.path.normpath(x) for x in files]

    for i in intr.project_data['subprojects']:
        basedir = os.path.join(intr.subproject_dir, i['name'])
        i['buildsystem_files'] = [x for x in files if x.startswith(basedir)]
        files = [x for x in files if not x.startswith(basedir)]

    intr.project_data['buildsystem_files'] = files
    intr.project_data['subproject_dir'] = intr.subproject_dir
    return intr.project_data

def print_results(options, results: T.Sequence[T.Tuple[str, T.Union[dict, T.List[T.Any]]]], indent: int) -> int:
    if not results and not options.force_dict:
        print('No command specified')
        return 1
    elif len(results) == 1 and not options.force_dict:
        # Make to keep the existing output format for a single option
        print(json.dumps(results[0][1], indent=indent))
    else:
        out = {}
        for i in results:
            out[i[0]] = i[1]
        print(json.dumps(out, indent=indent))
    return 0

def run(options) -> int:
    datadir = 'meson-private'
    infodir = 'meson-info'
    if options.builddir is not None:
        datadir = os.path.join(options.builddir, datadir)
        infodir = os.path.join(options.builddir, infodir)
    indent = 4 if options.indent else None
    results = []  # type: T.List[T.Tuple[str, T.Union[dict, T.List[T.Any]]]]
    sourcedir = '.' if options.builddir == 'meson.build' else options.builddir[:-11]
    intro_types = get_meson_introspection_types(sourcedir=sourcedir)

    if 'meson.build' in [os.path.basename(options.builddir), options.builddir]:
        # Make sure that log entries in other parts of meson don't interfere with the JSON output
        mlog.disable()
        backend = backends.get_backend_from_name(options.backend, None)
        intr = IntrospectionInterpreter(sourcedir, '', backend.name, visitors = [AstIDGenerator(), AstIndentationGenerator(), AstConditionLevel()])
        intr.analyze()
        # Re-enable logging just in case
        mlog.enable()
        for key, val in intro_types.items():
            if (not options.all and not getattr(options, key, False)) or not val.no_bd:
                continue
            results += [(key, val.no_bd(intr))]
        return print_results(options, results, indent)

    infofile = get_meson_info_file(infodir)
    if not os.path.isdir(datadir) or not os.path.isdir(infodir) or not os.path.isfile(infofile):
        print('Current directory is not a meson build directory.\n'
              'Please specify a valid build dir or change the working directory to it.\n'
              'It is also possible that the build directory was generated with an old\n'
              'meson version. Please regenerate it in this case.')
        return 1

    with open(infofile, 'r') as fp:
        raw = json.load(fp)
        intro_vers = raw.get('introspection', {}).get('version', {}).get('full', '0.0.0')

    vers_to_check = get_meson_introspection_required_version()
    for i in vers_to_check:
        if not mesonlib.version_compare(intro_vers, i):
            print('Introspection version {} is not supported. '
                  'The required version is: {}'
                  .format(intro_vers, ' and '.join(vers_to_check)))
            return 1

    # Extract introspection information from JSON
    for i in intro_types.keys():
        if not intro_types[i].func:
            continue
        if not options.all and not getattr(options, i, False):
            continue
        curr = os.path.join(infodir, 'intro-{}.json'.format(i))
        if not os.path.isfile(curr):
            print('Introspection file {} does not exist.'.format(curr))
            return 1
        with open(curr, 'r') as fp:
            results += [(i, json.load(fp))]

    return print_results(options, results, indent)

updated_introspection_files = []  # type: T.List[str]

def write_intro_info(intro_info: T.Sequence[T.Tuple[str, T.Union[dict, T.List[T.Any]]]], info_dir: str) -> None:
    global updated_introspection_files
    for i in intro_info:
        out_file = os.path.join(info_dir, 'intro-{}.json'.format(i[0]))
        tmp_file = os.path.join(info_dir, 'tmp_dump.json')
        with open(tmp_file, 'w') as fp:
            json.dump(i[1], fp)
            fp.flush() # Not sure if this is needed
        os.replace(tmp_file, out_file)
        updated_introspection_files += [i[0]]

def generate_introspection_file(builddata: build.Build, backend: backends.Backend) -> None:
    coredata = builddata.environment.get_coredata()
    intro_types = get_meson_introspection_types(coredata=coredata, builddata=builddata, backend=backend)
    intro_info = []  # type: T.List[T.Tuple[str, T.Union[dict, T.List[T.Any]]]]

    for key, val in intro_types.items():
        if not val.func:
            continue
        intro_info += [(key, val.func())]

    write_intro_info(intro_info, builddata.environment.info_dir)

def update_build_options(coredata: cdata.CoreData, info_dir) -> None:
    intro_info = [
        ('buildoptions', list_buildoptions(coredata))
    ]

    write_intro_info(intro_info, info_dir)

def split_version_string(version: str) -> T.Dict[str, T.Union[str, int]]:
    vers_list = version.split('.')
    return {
        'full': version,
        'major': int(vers_list[0] if len(vers_list) > 0 else 0),
        'minor': int(vers_list[1] if len(vers_list) > 1 else 0),
        'patch': int(vers_list[2] if len(vers_list) > 2 else 0)
    }

def write_meson_info_file(builddata: build.Build, errors: list, build_files_updated: bool = False) -> None:
    global updated_introspection_files
    info_dir = builddata.environment.info_dir
    info_file = get_meson_info_file(info_dir)
    intro_types = get_meson_introspection_types()
    intro_info = {}

    for i in intro_types.keys():
        if not intro_types[i].func:
            continue
        intro_info[i] = {
            'file': 'intro-{}.json'.format(i),
            'updated': i in updated_introspection_files
        }

    info_data = {
        'meson_version': split_version_string(cdata.version),
        'directories': {
            'source': builddata.environment.get_source_dir(),
            'build': builddata.environment.get_build_dir(),
            'info': info_dir,
        },
        'introspection': {
            'version': split_version_string(get_meson_introspection_version()),
            'information': intro_info,
        },
        'build_files_updated': build_files_updated,
    }

    if errors:
        info_data['error'] = True
        info_data['error_list'] = [x if isinstance(x, str) else str(x) for x in errors]
    else:
        info_data['error'] = False

    # Write the data to disc
    tmp_file = os.path.join(info_dir, 'tmp_dump.json')
    with open(tmp_file, 'w') as fp:
        json.dump(info_data, fp)
        fp.flush()
    os.replace(tmp_file, info_file)
meson-0.53.2/mesonbuild/mlog.py0000644000175000017500000002535613625260316020004 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2014 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import io
import sys
import time
import platform
import typing as T
from contextlib import contextmanager
from pathlib import Path

"""This is (mostly) a standalone module used to write logging
information about Meson runs. Some output goes to screen,
some to logging dir and some goes to both."""

def _windows_ansi() -> bool:
    # windll only exists on windows, so mypy will get mad
    from ctypes import windll, byref  # type: ignore
    from ctypes.wintypes import DWORD

    kernel = windll.kernel32
    stdout = kernel.GetStdHandle(-11)
    mode = DWORD()
    if not kernel.GetConsoleMode(stdout, byref(mode)):
        return False
    # ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0x4
    # If the call to enable VT processing fails (returns 0), we fallback to
    # original behavior
    return bool(kernel.SetConsoleMode(stdout, mode.value | 0x4) or os.environ.get('ANSICON'))

def setup_console() -> bool:
    try:
        if platform.system().lower() == 'windows':
            return os.isatty(sys.stdout.fileno()) and _windows_ansi()
        return os.isatty(sys.stdout.fileno()) and os.environ.get('TERM') != 'dumb'
    except Exception:
        return False

colorize_console = setup_console()
log_dir = None               # type: T.Optional[str]
log_file = None              # type: T.Optional[T.TextIO]
log_fname = 'meson-log.txt'  # type: str
log_depth = 0                # type: int
log_timestamp_start = None   # type: T.Optional[float]
log_fatal_warnings = False   # type: bool
log_disable_stdout = False   # type: bool
log_errors_only = False      # type: bool
_in_ci = 'CI' in os.environ  # type: bool
_logged_once = set()         # type: T.Set[T.Tuple[str, ...]]

def disable() -> None:
    global log_disable_stdout
    log_disable_stdout = True

def enable() -> None:
    global log_disable_stdout
    log_disable_stdout = False

def set_quiet() -> None:
    global log_errors_only
    log_errors_only = True

def set_verbose() -> None:
    global log_errors_only
    log_errors_only = False

def initialize(logdir: str, fatal_warnings: bool = False) -> None:
    global log_dir, log_file, log_fatal_warnings
    log_dir = logdir
    log_file = open(os.path.join(logdir, log_fname), 'w', encoding='utf8')
    log_fatal_warnings = fatal_warnings

def set_timestamp_start(start: float) -> None:
    global log_timestamp_start
    log_timestamp_start = start

def shutdown() -> T.Optional[str]:
    global log_file
    if log_file is not None:
        path = log_file.name
        exception_around_goer = log_file
        log_file = None
        exception_around_goer.close()
        return path
    return None

class AnsiDecorator:
    plain_code = "\033[0m"

    def __init__(self, text: str, code: str, quoted: bool = False):
        self.text = text
        self.code = code
        self.quoted = quoted

    def get_text(self, with_codes: bool) -> str:
        text = self.text
        if with_codes:
            text = self.code + self.text + AnsiDecorator.plain_code
        if self.quoted:
            text = '"{}"'.format(text)
        return text

def bold(text: str, quoted: bool = False) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[1m", quoted=quoted)

def red(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[1;31m")

def green(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[1;32m")

def yellow(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[1;33m")

def blue(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[1;34m")

def cyan(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[1;36m")

def normal_red(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[31m")

def normal_green(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[32m")

def normal_yellow(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[33m")

def normal_blue(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[34m")

def normal_cyan(text: str) -> AnsiDecorator:
    return AnsiDecorator(text, "\033[36m")

# This really should be AnsiDecorator or anything that implements
# __str__(), but that requires protocols from typing_extensions
def process_markup(args: T.Sequence[T.Union[AnsiDecorator, str]], keep: bool) -> T.List[str]:
    arr = []  # type: T.List[str]
    if log_timestamp_start is not None:
        arr = ['[{:.3f}]'.format(time.monotonic() - log_timestamp_start)]
    for arg in args:
        if arg is None:
            continue
        if isinstance(arg, str):
            arr.append(arg)
        elif isinstance(arg, AnsiDecorator):
            arr.append(arg.get_text(keep))
        else:
            arr.append(str(arg))
    return arr

def force_print(*args: str, **kwargs: T.Any) -> None:
    if log_disable_stdout:
        return
    iostr = io.StringIO()
    kwargs['file'] = iostr
    print(*args, **kwargs)

    raw = iostr.getvalue()
    if log_depth > 0:
        prepend = '|' * log_depth
        raw = prepend + raw.replace('\n', '\n' + prepend, raw.count('\n') - 1)

    # _Something_ is going to get printed.
    try:
        print(raw, end='')
    except UnicodeEncodeError:
        cleaned = raw.encode('ascii', 'replace').decode('ascii')
        print(cleaned, end='')

# We really want a heterogeneous dict for this, but that's in typing_extensions
def debug(*args: T.Union[str, AnsiDecorator], **kwargs: T.Any) -> None:
    arr = process_markup(args, False)
    if log_file is not None:
        print(*arr, file=log_file, **kwargs)
        log_file.flush()

def _debug_log_cmd(cmd: str, args: T.List[str]) -> None:
    if not _in_ci:
        return
    args = ['"{}"'.format(x) for x in args]  # Quote all args, just in case
    debug('!meson_ci!/{} {}'.format(cmd, ' '.join(args)))

def cmd_ci_include(file: str) -> None:
    _debug_log_cmd('ci_include', [file])

def log(*args: T.Union[str, AnsiDecorator], is_error: bool = False,
        **kwargs: T.Any) -> None:
    arr = process_markup(args, False)
    if log_file is not None:
        print(*arr, file=log_file, **kwargs)
        log_file.flush()
    if colorize_console:
        arr = process_markup(args, True)
    if not log_errors_only or is_error:
        force_print(*arr, **kwargs)

def log_once(*args: T.Union[str, AnsiDecorator], is_error: bool = False,
             **kwargs: T.Any) -> None:
    """Log variant that only prints a given message one time per meson invocation.

    This considers nasi decorated values by the values they wrap without
    regard for the AnsiDecorator itself.
    """
    t = tuple(a.text if isinstance(a, AnsiDecorator) else a for a in args)
    if t in _logged_once:
        return
    _logged_once.add(t)
    log(*args, is_error=is_error, **kwargs)

def _log_error(severity: str, *rargs: T.Union[str, AnsiDecorator],
               once: bool = False, **kwargs: T.Any) -> None:
    from .mesonlib import get_error_location_string
    from .environment import build_filename
    from .mesonlib import MesonException

    # The tping requirements here are non-obvious. Lists are invariant,
    # therefore T.List[A] and T.List[T.Union[A, B]] are not able to be joined
    if severity == 'warning':
        label = [yellow('WARNING:')]  # type: T.List[T.Union[str, AnsiDecorator]]
    elif severity == 'error':
        label = [red('ERROR:')]
    elif severity == 'deprecation':
        label = [red('DEPRECATION:')]
    else:
        raise MesonException('Invalid severity ' + severity)
    # rargs is a tuple, not a list
    args = label + list(rargs)

    location = kwargs.pop('location', None)
    if location is not None:
        location_file = os.path.join(location.subdir, build_filename)
        location_str = get_error_location_string(location_file, location.lineno)
        # Unions are frankly awful, and we have to T.cast here to get mypy
        # to understand that the list concatenation is safe
        location_list = T.cast(T.List[T.Union[str, AnsiDecorator]], [location_str])
        args = location_list + args

    if once:
        log_once(*args, **kwargs)
    else:
        log(*args, **kwargs)

    if log_fatal_warnings:
        raise MesonException("Fatal warnings enabled, aborting")

def error(*args: T.Union[str, AnsiDecorator], once: bool = False, **kwargs: T.Any) -> None:
    return _log_error('error', *args, **kwargs, is_error=True, once=once)

def warning(*args: T.Union[str, AnsiDecorator], once: bool = False, **kwargs: T.Any) -> None:
    return _log_error('warning', *args, **kwargs, is_error=True, once=once)

def deprecation(*args: T.Union[str, AnsiDecorator], once: bool = False, **kwargs: T.Any) -> None:
    return _log_error('deprecation', *args, **kwargs, is_error=True, once=once)

def get_relative_path(target: Path, current: Path) -> Path:
    """Get the path to target from current"""
    # Go up "current" until we find a common ancestor to target
    acc = ['.']
    for part in [current, *current.parents]:
        try:
            path = target.relative_to(part)
            return Path(*acc, path)
        except ValueError:
            pass
        acc += ['..']

    # we failed, should not get here
    return target

def exception(e: Exception, prefix: T.Optional[AnsiDecorator] = None) -> None:
    if prefix is None:
        prefix = red('ERROR:')
    log()
    args = []  # type: T.List[T.Union[AnsiDecorator, str]]
    if hasattr(e, 'file') and hasattr(e, 'lineno') and hasattr(e, 'colno'):
        # Mypy can't figure this out, and it's pretty easy to vidual inspect
        # that this is correct, so we'll just ignore it.
        path = get_relative_path(Path(e.file), Path(os.getcwd()))
        args.append('%s:%d:%d:' % (path, e.lineno, e.colno))  # type: ignore
    if prefix:
        args.append(prefix)
    args.append(str(e))
    log(*args)

# Format a list for logging purposes as a string. It separates
# all but the last item with commas, and the last with 'and'.
def format_list(input_list: T.List[str]) -> str:
    l = len(input_list)
    if l > 2:
        return ' and '.join([', '.join(input_list[:-1]), input_list[-1]])
    elif l == 2:
        return ' and '.join(input_list)
    elif l == 1:
        return input_list[0]
    else:
        return ''

@contextmanager
def nested() -> T.Generator[None, None, None]:
    global log_depth
    log_depth += 1
    try:
        yield
    finally:
        log_depth -= 1
meson-0.53.2/mesonbuild/modules/0000755000175000017500000000000013625242354020133 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/modules/__init__.py0000644000175000017500000000572013571777336022265 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for external dependencies that
# are UI-related.

import os

from .. import build


class ExtensionModule:
    def __init__(self, interpreter):
        self.interpreter = interpreter
        self.snippets = set() # List of methods that operate only on the interpreter.

    def is_snippet(self, funcname):
        return funcname in self.snippets


def get_include_args(include_dirs, prefix='-I'):
    '''
    Expand include arguments to refer to the source and build dirs
    by using @SOURCE_ROOT@ and @BUILD_ROOT@ for later substitution
    '''
    if not include_dirs:
        return []

    dirs_str = []
    for incdirs in include_dirs:
        if hasattr(incdirs, "held_object"):
            dirs = incdirs.held_object
        else:
            dirs = incdirs

        if isinstance(dirs, str):
            dirs_str += ['%s%s' % (prefix, dirs)]
            continue

        # Should be build.IncludeDirs object.
        basedir = dirs.get_curdir()
        for d in dirs.get_incdirs():
            expdir = os.path.join(basedir, d)
            srctreedir = os.path.join('@SOURCE_ROOT@', expdir)
            buildtreedir = os.path.join('@BUILD_ROOT@', expdir)
            dirs_str += ['%s%s' % (prefix, buildtreedir),
                         '%s%s' % (prefix, srctreedir)]
        for d in dirs.get_extra_build_dirs():
            dirs_str += ['%s%s' % (prefix, d)]

    return dirs_str

class ModuleReturnValue:
    def __init__(self, return_value, new_objects):
        self.return_value = return_value
        assert(isinstance(new_objects, list))
        self.new_objects = new_objects

class GResourceTarget(build.CustomTarget):
    def __init__(self, name, subdir, subproject, kwargs):
        super().__init__(name, subdir, subproject, kwargs)

class GResourceHeaderTarget(build.CustomTarget):
    def __init__(self, name, subdir, subproject, kwargs):
        super().__init__(name, subdir, subproject, kwargs)

class GirTarget(build.CustomTarget):
    def __init__(self, name, subdir, subproject, kwargs):
        super().__init__(name, subdir, subproject, kwargs)

class TypelibTarget(build.CustomTarget):
    def __init__(self, name, subdir, subproject, kwargs):
        super().__init__(name, subdir, subproject, kwargs)

class VapiTarget(build.CustomTarget):
    def __init__(self, name, subdir, subproject, kwargs):
        super().__init__(name, subdir, subproject, kwargs)
meson-0.53.2/mesonbuild/modules/cmake.py0000644000175000017500000003054613625260316021573 0ustar  jpakkanejpakkane00000000000000# Copyright 2018 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re
import os, os.path, pathlib
import shutil

from . import ExtensionModule, ModuleReturnValue

from .. import build, dependencies, mesonlib, mlog
from ..interpreterbase import permittedKwargs, FeatureNew, stringArgs, InterpreterObject, ObjectHolder, noPosargs
from ..interpreter import ConfigurationDataHolder, InterpreterException, SubprojectHolder


COMPATIBILITIES = ['AnyNewerVersion', 'SameMajorVersion', 'SameMinorVersion', 'ExactVersion']

# Taken from https://github.com/Kitware/CMake/blob/master/Modules/CMakePackageConfigHelpers.cmake
PACKAGE_INIT_BASE = '''
####### Expanded from \\@PACKAGE_INIT\\@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was @inputFileName@ ########

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/@PACKAGE_RELATIVE_PATH@" ABSOLUTE)
'''
PACKAGE_INIT_EXT = '''
# Use original install prefix when loaded through a "/usr move"
# cross-prefix symbolic link such as /lib -> /usr/lib.
get_filename_component(_realCurr "${CMAKE_CURRENT_LIST_DIR}" REALPATH)
get_filename_component(_realOrig "@absInstallDir@" REALPATH)
if(_realCurr STREQUAL _realOrig)
  set(PACKAGE_PREFIX_DIR "@installPrefix@")
endif()
unset(_realOrig)
unset(_realCurr)
'''
PACKAGE_INIT_SET_AND_CHECK = '''
macro(set_and_check _var _file)
  set(${_var} "${_file}")
  if(NOT EXISTS "${_file}")
    message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
  endif()
endmacro()

####################################################################################
'''

class CMakeSubprojectHolder(InterpreterObject, ObjectHolder):
    def __init__(self, subp, pv):
        assert(isinstance(subp, SubprojectHolder))
        assert(hasattr(subp, 'cm_interpreter'))
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, subp, pv)
        self.methods.update({'get_variable': self.get_variable,
                             'dependency': self.dependency,
                             'include_directories': self.include_directories,
                             'target': self.target,
                             'target_type': self.target_type,
                             'target_list': self.target_list,
                             'found': self.found_method,
                             })

    def _args_to_info(self, args):
        if len(args) != 1:
            raise InterpreterException('Exactly one argument is required.')

        tgt = args[0]
        res = self.held_object.cm_interpreter.target_info(tgt)
        if res is None:
            raise InterpreterException('The CMake target {} does not exist'.format(tgt))

        # Make sure that all keys are present (if not this is a bug)
        assert(all([x in res for x in ['inc', 'src', 'dep', 'tgt', 'func']]))
        return res

    @permittedKwargs({})
    def get_variable(self, args, kwargs):
        return self.held_object.get_variable_method(args, kwargs)

    @permittedKwargs({})
    def dependency(self, args, kwargs):
        info = self._args_to_info(args)
        return self.get_variable([info['dep']], kwargs)

    @permittedKwargs({})
    def include_directories(self, args, kwargs):
        info = self._args_to_info(args)
        return self.get_variable([info['inc']], kwargs)

    @permittedKwargs({})
    def target(self, args, kwargs):
        info = self._args_to_info(args)
        return self.get_variable([info['tgt']], kwargs)

    @permittedKwargs({})
    def target_type(self, args, kwargs):
        info = self._args_to_info(args)
        return info['func']

    @noPosargs
    @permittedKwargs({})
    def target_list(self, args, kwargs):
        return self.held_object.cm_interpreter.target_list()

    @noPosargs
    @permittedKwargs({})
    @FeatureNew('CMakeSubproject.found()', '0.53.2')
    def found_method(self, args, kwargs):
        return self.held_object is not None


class CmakeModule(ExtensionModule):
    cmake_detected = False
    cmake_root = None

    def __init__(self, interpreter):
        super().__init__(interpreter)
        self.snippets.add('configure_package_config_file')
        self.snippets.add('subproject')

    def detect_voidp_size(self, env):
        compilers = env.coredata.compilers.host
        compiler = compilers.get('c', None)
        if not compiler:
            compiler = compilers.get('cpp', None)

        if not compiler:
            raise mesonlib.MesonException('Requires a C or C++ compiler to compute sizeof(void *).')

        return compiler.sizeof('void *', '', env)

    def detect_cmake(self):
        if self.cmake_detected:
            return True

        cmakebin = dependencies.ExternalProgram('cmake', silent=False)
        p, stdout, stderr = mesonlib.Popen_safe(cmakebin.get_command() + ['--system-information', '-G', 'Ninja'])[0:3]
        if p.returncode != 0:
            mlog.log('error retrieving cmake information: returnCode={0} stdout={1} stderr={2}'.format(p.returncode, stdout, stderr))
            return False

        match = re.search('\nCMAKE_ROOT \\"([^"]+)"\n', stdout.strip())
        if not match:
            mlog.log('unable to determine cmake root')
            return False

        cmakePath = pathlib.PurePath(match.group(1))
        self.cmake_root = os.path.join(*cmakePath.parts)
        self.cmake_detected = True
        return True

    @permittedKwargs({'version', 'name', 'compatibility', 'install_dir'})
    def write_basic_package_version_file(self, state, _args, kwargs):
        version = kwargs.get('version', None)
        if not isinstance(version, str):
            raise mesonlib.MesonException('Version must be specified.')

        name = kwargs.get('name', None)
        if not isinstance(name, str):
            raise mesonlib.MesonException('Name not specified.')

        compatibility = kwargs.get('compatibility', 'AnyNewerVersion')
        if not isinstance(compatibility, str):
            raise mesonlib.MesonException('compatibility is not string.')
        if compatibility not in COMPATIBILITIES:
            raise mesonlib.MesonException('compatibility must be either AnyNewerVersion, SameMajorVersion or ExactVersion.')

        if not self.detect_cmake():
            raise mesonlib.MesonException('Unable to find cmake')

        pkgroot = kwargs.get('install_dir', None)
        if pkgroot is None:
            pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'cmake', name)
        if not isinstance(pkgroot, str):
            raise mesonlib.MesonException('Install_dir must be a string.')

        template_file = os.path.join(self.cmake_root, 'Modules', 'BasicConfigVersion-{}.cmake.in'.format(compatibility))
        if not os.path.exists(template_file):
            raise mesonlib.MesonException('your cmake installation doesn\'t support the {} compatibility'.format(compatibility))

        version_file = os.path.join(state.environment.scratch_dir, '{}ConfigVersion.cmake'.format(name))

        conf = {
            'CVF_VERSION': (version, ''),
            'CMAKE_SIZEOF_VOID_P': (str(self.detect_voidp_size(state.environment)), '')
        }
        mesonlib.do_conf_file(template_file, version_file, conf, 'meson')

        res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), version_file), pkgroot)
        return ModuleReturnValue(res, [res])

    def create_package_file(self, infile, outfile, PACKAGE_RELATIVE_PATH, extra, confdata):
        package_init = PACKAGE_INIT_BASE.replace('@PACKAGE_RELATIVE_PATH@', PACKAGE_RELATIVE_PATH)
        package_init = package_init.replace('@inputFileName@', infile)
        package_init += extra
        package_init += PACKAGE_INIT_SET_AND_CHECK

        try:
            with open(infile, "r") as fin:
                data = fin.readlines()
        except Exception as e:
            raise mesonlib.MesonException('Could not read input file %s: %s' % (infile, str(e)))

        result = []
        regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@')
        for line in data:
            line = line.replace('@PACKAGE_INIT@', package_init)
            line, _missing = mesonlib.do_replacement(regex, line, 'meson', confdata)

            result.append(line)

        outfile_tmp = outfile + "~"
        with open(outfile_tmp, "w", encoding='utf-8') as fout:
            fout.writelines(result)

        shutil.copymode(infile, outfile_tmp)
        mesonlib.replace_if_different(outfile, outfile_tmp)

    @permittedKwargs({'input', 'name', 'install_dir', 'configuration'})
    def configure_package_config_file(self, interpreter, state, args, kwargs):
        if args:
            raise mesonlib.MesonException('configure_package_config_file takes only keyword arguments.')

        if 'input' not in kwargs:
            raise mesonlib.MesonException('configure_package_config_file requires "input" keyword.')
        inputfile = kwargs['input']
        if isinstance(inputfile, list):
            if len(inputfile) != 1:
                m = "Keyword argument 'input' requires exactly one file"
                raise mesonlib.MesonException(m)
            inputfile = inputfile[0]
        if not isinstance(inputfile, (str, mesonlib.File)):
            raise mesonlib.MesonException("input must be a string or a file")
        if isinstance(inputfile, str):
            inputfile = mesonlib.File.from_source_file(state.environment.source_dir, state.subdir, inputfile)

        ifile_abs = inputfile.absolute_path(state.environment.source_dir, state.environment.build_dir)

        if 'name' not in kwargs:
            raise mesonlib.MesonException('"name" not specified.')
        name = kwargs['name']

        (ofile_path, ofile_fname) = os.path.split(os.path.join(state.subdir, '{}Config.cmake'.format(name)))
        ofile_abs = os.path.join(state.environment.build_dir, ofile_path, ofile_fname)

        if 'install_dir' not in kwargs:
            install_dir = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'cmake', name)
        if not isinstance(install_dir, str):
            raise mesonlib.MesonException('"install_dir" must be a string.')

        if 'configuration' not in kwargs:
            raise mesonlib.MesonException('"configuration" not specified.')
        conf = kwargs['configuration']
        if not isinstance(conf, ConfigurationDataHolder):
            raise mesonlib.MesonException('Argument "configuration" is not of type configuration_data')

        prefix = state.environment.coredata.get_builtin_option('prefix')
        abs_install_dir = install_dir
        if not os.path.isabs(abs_install_dir):
            abs_install_dir = os.path.join(prefix, install_dir)

        PACKAGE_RELATIVE_PATH = os.path.relpath(prefix, abs_install_dir)
        extra = ''
        if re.match('^(/usr)?/lib(64)?/.+', abs_install_dir):
            extra = PACKAGE_INIT_EXT.replace('@absInstallDir@', abs_install_dir)
            extra = extra.replace('@installPrefix@', prefix)

        self.create_package_file(ifile_abs, ofile_abs, PACKAGE_RELATIVE_PATH, extra, conf.held_object)
        conf.mark_used()

        conffile = os.path.normpath(inputfile.relative_name())
        if conffile not in interpreter.build_def_files:
            interpreter.build_def_files.append(conffile)

        res = build.Data(mesonlib.File(True, ofile_path, ofile_fname), install_dir)
        interpreter.build.data.append(res)

        return res

    @FeatureNew('subproject', '0.51.0')
    @permittedKwargs({'cmake_options', 'required'})
    @stringArgs
    def subproject(self, interpreter, state, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Subproject takes exactly one argument')
        dirname = args[0]
        subp = interpreter.do_subproject(dirname, 'cmake', kwargs)
        if not subp.held_object:
            return subp
        return CMakeSubprojectHolder(subp, dirname)

def initialize(*args, **kwargs):
    return CmakeModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/dlang.py0000644000175000017500000001175213366273150021600 0ustar  jpakkanejpakkane00000000000000# Copyright 2018 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file contains the detection logic for external dependencies that
# are UI-related.

import json
import os

from . import ExtensionModule

from .. import mlog

from ..mesonlib import (
    Popen_safe, MesonException
)

from ..dependencies.base import (
    ExternalProgram, DubDependency
)

from ..interpreter import DependencyHolder

class DlangModule(ExtensionModule):
    class_dubbin = None
    init_dub = False

    def __init__(self, interpreter):
        super().__init__(interpreter)
        self.snippets.add('generate_dub_file')

    def _init_dub(self):
        if DlangModule.class_dubbin is None:
            self.dubbin = DubDependency.class_dubbin
            DlangModule.class_dubbin = self.dubbin
        else:
            self.dubbin = DlangModule.class_dubbin

        if DlangModule.class_dubbin is None:
            self.dubbin = self.check_dub()
            DlangModule.class_dubbin = self.dubbin
        else:
            self.dubbin = DlangModule.class_dubbin

        if not self.dubbin:
            if not self.dubbin:
                raise MesonException('DUB not found.')

    def generate_dub_file(self, interpreter, state, args, kwargs):
        if not DlangModule.init_dub:
            self._init_dub()

        if len(args) < 2:
            raise MesonException('Missing arguments')

        config = {
            'name': args[0]
        }

        config_path = os.path.join(args[1], 'dub.json')
        if os.path.exists(config_path):
            with open(config_path, 'r', encoding='utf8') as ofile:
                try:
                    config = json.load(ofile)
                except ValueError:
                    mlog.warning('Failed to load the data in dub.json')

        warn_publishing = ['description', 'license']
        for arg in warn_publishing:
            if arg not in kwargs and \
               arg not in config:
                mlog.warning('Without', mlog.bold(arg), 'the DUB package can\'t be published')

        for key, value in kwargs.items():
            if key == 'dependencies':
                config[key] = {}
                if isinstance(value, list):
                    for dep in value:
                        if isinstance(dep, DependencyHolder):
                            name = dep.method_call('name', [], [])
                            ret, res = self._call_dubbin(['describe', name])
                            if ret == 0:
                                version = dep.method_call('version', [], [])
                                if version is None:
                                    config[key][name] = ''
                                else:
                                    config[key][name] = version
                elif isinstance(value, DependencyHolder):
                    name = value.method_call('name', [], [])
                    ret, res = self._call_dubbin(['describe', name])
                    if ret == 0:
                        version = value.method_call('version', [], [])
                        if version is None:
                            config[key][name] = ''
                        else:
                            config[key][name] = version
            else:
                config[key] = value

        with open(config_path, 'w', encoding='utf8') as ofile:
            ofile.write(json.dumps(config, indent=4, ensure_ascii=False))

    def _call_dubbin(self, args, env=None):
        p, out = Popen_safe(self.dubbin.get_command() + args, env=env)[0:2]
        return p.returncode, out.strip()

    def check_dub(self):
        dubbin = ExternalProgram('dub', silent=True)
        if dubbin.found():
            try:
                p, out = Popen_safe(dubbin.get_command() + ['--version'])[0:2]
                if p.returncode != 0:
                    mlog.warning('Found dub {!r} but couldn\'t run it'
                                 ''.format(' '.join(dubbin.get_command())))
                    # Set to False instead of None to signify that we've already
                    # searched for it and not found it
                    dubbin = False
            except (FileNotFoundError, PermissionError):
                dubbin = False
        else:
            dubbin = False
        if dubbin:
            mlog.log('Found DUB:', mlog.bold(dubbin.get_path()),
                     '(%s)' % out.strip())
        else:
            mlog.log('Found DUB:', mlog.red('NO'))
        return dubbin

def initialize(*args, **kwargs):
    return DlangModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/fs.py0000644000175000017500000001265313612313307021115 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import typing as T
import hashlib
from pathlib import Path, PurePath

from .. import mlog
from . import ExtensionModule
from . import ModuleReturnValue
from ..mesonlib import MesonException

from ..interpreterbase import stringArgs, noKwargs
if T.TYPE_CHECKING:
    from ..interpreter import ModuleState

class FSModule(ExtensionModule):

    def __init__(self, interpreter):
        super().__init__(interpreter)
        self.snippets.add('generate_dub_file')

    def _resolve_dir(self, state: 'ModuleState', arg: str) -> Path:
        """
        resolves (makes absolute) a directory relative to calling meson.build,
        if not already absolute
        """
        return Path(state.source_root) / state.subdir / Path(arg).expanduser()

    def _check(self, check: str, state: 'ModuleState', args: T.Sequence[str]) -> ModuleReturnValue:
        if len(args) != 1:
            raise MesonException('fs.{} takes exactly one argument.'.format(check))
        test_file = self._resolve_dir(state, args[0])
        return ModuleReturnValue(getattr(test_file, check)(), [])

    @stringArgs
    @noKwargs
    def exists(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        return self._check('exists', state, args)

    @stringArgs
    @noKwargs
    def is_symlink(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        return self._check('is_symlink', state, args)

    @stringArgs
    @noKwargs
    def is_file(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        return self._check('is_file', state, args)

    @stringArgs
    @noKwargs
    def is_dir(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        return self._check('is_dir', state, args)

    @stringArgs
    @noKwargs
    def hash(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        if len(args) != 2:
            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))
        try:
            h = hashlib.new(args[1])
        except ValueError:
            raise MesonException('hash algorithm {} is not available'.format(args[1]))
        mlog.debug('computing {} sum of {} size {} bytes'.format(args[1], file, file.stat().st_size))
        h.update(file.read_bytes())
        return ModuleReturnValue(h.hexdigest(), [])

    @stringArgs
    @noKwargs
    def size(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        if len(args) != 1:
            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))
        try:
            return ModuleReturnValue(file.stat().st_size, [])
        except ValueError:
            raise MesonException('{} size could not be determined'.format(args[0]))

    @stringArgs
    @noKwargs
    def is_samepath(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        if len(args) != 2:
            raise MesonException('fs.is_samepath takes exactly two arguments.')
        file1 = self._resolve_dir(state, args[0])
        file2 = self._resolve_dir(state, args[1])
        if not file1.exists():
            return ModuleReturnValue(False, [])
        if not file2.exists():
            return ModuleReturnValue(False, [])
        try:
            return ModuleReturnValue(file1.samefile(file2), [])
        except OSError:
            return ModuleReturnValue(False, [])

    @stringArgs
    @noKwargs
    def replace_suffix(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        if len(args) != 2:
            raise MesonException('method takes exactly two arguments.')
        original = PurePath(args[0])
        new = original.with_suffix(args[1])
        return ModuleReturnValue(str(new), [])

    @stringArgs
    @noKwargs
    def parent(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        if len(args) != 1:
            raise MesonException('method takes exactly one argument.')
        original = PurePath(args[0])
        new = original.parent
        return ModuleReturnValue(str(new), [])

    @stringArgs
    @noKwargs
    def name(self, state: 'ModuleState', args: T.Sequence[str], kwargs: dict) -> ModuleReturnValue:
        if len(args) != 1:
            raise MesonException('method takes exactly one argument.')
        original = PurePath(args[0])
        new = original.name
        return ModuleReturnValue(str(new), [])

def initialize(*args, **kwargs) -> FSModule:
    return FSModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/gnome.py0000644000175000017500000023530513571777336021637 0ustar  jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

'''This module provides helper functions for Gnome/GLib related
functionality such as gobject-introspection, gresources and gtk-doc'''

import os
import copy
import subprocess
import functools

from .. import build
from .. import mlog
from .. import mesonlib
from .. import interpreter
from . import GResourceTarget, GResourceHeaderTarget, GirTarget, TypelibTarget, VapiTarget
from . import get_include_args
from . import ExtensionModule
from . import ModuleReturnValue
from ..mesonlib import (
    MachineChoice, MesonException, OrderedSet, Popen_safe, extract_as_list, join_args
)
from ..dependencies import Dependency, PkgConfigDependency, InternalDependency
from ..interpreterbase import noKwargs, permittedKwargs, FeatureNew, FeatureNewKwargs

# gresource compilation is broken due to the way
# the resource compiler and Ninja clash about it
#
# https://github.com/ninja-build/ninja/issues/1184
# https://bugzilla.gnome.org/show_bug.cgi?id=774368
gresource_dep_needed_version = '>= 2.51.1'

native_glib_version = None

@functools.lru_cache(maxsize=None)
def gir_has_option(intr_obj, option):
    try:
        g_ir_scanner = intr_obj.find_program_impl('g-ir-scanner')
        # Handle overridden g-ir-scanner
        if isinstance(getattr(g_ir_scanner, "held_object", g_ir_scanner), interpreter.OverrideProgram):
            assert option in ['--extra-library', '--sources-top-dirs']
            return True

        opts = Popen_safe(g_ir_scanner.get_command() + ['--help'], stderr=subprocess.STDOUT)[1]
        return option in opts
    except (MesonException, FileNotFoundError, subprocess.CalledProcessError):
        return False

class GnomeModule(ExtensionModule):
    gir_dep = None

    @staticmethod
    def _get_native_glib_version(state):
        global native_glib_version
        if native_glib_version is None:
            glib_dep = PkgConfigDependency('glib-2.0', state.environment,
                                           {'native': True, 'required': False})
            if glib_dep.found():
                native_glib_version = glib_dep.get_version()
            else:
                mlog.warning('Could not detect glib version, assuming 2.54. '
                             'You may get build errors if your glib is older.')
                native_glib_version = '2.54'
        return native_glib_version

    @mesonlib.run_once
    def __print_gresources_warning(self, state):
        if not mesonlib.version_compare(self._get_native_glib_version(state),
                                        gresource_dep_needed_version):
            mlog.warning('GLib compiled dependencies do not work reliably with \n'
                         'the current version of GLib. See the following upstream issue:',
                         mlog.bold('https://bugzilla.gnome.org/show_bug.cgi?id=774368'))

    @staticmethod
    @mesonlib.run_once
    def _print_gdbus_warning():
        mlog.warning('Code generated with gdbus_codegen() requires the root directory be added to\n'
                     '  include_directories of targets with GLib < 2.51.3:',
                     mlog.bold('https://github.com/mesonbuild/meson/issues/1387'))

    @FeatureNewKwargs('gnome.compile_resources', '0.37.0', ['gresource_bundle', 'export', 'install_header'])
    @permittedKwargs({'source_dir', 'c_name', 'dependencies', 'export', 'gresource_bundle', 'install_header',
                      'install', 'install_dir', 'extra_args', 'build_by_default'})
    def compile_resources(self, state, args, kwargs):
        self.__print_gresources_warning(state)
        glib_version = self._get_native_glib_version(state)

        cmd = ['glib-compile-resources', '@INPUT@']

        source_dirs, dependencies = mesonlib.extract_as_list(kwargs, 'source_dir', 'dependencies', pop=True)

        if len(args) < 2:
            raise MesonException('Not enough arguments; the name of the resource '
                                 'and the path to the XML file are required')

        # Validate dependencies
        for (ii, dep) in enumerate(dependencies):
            if hasattr(dep, 'held_object'):
                dependencies[ii] = dep = dep.held_object
            if not isinstance(dep, (mesonlib.File, build.CustomTarget, build.CustomTargetIndex)):
                m = 'Unexpected dependency type {!r} for gnome.compile_resources() ' \
                    '"dependencies" argument.\nPlease pass the return value of ' \
                    'custom_target() or configure_file()'
                raise MesonException(m.format(dep))
            if isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)):
                if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
                    m = 'The "dependencies" argument of gnome.compile_resources() can not\n' \
                        'be used with the current version of glib-compile-resources due to\n' \
                        ''
                    raise MesonException(m)

        ifile = args[1]
        if isinstance(ifile, mesonlib.File):
            # glib-compile-resources will be run inside the source dir,
            # so we need either 'src_to_build' or the absolute path.
            # Absolute path is the easiest choice.
            if ifile.is_built:
                ifile = os.path.join(state.environment.get_build_dir(), ifile.subdir, ifile.fname)
            else:
                ifile = os.path.join(ifile.subdir, ifile.fname)
        elif isinstance(ifile, str):
            ifile = os.path.join(state.subdir, ifile)
        elif isinstance(ifile, (interpreter.CustomTargetHolder,
                                interpreter.CustomTargetIndexHolder,
                                interpreter.GeneratedObjectsHolder)):
            m = 'Resource xml files generated at build-time cannot be used ' \
                'with gnome.compile_resources() because we need to scan ' \
                'the xml for dependencies. Use configure_file() instead ' \
                'to generate it at configure-time.'
            raise MesonException(m)
        else:
            raise MesonException('Invalid file argument: {!r}'.format(ifile))

        depend_files, depends, subdirs = self._get_gresource_dependencies(
            state, ifile, source_dirs, dependencies)

        # Make source dirs relative to build dir now
        source_dirs = [os.path.join(state.build_to_src, state.subdir, d) for d in source_dirs]
        # Ensure build directories of generated deps are included
        source_dirs += subdirs
        # Always include current directory, but after paths set by user
        source_dirs.append(os.path.join(state.build_to_src, state.subdir))

        for source_dir in OrderedSet(source_dirs):
            cmd += ['--sourcedir', source_dir]

        if 'c_name' in kwargs:
            cmd += ['--c-name', kwargs.pop('c_name')]
        export = kwargs.pop('export', False)
        if not export:
            cmd += ['--internal']

        cmd += ['--generate', '--target', '@OUTPUT@']

        cmd += mesonlib.stringlistify(kwargs.pop('extra_args', []))

        gresource = kwargs.pop('gresource_bundle', False)
        if gresource:
            output = args[0] + '.gresource'
            name = args[0] + '_gresource'
        else:
            output = args[0] + '.c'
            name = args[0] + '_c'

        if kwargs.get('install', False) and not gresource:
            raise MesonException('The install kwarg only applies to gresource bundles, see install_header')

        install_header = kwargs.pop('install_header', False)
        if install_header and gresource:
            raise MesonException('The install_header kwarg does not apply to gresource bundles')
        if install_header and not export:
            raise MesonException('GResource header is installed yet export is not enabled')

        kwargs['input'] = args[1]
        kwargs['output'] = output
        kwargs['depends'] = depends
        if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
            # This will eventually go out of sync if dependencies are added
            kwargs['depend_files'] = depend_files
            kwargs['command'] = cmd
        else:
            depfile = kwargs['output'] + '.d'
            kwargs['depfile'] = depfile
            kwargs['command'] = copy.copy(cmd) + ['--dependency-file', '@DEPFILE@']
        target_c = GResourceTarget(name, state.subdir, state.subproject, kwargs)

        if gresource: # Only one target for .gresource files
            return ModuleReturnValue(target_c, [target_c])

        h_kwargs = {
            'command': cmd,
            'input': args[1],
            'output': args[0] + '.h',
            # The header doesn't actually care about the files yet it errors if missing
            'depends': depends
        }
        if 'build_by_default' in kwargs:
            h_kwargs['build_by_default'] = kwargs['build_by_default']
        if install_header:
            h_kwargs['install'] = install_header
            h_kwargs['install_dir'] = kwargs.get('install_dir',
                                                 state.environment.coredata.get_builtin_option('includedir'))
        target_h = GResourceHeaderTarget(args[0] + '_h', state.subdir, state.subproject, h_kwargs)
        rv = [target_c, target_h]
        return ModuleReturnValue(rv, rv)

    def _get_gresource_dependencies(self, state, input_file, source_dirs, dependencies):

        cmd = ['glib-compile-resources',
               input_file,
               '--generate-dependencies']

        # Prefer generated files over source files
        cmd += ['--sourcedir', state.subdir] # Current build dir
        for source_dir in source_dirs:
            cmd += ['--sourcedir', os.path.join(state.subdir, source_dir)]

        pc, stdout, stderr = Popen_safe(cmd, cwd=state.environment.get_source_dir())
        if pc.returncode != 0:
            m = 'glib-compile-resources failed to get dependencies for {}:\n{}'
            mlog.warning(m.format(cmd[1], stderr))
            raise subprocess.CalledProcessError(pc.returncode, cmd)

        dep_files = stdout.split('\n')[:-1]

        depends = []
        subdirs = []
        for resfile in dep_files[:]:
            resbasename = os.path.basename(resfile)
            for dep in dependencies:
                if hasattr(dep, 'held_object'):
                    dep = dep.held_object
                if isinstance(dep, mesonlib.File):
                    if dep.fname != resbasename:
                        continue
                    dep_files.remove(resfile)
                    dep_files.append(dep)
                    subdirs.append(dep.subdir)
                    break
                elif isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)):
                    fname = None
                    outputs = {(o, os.path.basename(o)) for o in dep.get_outputs()}
                    for o, baseo in outputs:
                        if baseo == resbasename:
                            fname = o
                            break
                    if fname is not None:
                        dep_files.remove(resfile)
                        depends.append(dep)
                        subdirs.append(dep.get_subdir())
                        break
            else:
                # In generate-dependencies mode, glib-compile-resources doesn't raise
                # an error for missing resources but instead prints whatever filename
                # was listed in the input file.  That's good because it means we can
                # handle resource files that get generated as part of the build, as
                # follows.
                #
                # If there are multiple generated resource files with the same basename
                # then this code will get confused.
                try:
                    f = mesonlib.File.from_source_file(state.environment.get_source_dir(),
                                                       ".", resfile)
                except MesonException:
                    raise MesonException(
                        'Resource "%s" listed in "%s" was not found. If this is a '
                        'generated file, pass the target that generates it to '
                        'gnome.compile_resources() using the "dependencies" '
                        'keyword argument.' % (resfile, input_file))
                dep_files.remove(resfile)
                dep_files.append(f)
        return dep_files, depends, subdirs

    def _get_link_args(self, state, lib, depends, include_rpath=False,
                       use_gir_args=False):
        link_command = []
        # Construct link args
        if isinstance(lib, build.SharedLibrary):
            libdir = os.path.join(state.environment.get_build_dir(), state.backend.get_target_dir(lib))
            link_command.append('-L' + libdir)
            if include_rpath:
                link_command.append('-Wl,-rpath,' + libdir)
            depends.append(lib)
            # Needed for the following binutils bug:
            # https://github.com/mesonbuild/meson/issues/1911
            # However, g-ir-scanner does not understand -Wl,-rpath
            # so we need to use -L instead
            for d in state.backend.determine_rpath_dirs(lib):
                d = os.path.join(state.environment.get_build_dir(), d)
                link_command.append('-L' + d)
                if include_rpath:
                    link_command.append('-Wl,-rpath,' + d)
        if gir_has_option(self.interpreter, '--extra-library') and use_gir_args:
            link_command.append('--extra-library=' + lib.name)
        else:
            link_command.append('-l' + lib.name)
        return link_command

    def _get_dependencies_flags(self, deps, state, depends, include_rpath=False,
                                use_gir_args=False, separate_nodedup=False):
        cflags = OrderedSet()
        internal_ldflags = OrderedSet()
        external_ldflags = OrderedSet()
        # External linker flags that can't be de-duped reliably because they
        # require two args in order, such as -framework AVFoundation
        external_ldflags_nodedup = []
        gi_includes = OrderedSet()
        deps = mesonlib.listify(deps, unholder=True)

        for dep in deps:
            if isinstance(dep, InternalDependency):
                cflags.update(dep.get_compile_args())
                cflags.update(get_include_args(dep.include_directories))
                for lib in dep.libraries:
                    if hasattr(lib, 'held_object'):
                        lib = lib.held_object
                    if isinstance(lib, build.SharedLibrary):
                        internal_ldflags.update(self._get_link_args(state, lib, depends, include_rpath))
                        libdepflags = self._get_dependencies_flags(lib.get_external_deps(), state, depends, include_rpath,
                                                                   use_gir_args, True)
                        cflags.update(libdepflags[0])
                        internal_ldflags.update(libdepflags[1])
                        external_ldflags.update(libdepflags[2])
                        external_ldflags_nodedup += libdepflags[3]
                        gi_includes.update(libdepflags[4])
                extdepflags = self._get_dependencies_flags(dep.ext_deps, state, depends, include_rpath,
                                                           use_gir_args, True)
                cflags.update(extdepflags[0])
                internal_ldflags.update(extdepflags[1])
                external_ldflags.update(extdepflags[2])
                external_ldflags_nodedup += extdepflags[3]
                gi_includes.update(extdepflags[4])
                for source in dep.sources:
                    if hasattr(source, 'held_object'):
                        source = source.held_object
                    if isinstance(source, GirTarget):
                        gi_includes.update([os.path.join(state.environment.get_build_dir(),
                                            source.get_subdir())])
            # This should be any dependency other than an internal one.
            elif isinstance(dep, Dependency):
                cflags.update(dep.get_compile_args())
                ldflags = iter(dep.get_link_args(raw=True))
                for lib in ldflags:
                    if (os.path.isabs(lib) and
                            # For PkgConfigDependency only:
                            getattr(dep, 'is_libtool', False)):
                        lib_dir = os.path.dirname(lib)
                        external_ldflags.update(["-L%s" % lib_dir])
                        if include_rpath:
                            external_ldflags.update(['-Wl,-rpath {}'.format(lib_dir)])
                        libname = os.path.basename(lib)
                        if libname.startswith("lib"):
                            libname = libname[3:]
                        libname = libname.split(".so")[0]
                        lib = "-l%s" % libname
                    # FIXME: Hack to avoid passing some compiler options in
                    if lib.startswith("-W"):
                        continue
                    # If it's a framework arg, slurp the framework name too
                    # to preserve the order of arguments
                    if lib == '-framework':
                        external_ldflags_nodedup += [lib, next(ldflags)]
                    else:
                        external_ldflags.update([lib])

                if isinstance(dep, PkgConfigDependency):
                    girdir = dep.get_pkgconfig_variable("girdir", {'default': ''})
                    if girdir:
                        gi_includes.update([girdir])
            elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
                cflags.update(get_include_args(dep.get_include_dirs()))
                depends.append(dep)
            else:
                mlog.log('dependency {!r} not handled to build gir files'.format(dep))
                continue

        if gir_has_option(self.interpreter, '--extra-library') and use_gir_args:
            def fix_ldflags(ldflags):
                fixed_ldflags = OrderedSet()
                for ldflag in ldflags:
                    if ldflag.startswith("-l"):
                        ldflag = ldflag.replace('-l', '--extra-library=', 1)
                    fixed_ldflags.add(ldflag)
                return fixed_ldflags
            internal_ldflags = fix_ldflags(internal_ldflags)
            external_ldflags = fix_ldflags(external_ldflags)
        if not separate_nodedup:
            external_ldflags.update(external_ldflags_nodedup)
            return cflags, internal_ldflags, external_ldflags, gi_includes
        else:
            return cflags, internal_ldflags, external_ldflags, external_ldflags_nodedup, gi_includes

    def _unwrap_gir_target(self, girtarget, state):
        while hasattr(girtarget, 'held_object'):
            girtarget = girtarget.held_object

        if not isinstance(girtarget, (build.Executable, build.SharedLibrary,
                                      build.StaticLibrary)):
            raise MesonException('Gir target must be an executable or library')

        STATIC_BUILD_REQUIRED_VERSION = ">=1.58.1"
        if isinstance(girtarget, (build.StaticLibrary)) and \
           not mesonlib.version_compare(
               self._get_gir_dep(state)[0].get_version(),
               STATIC_BUILD_REQUIRED_VERSION):
            raise MesonException('Static libraries can only be introspected with GObject-Introspection ' + STATIC_BUILD_REQUIRED_VERSION)

        return girtarget

    def _get_gir_dep(self, state):
        try:
            gir_dep = self.gir_dep or PkgConfigDependency('gobject-introspection-1.0',
                                                          state.environment,
                                                          {'native': True})
            pkgargs = gir_dep.get_compile_args()
        except Exception:
            raise MesonException('gobject-introspection dependency was not found, gir cannot be generated.')

        return gir_dep, pkgargs

    def _scan_header(self, kwargs):
        ret = []
        header = kwargs.pop('header', None)
        if header:
            if not isinstance(header, str):
                raise MesonException('header must be a string')
            ret = ['--c-include=' + header]
        return ret

    def _scan_extra_args(self, kwargs):
        return mesonlib.stringlistify(kwargs.pop('extra_args', []))

    def _scan_link_withs(self, state, depends, kwargs):
        ret = []
        if 'link_with' in kwargs:
            link_with = mesonlib.extract_as_list(kwargs, 'link_with', pop = True)

            for link in link_with:
                ret += self._get_link_args(state, link.held_object, depends,
                                           use_gir_args=True)
        return ret

    # May mutate depends and gir_inc_dirs
    def _scan_include(self, state, depends, gir_inc_dirs, kwargs):
        ret = []

        if 'includes' in kwargs:
            includes = mesonlib.extract_as_list(kwargs, 'includes', pop = True)
            for inc in includes:
                if hasattr(inc, 'held_object'):
                    inc = inc.held_object
                if isinstance(inc, str):
                    ret += ['--include=%s' % (inc, )]
                elif isinstance(inc, GirTarget):
                    gir_inc_dirs += [
                        os.path.join(state.environment.get_build_dir(),
                                     inc.get_subdir()),
                    ]
                    ret += [
                        "--include-uninstalled=%s" % (os.path.join(inc.get_subdir(), inc.get_basename()), )
                    ]
                    depends += [inc]
                else:
                    raise MesonException(
                        'Gir includes must be str, GirTarget, or list of them')

        return ret

    def _scan_symbol_prefix(self, kwargs):
        ret = []

        if 'symbol_prefix' in kwargs:
            sym_prefixes = mesonlib.stringlistify(kwargs.pop('symbol_prefix', []))
            ret += ['--symbol-prefix=%s' % sym_prefix for sym_prefix in sym_prefixes]

        return ret

    def _scan_identifier_prefix(self, kwargs):
        ret = []

        if 'identifier_prefix' in kwargs:
            identifier_prefix = kwargs.pop('identifier_prefix')
            if not isinstance(identifier_prefix, str):
                raise MesonException('Gir identifier prefix must be str')
            ret += ['--identifier-prefix=%s' % identifier_prefix]

        return ret

    def _scan_export_packages(self, kwargs):
        ret = []

        if 'export_packages' in kwargs:
            pkgs = kwargs.pop('export_packages')
            if isinstance(pkgs, str):
                ret += ['--pkg-export=%s' % pkgs]
            elif isinstance(pkgs, list):
                ret += ['--pkg-export=%s' % pkg for pkg in pkgs]
            else:
                raise MesonException('Gir export packages must be str or list')

        return ret

    def _scan_inc_dirs(self, kwargs):
        ret = mesonlib.extract_as_list(kwargs, 'include_directories', pop = True)
        for incd in ret:
            if not isinstance(incd.held_object, (str, build.IncludeDirs)):
                raise MesonException(
                    'Gir include dirs should be include_directories().')
        return ret

    def _scan_langs(self, state, langs):
        ret = []

        for lang in langs:
            link_args = state.environment.coredata.get_external_link_args(MachineChoice.HOST, lang)
            for link_arg in link_args:
                if link_arg.startswith('-L'):
                    ret.append(link_arg)

        return ret

    def _scan_gir_targets(self, state, girtargets):
        ret = []

        for girtarget in girtargets:
            if isinstance(girtarget, build.Executable):
                ret += ['--program', girtarget]
            else:
                # Because of https://gitlab.gnome.org/GNOME/gobject-introspection/merge_requests/72
                # we can't use the full path until this is merged.
                if isinstance(girtarget, build.SharedLibrary):
                    libname = girtarget.get_basename()
                else:
                    libname = os.path.join("@PRIVATE_OUTDIR_ABS_%s@" % girtarget.get_id(), girtarget.get_filename())
                ret += ['--library', libname]
                # need to put our output directory first as we need to use the
                # generated libraries instead of any possibly installed system/prefix
                # ones.
                ret += ["-L@PRIVATE_OUTDIR_ABS_%s@" % girtarget.get_id()]
                # Needed for the following binutils bug:
                # https://github.com/mesonbuild/meson/issues/1911
                # However, g-ir-scanner does not understand -Wl,-rpath
                # so we need to use -L instead
                for d in state.backend.determine_rpath_dirs(girtarget):
                    d = os.path.join(state.environment.get_build_dir(), d)
                    ret.append('-L' + d)

        return ret

    def _get_girtargets_langs_compilers(self, girtargets):
        ret = []
        for girtarget in girtargets:
            for lang, compiler in girtarget.compilers.items():
                # XXX: Can you use g-i with any other language?
                if lang in ('c', 'cpp', 'objc', 'objcpp', 'd'):
                    ret.append((lang, compiler))
                    break

        return ret

    def _get_gir_targets_deps(self, girtargets):
        ret = []
        for girtarget in girtargets:
            ret += girtarget.get_all_link_deps()
            ret += girtarget.get_external_deps()
        return ret

    def _get_gir_targets_inc_dirs(self, girtargets):
        ret = []
        for girtarget in girtargets:
            ret += girtarget.get_include_dirs()
        return ret

    def _get_langs_compilers_flags(self, state, langs_compilers):
        cflags = []
        internal_ldflags = []
        external_ldflags = []

        for lang, compiler in langs_compilers:
            if state.global_args.get(lang):
                cflags += state.global_args[lang]
            if state.project_args.get(lang):
                cflags += state.project_args[lang]
            if 'b_sanitize' in compiler.base_options:
                sanitize = state.environment.coredata.base_options['b_sanitize'].value
                cflags += compiler.sanitizer_compile_args(sanitize)
                sanitize = sanitize.split(',')
                # These must be first in ldflags
                if 'address' in sanitize:
                    internal_ldflags += ['-lasan']
                if 'thread' in sanitize:
                    internal_ldflags += ['-ltsan']
                if 'undefined' in sanitize:
                    internal_ldflags += ['-lubsan']
                # FIXME: Linking directly to lib*san is not recommended but g-ir-scanner
                # does not understand -f LDFLAGS. https://bugzilla.gnome.org/show_bug.cgi?id=783892
                # ldflags += compiler.sanitizer_link_args(sanitize)

        return cflags, internal_ldflags, external_ldflags

    def _make_gir_filelist(self, state, srcdir, ns, nsversion, girtargets, libsources):
        gir_filelist_dir = state.backend.get_target_private_dir_abs(girtargets[0])
        if not os.path.isdir(gir_filelist_dir):
            os.mkdir(gir_filelist_dir)
        gir_filelist_filename = os.path.join(gir_filelist_dir, '%s_%s_gir_filelist' % (ns, nsversion))

        with open(gir_filelist_filename, 'w', encoding='utf-8') as gir_filelist:
            for s in libsources:
                if hasattr(s, 'held_object'):
                    s = s.held_object
                if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)):
                    for custom_output in s.get_outputs():
                        gir_filelist.write(os.path.join(state.environment.get_build_dir(),
                                                        state.backend.get_target_dir(s),
                                                        custom_output) + '\n')
                elif isinstance(s, mesonlib.File):
                    gir_filelist.write(s.rel_to_builddir(state.build_to_src) + '\n')
                elif isinstance(s, build.GeneratedList):
                    for gen_src in s.get_outputs():
                        gir_filelist.write(os.path.join(srcdir, gen_src) + '\n')
                else:
                    gir_filelist.write(os.path.join(srcdir, s) + '\n')

        return gir_filelist_filename

    def _make_gir_target(self, state, girfile, scan_command, depends, kwargs):
        scankwargs = {'output': girfile,
                      'command': scan_command,
                      'depends': depends}

        if 'install' in kwargs:
            scankwargs['install'] = kwargs['install']
            scankwargs['install_dir'] = kwargs.get('install_dir_gir',
                                                   os.path.join(state.environment.get_datadir(), 'gir-1.0'))

        if 'build_by_default' in kwargs:
            scankwargs['build_by_default'] = kwargs['build_by_default']

        return GirTarget(girfile, state.subdir, state.subproject, scankwargs)

    def _make_typelib_target(self, state, typelib_output, typelib_cmd, kwargs):
        typelib_kwargs = {
            'output': typelib_output,
            'command': typelib_cmd,
        }

        if 'install' in kwargs:
            typelib_kwargs['install'] = kwargs['install']
            typelib_kwargs['install_dir'] = kwargs.get('install_dir_typelib',
                                                       os.path.join(state.environment.get_libdir(), 'girepository-1.0'))

        if 'build_by_default' in kwargs:
            typelib_kwargs['build_by_default'] = kwargs['build_by_default']

        return TypelibTarget(typelib_output, state.subdir, state.subproject, typelib_kwargs)

    # May mutate depends
    def _gather_typelib_includes_and_update_depends(self, state, deps, depends):
        # Need to recursively add deps on GirTarget sources from our
        # dependencies and also find the include directories needed for the
        # typelib generation custom target below.
        typelib_includes = []
        for dep in deps:
            if hasattr(dep, 'held_object'):
                dep = dep.held_object
            # Add a dependency on each GirTarget listed in dependencies and add
            # the directory where it will be generated to the typelib includes
            if isinstance(dep, InternalDependency):
                for source in dep.sources:
                    if hasattr(source, 'held_object'):
                        source = source.held_object
                    if isinstance(source, GirTarget) and source not in depends:
                        depends.append(source)
                        subdir = os.path.join(state.environment.get_build_dir(),
                                              source.get_subdir())
                        if subdir not in typelib_includes:
                            typelib_includes.append(subdir)
            # Do the same, but for dependencies of dependencies. These are
            # stored in the list of generated sources for each link dep (from
            # girtarget.get_all_link_deps() above).
            # FIXME: Store this in the original form from declare_dependency()
            # so it can be used here directly.
            elif isinstance(dep, build.SharedLibrary):
                for source in dep.generated:
                    if isinstance(source, GirTarget):
                        subdir = os.path.join(state.environment.get_build_dir(),
                                              source.get_subdir())
                        if subdir not in typelib_includes:
                            typelib_includes.append(subdir)
            elif isinstance(dep, PkgConfigDependency):
                girdir = dep.get_pkgconfig_variable("girdir", {'default': ''})
                if girdir and girdir not in typelib_includes:
                    typelib_includes.append(girdir)

        return typelib_includes

    def _get_external_args_for_langs(self, state, langs):
        ret = []
        for lang in langs:
            ret += state.environment.coredata.get_external_args(MachineChoice.HOST, lang)
        return ret

    @staticmethod
    def _get_scanner_cflags(cflags):
        'g-ir-scanner only accepts -I/-D/-U; must ignore all other flags'
        for f in cflags:
            if f.startswith(('-D', '-U', '-I')):
                yield f

    @staticmethod
    def _get_scanner_ldflags(ldflags):
        'g-ir-scanner only accepts -L/-l; must ignore -F and other linker flags'
        for f in ldflags:
            if f.startswith(('-L', '-l', '--extra-library')):
                yield f

    @FeatureNewKwargs('build target', '0.40.0', ['build_by_default'])
    @permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix',
                      'export_packages', 'includes', 'dependencies', 'link_with', 'include_directories',
                      'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args',
                      'packages', 'header', 'build_by_default'})
    def generate_gir(self, state, args, kwargs):
        if not args:
            raise MesonException('generate_gir takes at least one argument')
        if kwargs.get('install_dir'):
            raise MesonException('install_dir is not supported with generate_gir(), see "install_dir_gir" and "install_dir_typelib"')

        giscanner = self.interpreter.find_program_impl('g-ir-scanner')
        gicompiler = self.interpreter.find_program_impl('g-ir-compiler')

        girtargets = [self._unwrap_gir_target(arg, state) for arg in args]

        if len(girtargets) > 1 and any([isinstance(el, build.Executable) for el in girtargets]):
            raise MesonException('generate_gir only accepts a single argument when one of the arguments is an executable')

        self.gir_dep, pkgargs = self._get_gir_dep(state)

        ns = kwargs.pop('namespace')
        nsversion = kwargs.pop('nsversion')
        libsources = mesonlib.extract_as_list(kwargs, 'sources', pop=True)
        girfile = '%s-%s.gir' % (ns, nsversion)
        srcdir = os.path.join(state.environment.get_source_dir(), state.subdir)
        builddir = os.path.join(state.environment.get_build_dir(), state.subdir)
        depends = [] + girtargets
        gir_inc_dirs = []
        langs_compilers = self._get_girtargets_langs_compilers(girtargets)
        cflags, internal_ldflags, external_ldflags = self._get_langs_compilers_flags(state, langs_compilers)
        deps = self._get_gir_targets_deps(girtargets)
        deps += extract_as_list(kwargs, 'dependencies', pop=True, unholder=True)
        typelib_includes = self._gather_typelib_includes_and_update_depends(state, deps, depends)
        # ldflags will be misinterpreted by gir scanner (showing
        # spurious dependencies) but building GStreamer fails if they
        # are not used here.
        dep_cflags, dep_internal_ldflags, dep_external_ldflags, gi_includes = \
            self._get_dependencies_flags(deps, state, depends, use_gir_args=True)
        cflags += list(self._get_scanner_cflags(dep_cflags))
        cflags += list(self._get_scanner_cflags(self._get_external_args_for_langs(state, [lc[0] for lc in langs_compilers])))
        internal_ldflags += list(self._get_scanner_ldflags(dep_internal_ldflags))
        external_ldflags += list(self._get_scanner_ldflags(dep_external_ldflags))
        girtargets_inc_dirs = self._get_gir_targets_inc_dirs(girtargets)
        inc_dirs = self._scan_inc_dirs(kwargs)

        scan_command = [giscanner]
        scan_command += pkgargs
        scan_command += ['--no-libtool']
        scan_command += ['--namespace=' + ns, '--nsversion=' + nsversion]
        scan_command += ['--warn-all']
        scan_command += ['--output', '@OUTPUT@']
        scan_command += self._scan_header(kwargs)
        scan_command += self._scan_extra_args(kwargs)
        scan_command += ['-I' + srcdir, '-I' + builddir]
        scan_command += get_include_args(girtargets_inc_dirs)
        scan_command += ['--filelist=' + self._make_gir_filelist(state, srcdir, ns, nsversion, girtargets, libsources)]
        scan_command += self._scan_link_withs(state, depends, kwargs)
        scan_command += self._scan_include(state, depends, gir_inc_dirs, kwargs)
        scan_command += self._scan_symbol_prefix(kwargs)
        scan_command += self._scan_identifier_prefix(kwargs)
        scan_command += self._scan_export_packages(kwargs)
        scan_command += ['--cflags-begin']
        scan_command += cflags
        scan_command += ['--cflags-end']
        scan_command += get_include_args(inc_dirs)
        scan_command += get_include_args(list(gi_includes) + gir_inc_dirs + inc_dirs, prefix='--add-include-path=')
        scan_command += list(internal_ldflags)
        scan_command += self._scan_gir_targets(state, girtargets)
        scan_command += self._scan_langs(state, [lc[0] for lc in langs_compilers])
        scan_command += list(external_ldflags)

        if gir_has_option(self.interpreter, '--sources-top-dirs'):
            scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_source_dir(), self.interpreter.subproject_dir, state.subproject)]
            scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_build_dir(), self.interpreter.subproject_dir, state.subproject)]

        scan_target = self._make_gir_target(state, girfile, scan_command, depends, kwargs)

        typelib_output = '%s-%s.typelib' % (ns, nsversion)
        typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
        typelib_cmd += get_include_args(gir_inc_dirs, prefix='--includedir=')

        for incdir in typelib_includes:
            typelib_cmd += ["--includedir=" + incdir]

        typelib_target = self._make_typelib_target(state, typelib_output, typelib_cmd, kwargs)

        rv = [scan_target, typelib_target]

        return ModuleReturnValue(rv, rv)

    @FeatureNewKwargs('build target', '0.40.0', ['build_by_default'])
    @permittedKwargs({'build_by_default', 'depend_files'})
    def compile_schemas(self, state, args, kwargs):
        if args:
            raise MesonException('Compile_schemas does not take positional arguments.')
        srcdir = os.path.join(state.build_to_src, state.subdir)
        outdir = state.subdir

        cmd = [self.interpreter.find_program_impl('glib-compile-schemas')]
        cmd += ['--targetdir', outdir, srcdir]
        kwargs['command'] = cmd
        kwargs['input'] = []
        kwargs['output'] = 'gschemas.compiled'
        if state.subdir == '':
            targetname = 'gsettings-compile'
        else:
            targetname = 'gsettings-compile-' + state.subdir.replace('/', '_')
        target_g = build.CustomTarget(targetname, state.subdir, state.subproject, kwargs)
        return ModuleReturnValue(target_g, [target_g])

    @permittedKwargs({'sources', 'media', 'symlink_media', 'languages'})
    def yelp(self, state, args, kwargs):
        if len(args) < 1:
            raise MesonException('Yelp requires a project id')

        project_id = args[0]
        sources = mesonlib.stringlistify(kwargs.pop('sources', []))
        if not sources:
            if len(args) > 1:
                sources = mesonlib.stringlistify(args[1:])
            if not sources:
                raise MesonException('Yelp requires a list of sources')
        source_str = '@@'.join(sources)

        langs = mesonlib.stringlistify(kwargs.pop('languages', []))
        if langs:
            mlog.deprecation('''The "languages" argument of gnome.yelp() is deprecated.
Use a LINGUAS file in the sources directory instead.
This will become a hard error in the future.''')

        media = mesonlib.stringlistify(kwargs.pop('media', []))
        symlinks = kwargs.pop('symlink_media', True)

        if not isinstance(symlinks, bool):
            raise MesonException('symlink_media must be a boolean')

        if kwargs:
            raise MesonException('Unknown arguments passed: {}'.format(', '.join(kwargs.keys())))

        script = state.environment.get_build_command()
        args = ['--internal',
                'yelphelper',
                'install',
                '--subdir=' + state.subdir,
                '--id=' + project_id,
                '--installdir=' + os.path.join(state.environment.get_datadir(), 'help'),
                '--sources=' + source_str]
        if symlinks:
            args.append('--symlinks=true')
        if media:
            args.append('--media=' + '@@'.join(media))
        if langs:
            args.append('--langs=' + '@@'.join(langs))
        inscript = build.RunScript(script, args)

        potargs = state.environment.get_build_command() + [
            '--internal', 'yelphelper', 'pot',
            '--subdir=' + state.subdir,
            '--id=' + project_id,
            '--sources=' + source_str,
        ]
        pottarget = build.RunTarget('help-' + project_id + '-pot', potargs[0],
                                    potargs[1:], [], state.subdir, state.subproject)

        poargs = state.environment.get_build_command() + [
            '--internal', 'yelphelper', 'update-po',
            '--subdir=' + state.subdir,
            '--id=' + project_id,
            '--sources=' + source_str,
            '--langs=' + '@@'.join(langs),
        ]
        potarget = build.RunTarget('help-' + project_id + '-update-po', poargs[0],
                                   poargs[1:], [], state.subdir, state.subproject)

        rv = [inscript, pottarget, potarget]
        return ModuleReturnValue(None, rv)

    @FeatureNewKwargs('gnome.gtkdoc', '0.52.0', ['check'])
    @FeatureNewKwargs('gnome.gtkdoc', '0.48.0', ['c_args'])
    @FeatureNewKwargs('gnome.gtkdoc', '0.48.0', ['module_version'])
    @FeatureNewKwargs('gnome.gtkdoc', '0.37.0', ['namespace', 'mode'])
    @permittedKwargs({'main_xml', 'main_sgml', 'src_dir', 'dependencies', 'install',
                      'install_dir', 'scan_args', 'scanobjs_args', 'gobject_typesfile',
                      'fixxref_args', 'html_args', 'html_assets', 'content_files',
                      'mkdb_args', 'ignore_headers', 'include_directories',
                      'namespace', 'mode', 'expand_content_files', 'module_version',
                      'c_args'})
    def gtkdoc(self, state, args, kwargs):
        if len(args) != 1:
            raise MesonException('Gtkdoc must have one positional argument.')
        modulename = args[0]
        if not isinstance(modulename, str):
            raise MesonException('Gtkdoc arg must be string.')
        if 'src_dir' not in kwargs:
            raise MesonException('Keyword argument src_dir missing.')
        main_file = kwargs.get('main_sgml', '')
        if not isinstance(main_file, str):
            raise MesonException('Main sgml keyword argument must be a string.')
        main_xml = kwargs.get('main_xml', '')
        if not isinstance(main_xml, str):
            raise MesonException('Main xml keyword argument must be a string.')
        moduleversion = kwargs.get('module_version', '')
        if not isinstance(moduleversion, str):
            raise MesonException('Module version keyword argument must be a string.')
        if main_xml != '':
            if main_file != '':
                raise MesonException('You can only specify main_xml or main_sgml, not both.')
            main_file = main_xml
        targetname = modulename + ('-' + moduleversion if moduleversion else '') + '-doc'
        command = state.environment.get_build_command()

        namespace = kwargs.get('namespace', '')
        mode = kwargs.get('mode', 'auto')
        VALID_MODES = ('xml', 'sgml', 'none', 'auto')
        if mode not in VALID_MODES:
            raise MesonException('gtkdoc: Mode {} is not a valid mode: {}'.format(mode, VALID_MODES))

        src_dirs = mesonlib.extract_as_list(kwargs, 'src_dir')
        header_dirs = []
        for src_dir in src_dirs:
            if hasattr(src_dir, 'held_object'):
                src_dir = src_dir.held_object
                if not isinstance(src_dir, build.IncludeDirs):
                    raise MesonException('Invalid keyword argument for src_dir.')
                for inc_dir in src_dir.get_incdirs():
                    header_dirs.append(os.path.join(state.environment.get_source_dir(),
                                                    src_dir.get_curdir(), inc_dir))
                    header_dirs.append(os.path.join(state.environment.get_build_dir(),
                                                    src_dir.get_curdir(), inc_dir))
            else:
                header_dirs.append(src_dir)

        args = ['--internal', 'gtkdoc',
                '--sourcedir=' + state.environment.get_source_dir(),
                '--builddir=' + state.environment.get_build_dir(),
                '--subdir=' + state.subdir,
                '--headerdirs=' + '@@'.join(header_dirs),
                '--mainfile=' + main_file,
                '--modulename=' + modulename,
                '--moduleversion=' + moduleversion,
                '--mode=' + mode]
        for tool in ['scan', 'scangobj', 'mkdb', 'mkhtml', 'fixxref']:
            program_name = 'gtkdoc-' + tool
            program = self.interpreter.find_program_impl(program_name)
            path = program.held_object.get_path()
            args.append('--{}={}'.format(program_name, path))
        if namespace:
            args.append('--namespace=' + namespace)
        args += self._unpack_args('--htmlargs=', 'html_args', kwargs)
        args += self._unpack_args('--scanargs=', 'scan_args', kwargs)
        args += self._unpack_args('--scanobjsargs=', 'scanobjs_args', kwargs)
        args += self._unpack_args('--gobjects-types-file=', 'gobject_typesfile', kwargs, state)
        args += self._unpack_args('--fixxrefargs=', 'fixxref_args', kwargs)
        args += self._unpack_args('--mkdbargs=', 'mkdb_args', kwargs)
        args += self._unpack_args('--html-assets=', 'html_assets', kwargs, state)

        depends = []
        content_files = []
        for s in mesonlib.extract_as_list(kwargs, 'content_files'):
            if hasattr(s, 'held_object'):
                s = s.held_object
            if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)):
                depends.append(s)
                for o in s.get_outputs():
                    content_files.append(os.path.join(state.environment.get_build_dir(),
                                                      state.backend.get_target_dir(s),
                                                      o))
            elif isinstance(s, mesonlib.File):
                content_files.append(s.absolute_path(state.environment.get_source_dir(),
                                                     state.environment.get_build_dir()))
            elif isinstance(s, build.GeneratedList):
                depends.append(s)
                for gen_src in s.get_outputs():
                    content_files.append(os.path.join(state.environment.get_source_dir(),
                                                      state.subdir,
                                                      gen_src))
            elif isinstance(s, str):
                content_files.append(os.path.join(state.environment.get_source_dir(),
                                                  state.subdir,
                                                  s))
            else:
                raise MesonException(
                    'Invalid object type: {!r}'.format(s.__class__.__name__))
        args += ['--content-files=' + '@@'.join(content_files)]

        args += self._unpack_args('--expand-content-files=', 'expand_content_files', kwargs, state)
        args += self._unpack_args('--ignore-headers=', 'ignore_headers', kwargs)
        args += self._unpack_args('--installdir=', 'install_dir', kwargs)
        args += self._get_build_args(kwargs, state, depends)
        custom_kwargs = {'output': modulename + '-decl.txt',
                         'command': command + args,
                         'depends': depends,
                         'build_always_stale': True,
                         }
        custom_target = build.CustomTarget(targetname, state.subdir, state.subproject, custom_kwargs)
        alias_target = build.AliasTarget(targetname, [custom_target], state.subdir, state.subproject)
        if kwargs.get('check', False):
            check_cmd = self.interpreter.find_program_impl('gtkdoc-check')
            check_env = ['DOC_MODULE=' + modulename,
                         'DOC_MAIN_SGML_FILE=' + main_file]
            check_args = [targetname + '-check', check_cmd]
            check_kwargs = {'env': check_env,
                            'workdir': os.path.join(state.environment.get_build_dir(), state.subdir),
                            'depends': custom_target}
            self.interpreter.add_test(state.current_node, check_args, check_kwargs, True)
        res = [custom_target, alias_target]
        if kwargs.get('install', True):
            res.append(build.RunScript(command, args))
        return ModuleReturnValue(custom_target, res)

    def _get_build_args(self, kwargs, state, depends):
        args = []
        deps = extract_as_list(kwargs, 'dependencies', unholder=True)
        cflags = []
        cflags.extend(mesonlib.stringlistify(kwargs.pop('c_args', [])))
        deps_cflags, internal_ldflags, external_ldflags, gi_includes = \
            self._get_dependencies_flags(deps, state, depends, include_rpath=True)
        inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories')
        for incd in inc_dirs:
            if not isinstance(incd.held_object, (str, build.IncludeDirs)):
                raise MesonException(
                    'Gir include dirs should be include_directories().')

        cflags.extend(deps_cflags)
        cflags.extend(get_include_args(inc_dirs))
        ldflags = []
        ldflags.extend(internal_ldflags)
        ldflags.extend(external_ldflags)

        cflags.extend(state.environment.coredata.get_external_args(MachineChoice.HOST, 'c'))
        ldflags.extend(state.environment.coredata.get_external_link_args(MachineChoice.HOST, 'c'))
        compiler = state.environment.coredata.compilers[MachineChoice.HOST]['c']

        compiler_flags = self._get_langs_compilers_flags(state, [('c', compiler)])
        cflags.extend(compiler_flags[0])
        ldflags.extend(compiler_flags[1])
        ldflags.extend(compiler_flags[2])
        if compiler:
            args += ['--cc=%s' % join_args(compiler.get_exelist())]
            args += ['--ld=%s' % join_args(compiler.get_linker_exelist())]
        if cflags:
            args += ['--cflags=%s' % join_args(cflags)]
        if ldflags:
            args += ['--ldflags=%s' % join_args(ldflags)]

        return args

    @noKwargs
    def gtkdoc_html_dir(self, state, args, kwargs):
        if len(args) != 1:
            raise MesonException('Must have exactly one argument.')
        modulename = args[0]
        if not isinstance(modulename, str):
            raise MesonException('Argument must be a string')
        return ModuleReturnValue(os.path.join('share/gtk-doc/html', modulename), [])

    @staticmethod
    def _unpack_args(arg, kwarg_name, kwargs, expend_file_state=None):
        if kwarg_name not in kwargs:
            return []

        new_args = mesonlib.extract_as_list(kwargs, kwarg_name)
        args = []
        for i in new_args:
            if expend_file_state and isinstance(i, mesonlib.File):
                i = i.absolute_path(expend_file_state.environment.get_source_dir(), expend_file_state.environment.get_build_dir())
            elif expend_file_state and isinstance(i, str):
                i = os.path.join(expend_file_state.environment.get_source_dir(), expend_file_state.subdir, i)
            elif not isinstance(i, str):
                raise MesonException(kwarg_name + ' values must be strings.')
            args.append(i)

        if args:
            return [arg + '@@'.join(args)]

        return []

    def _get_autocleanup_args(self, kwargs, glib_version):
        if not mesonlib.version_compare(glib_version, '>= 2.49.1'):
            # Warn if requested, silently disable if not
            if 'autocleanup' in kwargs:
                mlog.warning('Glib version ({}) is too old to support the \'autocleanup\' '
                             'kwarg, need 2.49.1 or newer'.format(glib_version))
            return []
        autocleanup = kwargs.pop('autocleanup', 'all')
        values = ('none', 'objects', 'all')
        if autocleanup not in values:
            raise MesonException('gdbus_codegen does not support {!r} as an autocleanup value, '
                                 'must be one of: {!r}'.format(autocleanup, ', '.join(values)))
        return ['--c-generate-autocleanup', autocleanup]

    @FeatureNewKwargs('build target', '0.46.0', ['install_header', 'install_dir', 'sources'])
    @FeatureNewKwargs('build target', '0.40.0', ['build_by_default'])
    @FeatureNewKwargs('build target', '0.47.0', ['extra_args', 'autocleanup'])
    @permittedKwargs({'interface_prefix', 'namespace', 'extra_args', 'autocleanup', 'object_manager', 'build_by_default',
                      'annotations', 'docbook', 'install_header', 'install_dir', 'sources'})
    def gdbus_codegen(self, state, args, kwargs):
        if len(args) not in (1, 2):
            raise MesonException('gdbus_codegen takes at most two arguments, name and xml file.')
        namebase = args[0]
        xml_files = args[1:]
        cmd = [self.interpreter.find_program_impl('gdbus-codegen')]
        extra_args = mesonlib.stringlistify(kwargs.pop('extra_args', []))
        cmd += extra_args
        # Autocleanup supported?
        glib_version = self._get_native_glib_version(state)
        cmd += self._get_autocleanup_args(kwargs, glib_version)
        if 'interface_prefix' in kwargs:
            cmd += ['--interface-prefix', kwargs.pop('interface_prefix')]
        if 'namespace' in kwargs:
            cmd += ['--c-namespace', kwargs.pop('namespace')]
        if kwargs.get('object_manager', False):
            cmd += ['--c-generate-object-manager']
        if 'sources' in kwargs:
            xml_files += mesonlib.listify(kwargs.pop('sources'))
        build_by_default = kwargs.get('build_by_default', False)

        # Annotations are a bit ugly in that they are a list of lists of strings...
        annotations = kwargs.pop('annotations', [])
        if not isinstance(annotations, list):
            raise MesonException('annotations takes a list')
        if annotations and isinstance(annotations, list) and not isinstance(annotations[0], list):
            annotations = [annotations]

        for annotation in annotations:
            if len(annotation) != 3 or not all(isinstance(i, str) for i in annotation):
                raise MesonException('Annotations must be made up of 3 strings for ELEMENT, KEY, and VALUE')
            cmd += ['--annotate'] + annotation

        targets = []
        install_header = kwargs.get('install_header', False)
        install_dir = kwargs.get('install_dir', state.environment.coredata.get_builtin_option('includedir'))

        output = namebase + '.c'
        # Added in https://gitlab.gnome.org/GNOME/glib/commit/e4d68c7b3e8b01ab1a4231bf6da21d045cb5a816 (2.55.2)
        # Fixed in https://gitlab.gnome.org/GNOME/glib/commit/cd1f82d8fc741a2203582c12cc21b4dacf7e1872 (2.56.2)
        if mesonlib.version_compare(glib_version, '>= 2.56.2'):
            custom_kwargs = {'input': xml_files,
                             'output': output,
                             'command': cmd + ['--body', '--output', '@OUTPUT@', '@INPUT@'],
                             'build_by_default': build_by_default
                             }
        else:
            if 'docbook' in kwargs:
                docbook = kwargs['docbook']
                if not isinstance(docbook, str):
                    raise MesonException('docbook value must be a string.')

                cmd += ['--generate-docbook', docbook]

            # https://git.gnome.org/browse/glib/commit/?id=ee09bb704fe9ccb24d92dd86696a0e6bb8f0dc1a
            if mesonlib.version_compare(glib_version, '>= 2.51.3'):
                cmd += ['--output-directory', '@OUTDIR@', '--generate-c-code', namebase, '@INPUT@']
            else:
                self._print_gdbus_warning()
                cmd += ['--generate-c-code', '@OUTDIR@/' + namebase, '@INPUT@']

            custom_kwargs = {'input': xml_files,
                             'output': output,
                             'command': cmd,
                             'build_by_default': build_by_default
                             }

        cfile_custom_target = build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs)
        targets.append(cfile_custom_target)

        output = namebase + '.h'
        if mesonlib.version_compare(glib_version, '>= 2.56.2'):
            custom_kwargs = {'input': xml_files,
                             'output': output,
                             'command': cmd + ['--header', '--output', '@OUTPUT@', '@INPUT@'],
                             'build_by_default': build_by_default,
                             'install': install_header,
                             'install_dir': install_dir
                             }
        else:
            custom_kwargs = {'input': xml_files,
                             'output': output,
                             'command': cmd,
                             'build_by_default': build_by_default,
                             'install': install_header,
                             'install_dir': install_dir,
                             'depends': cfile_custom_target
                             }

        hfile_custom_target = build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs)
        targets.append(hfile_custom_target)

        if 'docbook' in kwargs:
            docbook = kwargs['docbook']
            if not isinstance(docbook, str):
                raise MesonException('docbook value must be a string.')

            docbook_cmd = cmd + ['--output-directory', '@OUTDIR@', '--generate-docbook', docbook, '@INPUT@']

            # The docbook output is always ${docbook}-${name_of_xml_file}
            output = namebase + '-docbook'
            outputs = []
            for f in xml_files:
                outputs.append('{}-{}'.format(docbook, os.path.basename(str(f))))

            if mesonlib.version_compare(glib_version, '>= 2.56.2'):
                custom_kwargs = {'input': xml_files,
                                 'output': outputs,
                                 'command': docbook_cmd,
                                 'build_by_default': build_by_default
                                 }
            else:
                custom_kwargs = {'input': xml_files,
                                 'output': outputs,
                                 'command': cmd,
                                 'build_by_default': build_by_default,
                                 'depends': cfile_custom_target
                                 }

            docbook_custom_target = build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs)
            targets.append(docbook_custom_target)

        return ModuleReturnValue(targets, targets)

    @permittedKwargs({'sources', 'c_template', 'h_template', 'install_header', 'install_dir',
                      'comments', 'identifier_prefix', 'symbol_prefix', 'eprod', 'vprod',
                      'fhead', 'fprod', 'ftail', 'vhead', 'vtail', 'depends'})
    def mkenums(self, state, args, kwargs):
        if len(args) != 1:
            raise MesonException('Mkenums requires one positional argument.')
        basename = args[0]

        if 'sources' not in kwargs:
            raise MesonException('Missing keyword argument "sources".')
        sources = kwargs.pop('sources')
        if isinstance(sources, str):
            sources = [sources]
        elif not isinstance(sources, list):
            raise MesonException(
                'Sources keyword argument must be a string or array.')

        cmd = []
        known_kwargs = ['comments', 'eprod', 'fhead', 'fprod', 'ftail',
                        'identifier_prefix', 'symbol_prefix', 'template',
                        'vhead', 'vprod', 'vtail']
        known_custom_target_kwargs = ['install_dir', 'build_always',
                                      'depends', 'depend_files']
        c_template = h_template = None
        install_header = False
        for arg, value in kwargs.items():
            if arg == 'sources':
                raise AssertionError("sources should've already been handled")
            elif arg == 'c_template':
                c_template = value
                if isinstance(c_template, mesonlib.File):
                    c_template = c_template.absolute_path(state.environment.source_dir, state.environment.build_dir)
                if 'template' in kwargs:
                    raise MesonException('Mkenums does not accept both '
                                         'c_template and template keyword '
                                         'arguments at the same time.')
            elif arg == 'h_template':
                h_template = value
                if isinstance(h_template, mesonlib.File):
                    h_template = h_template.absolute_path(state.environment.source_dir, state.environment.build_dir)
                if 'template' in kwargs:
                    raise MesonException('Mkenums does not accept both '
                                         'h_template and template keyword '
                                         'arguments at the same time.')
            elif arg == 'install_header':
                install_header = value
            elif arg in known_kwargs:
                cmd += ['--' + arg.replace('_', '-'), value]
            elif arg not in known_custom_target_kwargs:
                raise MesonException(
                    'Mkenums does not take a %s keyword argument.' % (arg, ))
        cmd = [self.interpreter.find_program_impl(['glib-mkenums', 'mkenums'])] + cmd
        custom_kwargs = {}
        for arg in known_custom_target_kwargs:
            if arg in kwargs:
                custom_kwargs[arg] = kwargs[arg]

        targets = []

        if h_template is not None:
            h_output = os.path.basename(os.path.splitext(h_template)[0])
            # We always set template as the first element in the source array
            # so --template consumes it.
            h_cmd = cmd + ['--template', '@INPUT@']
            h_sources = [h_template] + sources
            custom_kwargs['install'] = install_header
            if 'install_dir' not in custom_kwargs:
                custom_kwargs['install_dir'] = \
                    state.environment.coredata.get_builtin_option('includedir')
            h_target = self._make_mkenum_custom_target(state, h_sources,
                                                       h_output, h_cmd,
                                                       custom_kwargs)
            targets.append(h_target)

        if c_template is not None:
            c_output = os.path.basename(os.path.splitext(c_template)[0])
            # We always set template as the first element in the source array
            # so --template consumes it.
            c_cmd = cmd + ['--template', '@INPUT@']
            c_sources = [c_template] + sources
            # Never install the C file. Complain on bug tracker if you need it.
            custom_kwargs['install'] = False
            if h_template is not None:
                if 'depends' in custom_kwargs:
                    custom_kwargs['depends'] += [h_target]
                else:
                    custom_kwargs['depends'] = h_target
            c_target = self._make_mkenum_custom_target(state, c_sources,
                                                       c_output, c_cmd,
                                                       custom_kwargs)
            targets.insert(0, c_target)

        if c_template is None and h_template is None:
            generic_cmd = cmd + ['@INPUT@']
            custom_kwargs['install'] = install_header
            if 'install_dir' not in custom_kwargs:
                custom_kwargs['install_dir'] = \
                    state.environment.coredata.get_builtin_option('includedir')
            target = self._make_mkenum_custom_target(state, sources, basename,
                                                     generic_cmd, custom_kwargs)
            return ModuleReturnValue(target, [target])
        elif len(targets) == 1:
            return ModuleReturnValue(targets[0], [targets[0]])
        else:
            return ModuleReturnValue(targets, targets)

    @FeatureNew('gnome.mkenums_simple', '0.42.0')
    def mkenums_simple(self, state, args, kwargs):
        hdr_filename = args[0] + '.h'
        body_filename = args[0] + '.c'

        # not really needed, just for sanity checking
        forbidden_kwargs = ['c_template', 'h_template', 'eprod', 'fhead',
                            'fprod', 'ftail', 'vhead', 'vtail', 'comments']
        for arg in forbidden_kwargs:
            if arg in kwargs:
                raise MesonException('mkenums_simple() does not take a %s keyword argument' % (arg, ))

        # kwargs to pass as-is from mkenums_simple() to mkenums()
        shared_kwargs = ['sources', 'install_header', 'install_dir',
                         'identifier_prefix', 'symbol_prefix']
        mkenums_kwargs = {}
        for arg in shared_kwargs:
            if arg in kwargs:
                mkenums_kwargs[arg] = kwargs[arg]

        # .c file generation
        c_file_kwargs = copy.deepcopy(mkenums_kwargs)
        if 'sources' not in kwargs:
            raise MesonException('Missing keyword argument "sources".')
        sources = kwargs['sources']
        if isinstance(sources, str):
            sources = [sources]
        elif not isinstance(sources, list):
            raise MesonException(
                'Sources keyword argument must be a string or array.')

        # The `install_header` argument will be used by mkenums() when
        # not using template files, so we need to forcibly unset it
        # when generating the C source file, otherwise we will end up
        # installing it
        c_file_kwargs['install_header'] = False

        header_prefix = kwargs.get('header_prefix', '')
        decl_decorator = kwargs.get('decorator', '')
        func_prefix = kwargs.get('function_prefix', '')
        body_prefix = kwargs.get('body_prefix', '')

        # Maybe we should write our own template files into the build dir
        # instead, but that seems like much more work, nice as it would be.
        fhead = ''
        if body_prefix != '':
            fhead += '%s\n' % body_prefix
        fhead += '#include "%s"\n' % hdr_filename
        for hdr in sources:
            fhead += '#include "%s"\n' % os.path.basename(str(hdr))
        fhead += '''
#define C_ENUM(v) ((gint) v)
#define C_FLAGS(v) ((guint) v)
'''
        c_file_kwargs['fhead'] = fhead

        c_file_kwargs['fprod'] = '''
/* enumerations from "@basename@" */
'''

        c_file_kwargs['vhead'] = '''
GType
%s@enum_name@_get_type (void)
{
  static volatile gsize gtype_id = 0;
  static const G@Type@Value values[] = {''' % func_prefix

        c_file_kwargs['vprod'] = '    { C_@TYPE@(@VALUENAME@), "@VALUENAME@", "@valuenick@" },'

        c_file_kwargs['vtail'] = '''    { 0, NULL, NULL }
  };
  if (g_once_init_enter (>ype_id)) {
    GType new_type = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
    g_once_init_leave (>ype_id, new_type);
  }
  return (GType) gtype_id;
}'''

        rv = self.mkenums(state, [body_filename], c_file_kwargs)
        c_file = rv.return_value

        # .h file generation
        h_file_kwargs = copy.deepcopy(mkenums_kwargs)

        h_file_kwargs['fhead'] = '''#pragma once

#include 
{}

G_BEGIN_DECLS
'''.format(header_prefix)

        h_file_kwargs['fprod'] = '''
/* enumerations from "@basename@" */
'''

        h_file_kwargs['vhead'] = '''
{}
GType {}@enum_name@_get_type (void);
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ ({}@enum_name@_get_type())'''.format(decl_decorator, func_prefix, func_prefix)

        h_file_kwargs['ftail'] = '''
G_END_DECLS'''

        rv = self.mkenums(state, [hdr_filename], h_file_kwargs)
        h_file = rv.return_value

        return ModuleReturnValue([c_file, h_file], [c_file, h_file])

    @staticmethod
    def _make_mkenum_custom_target(state, sources, output, cmd, kwargs):
        custom_kwargs = {
            'input': sources,
            'output': output,
            'capture': True,
            'command': cmd
        }
        custom_kwargs.update(kwargs)
        return build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs,
                                  # https://github.com/mesonbuild/meson/issues/973
                                  absolute_paths=True)

    @permittedKwargs({'sources', 'prefix', 'install_header', 'install_dir', 'stdinc',
                      'nostdinc', 'internal', 'skip_source', 'valist_marshallers',
                      'extra_args'})
    def genmarshal(self, state, args, kwargs):
        if len(args) != 1:
            raise MesonException(
                'Genmarshal requires one positional argument.')
        output = args[0]

        if 'sources' not in kwargs:
            raise MesonException('Missing keyword argument "sources".')
        sources = kwargs.pop('sources')
        if isinstance(sources, str):
            sources = [sources]
        elif not isinstance(sources, list):
            raise MesonException(
                'Sources keyword argument must be a string or array.')

        new_genmarshal = mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.53.3')

        cmd = [self.interpreter.find_program_impl('glib-genmarshal')]
        known_kwargs = ['internal', 'nostdinc', 'skip_source', 'stdinc',
                        'valist_marshallers', 'extra_args']
        known_custom_target_kwargs = ['build_always', 'depends',
                                      'depend_files', 'install_dir',
                                      'install_header']
        for arg, value in kwargs.items():
            if arg == 'prefix':
                cmd += ['--prefix', value]
            elif arg == 'extra_args':
                if new_genmarshal:
                    cmd += mesonlib.stringlistify(value)
                else:
                    mlog.warning('The current version of GLib does not support extra arguments \n'
                                 'for glib-genmarshal. You need at least GLib 2.53.3. See ',
                                 mlog.bold('https://github.com/mesonbuild/meson/pull/2049'))
            elif arg in known_kwargs and value:
                cmd += ['--' + arg.replace('_', '-')]
            elif arg not in known_custom_target_kwargs:
                raise MesonException(
                    'Genmarshal does not take a %s keyword argument.' % (
                        arg, ))

        install_header = kwargs.pop('install_header', False)
        install_dir = kwargs.pop('install_dir', None)

        custom_kwargs = {
            'input': sources,
        }

        # https://github.com/GNOME/glib/commit/0fbc98097fac4d3e647684f344e508abae109fdf
        if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.0'):
            cmd += ['--output', '@OUTPUT@']
        else:
            custom_kwargs['capture'] = True

        for arg in known_custom_target_kwargs:
            if arg in kwargs:
                custom_kwargs[arg] = kwargs[arg]

        header_file = output + '.h'
        custom_kwargs['command'] = cmd + ['--body', '@INPUT@']
        if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.53.4'):
            # Silence any warnings about missing prototypes
            custom_kwargs['command'] += ['--include-header', header_file]
        custom_kwargs['output'] = output + '.c'
        body = build.CustomTarget(output + '_c', state.subdir, state.subproject, custom_kwargs)

        custom_kwargs['install'] = install_header
        if install_dir is not None:
            custom_kwargs['install_dir'] = install_dir
        if new_genmarshal:
            cmd += ['--pragma-once']
        custom_kwargs['command'] = cmd + ['--header', '@INPUT@']
        custom_kwargs['output'] = header_file
        header = build.CustomTarget(output + '_h', state.subdir, state.subproject, custom_kwargs)

        rv = [body, header]
        return ModuleReturnValue(rv, rv)

    @staticmethod
    def _vapi_args_to_command(prefix, variable, kwargs, accept_vapi=False):
        arg_list = mesonlib.extract_as_list(kwargs, variable)
        ret = []
        for arg in arg_list:
            if not isinstance(arg, str):
                types = 'strings' + ' or InternalDependencys' if accept_vapi else ''
                raise MesonException('All {} must be {}'.format(variable, types))
            ret.append(prefix + arg)
        return ret

    def _extract_vapi_packages(self, state, kwargs):
        '''
        Packages are special because we need to:
        - Get a list of packages for the .deps file
        - Get a list of depends for any VapiTargets
        - Get package name from VapiTargets
        - Add include dirs for any VapiTargets
        '''
        arg_list = kwargs.get('packages')
        if not arg_list:
            return [], [], [], []
        arg_list = mesonlib.listify(arg_list)
        vapi_depends = []
        vapi_packages = []
        vapi_includes = []
        ret = []
        remaining_args = []
        for arg in arg_list:
            if hasattr(arg, 'held_object'):
                arg = arg.held_object
            if isinstance(arg, InternalDependency):
                targets = [t for t in arg.sources if isinstance(t, VapiTarget)]
                for target in targets:
                    srcdir = os.path.join(state.environment.get_source_dir(),
                                          target.get_subdir())
                    outdir = os.path.join(state.environment.get_build_dir(),
                                          target.get_subdir())
                    outfile = target.get_outputs()[0][:-5] # Strip .vapi
                    ret.append('--vapidir=' + outdir)
                    ret.append('--girdir=' + outdir)
                    ret.append('--pkg=' + outfile)
                    vapi_depends.append(target)
                    vapi_packages.append(outfile)
                    vapi_includes.append(srcdir)
            else:
                vapi_packages.append(arg)
                remaining_args.append(arg)

        kwargs['packages'] = remaining_args
        vapi_args = ret + self._vapi_args_to_command('--pkg=', 'packages', kwargs, accept_vapi=True)
        return vapi_args, vapi_depends, vapi_packages, vapi_includes

    def _generate_deps(self, state, library, packages, install_dir):
        outdir = state.environment.scratch_dir
        fname = os.path.join(outdir, library + '.deps')
        with open(fname, 'w') as ofile:
            for package in packages:
                ofile.write(package + '\n')
        return build.Data(mesonlib.File(True, outdir, fname), install_dir)

    def _get_vapi_link_with(self, target):
        link_with = []
        for dep in target.get_target_dependencies():
            if isinstance(dep, build.SharedLibrary):
                link_with.append(dep)
            elif isinstance(dep, GirTarget):
                link_with += self._get_vapi_link_with(dep)
        return link_with

    @permittedKwargs({'sources', 'packages', 'metadata_dirs', 'gir_dirs',
                      'vapi_dirs', 'install', 'install_dir'})
    def generate_vapi(self, state, args, kwargs):
        if len(args) != 1:
            raise MesonException('The library name is required')

        if not isinstance(args[0], str):
            raise MesonException('The first argument must be the name of the library')
        created_values = []

        library = args[0]
        build_dir = os.path.join(state.environment.get_build_dir(), state.subdir)
        source_dir = os.path.join(state.environment.get_source_dir(), state.subdir)
        pkg_cmd, vapi_depends, vapi_packages, vapi_includes = self._extract_vapi_packages(state, kwargs)
        if 'VAPIGEN' in os.environ:
            cmd = [self.interpreter.find_program_impl(os.environ['VAPIGEN'])]
        else:
            cmd = [self.interpreter.find_program_impl('vapigen')]
        cmd += ['--quiet', '--library=' + library, '--directory=' + build_dir]
        cmd += self._vapi_args_to_command('--vapidir=', 'vapi_dirs', kwargs)
        cmd += self._vapi_args_to_command('--metadatadir=', 'metadata_dirs', kwargs)
        cmd += self._vapi_args_to_command('--girdir=', 'gir_dirs', kwargs)
        cmd += pkg_cmd
        cmd += ['--metadatadir=' + source_dir]

        if 'sources' not in kwargs:
            raise MesonException('sources are required to generate the vapi file')

        inputs = mesonlib.extract_as_list(kwargs, 'sources')

        link_with = []
        for i in inputs:
            if isinstance(i, str):
                cmd.append(os.path.join(source_dir, i))
            elif hasattr(i, 'held_object') and isinstance(i.held_object, GirTarget):
                link_with += self._get_vapi_link_with(i.held_object)
                subdir = os.path.join(state.environment.get_build_dir(),
                                      i.held_object.get_subdir())
                gir_file = os.path.join(subdir, i.held_object.get_outputs()[0])
                cmd.append(gir_file)
            else:
                raise MesonException('Input must be a str or GirTarget')

        vapi_output = library + '.vapi'
        custom_kwargs = {
            'command': cmd,
            'input': inputs,
            'output': vapi_output,
            'depends': vapi_depends,
        }
        install_dir = kwargs.get('install_dir',
                                 os.path.join(state.environment.coredata.get_builtin_option('datadir'),
                                              'vala', 'vapi'))
        if kwargs.get('install'):
            custom_kwargs['install'] = kwargs['install']
            custom_kwargs['install_dir'] = install_dir

            # We shouldn't need this locally but we install it
            deps_target = self._generate_deps(state, library, vapi_packages, install_dir)
            created_values.append(deps_target)
        vapi_target = VapiTarget(vapi_output, state.subdir, state.subproject, custom_kwargs)

        # So to try our best to get this to just work we need:
        # - link with with the correct library
        # - include the vapi and dependent vapi files in sources
        # - add relevant directories to include dirs
        incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False)]
        sources = [vapi_target] + vapi_depends
        rv = InternalDependency(None, incs, [], [], link_with, [], sources, [])
        created_values.append(rv)
        return ModuleReturnValue(rv, created_values)

def initialize(*args, **kwargs):
    return GnomeModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/hotdoc.py0000644000175000017500000004263513567762030022002 0ustar  jpakkanejpakkane00000000000000# Copyright 2018 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

'''This module provides helper functions for generating documentation using hotdoc'''

import os
from collections import OrderedDict

from mesonbuild import mesonlib
from mesonbuild import mlog, build
from mesonbuild.coredata import MesonException
from . import ModuleReturnValue
from . import ExtensionModule
from . import get_include_args
from ..dependencies import Dependency, InternalDependency, ExternalProgram
from ..interpreterbase import FeatureNew, InvalidArguments, noPosargs, noKwargs
from ..interpreter import CustomTargetHolder


def ensure_list(value):
    if not isinstance(value, list):
        return [value]
    return value


MIN_HOTDOC_VERSION = '0.8.100'


class HotdocTargetBuilder:
    def __init__(self, name, state, hotdoc, interpreter, kwargs):
        self.hotdoc = hotdoc
        self.build_by_default = kwargs.pop('build_by_default', False)
        self.kwargs = kwargs
        self.name = name
        self.state = state
        self.interpreter = interpreter
        self.include_paths = OrderedDict()

        self.builddir = state.environment.get_build_dir()
        self.sourcedir = state.environment.get_source_dir()
        self.subdir = state.subdir
        self.build_command = state.environment.get_build_command()

        self.cmd = ['conf', '--project-name', name, "--disable-incremental-build",
                    '--output', os.path.join(self.builddir, self.subdir, self.name + '-doc')]

        self._extra_extension_paths = set()
        self.extra_assets = set()
        self._dependencies = []
        self._subprojects = []

    def process_known_arg(self, option, types, argname=None,
                          value_processor=None, mandatory=False,
                          force_list=False):
        if not argname:
            argname = option.strip("-").replace("-", "_")

        value, _ = self.get_value(
            types, argname, None, value_processor, mandatory, force_list)

        self.set_arg_value(option, value)

    def set_arg_value(self, option, value):
        if value is None:
            return

        if isinstance(value, bool):
            if value:
                self.cmd.append(option)
        elif isinstance(value, list):
            # Do not do anything on empty lists
            if value:
                # https://bugs.python.org/issue9334 (from 2010 :( )
                # The syntax with nargs=+ is inherently ambiguous
                # A workaround for this case is to simply prefix with a space
                # every value starting with a dash
                escaped_value = []
                for e in value:
                    if isinstance(e, str) and e.startswith('-'):
                        escaped_value += [' %s' % e]
                    else:
                        escaped_value += [e]
                if option:
                    self.cmd.extend([option] + escaped_value)
                else:
                    self.cmd.extend(escaped_value)
        else:
            # argparse gets confused if value(s) start with a dash.
            # When an option expects a single value, the unambiguous way
            # to specify it is with =
            if isinstance(value, str):
                self.cmd.extend(['%s=%s' % (option, value)])
            else:
                self.cmd.extend([option, value])

    def check_extra_arg_type(self, arg, value):
        value = getattr(value, 'held_object', value)
        if isinstance(value, list):
            for v in value:
                self.check_extra_arg_type(arg, v)
            return

        valid_types = (str, bool, mesonlib.File, build.IncludeDirs, build.CustomTarget, build.BuildTarget)
        if not isinstance(value, valid_types):
            raise InvalidArguments('Argument "%s=%s" should be of type: %s.' % (
                arg, value, [t.__name__ for t in valid_types]))

    def process_extra_args(self):
        for arg, value in self.kwargs.items():
            option = "--" + arg.replace("_", "-")
            self.check_extra_arg_type(arg, value)
            self.set_arg_value(option, value)

    def get_value(self, types, argname, default=None, value_processor=None,
                  mandatory=False, force_list=False):
        if not isinstance(types, list):
            types = [types]
        try:
            uvalue = value = self.kwargs.pop(argname)
            if value_processor:
                value = value_processor(value)

            for t in types:
                if isinstance(value, t):
                    if force_list and not isinstance(value, list):
                        return [value], uvalue
                    return value, uvalue
            raise MesonException("%s field value %s is not valid,"
                                 " valid types are %s" % (argname, value,
                                                          types))
        except KeyError:
            if mandatory:
                raise MesonException("%s mandatory field not found" % argname)

            if default is not None:
                return default, default

        return None, None

    def setup_extension_paths(self, paths):
        if not isinstance(paths, list):
            paths = [paths]

        for path in paths:
            self.add_extension_paths([path])

        return []

    def add_extension_paths(self, paths):
        for path in paths:
            if path in self._extra_extension_paths:
                continue

            self._extra_extension_paths.add(path)
            self.cmd.extend(["--extra-extension-path", path])

    def process_extra_extension_paths(self):
        self.get_value([list, str], 'extra_extensions_paths',
                       default="", value_processor=self.setup_extension_paths)

    def replace_dirs_in_string(self, string):
        return string.replace("@SOURCE_ROOT@", self.sourcedir).replace("@BUILD_ROOT@", self.builddir)

    def process_gi_c_source_roots(self):
        if self.hotdoc.run_hotdoc(['--has-extension=gi-extension']) != 0:
            return

        value, _ = self.get_value([list, str], 'gi_c_source_roots', default=[], force_list=True)
        value.extend([
            os.path.join(self.state.environment.get_source_dir(),
                         self.interpreter.subproject_dir, self.state.subproject),
            os.path.join(self.state.environment.get_build_dir(), self.interpreter.subproject_dir, self.state.subproject)
        ])

        self.cmd += ['--gi-c-source-roots'] + value

    def process_dependencies(self, deps):
        cflags = set()
        for dep in mesonlib.listify(ensure_list(deps)):
            dep = getattr(dep, "held_object", dep)
            if isinstance(dep, InternalDependency):
                inc_args = get_include_args(dep.include_directories)
                cflags.update([self.replace_dirs_in_string(x)
                               for x in inc_args])
                cflags.update(self.process_dependencies(dep.libraries))
                cflags.update(self.process_dependencies(dep.sources))
                cflags.update(self.process_dependencies(dep.ext_deps))
            elif isinstance(dep, Dependency):
                cflags.update(dep.get_compile_args())
            elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
                self._dependencies.append(dep)
                for incd in dep.get_include_dirs():
                    cflags.update(incd.get_incdirs())
            elif isinstance(dep, HotdocTarget):
                # Recurse in hotdoc target dependencies
                self.process_dependencies(dep.get_target_dependencies())
                self._subprojects.extend(dep.subprojects)
                self.process_dependencies(dep.subprojects)
                self.add_include_path(os.path.join(self.builddir, dep.hotdoc_conf.subdir))
                self.cmd += ['--extra-assets=' + p for p in dep.extra_assets]
                self.add_extension_paths(dep.extra_extension_paths)
            elif isinstance(dep, build.CustomTarget) or isinstance(dep, build.BuildTarget):
                self._dependencies.append(dep)

        return [f.strip('-I') for f in cflags]

    def process_extra_assets(self):
        self._extra_assets, _ = self.get_value("--extra-assets", (str, list), default=[],
                                               force_list=True)
        for assets_path in self._extra_assets:
            self.cmd.extend(["--extra-assets", assets_path])

    def process_subprojects(self):
        _, value = self.get_value([
            list, HotdocTarget], argname="subprojects",
            force_list=True, value_processor=self.process_dependencies)

        if value is not None:
            self._subprojects.extend(value)

    def flatten_config_command(self):
        cmd = []
        for arg in mesonlib.listify(self.cmd, flatten=True):
            arg = getattr(arg, 'held_object', arg)
            if isinstance(arg, mesonlib.File):
                arg = arg.absolute_path(self.state.environment.get_source_dir(),
                                        self.state.environment.get_build_dir())
            elif isinstance(arg, build.IncludeDirs):
                for inc_dir in arg.get_incdirs():
                    cmd.append(os.path.join(self.sourcedir, arg.get_curdir(), inc_dir))
                    cmd.append(os.path.join(self.builddir, arg.get_curdir(), inc_dir))

                continue
            elif isinstance(arg, build.CustomTarget) or isinstance(arg, build.BuildTarget):
                self._dependencies.append(arg)
                arg = self.interpreter.backend.get_target_filename_abs(arg)

            cmd.append(arg)

        return cmd

    def generate_hotdoc_config(self):
        cwd = os.path.abspath(os.curdir)
        ncwd = os.path.join(self.sourcedir, self.subdir)
        mlog.log('Generating Hotdoc configuration for: ', mlog.bold(self.name))
        os.chdir(ncwd)
        self.hotdoc.run_hotdoc(self.flatten_config_command())
        os.chdir(cwd)

    def ensure_file(self, value):
        if isinstance(value, list):
            res = []
            for val in value:
                res.append(self.ensure_file(val))
            return res

        if not isinstance(value, mesonlib.File):
            return mesonlib.File.from_source_file(self.sourcedir, self.subdir, value)

        return value

    def ensure_dir(self, value):
        if os.path.isabs(value):
            _dir = value
        else:
            _dir = os.path.join(self.sourcedir, self.subdir, value)

        if not os.path.isdir(_dir):
            raise InvalidArguments('"%s" is not a directory.' % _dir)

        return os.path.relpath(_dir, os.path.join(self.builddir, self.subdir))

    def check_forbiden_args(self):
        for arg in ['conf_file']:
            if arg in self.kwargs:
                raise InvalidArguments('Argument "%s" is forbidden.' % arg)

    def add_include_path(self, path):
        self.include_paths[path] = path

    def make_targets(self):
        self.check_forbiden_args()
        file_types = (str, mesonlib.File)
        self.process_known_arg("--index", file_types, mandatory=True, value_processor=self.ensure_file)
        self.process_known_arg("--project-version", str, mandatory=True)
        self.process_known_arg("--sitemap", file_types, mandatory=True, value_processor=self.ensure_file)
        self.process_known_arg("--html-extra-theme", str, value_processor=self.ensure_dir)
        self.process_known_arg(None, list, "include_paths", force_list=True,
                               value_processor=lambda x: [self.add_include_path(self.ensure_dir(v)) for v in ensure_list(x)])
        self.process_known_arg('--c-include-directories',
                               [Dependency, build.StaticLibrary, build.SharedLibrary, list], argname="dependencies",
                               force_list=True, value_processor=self.process_dependencies)
        self.process_gi_c_source_roots()
        self.process_extra_assets()
        self.process_extra_extension_paths()
        self.process_subprojects()

        install, install = self.get_value(bool, "install", mandatory=False)
        self.process_extra_args()

        fullname = self.name + '-doc'
        hotdoc_config_name = fullname + '.json'
        hotdoc_config_path = os.path.join(
            self.builddir, self.subdir, hotdoc_config_name)
        with open(hotdoc_config_path, 'w') as f:
            f.write('{}')

        self.cmd += ['--conf-file', hotdoc_config_path]
        self.add_include_path(os.path.join(self.builddir, self.subdir))
        self.add_include_path(os.path.join(self.sourcedir, self.subdir))

        depfile = os.path.join(self.builddir, self.subdir, self.name + '.deps')
        self.cmd += ['--deps-file-dest', depfile]

        for path in self.include_paths.keys():
            self.cmd.extend(['--include-path', path])

        if self.state.environment.coredata.get_builtin_option('werror'):
            self.cmd.append('--fatal-warning')
        self.generate_hotdoc_config()

        target_cmd = self.build_command + ["--internal", "hotdoc"] + \
            self.hotdoc.get_command() + ['run', '--conf-file', hotdoc_config_name] + \
            ['--builddir', os.path.join(self.builddir, self.subdir)]

        target = HotdocTarget(fullname,
                              subdir=self.subdir,
                              subproject=self.state.subproject,
                              hotdoc_conf=mesonlib.File.from_built_file(
                                  self.subdir, hotdoc_config_name),
                              extra_extension_paths=self._extra_extension_paths,
                              extra_assets=self._extra_assets,
                              subprojects=self._subprojects,
                              command=target_cmd,
                              depends=self._dependencies,
                              output=fullname,
                              depfile=os.path.basename(depfile),
                              build_by_default=self.build_by_default)

        install_script = None
        if install is True:
            install_script = HotdocRunScript(self.build_command, [
                "--internal", "hotdoc",
                "--install", os.path.join(fullname, 'html'),
                '--name', self.name,
                '--builddir', os.path.join(self.builddir, self.subdir)] +
                self.hotdoc.get_command() +
                ['run', '--conf-file', hotdoc_config_name])

        return (target, install_script)


class HotdocTargetHolder(CustomTargetHolder):
    def __init__(self, target, interp):
        super().__init__(target, interp)
        self.methods.update({'config_path': self.config_path_method})

    @noPosargs
    @noKwargs
    def config_path_method(self, *args, **kwargs):
        conf = self.held_object.hotdoc_conf.absolute_path(self.interpreter.environment.source_dir,
                                                          self.interpreter.environment.build_dir)
        return self.interpreter.holderify(conf)


class HotdocTarget(build.CustomTarget):
    def __init__(self, name, subdir, subproject, hotdoc_conf, extra_extension_paths, extra_assets,
                 subprojects, **kwargs):
        super().__init__(name, subdir, subproject, kwargs, absolute_paths=True)
        self.hotdoc_conf = hotdoc_conf
        self.extra_extension_paths = extra_extension_paths
        self.extra_assets = extra_assets
        self.subprojects = subprojects

    def __getstate__(self):
        # Make sure we do not try to pickle subprojects
        res = self.__dict__.copy()
        res['subprojects'] = []

        return res


class HotdocRunScript(build.RunScript):
    def __init__(self, script, args):
        super().__init__(script, args)


class HotDocModule(ExtensionModule):
    @FeatureNew('Hotdoc Module', '0.48.0')
    def __init__(self, interpreter):
        super().__init__(interpreter)
        self.hotdoc = ExternalProgram('hotdoc')
        if not self.hotdoc.found():
            raise MesonException('hotdoc executable not found')

        try:
            from hotdoc.run_hotdoc import run  # noqa: F401
            self.hotdoc.run_hotdoc = run
        except Exception as e:
            raise MesonException('hotdoc %s required but not found. (%s)' % (
                MIN_HOTDOC_VERSION, e))

    @noKwargs
    def has_extensions(self, state, args, kwargs):
        res = self.hotdoc.run_hotdoc(['--has-extension=%s' % extension for extension in args]) == 0
        return ModuleReturnValue(res, [res])

    def generate_doc(self, state, args, kwargs):
        if len(args) != 1:
            raise MesonException('One positional argument is'
                                 ' required for the project name.')

        project_name = args[0]
        builder = HotdocTargetBuilder(project_name, state, self.hotdoc, self.interpreter, kwargs)
        target, install_script = builder.make_targets()
        targets = [HotdocTargetHolder(target, self.interpreter)]
        if install_script:
            targets.append(install_script)

        return ModuleReturnValue(targets[0], targets)


def initialize(interpreter):
    return HotDocModule(interpreter)
meson-0.53.2/mesonbuild/modules/i18n.py0000644000175000017500000002002013543771101021252 0ustar  jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import shutil

from os import path
from .. import coredata, mesonlib, build, mlog
from ..mesonlib import MesonException, run_once
from . import ModuleReturnValue
from . import ExtensionModule
from ..interpreterbase import permittedKwargs, FeatureNew, FeatureNewKwargs

PRESET_ARGS = {
    'glib': [
        '--from-code=UTF-8',
        '--add-comments',

        # https://developer.gnome.org/glib/stable/glib-I18N.html
        '--keyword=_',
        '--keyword=N_',
        '--keyword=C_:1c,2',
        '--keyword=NC_:1c,2',
        '--keyword=g_dcgettext:2',
        '--keyword=g_dngettext:2,3',
        '--keyword=g_dpgettext2:2c,3',

        '--flag=N_:1:pass-c-format',
        '--flag=C_:2:pass-c-format',
        '--flag=NC_:2:pass-c-format',
        '--flag=g_dngettext:2:pass-c-format',
        '--flag=g_strdup_printf:1:c-format',
        '--flag=g_string_printf:2:c-format',
        '--flag=g_string_append_printf:2:c-format',
        '--flag=g_error_new:3:c-format',
        '--flag=g_set_error:4:c-format',
        '--flag=g_markup_printf_escaped:1:c-format',
        '--flag=g_log:3:c-format',
        '--flag=g_print:1:c-format',
        '--flag=g_printerr:1:c-format',
        '--flag=g_printf:1:c-format',
        '--flag=g_fprintf:2:c-format',
        '--flag=g_sprintf:2:c-format',
        '--flag=g_snprintf:3:c-format',
    ]
}


class I18nModule(ExtensionModule):

    @staticmethod
    @run_once
    def nogettext_warning():
        mlog.warning('Gettext not found, all translation targets will be ignored.')
        return ModuleReturnValue(None, [])

    @staticmethod
    def _get_data_dirs(state, dirs):
        """Returns source directories of relative paths"""
        src_dir = path.join(state.environment.get_source_dir(), state.subdir)
        return [path.join(src_dir, d) for d in dirs]

    @FeatureNew('i18n.merge_file', '0.37.0')
    @FeatureNewKwargs('i18n.merge_file', '0.51.0', ['args'])
    @permittedKwargs(build.CustomTarget.known_kwargs | {'data_dirs', 'po_dir', 'type', 'args'})
    def merge_file(self, state, args, kwargs):
        if not shutil.which('xgettext'):
            return self.nogettext_warning()
        podir = kwargs.pop('po_dir', None)
        if not podir:
            raise MesonException('i18n: po_dir is a required kwarg')
        podir = path.join(state.build_to_src, state.subdir, podir)

        file_type = kwargs.pop('type', 'xml')
        VALID_TYPES = ('xml', 'desktop')
        if file_type not in VALID_TYPES:
            raise MesonException('i18n: "{}" is not a valid type {}'.format(file_type, VALID_TYPES))

        datadirs = self._get_data_dirs(state, mesonlib.stringlistify(kwargs.pop('data_dirs', [])))
        datadirs = '--datadirs=' + ':'.join(datadirs) if datadirs else None

        command = state.environment.get_build_command() + [
            '--internal', 'msgfmthelper',
            '@INPUT@', '@OUTPUT@', file_type, podir
        ]
        if datadirs:
            command.append(datadirs)

        if 'args' in kwargs:
            command.append('--')
            command.append(mesonlib.stringlistify(kwargs.pop('args', [])))

        kwargs['command'] = command

        inputfile = kwargs['input']
        if hasattr(inputfile, 'held_object'):
            ct = build.CustomTarget(kwargs['output'] + '_merge', state.subdir, state.subproject, kwargs)
        else:
            if isinstance(inputfile, list):
                # We only use this input file to create a name of the custom target.
                # Thus we can ignore the other entries.
                inputfile = inputfile[0]
            if isinstance(inputfile, str):
                inputfile = mesonlib.File.from_source_file(state.environment.source_dir,
                                                           state.subdir, inputfile)
            output = kwargs['output']
            ifile_abs = inputfile.absolute_path(state.environment.source_dir,
                                                state.environment.build_dir)
            values = mesonlib.get_filenames_templates_dict([ifile_abs], None)
            outputs = mesonlib.substitute_values([output], values)
            output = outputs[0]
            ct = build.CustomTarget(output + '_' + state.subdir.replace('/', '@').replace('\\', '@') + '_merge', state.subdir, state.subproject, kwargs)
        return ModuleReturnValue(ct, [ct])

    @FeatureNewKwargs('i18n.gettext', '0.37.0', ['preset'])
    @FeatureNewKwargs('i18n.gettext', '0.50.0', ['install_dir'])
    @permittedKwargs({'po_dir', 'data_dirs', 'type', 'languages', 'args', 'preset', 'install', 'install_dir'})
    def gettext(self, state, args, kwargs):
        if len(args) != 1:
            raise coredata.MesonException('Gettext requires one positional argument (package name).')
        if not shutil.which('xgettext'):
            return self.nogettext_warning()
        packagename = args[0]
        languages = mesonlib.stringlistify(kwargs.get('languages', []))
        datadirs = self._get_data_dirs(state, mesonlib.stringlistify(kwargs.get('data_dirs', [])))
        extra_args = mesonlib.stringlistify(kwargs.get('args', []))

        preset = kwargs.pop('preset', None)
        if preset:
            preset_args = PRESET_ARGS.get(preset)
            if not preset_args:
                raise coredata.MesonException('i18n: Preset "{}" is not one of the valid options: {}'.format(
                                              preset, list(PRESET_ARGS.keys())))
            extra_args = set(preset_args + extra_args)

        pkg_arg = '--pkgname=' + packagename
        lang_arg = '--langs=' + '@@'.join(languages) if languages else None
        datadirs = '--datadirs=' + ':'.join(datadirs) if datadirs else None
        extra_args = '--extra-args=' + '@@'.join(extra_args) if extra_args else None

        potargs = state.environment.get_build_command() + ['--internal', 'gettext', 'pot', pkg_arg]
        if datadirs:
            potargs.append(datadirs)
        if extra_args:
            potargs.append(extra_args)
        pottarget = build.RunTarget(packagename + '-pot', potargs[0], potargs[1:], [], state.subdir, state.subproject)

        gmoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'gen_gmo']
        if lang_arg:
            gmoargs.append(lang_arg)
        gmotarget = build.RunTarget(packagename + '-gmo', gmoargs[0], gmoargs[1:], [], state.subdir, state.subproject)

        updatepoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'update_po', pkg_arg]
        if lang_arg:
            updatepoargs.append(lang_arg)
        if datadirs:
            updatepoargs.append(datadirs)
        if extra_args:
            updatepoargs.append(extra_args)
        updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs[0], updatepoargs[1:], [], state.subdir, state.subproject)

        targets = [pottarget, gmotarget, updatepotarget]

        install = kwargs.get('install', True)
        if install:
            install_dir = kwargs.get('install_dir', state.environment.coredata.get_builtin_option('localedir'))
            script = state.environment.get_build_command()
            args = ['--internal', 'gettext', 'install',
                    '--subdir=' + state.subdir,
                    '--localedir=' + install_dir,
                    pkg_arg]
            if lang_arg:
                args.append(lang_arg)
            iscript = build.RunScript(script, args)
            targets.append(iscript)

        return ModuleReturnValue(None, targets)

def initialize(*args, **kwargs):
    return I18nModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/modtest.py0000644000175000017500000000170313340206727022163 0ustar  jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import ModuleReturnValue
from . import ExtensionModule
from ..interpreterbase import noKwargs

class TestModule(ExtensionModule):

    @noKwargs
    def print_hello(self, state, args, kwargs):
        print('Hello from a Meson module')
        rv = ModuleReturnValue(None, [])
        return rv

def initialize(*args, **kwargs):
    return TestModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/pkgconfig.py0000644000175000017500000005401413612417061022453 0ustar  jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os, types
from pathlib import PurePath

from .. import build
from .. import dependencies
from .. import mesonlib
from .. import mlog
from . import ModuleReturnValue
from . import ExtensionModule
from ..interpreterbase import permittedKwargs, FeatureNew, FeatureNewKwargs

already_warned_objs = set()

class DependenciesHelper:
    def __init__(self, name):
        self.name = name
        self.pub_libs = []
        self.pub_reqs = []
        self.priv_libs = []
        self.priv_reqs = []
        self.cflags = []
        self.version_reqs = {}

    def add_pub_libs(self, libs):
        libs, reqs, cflags = self._process_libs(libs, True)
        self.pub_libs = libs + self.pub_libs # prepend to preserve dependencies
        self.pub_reqs += reqs
        self.cflags += cflags

    def add_priv_libs(self, libs):
        libs, reqs, _ = self._process_libs(libs, False)
        self.priv_libs = libs + self.priv_libs
        self.priv_reqs += reqs

    def add_pub_reqs(self, reqs):
        self.pub_reqs += self._process_reqs(reqs)

    def add_priv_reqs(self, reqs):
        self.priv_reqs += self._process_reqs(reqs)

    def _check_generated_pc_deprecation(self, obj):
        if not hasattr(obj, 'generated_pc_warn'):
            return
        name = obj.generated_pc_warn[0]
        if (name, obj.name) in already_warned_objs:
            return
        mlog.deprecation('Library', mlog.bold(obj.name), 'was passed to the '
                         '"libraries" keyword argument of a previous call '
                         'to generate() method instead of first positional '
                         'argument.', 'Adding', mlog.bold(obj.generated_pc),
                         'to "Requires" field, but this is a deprecated '
                         'behaviour that will change in a future version '
                         'of Meson. Please report the issue if this '
                         'warning cannot be avoided in your case.',
                         location=obj.generated_pc_warn[1])
        already_warned_objs.add((name, obj.name))

    def _process_reqs(self, reqs):
        '''Returns string names of requirements'''
        processed_reqs = []
        for obj in mesonlib.listify(reqs, unholder=True):
            if hasattr(obj, 'generated_pc'):
                self._check_generated_pc_deprecation(obj)
                processed_reqs.append(obj.generated_pc)
            elif hasattr(obj, 'pcdep'):
                pcdeps = mesonlib.listify(obj.pcdep)
                for d in pcdeps:
                    processed_reqs.append(d.name)
                    self.add_version_reqs(d.name, obj.version_reqs)
            elif isinstance(obj, dependencies.PkgConfigDependency):
                if obj.found():
                    processed_reqs.append(obj.name)
                    self.add_version_reqs(obj.name, obj.version_reqs)
            elif isinstance(obj, str):
                name, version_req = self.split_version_req(obj)
                processed_reqs.append(name)
                self.add_version_reqs(name, version_req)
            elif isinstance(obj, dependencies.Dependency) and not obj.found():
                pass
            elif isinstance(obj, dependencies.ThreadDependency):
                pass
            else:
                raise mesonlib.MesonException('requires argument not a string, '
                                              'library with pkgconfig-generated file '
                                              'or pkgconfig-dependency object, '
                                              'got {!r}'.format(obj))
        return processed_reqs

    def add_cflags(self, cflags):
        self.cflags += mesonlib.stringlistify(cflags)

    def _process_libs(self, libs, public):
        libs = mesonlib.listify(libs, unholder=True)
        processed_libs = []
        processed_reqs = []
        processed_cflags = []
        for obj in libs:
            shared_library_only = getattr(obj, 'shared_library_only', False)
            if hasattr(obj, 'pcdep'):
                pcdeps = mesonlib.listify(obj.pcdep)
                for d in pcdeps:
                    processed_reqs.append(d.name)
                    self.add_version_reqs(d.name, obj.version_reqs)
            elif hasattr(obj, 'generated_pc'):
                self._check_generated_pc_deprecation(obj)
                processed_reqs.append(obj.generated_pc)
            elif isinstance(obj, dependencies.PkgConfigDependency):
                if obj.found():
                    processed_reqs.append(obj.name)
                    self.add_version_reqs(obj.name, obj.version_reqs)
            elif isinstance(obj, dependencies.ThreadDependency):
                processed_libs += obj.get_compiler().thread_link_flags(obj.env)
                processed_cflags += obj.get_compiler().thread_flags(obj.env)
            elif isinstance(obj, dependencies.InternalDependency):
                if obj.found():
                    processed_libs += obj.get_link_args()
                    processed_cflags += obj.get_compile_args()
                    if public:
                        self.add_pub_libs(obj.libraries)
                    else:
                        self.add_priv_libs(obj.libraries)
            elif isinstance(obj, dependencies.Dependency):
                if obj.found():
                    processed_libs += obj.get_link_args()
                    processed_cflags += obj.get_compile_args()
            elif isinstance(obj, build.SharedLibrary) and shared_library_only:
                # Do not pull dependencies for shared libraries because they are
                # only required for static linking. Adding private requires has
                # the side effect of exposing their cflags, which is the
                # intended behaviour of pkg-config but force Debian to add more
                # than needed build deps.
                # See https://bugs.freedesktop.org/show_bug.cgi?id=105572
                processed_libs.append(obj)
            elif isinstance(obj, (build.SharedLibrary, build.StaticLibrary)):
                processed_libs.append(obj)
                if isinstance(obj, build.StaticLibrary) and public:
                    self.add_pub_libs(obj.get_dependencies(for_pkgconfig=True))
                    self.add_pub_libs(obj.get_external_deps())
                else:
                    self.add_priv_libs(obj.get_dependencies(for_pkgconfig=True))
                    self.add_priv_libs(obj.get_external_deps())
            elif isinstance(obj, str):
                processed_libs.append(obj)
            else:
                raise mesonlib.MesonException('library argument not a string, library or dependency object.')

        return processed_libs, processed_reqs, processed_cflags

    def add_version_reqs(self, name, version_reqs):
        if version_reqs:
            if name not in self.version_reqs:
                self.version_reqs[name] = set()
            # Note that pkg-config is picky about whitespace.
            # 'foo > 1.2' is ok but 'foo>1.2' is not.
            # foo, bar' is ok, but 'foo,bar' is not.
            new_vreqs = [s for s in mesonlib.stringlistify(version_reqs)]
            self.version_reqs[name].update(new_vreqs)

    def split_version_req(self, s):
        for op in ['>=', '<=', '!=', '==', '=', '>', '<']:
            pos = s.find(op)
            if pos > 0:
                return s[0:pos].strip(), s[pos:].strip()
        return s, None

    def format_vreq(self, vreq):
        # vreq are '>=1.0' and pkgconfig wants '>= 1.0'
        for op in ['>=', '<=', '!=', '==', '=', '>', '<']:
            if vreq.startswith(op):
                return op + ' ' + vreq[len(op):]
        return vreq

    def format_reqs(self, reqs):
        result = []
        for name in reqs:
            vreqs = self.version_reqs.get(name, None)
            if vreqs:
                result += [name + ' ' + self.format_vreq(vreq) for vreq in vreqs]
            else:
                result += [name]
        return ', '.join(result)

    def remove_dups(self):
        def _fn(xs, libs=False):
            # Remove duplicates whilst preserving original order
            result = []
            for x in xs:
                # Don't de-dup unknown strings to avoid messing up arguments like:
                # ['-framework', 'CoreAudio', '-framework', 'CoreMedia']
                known_flags = ['-pthread']
                cannot_dedup = libs and isinstance(x, str) and \
                    not x.startswith(('-l', '-L')) and \
                    x not in known_flags
                if x not in result or cannot_dedup:
                    result.append(x)
            return result
        self.pub_libs = _fn(self.pub_libs, True)
        self.pub_reqs = _fn(self.pub_reqs)
        self.priv_libs = _fn(self.priv_libs, True)
        self.priv_reqs = _fn(self.priv_reqs)
        self.cflags = _fn(self.cflags)

        # Remove from private libs/reqs if they are in public already
        self.priv_libs = [i for i in self.priv_libs if i not in self.pub_libs]
        self.priv_reqs = [i for i in self.priv_reqs if i not in self.pub_reqs]

class PkgConfigModule(ExtensionModule):

    def _get_lname(self, l, msg, pcfile):
        # Nothing special
        if not l.name_prefix_set:
            return l.name
        # Sometimes people want the library to start with 'lib' everywhere,
        # which is achieved by setting name_prefix to '' and the target name to
        # 'libfoo'. In that case, try to get the pkg-config '-lfoo' arg correct.
        if l.prefix == '' and l.name.startswith('lib'):
            return l.name[3:]
        # If the library is imported via an import library which is always
        # named after the target name, '-lfoo' is correct.
        if isinstance(l, build.SharedLibrary) and l.import_filename:
            return l.name
        # In other cases, we can't guarantee that the compiler will be able to
        # find the library via '-lfoo', so tell the user that.
        mlog.warning(msg.format(l.name, 'name_prefix', l.name, pcfile))
        return l.name

    def _escape(self, value):
        '''
        We cannot use quote_arg because it quotes with ' and " which does not
        work with pkg-config and pkgconf at all.
        '''
        # We should always write out paths with / because pkg-config requires
        # spaces to be quoted with \ and that messes up on Windows:
        # https://bugs.freedesktop.org/show_bug.cgi?id=103203
        if isinstance(value, PurePath):
            value = value.as_posix()
        return value.replace(' ', r'\ ')

    def _make_relative(self, prefix, subdir):
        if isinstance(prefix, PurePath):
            prefix = prefix.as_posix()
        if isinstance(subdir, PurePath):
            subdir = subdir.as_posix()
        if subdir.startswith(prefix):
            subdir = subdir.replace(prefix, '')
        return subdir

    def generate_pkgconfig_file(self, state, deps, subdirs, name, description,
                                url, version, pcfile, conflicts, variables):
        deps.remove_dups()
        coredata = state.environment.get_coredata()
        outdir = state.environment.scratch_dir
        fname = os.path.join(outdir, pcfile)
        prefix = PurePath(coredata.get_builtin_option('prefix'))
        # These always return paths relative to prefix
        libdir = PurePath(coredata.get_builtin_option('libdir'))
        incdir = PurePath(coredata.get_builtin_option('includedir'))
        with open(fname, 'w', encoding='utf-8') as ofile:
            ofile.write('prefix={}\n'.format(self._escape(prefix)))
            ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir)))
            ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir)))
            if variables:
                ofile.write('\n')
            for k, v in variables:
                ofile.write('{}={}\n'.format(k, self._escape(v)))
            ofile.write('\n')
            ofile.write('Name: %s\n' % name)
            if len(description) > 0:
                ofile.write('Description: %s\n' % description)
            if len(url) > 0:
                ofile.write('URL: %s\n' % url)
            ofile.write('Version: %s\n' % version)
            reqs_str = deps.format_reqs(deps.pub_reqs)
            if len(reqs_str) > 0:
                ofile.write('Requires: {}\n'.format(reqs_str))
            reqs_str = deps.format_reqs(deps.priv_reqs)
            if len(reqs_str) > 0:
                ofile.write('Requires.private: {}\n'.format(reqs_str))
            if len(conflicts) > 0:
                ofile.write('Conflicts: {}\n'.format(' '.join(conflicts)))

            def generate_libs_flags(libs):
                msg = 'Library target {0!r} has {1!r} set. Compilers ' \
                      'may not find it from its \'-l{2}\' linker flag in the ' \
                      '{3!r} pkg-config file.'
                Lflags = []
                for l in libs:
                    if isinstance(l, str):
                        yield l
                    else:
                        install_dir = l.get_custom_install_dir()[0]
                        if install_dir is False:
                            continue
                        if 'cs' in l.compilers:
                            if isinstance(install_dir, str):
                                Lflag = '-r${prefix}/%s/%s ' % (self._escape(self._make_relative(prefix, install_dir)), l.filename)
                            else:  # install_dir is True
                                Lflag = '-r${libdir}/%s' % l.filename
                        else:
                            if isinstance(install_dir, str):
                                Lflag = '-L${prefix}/%s ' % self._escape(self._make_relative(prefix, install_dir))
                            else:  # install_dir is True
                                Lflag = '-L${libdir}'
                        if Lflag not in Lflags:
                            Lflags.append(Lflag)
                            yield Lflag
                        lname = self._get_lname(l, msg, pcfile)
                        # If using a custom suffix, the compiler may not be able to
                        # find the library
                        if l.name_suffix_set:
                            mlog.warning(msg.format(l.name, 'name_suffix', lname, pcfile))
                        if 'cs' not in l.compilers:
                            yield '-l%s' % lname

            if len(deps.pub_libs) > 0:
                ofile.write('Libs: {}\n'.format(' '.join(generate_libs_flags(deps.pub_libs))))
            if len(deps.priv_libs) > 0:
                ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(deps.priv_libs))))
            ofile.write('Cflags:')
            for h in subdirs:
                ofile.write(' ')
                if h == '.':
                    ofile.write('-I${includedir}')
                else:
                    ofile.write(self._escape(PurePath('-I${includedir}') / h))
            for f in deps.cflags:
                ofile.write(' ')
                ofile.write(self._escape(f))
            ofile.write('\n')

    @FeatureNewKwargs('pkgconfig.generate', '0.42.0', ['extra_cflags'])
    @FeatureNewKwargs('pkgconfig.generate', '0.41.0', ['variables'])
    @permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase',
                      'subdirs', 'requires', 'requires_private', 'libraries_private',
                      'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions'})
    def generate(self, state, args, kwargs):
        if 'variables' in kwargs:
            FeatureNew('custom pkgconfig variables', '0.41.0').use(state.subproject)
        default_version = state.project_version['version']
        default_install_dir = None
        default_description = None
        default_name = None
        mainlib = None
        if not args and 'version' not in kwargs:
            FeatureNew('pkgconfig.generate implicit version keyword', '0.46.0').use(state.subproject)
        elif len(args) == 1:
            FeatureNew('pkgconfig.generate optional positional argument', '0.46.0').use(state.subproject)
            mainlib = getattr(args[0], 'held_object', args[0])
            if not isinstance(mainlib, (build.StaticLibrary, build.SharedLibrary)):
                raise mesonlib.MesonException('Pkgconfig_gen first positional argument must be a library object')
            default_name = mainlib.name
            default_description = state.project_name + ': ' + mainlib.name
            install_dir = mainlib.get_custom_install_dir()[0]
            if isinstance(install_dir, str):
                default_install_dir = os.path.join(install_dir, 'pkgconfig')
        elif len(args) > 1:
            raise mesonlib.MesonException('Too many positional arguments passed to Pkgconfig_gen.')

        subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.']))
        version = kwargs.get('version', default_version)
        if not isinstance(version, str):
            raise mesonlib.MesonException('Version must be specified.')
        name = kwargs.get('name', default_name)
        if not isinstance(name, str):
            raise mesonlib.MesonException('Name not specified.')
        filebase = kwargs.get('filebase', name)
        if not isinstance(filebase, str):
            raise mesonlib.MesonException('Filebase must be a string.')
        description = kwargs.get('description', default_description)
        if not isinstance(description, str):
            raise mesonlib.MesonException('Description is not a string.')
        url = kwargs.get('url', '')
        if not isinstance(url, str):
            raise mesonlib.MesonException('URL is not a string.')
        conflicts = mesonlib.stringlistify(kwargs.get('conflicts', []))

        # Prepend the main library to public libraries list. This is required
        # so dep.add_pub_libs() can handle dependency ordering correctly and put
        # extra libraries after the main library.
        libraries = mesonlib.extract_as_list(kwargs, 'libraries')
        if mainlib:
            libraries = [mainlib] + libraries

        deps = DependenciesHelper(filebase)
        deps.add_pub_libs(libraries)
        deps.add_priv_libs(kwargs.get('libraries_private', []))
        deps.add_pub_reqs(kwargs.get('requires', []))
        deps.add_priv_reqs(kwargs.get('requires_private', []))
        deps.add_cflags(kwargs.get('extra_cflags', []))

        dversions = kwargs.get('d_module_versions', None)
        if dversions:
            compiler = state.environment.coredata.compilers.host.get('d')
            if compiler:
                deps.add_cflags(compiler.get_feature_args({'versions': dversions}, None))

        def parse_variable_list(stringlist):
            reserved = ['prefix', 'libdir', 'includedir']
            variables = []
            for var in stringlist:
                # foo=bar=baz is ('foo', 'bar=baz')
                l = var.split('=', 1)
                if len(l) < 2:
                    raise mesonlib.MesonException('Invalid variable "{}". Variables must be in \'name=value\' format'.format(var))

                name, value = l[0].strip(), l[1].strip()
                if not name or not value:
                    raise mesonlib.MesonException('Invalid variable "{}". Variables must be in \'name=value\' format'.format(var))

                # Variable names must not contain whitespaces
                if any(c.isspace() for c in name):
                    raise mesonlib.MesonException('Invalid whitespace in assignment "{}"'.format(var))

                if name in reserved:
                    raise mesonlib.MesonException('Variable "{}" is reserved'.format(name))

                variables.append((name, value))

            return variables

        variables = parse_variable_list(mesonlib.stringlistify(kwargs.get('variables', [])))

        pcfile = filebase + '.pc'
        pkgroot = kwargs.get('install_dir', default_install_dir)
        if pkgroot is None:
            if mesonlib.is_freebsd():
                pkgroot = os.path.join(state.environment.coredata.get_builtin_option('prefix'), 'libdata', 'pkgconfig')
            else:
                pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig')
        if not isinstance(pkgroot, str):
            raise mesonlib.MesonException('Install_dir must be a string.')
        self.generate_pkgconfig_file(state, deps, subdirs, name, description, url,
                                     version, pcfile, conflicts, variables)
        res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot)
        # Associate the main library with this generated pc file. If the library
        # is used in any subsequent call to the generated, it will generate a
        # 'Requires:' or 'Requires.private:'.
        # Backward compatibility: We used to set 'generated_pc' on all public
        # libraries instead of just the main one. Keep doing that but warn if
        # anyone is relying on that deprecated behaviour.
        if mainlib:
            if not hasattr(mainlib, 'generated_pc'):
                mainlib.generated_pc = filebase
            else:
                mlog.warning('Already generated a pkg-config file for', mlog.bold(mainlib.name))
        else:
            for lib in deps.pub_libs:
                if not isinstance(lib, str) and not hasattr(lib, 'generated_pc'):
                    lib.generated_pc = filebase
                    location = types.SimpleNamespace(subdir=state.subdir,
                                                     lineno=state.current_lineno)
                    lib.generated_pc_warn = [name, location]
        return ModuleReturnValue(res, [res])

def initialize(*args, **kwargs):
    return PkgConfigModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/python.py0000644000175000017500000006036313625260316022034 0ustar  jpakkanejpakkane00000000000000# Copyright 2018 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import json
import shutil
import typing as T

from pathlib import Path
from .. import mesonlib
from ..mesonlib import MesonException
from . import ExtensionModule
from mesonbuild.modules import ModuleReturnValue
from ..interpreterbase import (
    noPosargs, noKwargs, permittedKwargs,
    InvalidArguments,
    FeatureNew, FeatureNewKwargs, disablerIfNotFound
)
from ..interpreter import ExternalProgramHolder, extract_required_kwarg, permitted_kwargs
from ..build import known_shmod_kwargs
from .. import mlog
from ..environment import detect_cpu_family
from ..dependencies.base import (
    DependencyMethods, ExternalDependency,
    ExternalProgram, PkgConfigDependency,
    NonExistingExternalProgram
)

mod_kwargs = set(['subdir'])
mod_kwargs.update(known_shmod_kwargs)
mod_kwargs -= set(['name_prefix', 'name_suffix'])

class PythonDependency(ExternalDependency):

    def __init__(self, python_holder, environment, kwargs):
        super().__init__('python', environment, None, kwargs)
        self.name = 'python'
        self.static = kwargs.get('static', False)
        self.embed = kwargs.get('embed', False)
        self.version = python_holder.version
        self.platform = python_holder.platform
        self.pkgdep = None
        self.variables = python_holder.variables
        self.paths = python_holder.paths
        self.link_libpython = python_holder.link_libpython
        if mesonlib.version_compare(self.version, '>= 3.0'):
            self.major_version = 3
        else:
            self.major_version = 2

        # We first try to find the necessary python variables using pkgconfig
        if DependencyMethods.PKGCONFIG in self.methods and not python_holder.is_pypy:
            pkg_version = self.variables.get('LDVERSION') or self.version
            pkg_libdir = self.variables.get('LIBPC')
            pkg_embed = '-embed' if self.embed and mesonlib.version_compare(self.version, '>=3.8') else ''
            pkg_name = 'python-{}{}'.format(pkg_version, pkg_embed)

            # If python-X.Y.pc exists in LIBPC, we will try to use it
            if pkg_libdir is not None and Path(os.path.join(pkg_libdir, '{}.pc'.format(pkg_name))).is_file():
                old_pkg_libdir = os.environ.get('PKG_CONFIG_LIBDIR')
                old_pkg_path = os.environ.get('PKG_CONFIG_PATH')

                os.environ.pop('PKG_CONFIG_PATH', None)

                if pkg_libdir:
                    os.environ['PKG_CONFIG_LIBDIR'] = pkg_libdir

                try:
                    self.pkgdep = PkgConfigDependency(pkg_name, environment, kwargs)
                    mlog.debug('Found "{}" via pkgconfig lookup in LIBPC ({})'.format(pkg_name, pkg_libdir))
                    py_lookup_method = 'pkgconfig'
                except MesonException as e:
                    mlog.debug('"{}" could not be found in LIBPC ({})'.format(pkg_name, pkg_libdir))
                    mlog.debug(e)

                if old_pkg_path is not None:
                    os.environ['PKG_CONFIG_PATH'] = old_pkg_path

                if old_pkg_libdir is not None:
                    os.environ['PKG_CONFIG_LIBDIR'] = old_pkg_libdir
                else:
                    os.environ.pop('PKG_CONFIG_LIBDIR', None)
            else:
                mlog.debug('"{}" could not be found in LIBPC ({}), this is likely due to a relocated python installation'.format(pkg_name, pkg_libdir))

            # If lookup via LIBPC failed, try to use fallback PKG_CONFIG_LIBDIR/PKG_CONFIG_PATH mechanisms
            if self.pkgdep is None or not self.pkgdep.found():
                try:
                    self.pkgdep = PkgConfigDependency(pkg_name, environment, kwargs)
                    mlog.debug('Found "{}" via fallback pkgconfig lookup in PKG_CONFIG_LIBDIR/PKG_CONFIG_PATH'.format(pkg_name))
                    py_lookup_method = 'pkgconfig-fallback'
                except MesonException as e:
                    mlog.debug('"{}" could not be found via fallback pkgconfig lookup in PKG_CONFIG_LIBDIR/PKG_CONFIG_PATH'.format(pkg_name))
                    mlog.debug(e)

        if self.pkgdep and self.pkgdep.found():
            self.compile_args = self.pkgdep.get_compile_args()
            self.link_args = self.pkgdep.get_link_args()
            self.is_found = True
            self.pcdep = self.pkgdep
        else:
            self.pkgdep = None

            # Finally, try to find python via SYSCONFIG as a final measure
            if DependencyMethods.SYSCONFIG in self.methods:
                if mesonlib.is_windows():
                    self._find_libpy_windows(environment)
                else:
                    self._find_libpy(python_holder, environment)
                if self.is_found:
                    mlog.debug('Found "python-{}" via SYSCONFIG module'.format(self.version))
                    py_lookup_method = 'sysconfig'

        if self.is_found:
            mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES ({})'.format(py_lookup_method)))
        else:
            mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))

    def _find_libpy(self, python_holder, environment):
        if python_holder.is_pypy:
            if self.major_version == 3:
                libname = 'pypy3-c'
            else:
                libname = 'pypy-c'
            libdir = os.path.join(self.variables.get('base'), 'bin')
            libdirs = [libdir]
        else:
            libname = 'python{}'.format(self.version)
            if 'DEBUG_EXT' in self.variables:
                libname += self.variables['DEBUG_EXT']
            if 'ABIFLAGS' in self.variables:
                libname += self.variables['ABIFLAGS']
            libdirs = []

        largs = self.clib_compiler.find_library(libname, environment, libdirs)
        if largs is not None:
            self.link_args = largs

        self.is_found = largs is not None or self.link_libpython

        inc_paths = mesonlib.OrderedSet([
            self.variables.get('INCLUDEPY'),
            self.paths.get('include'),
            self.paths.get('platinclude')])

        self.compile_args += ['-I' + path for path in inc_paths if path]

    def get_windows_python_arch(self):
        if self.platform == 'mingw':
            pycc = self.variables.get('CC')
            if pycc.startswith('x86_64'):
                return '64'
            elif pycc.startswith(('i686', 'i386')):
                return '32'
            else:
                mlog.log('MinGW Python built with unknown CC {!r}, please file'
                         'a bug'.format(pycc))
                return None
        elif self.platform == 'win32':
            return '32'
        elif self.platform in ('win64', 'win-amd64'):
            return '64'
        mlog.log('Unknown Windows Python platform {!r}'.format(self.platform))
        return None

    def get_windows_link_args(self):
        if self.platform.startswith('win'):
            vernum = self.variables.get('py_version_nodot')
            if self.static:
                libpath = Path('libs') / 'libpython{}.a'.format(vernum)
            else:
                comp = self.get_compiler()
                if comp.id == "gcc":
                    libpath = 'python{}.dll'.format(vernum)
                else:
                    libpath = Path('libs') / 'python{}.lib'.format(vernum)
            lib = Path(self.variables.get('base')) / libpath
        elif self.platform == 'mingw':
            if self.static:
                libname = self.variables.get('LIBRARY')
            else:
                libname = self.variables.get('LDLIBRARY')
            lib = Path(self.variables.get('LIBDIR')) / libname
        if not lib.exists():
            mlog.log('Could not find Python3 library {!r}'.format(str(lib)))
            return None
        return [str(lib)]

    def _find_libpy_windows(self, env):
        '''
        Find python3 libraries on Windows and also verify that the arch matches
        what we are building for.
        '''
        pyarch = self.get_windows_python_arch()
        if pyarch is None:
            self.is_found = False
            return
        arch = detect_cpu_family(env.coredata.compilers.host)
        if arch == 'x86':
            arch = '32'
        elif arch == 'x86_64':
            arch = '64'
        else:
            # We can't cross-compile Python 3 dependencies on Windows yet
            mlog.log('Unknown architecture {!r} for'.format(arch),
                     mlog.bold(self.name))
            self.is_found = False
            return
        # Pyarch ends in '32' or '64'
        if arch != pyarch:
            mlog.log('Need', mlog.bold(self.name), 'for {}-bit, but '
                     'found {}-bit'.format(arch, pyarch))
            self.is_found = False
            return
        # This can fail if the library is not found
        largs = self.get_windows_link_args()
        if largs is None:
            self.is_found = False
            return
        self.link_args = largs
        # Compile args
        inc_paths = mesonlib.OrderedSet([
            self.variables.get('INCLUDEPY'),
            self.paths.get('include'),
            self.paths.get('platinclude')])

        self.compile_args += ['-I' + path for path in inc_paths if path]

        # https://sourceforge.net/p/mingw-w64/mailman/message/30504611/
        if pyarch == '64' and self.major_version == 2:
            self.compile_args += ['-DMS_WIN64']

        self.is_found = True

    @staticmethod
    def get_methods():
        if mesonlib.is_windows():
            return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSCONFIG]
        elif mesonlib.is_osx():
            return [DependencyMethods.PKGCONFIG, DependencyMethods.EXTRAFRAMEWORK]
        else:
            return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSCONFIG]

    def get_pkgconfig_variable(self, variable_name, kwargs):
        if self.pkgdep:
            return self.pkgdep.get_pkgconfig_variable(variable_name, kwargs)
        else:
            return super().get_pkgconfig_variable(variable_name, kwargs)


INTROSPECT_COMMAND = '''import sysconfig
import json
import sys

install_paths = sysconfig.get_paths(scheme='posix_prefix', vars={'base': '', 'platbase': '', 'installed_base': ''})

def links_against_libpython():
    from distutils.core import Distribution, Extension
    cmd = Distribution().get_command_obj('build_ext')
    cmd.ensure_finalized()
    return bool(cmd.get_libraries(Extension('dummy', [])))

print (json.dumps ({
  'variables': sysconfig.get_config_vars(),
  'paths': sysconfig.get_paths(),
  'install_paths': install_paths,
  'version': sysconfig.get_python_version(),
  'platform': sysconfig.get_platform(),
  'is_pypy': '__pypy__' in sys.builtin_module_names,
  'link_libpython': links_against_libpython(),
}))
'''


class PythonInstallation(ExternalProgramHolder):
    def __init__(self, interpreter, python, info):
        ExternalProgramHolder.__init__(self, python)
        self.interpreter = interpreter
        self.subproject = self.interpreter.subproject
        prefix = self.interpreter.environment.coredata.get_builtin_option('prefix')
        self.variables = info['variables']
        self.paths = info['paths']
        install_paths = info['install_paths']
        self.platlib_install_path = os.path.join(prefix, install_paths['platlib'][1:])
        self.purelib_install_path = os.path.join(prefix, install_paths['purelib'][1:])
        self.version = info['version']
        self.platform = info['platform']
        self.is_pypy = info['is_pypy']
        self.link_libpython = info['link_libpython']
        self.methods.update({
            'extension_module': self.extension_module_method,
            'dependency': self.dependency_method,
            'install_sources': self.install_sources_method,
            'get_install_dir': self.get_install_dir_method,
            'language_version': self.language_version_method,
            'found': self.found_method,
            'has_path': self.has_path_method,
            'get_path': self.get_path_method,
            'has_variable': self.has_variable_method,
            'get_variable': self.get_variable_method,
            'path': self.path_method,
        })

    @permittedKwargs(mod_kwargs)
    def extension_module_method(self, args, kwargs):
        if 'subdir' in kwargs and 'install_dir' in kwargs:
            raise InvalidArguments('"subdir" and "install_dir" are mutually exclusive')

        if 'subdir' in kwargs:
            subdir = kwargs.pop('subdir', '')
            if not isinstance(subdir, str):
                raise InvalidArguments('"subdir" argument must be a string.')

            kwargs['install_dir'] = os.path.join(self.platlib_install_path, subdir)

        # On macOS and some Linux distros (Debian) distutils doesn't link
        # extensions against libpython. We call into distutils and mirror its
        # behavior. See https://github.com/mesonbuild/meson/issues/4117
        if not self.link_libpython:
            new_deps = []
            for holder in mesonlib.extract_as_list(kwargs, 'dependencies'):
                dep = holder.held_object
                if isinstance(dep, PythonDependency):
                    holder = self.interpreter.holderify(dep.get_partial_dependency(compile_args=True))
                new_deps.append(holder)
            kwargs['dependencies'] = new_deps

        suffix = self.variables.get('EXT_SUFFIX') or self.variables.get('SO') or self.variables.get('.so')

        # msys2's python3 has "-cpython-36m.dll", we have to be clever
        split = suffix.rsplit('.', 1)
        suffix = split.pop(-1)
        args[0] += ''.join(s for s in split)

        kwargs['name_prefix'] = ''
        kwargs['name_suffix'] = suffix

        return self.interpreter.func_shared_module(None, args, kwargs)

    @permittedKwargs(permitted_kwargs['dependency'])
    @FeatureNewKwargs('python_installation.dependency', '0.53.0', ['embed'])
    def dependency_method(self, args, kwargs):
        if args:
            mlog.warning('python_installation.dependency() does not take any '
                         'positional arguments. It always returns a Python '
                         'dependency. This will become an error in the future.',
                         location=self.interpreter.current_node)
        dep = PythonDependency(self, self.interpreter.environment, kwargs)
        return self.interpreter.holderify(dep)

    @permittedKwargs(['pure', 'subdir'])
    def install_sources_method(self, args, kwargs):
        pure = kwargs.pop('pure', False)
        if not isinstance(pure, bool):
            raise InvalidArguments('"pure" argument must be a boolean.')

        subdir = kwargs.pop('subdir', '')
        if not isinstance(subdir, str):
            raise InvalidArguments('"subdir" argument must be a string.')

        if pure:
            kwargs['install_dir'] = os.path.join(self.purelib_install_path, subdir)
        else:
            kwargs['install_dir'] = os.path.join(self.platlib_install_path, subdir)

        return self.interpreter.holderify(self.interpreter.func_install_data(None, args, kwargs))

    @noPosargs
    @permittedKwargs(['pure', 'subdir'])
    def get_install_dir_method(self, args, kwargs):
        pure = kwargs.pop('pure', True)
        if not isinstance(pure, bool):
            raise InvalidArguments('"pure" argument must be a boolean.')

        subdir = kwargs.pop('subdir', '')
        if not isinstance(subdir, str):
            raise InvalidArguments('"subdir" argument must be a string.')

        if pure:
            res = os.path.join(self.purelib_install_path, subdir)
        else:
            res = os.path.join(self.platlib_install_path, subdir)

        return self.interpreter.module_method_callback(ModuleReturnValue(res, []))

    @noPosargs
    @noKwargs
    def language_version_method(self, args, kwargs):
        return self.interpreter.module_method_callback(ModuleReturnValue(self.version, []))

    @noKwargs
    def has_path_method(self, args, kwargs):
        if len(args) != 1:
            raise InvalidArguments('has_path takes exactly one positional argument.')
        path_name = args[0]
        if not isinstance(path_name, str):
            raise InvalidArguments('has_path argument must be a string.')

        return self.interpreter.module_method_callback(ModuleReturnValue(path_name in self.paths, []))

    @noKwargs
    def get_path_method(self, args, kwargs):
        if len(args) not in (1, 2):
            raise InvalidArguments('get_path must have one or two arguments.')
        path_name = args[0]
        if not isinstance(path_name, str):
            raise InvalidArguments('get_path argument must be a string.')

        try:
            path = self.paths[path_name]
        except KeyError:
            if len(args) == 2:
                path = args[1]
            else:
                raise InvalidArguments('{} is not a valid path name'.format(path_name))

        return self.interpreter.module_method_callback(ModuleReturnValue(path, []))

    @noKwargs
    def has_variable_method(self, args, kwargs):
        if len(args) != 1:
            raise InvalidArguments('has_variable takes exactly one positional argument.')
        var_name = args[0]
        if not isinstance(var_name, str):
            raise InvalidArguments('has_variable argument must be a string.')

        return self.interpreter.module_method_callback(ModuleReturnValue(var_name in self.variables, []))

    @noKwargs
    def get_variable_method(self, args, kwargs):
        if len(args) not in (1, 2):
            raise InvalidArguments('get_variable must have one or two arguments.')
        var_name = args[0]
        if not isinstance(var_name, str):
            raise InvalidArguments('get_variable argument must be a string.')

        try:
            var = self.variables[var_name]
        except KeyError:
            if len(args) == 2:
                var = args[1]
            else:
                raise InvalidArguments('{} is not a valid variable name'.format(var_name))

        return self.interpreter.module_method_callback(ModuleReturnValue(var, []))

    @noPosargs
    @noKwargs
    @FeatureNew('Python module path method', '0.50.0')
    def path_method(self, args, kwargs):
        return super().path_method(args, kwargs)


class PythonModule(ExtensionModule):

    @FeatureNew('Python Module', '0.46.0')
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.snippets.add('find_installation')

    # https://www.python.org/dev/peps/pep-0397/
    def _get_win_pythonpath(self, name_or_path):
        if name_or_path not in ['python2', 'python3']:
            return None
        if not shutil.which('py'):
            # program not installed, return without an exception
            return None
        ver = {'python2': '-2', 'python3': '-3'}[name_or_path]
        cmd = ['py', ver, '-c', "import sysconfig; print(sysconfig.get_config_var('BINDIR'))"]
        _, stdout, _ = mesonlib.Popen_safe(cmd)
        directory = stdout.strip()
        if os.path.exists(directory):
            return os.path.join(directory, 'python')
        else:
            return None

    def _check_version(self, name_or_path, version):
        if name_or_path == 'python2':
            return mesonlib.version_compare(version, '< 3.0')
        elif name_or_path == 'python3':
            return mesonlib.version_compare(version, '>= 3.0')
        return True

    @FeatureNewKwargs('python.find_installation', '0.49.0', ['disabler'])
    @FeatureNewKwargs('python.find_installation', '0.51.0', ['modules'])
    @disablerIfNotFound
    @permittedKwargs({'required', 'modules'})
    def find_installation(self, interpreter, state, args, kwargs):
        feature_check = FeatureNew('Passing "feature" option to find_installation', '0.48.0')
        disabled, required, feature = extract_required_kwarg(kwargs, state.subproject, feature_check)
        want_modules = mesonlib.extract_as_list(kwargs, 'modules')  # type: T.List[str]
        found_modules = []    # type: T.List[str]
        missing_modules = []  # type: T.List[str]

        if len(args) > 1:
            raise InvalidArguments('find_installation takes zero or one positional argument.')

        name_or_path = state.environment.binaries.host.lookup_entry('python')
        if name_or_path is None and args:
            name_or_path = args[0]
            if not isinstance(name_or_path, str):
                raise InvalidArguments('find_installation argument must be a string.')

        if disabled:
            mlog.log('Program', name_or_path or 'python', 'found:', mlog.red('NO'), '(disabled by:', mlog.bold(feature), ')')
            return ExternalProgramHolder(NonExistingExternalProgram())

        if not name_or_path:
            python = ExternalProgram('python3', mesonlib.python_command, silent=True)
        else:
            python = ExternalProgram.from_entry('python3', name_or_path)

            if not python.found() and mesonlib.is_windows():
                pythonpath = self._get_win_pythonpath(name_or_path)
                if pythonpath is not None:
                    name_or_path = pythonpath
                    python = ExternalProgram(name_or_path, silent=True)

            # Last ditch effort, python2 or python3 can be named python
            # on various platforms, let's not give up just yet, if an executable
            # named python is available and has a compatible version, let's use
            # it
            if not python.found() and name_or_path in ['python2', 'python3']:
                python = ExternalProgram('python', silent=True)

        if python.found() and want_modules:
            for mod in want_modules:
                p, out, err = mesonlib.Popen_safe(
                    python.command +
                    ['-c', 'import {0}'.format(mod)])
                if p.returncode != 0:
                    missing_modules.append(mod)
                else:
                    found_modules.append(mod)

        msg = ['Program', python.name]
        if want_modules:
            msg.append('({})'.format(', '.join(want_modules)))
        msg.append('found:')
        if python.found() and not missing_modules:
            msg.extend([mlog.green('YES'), '({})'.format(' '.join(python.command))])
        else:
            msg.append(mlog.red('NO'))
        if found_modules:
            msg.append('modules:')
            msg.append(', '.join(found_modules))

        mlog.log(*msg)

        if not python.found():
            if required:
                raise mesonlib.MesonException('{} not found'.format(name_or_path or 'python'))
            res = ExternalProgramHolder(NonExistingExternalProgram())
        elif missing_modules:
            if required:
                raise mesonlib.MesonException('{} is missing modules: {}'.format(name_or_path or 'python', ', '.join(missing_modules)))
            res = ExternalProgramHolder(NonExistingExternalProgram())
        else:
            # Sanity check, we expect to have something that at least quacks in tune
            try:
                cmd = python.get_command() + ['-c', INTROSPECT_COMMAND]
                p, stdout, stderr = mesonlib.Popen_safe(cmd)
                info = json.loads(stdout)
            except json.JSONDecodeError:
                info = None
                mlog.debug('Could not introspect Python (%s): exit code %d' % (str(p.args), p.returncode))
                mlog.debug('Program stdout:\n')
                mlog.debug(stdout)
                mlog.debug('Program stderr:\n')
                mlog.debug(stderr)

            if isinstance(info, dict) and 'version' in info and self._check_version(name_or_path, info['version']):
                res = PythonInstallation(interpreter, python, info)
            else:
                res = ExternalProgramHolder(NonExistingExternalProgram())
                if required:
                    raise mesonlib.MesonException('{} is not a valid python or it is missing setuptools'.format(python))

        return res


def initialize(*args, **kwargs):
    return PythonModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/python3.py0000644000175000017500000000625013426772647022130 0ustar  jpakkanejpakkane00000000000000# Copyright 2016-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sysconfig
from .. import mesonlib, dependencies

from . import ExtensionModule
from mesonbuild.modules import ModuleReturnValue
from ..interpreterbase import noKwargs, permittedKwargs, FeatureDeprecated
from ..build import known_shmod_kwargs


class Python3Module(ExtensionModule):
    @FeatureDeprecated('python3 module', '0.48.0')
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.snippets.add('extension_module')

    @permittedKwargs(known_shmod_kwargs)
    def extension_module(self, interpreter, state, args, kwargs):
        if 'name_prefix' in kwargs:
            raise mesonlib.MesonException('Name_prefix is set automatically, specifying it is forbidden.')
        if 'name_suffix' in kwargs:
            raise mesonlib.MesonException('Name_suffix is set automatically, specifying it is forbidden.')
        host_system = state.host_machine.system
        if host_system == 'darwin':
            # Default suffix is 'dylib' but Python does not use it for extensions.
            suffix = 'so'
        elif host_system == 'windows':
            # On Windows the extension is pyd for some unexplainable reason.
            suffix = 'pyd'
        else:
            suffix = []
        kwargs['name_prefix'] = ''
        kwargs['name_suffix'] = suffix
        return interpreter.func_shared_module(None, args, kwargs)

    @noKwargs
    def find_python(self, state, args, kwargs):
        command = state.environment.binaries.host.lookup_entry('python3')
        if command is not None:
            py3 = dependencies.ExternalProgram.from_entry('python3', command)
        else:
            py3 = dependencies.ExternalProgram('python3', mesonlib.python_command, silent=True)
        return ModuleReturnValue(py3, [py3])

    @noKwargs
    def language_version(self, state, args, kwargs):
        return ModuleReturnValue(sysconfig.get_python_version(), [])

    @noKwargs
    def sysconfig_path(self, state, args, kwargs):
        if len(args) != 1:
            raise mesonlib.MesonException('sysconfig_path() requires passing the name of path to get.')
        path_name = args[0]
        valid_names = sysconfig.get_path_names()
        if path_name not in valid_names:
            raise mesonlib.MesonException('{} is not a valid path name {}.'.format(path_name, valid_names))

        # Get a relative path without a prefix, e.g. lib/python3.6/site-packages
        path = sysconfig.get_path(path_name, vars={'base': '', 'platbase': '', 'installed_base': ''})[1:]
        return ModuleReturnValue(path, [])


def initialize(*args, **kwargs):
    return Python3Module(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/qt.py0000644000175000017500000003045613571777336021156 0ustar  jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
from .. import mlog
from .. import build
from ..mesonlib import MesonException, Popen_safe, extract_as_list, File
from ..dependencies import Dependency, Qt4Dependency, Qt5Dependency
import xml.etree.ElementTree as ET
from . import ModuleReturnValue, get_include_args, ExtensionModule
from ..interpreterbase import permittedKwargs, FeatureNew, FeatureNewKwargs

_QT_DEPS_LUT = {
    4: Qt4Dependency,
    5: Qt5Dependency
}


class QtBaseModule(ExtensionModule):
    tools_detected = False

    def __init__(self, interpreter, qt_version=5):
        ExtensionModule.__init__(self, interpreter)
        self.qt_version = qt_version

    def _detect_tools(self, env, method):
        if self.tools_detected:
            return
        mlog.log('Detecting Qt{version} tools'.format(version=self.qt_version))
        # FIXME: We currently require QtX to exist while importing the module.
        # We should make it gracefully degrade and not create any targets if
        # the import is marked as 'optional' (not implemented yet)
        kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true', 'method': method}
        qt = _QT_DEPS_LUT[self.qt_version](env, kwargs)
        # Get all tools and then make sure that they are the right version
        self.moc, self.uic, self.rcc, self.lrelease = qt.compilers_detect(self.interpreter)
        # Moc, uic and rcc write their version strings to stderr.
        # Moc and rcc return a non-zero result when doing so.
        # What kind of an idiot thought that was a good idea?
        for compiler, compiler_name in ((self.moc, "Moc"), (self.uic, "Uic"), (self.rcc, "Rcc"), (self.lrelease, "lrelease")):
            if compiler.found():
                # Workaround since there is no easy way to know which tool/version support which flag
                for flag in ['-v', '-version']:
                    p, stdout, stderr = Popen_safe(compiler.get_command() + [flag])[0:3]
                    if p.returncode == 0:
                        break
                stdout = stdout.strip()
                stderr = stderr.strip()
                if 'Qt {}'.format(self.qt_version) in stderr:
                    compiler_ver = stderr
                elif 'version {}.'.format(self.qt_version) in stderr:
                    compiler_ver = stderr
                elif ' {}.'.format(self.qt_version) in stdout:
                    compiler_ver = stdout
                else:
                    raise MesonException('{name} preprocessor is not for Qt {version}. Output:\n{stdo}\n{stderr}'.format(
                        name=compiler_name, version=self.qt_version, stdo=stdout, stderr=stderr))
                mlog.log(' {}:'.format(compiler_name.lower()), mlog.green('YES'), '({path}, {version})'.format(
                    path=compiler.get_path(), version=compiler_ver.split()[-1]))
            else:
                mlog.log(' {}:'.format(compiler_name.lower()), mlog.red('NO'))
        self.tools_detected = True

    def parse_qrc(self, state, rcc_file):
        if type(rcc_file) is str:
            abspath = os.path.join(state.environment.source_dir, state.subdir, rcc_file)
            rcc_dirname = os.path.dirname(abspath)
        elif type(rcc_file) is File:
            abspath = rcc_file.absolute_path(state.environment.source_dir, state.environment.build_dir)
            rcc_dirname = os.path.dirname(abspath)

        try:
            tree = ET.parse(abspath)
            root = tree.getroot()
            result = []
            for child in root[0]:
                if child.tag != 'file':
                    mlog.warning("malformed rcc file: ", os.path.join(state.subdir, rcc_file))
                    break
                else:
                    resource_path = child.text
                    # We need to guess if the pointed resource is:
                    #   a) in build directory -> implies a generated file
                    #   b) in source directory
                    #   c) somewhere else external dependency file to bundle
                    #
                    # Also from qrc documentation: relative path are always from qrc file
                    # So relative path must always be computed from qrc file !
                    if os.path.isabs(resource_path):
                        # a)
                        if resource_path.startswith(os.path.abspath(state.environment.build_dir)):
                            resource_relpath = os.path.relpath(resource_path, state.environment.build_dir)
                            result.append(File(is_built=True, subdir='', fname=resource_relpath))
                        # either b) or c)
                        else:
                            result.append(File(is_built=False, subdir=state.subdir, fname=resource_path))
                    else:
                        path_from_rcc = os.path.normpath(os.path.join(rcc_dirname, resource_path))
                        # a)
                        if path_from_rcc.startswith(state.environment.build_dir):
                            result.append(File(is_built=True, subdir=state.subdir, fname=resource_path))
                        # b)
                        else:
                            result.append(File(is_built=False, subdir=state.subdir, fname=path_from_rcc))
            return result
        except Exception:
            return []

    @FeatureNewKwargs('qt.preprocess', '0.49.0', ['uic_extra_arguments'])
    @FeatureNewKwargs('qt.preprocess', '0.44.0', ['moc_extra_arguments'])
    @FeatureNewKwargs('qt.preprocess', '0.49.0', ['rcc_extra_arguments'])
    @permittedKwargs({'moc_headers', 'moc_sources', 'uic_extra_arguments', 'moc_extra_arguments', 'rcc_extra_arguments', 'include_directories', 'dependencies', 'ui_files', 'qresources', 'method'})
    def preprocess(self, state, args, kwargs):
        rcc_files, ui_files, moc_headers, moc_sources, uic_extra_arguments, moc_extra_arguments, rcc_extra_arguments, sources, include_directories, dependencies \
            = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'uic_extra_arguments', 'moc_extra_arguments', 'rcc_extra_arguments', 'sources', 'include_directories', 'dependencies', pop = True)
        sources += args[1:]
        method = kwargs.get('method', 'auto')
        self._detect_tools(state.environment, method)
        err_msg = "{0} sources specified and couldn't find {1}, " \
                  "please check your qt{2} installation"
        if (moc_headers or moc_sources) and not self.moc.found():
            raise MesonException(err_msg.format('MOC', 'moc-qt{}'.format(self.qt_version), self.qt_version))
        if rcc_files:
            if not self.rcc.found():
                raise MesonException(err_msg.format('RCC', 'rcc-qt{}'.format(self.qt_version), self.qt_version))
            # custom output name set? -> one output file, multiple otherwise
            if args:
                qrc_deps = []
                for i in rcc_files:
                    qrc_deps += self.parse_qrc(state, i)
                name = args[0]
                rcc_kwargs = {'input': rcc_files,
                              'output': name + '.cpp',
                              'command': [self.rcc, '-name', name, '-o', '@OUTPUT@', rcc_extra_arguments, '@INPUT@'],
                              'depend_files': qrc_deps}
                res_target = build.CustomTarget(name, state.subdir, state.subproject, rcc_kwargs)
                sources.append(res_target)
            else:
                for rcc_file in rcc_files:
                    qrc_deps = self.parse_qrc(state, rcc_file)
                    if type(rcc_file) is str:
                        basename = os.path.basename(rcc_file)
                    elif type(rcc_file) is File:
                        basename = os.path.basename(rcc_file.fname)
                    name = 'qt' + str(self.qt_version) + '-' + basename.replace('.', '_')
                    rcc_kwargs = {'input': rcc_file,
                                  'output': name + '.cpp',
                                  'command': [self.rcc, '-name', '@BASENAME@', '-o', '@OUTPUT@', rcc_extra_arguments, '@INPUT@'],
                                  'depend_files': qrc_deps}
                    res_target = build.CustomTarget(name, state.subdir, state.subproject, rcc_kwargs)
                    sources.append(res_target)
        if ui_files:
            if not self.uic.found():
                raise MesonException(err_msg.format('UIC', 'uic-qt{}'.format(self.qt_version), self.qt_version))
            arguments = uic_extra_arguments + ['-o', '@OUTPUT@', '@INPUT@']
            ui_kwargs = {'output': 'ui_@BASENAME@.h',
                         'arguments': arguments}
            ui_gen = build.Generator([self.uic], ui_kwargs)
            ui_output = ui_gen.process_files('Qt{} ui'.format(self.qt_version), ui_files, state)
            sources.append(ui_output)
        inc = get_include_args(include_dirs=include_directories)
        compile_args = []
        for dep in dependencies:
            if hasattr(dep, 'held_object'):
                dep = dep.held_object
            if isinstance(dep, Dependency):
                for arg in dep.get_compile_args():
                    if arg.startswith('-I') or arg.startswith('-D'):
                        compile_args.append(arg)
            else:
                raise MesonException('Argument is of an unacceptable type {!r}.\nMust be '
                                     'either an external dependency (returned by find_library() or '
                                     'dependency()) or an internal dependency (returned by '
                                     'declare_dependency()).'.format(type(dep).__name__))
        if moc_headers:
            arguments = moc_extra_arguments + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT@']
            moc_kwargs = {'output': 'moc_@BASENAME@.cpp',
                          'arguments': arguments}
            moc_gen = build.Generator([self.moc], moc_kwargs)
            moc_output = moc_gen.process_files('Qt{} moc header'.format(self.qt_version), moc_headers, state)
            sources.append(moc_output)
        if moc_sources:
            arguments = moc_extra_arguments + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT@']
            moc_kwargs = {'output': '@BASENAME@.moc',
                          'arguments': arguments}
            moc_gen = build.Generator([self.moc], moc_kwargs)
            moc_output = moc_gen.process_files('Qt{} moc source'.format(self.qt_version), moc_sources, state)
            sources.append(moc_output)
        return ModuleReturnValue(sources, sources)

    @FeatureNew('qt.compile_translations', '0.44.0')
    @permittedKwargs({'ts_files', 'install', 'install_dir', 'build_by_default', 'method'})
    def compile_translations(self, state, args, kwargs):
        ts_files, install_dir = extract_as_list(kwargs, 'ts_files', 'install_dir', pop=True)
        self._detect_tools(state.environment, kwargs.get('method', 'auto'))
        translations = []
        for ts in ts_files:
            if not self.lrelease.found():
                raise MesonException('qt.compile_translations: ' +
                                     self.lrelease.name + ' not found')
            cmd = [self.lrelease, '@INPUT@', '-qm', '@OUTPUT@']
            lrelease_kwargs = {'output': '@BASENAME@.qm',
                               'input': ts,
                               'install': kwargs.get('install', False),
                               'build_by_default': kwargs.get('build_by_default', False),
                               'command': cmd}
            if install_dir is not None:
                lrelease_kwargs['install_dir'] = install_dir
            lrelease_target = build.CustomTarget('qt{}-compile-{}'.format(self.qt_version, ts), state.subdir, state.subproject, lrelease_kwargs)
            translations.append(lrelease_target)
        return ModuleReturnValue(translations, translations)
meson-0.53.2/mesonbuild/modules/qt4.py0000644000175000017500000000176713403223113021212 0ustar  jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .. import mlog
from .qt import QtBaseModule


class Qt4Module(QtBaseModule):

    def __init__(self, interpreter):
        QtBaseModule.__init__(self, interpreter, qt_version=4)


def initialize(*args, **kwargs):
    mlog.warning('rcc dependencies will not work properly until this upstream issue is fixed:',
                 mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460'))
    return Qt4Module(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/qt5.py0000644000175000017500000000176713403223113021213 0ustar  jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .. import mlog
from .qt import QtBaseModule


class Qt5Module(QtBaseModule):

    def __init__(self, interpreter):
        QtBaseModule.__init__(self, interpreter, qt_version=5)


def initialize(*args, **kwargs):
    mlog.warning('rcc dependencies will not work reliably until this upstream issue is fixed:',
                 mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460'))
    return Qt5Module(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/rpm.py0000644000175000017500000002016613602226377021312 0ustar  jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

'''This module provides helper functions for RPM related
functionality such as generating template RPM spec file.'''

from .. import build
from .. import compilers
import datetime
from .. import mlog
from . import GirTarget, TypelibTarget
from . import ModuleReturnValue
from . import ExtensionModule
from ..interpreterbase import noKwargs

import os

class RPMModule(ExtensionModule):

    @noKwargs
    def generate_spec_template(self, coredata, args, kwargs):
        self.coredata = coredata
        required_compilers = self.__get_required_compilers()
        proj = coredata.project_name.replace(' ', '_').replace('\t', '_')
        so_installed = False
        devel_subpkg = False
        files = set()
        files_devel = set()
        to_delete = set()
        for target in coredata.targets.values():
            if isinstance(target, build.Executable) and target.need_install:
                files.add('%%{_bindir}/%s' % target.get_filename())
            elif isinstance(target, build.SharedLibrary) and target.need_install:
                files.add('%%{_libdir}/%s' % target.get_filename())
                for alias in target.get_aliases():
                    if alias.endswith('.so'):
                        files_devel.add('%%{_libdir}/%s' % alias)
                    else:
                        files.add('%%{_libdir}/%s' % alias)
                so_installed = True
            elif isinstance(target, build.StaticLibrary) and target.need_install:
                to_delete.add('%%{buildroot}%%{_libdir}/%s' % target.get_filename())
                mlog.warning('removing', mlog.bold(target.get_filename()),
                             'from package because packaging static libs not recommended')
            elif isinstance(target, GirTarget) and target.should_install():
                files_devel.add('%%{_datadir}/gir-1.0/%s' % target.get_filename()[0])
            elif isinstance(target, TypelibTarget) and target.should_install():
                files.add('%%{_libdir}/girepository-1.0/%s' % target.get_filename()[0])
        for header in coredata.headers:
            if header.get_install_subdir():
                files_devel.add('%%{_includedir}/%s/' % header.get_install_subdir())
            else:
                for hdr_src in header.get_sources():
                    files_devel.add('%%{_includedir}/%s' % hdr_src)
        for man in coredata.man:
            for man_file in man.get_sources():
                files.add('%%{_mandir}/man%u/%s.*' % (int(man_file.split('.')[-1]), man_file))
        if files_devel:
            devel_subpkg = True

        filename = os.path.join(coredata.environment.get_build_dir(),
                                '%s.spec' % proj)
        with open(filename, 'w+') as fn:
            fn.write('Name: %s\n' % proj)
            fn.write('Version: # FIXME\n')
            fn.write('Release: 1%{?dist}\n')
            fn.write('Summary: # FIXME\n')
            fn.write('License: # FIXME\n')
            fn.write('\n')
            fn.write('Source0: %{name}-%{version}.tar.xz # FIXME\n')
            fn.write('\n')
            fn.write('BuildRequires: meson\n')
            for compiler in required_compilers:
                fn.write('BuildRequires: %s\n' % compiler)
            for dep in coredata.environment.coredata.deps.host:
                fn.write('BuildRequires: pkgconfig(%s)\n' % dep[0])
#   ext_libs and ext_progs have been removed from coredata so the following code
#   no longer works. It is kept as a reminder of the idea should anyone wish
#   to re-implement it.
#
#            for lib in state.environment.coredata.ext_libs.values():
#                name = lib.get_name()
#                fn.write('BuildRequires: {} # FIXME\n'.format(name))
#                mlog.warning('replace', mlog.bold(name), 'with the real package.',
#                             'You can use following command to find package which '
#                             'contains this lib:',
#                             mlog.bold("dnf provides '*/lib{}.so'".format(name)))
#            for prog in state.environment.coredata.ext_progs.values():
#                if not prog.found():
#                    fn.write('BuildRequires: %%{_bindir}/%s # FIXME\n' %
#                             prog.get_name())
#                else:
#                    fn.write('BuildRequires: {}\n'.format(prog.get_path()))
            fn.write('\n')
            fn.write('%description\n')
            fn.write('\n')
            if devel_subpkg:
                fn.write('%package devel\n')
                fn.write('Summary: Development files for %{name}\n')
                fn.write('Requires: %{name}%{?_isa} = %{?epoch:%{epoch}:}{version}-%{release}\n')
                fn.write('\n')
                fn.write('%description devel\n')
                fn.write('Development files for %{name}.\n')
                fn.write('\n')
            fn.write('%prep\n')
            fn.write('%autosetup\n')
            fn.write('\n')
            fn.write('%build\n')
            fn.write('%meson\n')
            fn.write('%meson_build\n')
            fn.write('\n')
            fn.write('%install\n')
            fn.write('%meson_install\n')
            if to_delete:
                fn.write('rm -vf %s\n' % ' '.join(to_delete))
            fn.write('\n')
            fn.write('%check\n')
            fn.write('%meson_test\n')
            fn.write('\n')
            fn.write('%files\n')
            for f in files:
                fn.write('%s\n' % f)
            fn.write('\n')
            if devel_subpkg:
                fn.write('%files devel\n')
                for f in files_devel:
                    fn.write('%s\n' % f)
                fn.write('\n')
            if so_installed:
                fn.write('%post -p /sbin/ldconfig\n')
                fn.write('%postun -p /sbin/ldconfig\n')
            fn.write('\n')
            fn.write('%changelog\n')
            fn.write('* %s meson  - \n' %
                     datetime.date.today().strftime('%a %b %d %Y'))
            fn.write('- \n')
            fn.write('\n')
        mlog.log('RPM spec template written to %s.spec.\n' % proj)
        return ModuleReturnValue(None, [])

    def __get_required_compilers(self):
        required_compilers = set()
        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')
            elif isinstance(compiler, compilers.GnuCPPCompiler):
                required_compilers.add('gcc-c++')
            elif isinstance(compiler, compilers.ElbrusCCompiler):
                required_compilers.add('lcc')
            elif isinstance(compiler, compilers.ElbrusCPPCompiler):
                required_compilers.add('lcc')
            elif isinstance(compiler, compilers.ElbrusFortranCompiler):
                required_compilers.add('lcc')
            elif isinstance(compiler, compilers.ValaCompiler):
                required_compilers.add('vala')
            elif isinstance(compiler, compilers.GnuFortranCompiler):
                required_compilers.add('gcc-gfortran')
            elif isinstance(compiler, compilers.GnuObjCCompiler):
                required_compilers.add('gcc-objc')
            elif compiler == compilers.GnuObjCPPCompiler:
                required_compilers.add('gcc-objc++')
            else:
                mlog.log('RPM spec file not created, generation not allowed for:',
                         mlog.bold(compiler.get_id()))
        return required_compilers


def initialize(*args, **kwargs):
    return RPMModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/sourceset.py0000644000175000017500000001721413531533273022525 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from collections import namedtuple
from .. import mesonlib
from ..mesonlib import listify
from . import ExtensionModule
from ..interpreterbase import (
    noPosargs, noKwargs, permittedKwargs,
    InterpreterObject, MutableInterpreterObject, ObjectHolder,
    InterpreterException, InvalidArguments, InvalidCode, FeatureNew,
)
from ..interpreter import (
    GeneratedListHolder, CustomTargetHolder,
    CustomTargetIndexHolder
)

SourceSetRule = namedtuple('SourceSetRule', 'keys sources if_false sourcesets dependencies extra_deps')
SourceFiles = namedtuple('SourceFiles', 'sources dependencies')

class SourceSetHolder(MutableInterpreterObject, ObjectHolder):
    def __init__(self, interpreter):
        MutableInterpreterObject.__init__(self)
        ObjectHolder.__init__(self, list())
        self.subproject = interpreter.subproject
        self.environment = interpreter.environment
        self.subdir = interpreter.subdir
        self.frozen = False
        self.methods.update({
            'add': self.add_method,
            'add_all': self.add_all_method,
            'all_sources': self.all_sources_method,
            'all_dependencies': self.all_dependencies_method,
            'apply': self.apply_method,
        })

    def check_source_files(self, arg, allow_deps):
        sources = []
        deps = []
        for x in arg:
            if isinstance(x, (str, mesonlib.File,
                              GeneratedListHolder, CustomTargetHolder,
                              CustomTargetIndexHolder)):
                sources.append(x)
            elif hasattr(x, 'found'):
                if not allow_deps:
                    msg = 'Dependencies are not allowed in the if_false argument.'
                    raise InvalidArguments(msg)
                deps.append(x)
            else:
                msg = 'Sources must be strings or file-like objects.'
                raise InvalidArguments(msg)
        mesonlib.check_direntry_issues(sources)
        return sources, deps

    def check_conditions(self, arg):
        keys = []
        deps = []
        for x in listify(arg):
            if isinstance(x, str):
                keys.append(x)
            elif hasattr(x, 'found'):
                deps.append(x)
            else:
                raise InvalidArguments('Conditions must be strings or dependency object')
        return keys, deps

    @permittedKwargs(['when', 'if_false', 'if_true'])
    def add_method(self, args, kwargs):
        if self.frozen:
            raise InvalidCode('Tried to use \'add\' after querying the source set')
        when = listify(kwargs.get('when', []))
        if_true = listify(kwargs.get('if_true', []))
        if_false = listify(kwargs.get('if_false', []))
        if not when and not if_true and not if_false:
            if_true = args
        elif args:
            raise InterpreterException('add called with both positional and keyword arguments')
        keys, dependencies = self.check_conditions(when)
        sources, extra_deps = self.check_source_files(if_true, True)
        if_false, _ = self.check_source_files(if_false, False)
        self.held_object.append(SourceSetRule(keys, sources, if_false, [], dependencies, extra_deps))

    @permittedKwargs(['when', 'if_true'])
    def add_all_method(self, args, kwargs):
        if self.frozen:
            raise InvalidCode('Tried to use \'add_all\' after querying the source set')
        when = listify(kwargs.get('when', []))
        if_true = listify(kwargs.get('if_true', []))
        if not when and not if_true:
            if_true = args
        elif args:
            raise InterpreterException('add_all called with both positional and keyword arguments')
        keys, dependencies = self.check_conditions(when)
        for s in if_true:
            if not isinstance(s, SourceSetHolder):
                raise InvalidCode('Arguments to \'add_all\' after the first must be source sets')
            s.frozen = True
        self.held_object.append(SourceSetRule(keys, [], [], if_true, dependencies, []))

    def collect(self, enabled_fn, all_sources, into=None):
        if not into:
            into = SourceFiles(set(), set())
        for entry in self.held_object:
            if all(x.found() for x in entry.dependencies) and \
               all(enabled_fn(key) for key in entry.keys):
                into.sources.update(entry.sources)
                into.dependencies.update(entry.dependencies)
                into.dependencies.update(entry.extra_deps)
                for ss in entry.sourcesets:
                    ss.collect(enabled_fn, all_sources, into)
                if not all_sources:
                    continue
            into.sources.update(entry.if_false)
        return into

    @noKwargs
    @noPosargs
    def all_sources_method(self, args, kwargs):
        self.frozen = True
        files = self.collect(lambda x: True, True)
        return list(files.sources)

    @noKwargs
    @noPosargs
    @FeatureNew('source_set.all_dependencies() method', '0.52.0')
    def all_dependencies_method(self, args, kwargs):
        self.frozen = True
        files = self.collect(lambda x: True, True)
        return list(files.dependencies)

    @permittedKwargs(['strict'])
    def apply_method(self, args, kwargs):
        if len(args) != 1:
            raise InterpreterException('Apply takes exactly one argument')
        config_data = args[0]
        self.frozen = True
        strict = kwargs.get('strict', True)
        if isinstance(config_data, dict):
            def _get_from_config_data(key):
                if strict and key not in config_data:
                    raise InterpreterException('Entry %s not in configuration dictionary.' % key)
                return config_data.get(key, False)
        else:
            config_cache = dict()

            def _get_from_config_data(key):
                nonlocal config_cache
                if key not in config_cache:
                    args = [key] if strict else [key, False]
                    config_cache[key] = config_data.get_method(args, {})
                return config_cache[key]

        files = self.collect(_get_from_config_data, False)
        res = SourceFilesHolder(files)
        return res

class SourceFilesHolder(InterpreterObject, ObjectHolder):
    def __init__(self, files):
        InterpreterObject.__init__(self)
        ObjectHolder.__init__(self, files)
        self.methods.update({
            'sources': self.sources_method,
            'dependencies': self.dependencies_method,
        })

    @noPosargs
    @noKwargs
    def sources_method(self, args, kwargs):
        return list(self.held_object.sources)

    @noPosargs
    @noKwargs
    def dependencies_method(self, args, kwargs):
        return list(self.held_object.dependencies)

class SourceSetModule(ExtensionModule):
    @FeatureNew('SourceSet module', '0.51.0')
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.snippets.add('source_set')

    @noKwargs
    @noPosargs
    def source_set(self, interpreter, state, args, kwargs):
        return SourceSetHolder(interpreter)

def initialize(*args, **kwargs):
    return SourceSetModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/unstable_cuda.py0000644000175000017500000002725013571777336023341 0ustar  jpakkanejpakkane00000000000000# Copyright 2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import re

from ..mesonlib import version_compare
from ..interpreter import CompilerHolder
from ..compilers import CudaCompiler

from . import ExtensionModule, ModuleReturnValue

from ..interpreterbase import (
    flatten, permittedKwargs, noKwargs,
    InvalidArguments, FeatureNew
)

class CudaModule(ExtensionModule):

    @FeatureNew('CUDA module', '0.50.0')
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    @noKwargs
    def min_driver_version(self, state, args, kwargs):
        argerror = InvalidArguments('min_driver_version must have exactly one positional argument: ' +
                                    'an NVCC compiler object, or its version string.')

        if len(args) != 1:
            raise argerror
        else:
            cuda_version = self._version_from_compiler(args[0])
            if cuda_version == 'unknown':
                raise argerror

        driver_version_table = [
            {'cuda_version': '>=10.2.89',  'windows': '441.22', 'linux': '440.33'},
            {'cuda_version': '>=10.1.105', 'windows': '418.96', 'linux': '418.39'},
            {'cuda_version': '>=10.0.130', 'windows': '411.31', 'linux': '410.48'},
            {'cuda_version': '>=9.2.148',  'windows': '398.26', 'linux': '396.37'},
            {'cuda_version': '>=9.2.88',   'windows': '397.44', 'linux': '396.26'},
            {'cuda_version': '>=9.1.85',   'windows': '391.29', 'linux': '390.46'},
            {'cuda_version': '>=9.0.76',   'windows': '385.54', 'linux': '384.81'},
            {'cuda_version': '>=8.0.61',   'windows': '376.51', 'linux': '375.26'},
            {'cuda_version': '>=8.0.44',   'windows': '369.30', 'linux': '367.48'},
            {'cuda_version': '>=7.5.16',   'windows': '353.66', 'linux': '352.31'},
            {'cuda_version': '>=7.0.28',   'windows': '347.62', 'linux': '346.46'},
        ]

        driver_version = 'unknown'
        for d in driver_version_table:
            if version_compare(cuda_version, d['cuda_version']):
                driver_version = d.get(state.host_machine.system, d['linux'])
                break

        return ModuleReturnValue(driver_version, [driver_version])

    @permittedKwargs(['detected'])
    def nvcc_arch_flags(self, state, args, kwargs):
        nvcc_arch_args = self._validate_nvcc_arch_args(state, args, kwargs)
        ret = self._nvcc_arch_flags(*nvcc_arch_args)[0]
        return ModuleReturnValue(ret, [ret])

    @permittedKwargs(['detected'])
    def nvcc_arch_readable(self, state, args, kwargs):
        nvcc_arch_args = self._validate_nvcc_arch_args(state, args, kwargs)
        ret = self._nvcc_arch_flags(*nvcc_arch_args)[1]
        return ModuleReturnValue(ret, [ret])

    @staticmethod
    def _break_arch_string(s):
        s = re.sub('[ \t\r\n,;]+', ';', s)
        s = s.strip(';').split(';')
        return s

    @staticmethod
    def _detected_cc_from_compiler(c):
        if isinstance(c, CompilerHolder):
            c = c.compiler
        if isinstance(c, CudaCompiler):
            return c.detected_cc
        return ''

    @staticmethod
    def _version_from_compiler(c):
        if isinstance(c, CompilerHolder):
            c = c.compiler
        if isinstance(c, CudaCompiler):
            return c.version
        if isinstance(c, str):
            return c
        return 'unknown'

    def _validate_nvcc_arch_args(self, state, args, kwargs):
        argerror = InvalidArguments('The first argument must be an NVCC compiler object, or its version string!')

        if len(args) < 1:
            raise argerror
        else:
            compiler = args[0]
            cuda_version = self._version_from_compiler(compiler)
            if cuda_version == 'unknown':
                raise argerror

        arch_list = [] if len(args) <= 1 else flatten(args[1:])
        arch_list = [self._break_arch_string(a) for a in arch_list]
        arch_list = flatten(arch_list)
        if len(arch_list) > 1 and not set(arch_list).isdisjoint({'All', 'Common', 'Auto'}):
            raise InvalidArguments('''The special architectures 'All', 'Common' and 'Auto' must appear alone, as a positional argument!''')
        arch_list = arch_list[0] if len(arch_list) == 1 else arch_list

        detected = kwargs.get('detected', self._detected_cc_from_compiler(compiler))
        detected = flatten([detected])
        detected = [self._break_arch_string(a) for a in detected]
        detected = flatten(detected)
        if not set(detected).isdisjoint({'All', 'Common', 'Auto'}):
            raise InvalidArguments('''The special architectures 'All', 'Common' and 'Auto' must appear alone, as a positional argument!''')

        return cuda_version, arch_list, detected

    def _nvcc_arch_flags(self, cuda_version, cuda_arch_list='Auto', detected=''):
        """
        Using the CUDA Toolkit version (the NVCC version) and the target
        architectures, compute the NVCC architecture flags.
        """

        cuda_known_gpu_architectures  = ['Fermi', 'Kepler', 'Maxwell']  # noqa: E221
        cuda_common_gpu_architectures = ['3.0', '3.5', '5.0']           # noqa: E221
        cuda_limit_gpu_architecture   = None                            # noqa: E221
        cuda_all_gpu_architectures    = ['3.0', '3.2', '3.5', '5.0']    # noqa: E221

        if version_compare(cuda_version, '<7.0'):
            cuda_limit_gpu_architecture = '5.2'

        if version_compare(cuda_version, '>=7.0'):
            cuda_known_gpu_architectures  += ['Kepler+Tegra', 'Kepler+Tesla', 'Maxwell+Tegra']  # noqa: E221
            cuda_common_gpu_architectures += ['5.2']                                            # noqa: E221

            if version_compare(cuda_version, '<8.0'):
                cuda_common_gpu_architectures += ['5.2+PTX']  # noqa: E221
                cuda_limit_gpu_architecture    = '6.0'        # noqa: E221

        if version_compare(cuda_version, '>=8.0'):
            cuda_known_gpu_architectures  += ['Pascal', 'Pascal+Tegra']  # noqa: E221
            cuda_common_gpu_architectures += ['6.0', '6.1']              # noqa: E221
            cuda_all_gpu_architectures    += ['6.0', '6.1', '6.2']       # noqa: E221

            if version_compare(cuda_version, '<9.0'):
                cuda_common_gpu_architectures += ['6.1+PTX']  # noqa: E221
                cuda_limit_gpu_architecture    = '7.0'        # noqa: E221

        if version_compare(cuda_version, '>=9.0'):
            cuda_known_gpu_architectures  += ['Volta', 'Xavier']                   # noqa: E221
            cuda_common_gpu_architectures += ['7.0', '7.0+PTX']                    # noqa: E221
            cuda_all_gpu_architectures    += ['7.0', '7.0+PTX', '7.2', '7.2+PTX']  # noqa: E221

            if version_compare(cuda_version, '<10.0'):
                cuda_limit_gpu_architecture = '7.5'

        if version_compare(cuda_version, '>=10.0'):
            cuda_known_gpu_architectures  += ['Turing']          # noqa: E221
            cuda_common_gpu_architectures += ['7.5', '7.5+PTX']  # noqa: E221
            cuda_all_gpu_architectures    += ['7.5', '7.5+PTX']  # noqa: E221

            if version_compare(cuda_version, '<11.0'):
                cuda_limit_gpu_architecture = '8.0'

        if not cuda_arch_list:
            cuda_arch_list = 'Auto'

        if   cuda_arch_list == 'All':     # noqa: E271
            cuda_arch_list = cuda_known_gpu_architectures
        elif cuda_arch_list == 'Common':  # noqa: E271
            cuda_arch_list = cuda_common_gpu_architectures
        elif cuda_arch_list == 'Auto':    # noqa: E271
            if detected:
                if isinstance(detected, list):
                    cuda_arch_list = detected
                else:
                    cuda_arch_list = self._break_arch_string(detected)

                if cuda_limit_gpu_architecture:
                    filtered_cuda_arch_list = []
                    for arch in cuda_arch_list:
                        if arch:
                            if version_compare(arch, '>=' + cuda_limit_gpu_architecture):
                                arch = cuda_common_gpu_architectures[-1]
                            if arch not in filtered_cuda_arch_list:
                                filtered_cuda_arch_list.append(arch)
                    cuda_arch_list = filtered_cuda_arch_list
            else:
                cuda_arch_list = cuda_common_gpu_architectures
        elif isinstance(cuda_arch_list, str):
            cuda_arch_list = self._break_arch_string(cuda_arch_list)

        cuda_arch_list = sorted([x for x in set(cuda_arch_list) if x])

        cuda_arch_bin = []
        cuda_arch_ptx = []
        for arch_name in cuda_arch_list:
            arch_bin = []
            arch_ptx = []
            add_ptx = arch_name.endswith('+PTX')
            if add_ptx:
                arch_name = arch_name[:-len('+PTX')]

            if re.fullmatch('[0-9]+\\.[0-9](\\([0-9]+\\.[0-9]\\))?', arch_name):
                arch_bin, arch_ptx = [arch_name], [arch_name]
            else:
                arch_bin, arch_ptx = {
                    'Fermi':         (['2.0', '2.1(2.0)'], []),
                    'Kepler+Tegra':  (['3.2'],             []),
                    'Kepler+Tesla':  (['3.7'],             []),
                    'Kepler':        (['3.0', '3.5'],      ['3.5']),
                    'Maxwell+Tegra': (['5.3'],             []),
                    'Maxwell':       (['5.0', '5.2'],      ['5.2']),
                    'Pascal':        (['6.0', '6.1'],      ['6.1']),
                    'Pascal+Tegra':  (['6.2'],             []),
                    'Volta':         (['7.0'],             ['7.0']),
                    'Xavier':        (['7.2'],             []),
                    'Turing':        (['7.5'],             ['7.5']),
                }.get(arch_name, (None, None))

            if arch_bin is None:
                raise InvalidArguments('Unknown CUDA Architecture Name {}!'
                                       .format(arch_name))

            cuda_arch_bin += arch_bin

            if add_ptx:
                if not arch_ptx:
                    arch_ptx = arch_bin
                cuda_arch_ptx += arch_ptx

        cuda_arch_bin = re.sub('\\.', '', ' '.join(cuda_arch_bin))
        cuda_arch_ptx = re.sub('\\.', '', ' '.join(cuda_arch_ptx))
        cuda_arch_bin = re.findall('[0-9()]+', cuda_arch_bin)
        cuda_arch_ptx = re.findall('[0-9]+',   cuda_arch_ptx)
        cuda_arch_bin = sorted(list(set(cuda_arch_bin)))
        cuda_arch_ptx = sorted(list(set(cuda_arch_ptx)))

        nvcc_flags = []
        nvcc_archs_readable = []

        for arch in cuda_arch_bin:
            m = re.match('([0-9]+)\\(([0-9]+)\\)', arch)
            if m:
                nvcc_flags += ['-gencode', 'arch=compute_' + m[2] + ',code=sm_' + m[1]]
                nvcc_archs_readable += ['sm_' + m[1]]
            else:
                nvcc_flags += ['-gencode', 'arch=compute_' + arch + ',code=sm_' + arch]
                nvcc_archs_readable += ['sm_' + arch]

        for arch in cuda_arch_ptx:
            nvcc_flags += ['-gencode', 'arch=compute_' + arch + ',code=compute_' + arch]
            nvcc_archs_readable += ['compute_' + arch]

        return nvcc_flags, nvcc_archs_readable

def initialize(*args, **kwargs):
    return CudaModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/unstable_icestorm.py0000644000175000017500000000723213462637046024240 0ustar  jpakkanejpakkane00000000000000# Copyright 2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .. import mesonlib
from ..interpreterbase import flatten
from ..interpreterbase import FeatureNew

from . import ExtensionModule

class IceStormModule(ExtensionModule):

    @FeatureNew('FPGA/Icestorm Module', '0.45.0')
    def __init__(self, interpreter):
        super().__init__(interpreter)
        self.snippets.add('project')
        self.yosys_bin = None

    def detect_binaries(self, interpreter):
        self.yosys_bin = interpreter.find_program_impl(['yosys'])
        self.arachne_bin = interpreter.find_program_impl(['arachne-pnr'])
        self.icepack_bin = interpreter.find_program_impl(['icepack'])
        self.iceprog_bin = interpreter.find_program_impl(['iceprog'])
        self.icetime_bin = interpreter.find_program_impl(['icetime'])

    def project(self, interpreter, state, args, kwargs):
        if not self.yosys_bin:
            self.detect_binaries(interpreter)
        if not args:
            raise mesonlib.MesonException('Project requires at least one argument, which is the project name.')
        proj_name = args[0]
        arg_sources = args[1:]
        if not isinstance(proj_name, str):
            raise mesonlib.MesonException('Argument must be a string.')
        kwarg_sources = kwargs.get('sources', [])
        if not isinstance(kwarg_sources, list):
            kwarg_sources = [kwarg_sources]
        all_sources = interpreter.source_strings_to_files(flatten(arg_sources + kwarg_sources))
        if 'constraint_file' not in kwargs:
            raise mesonlib.MesonException('Constraint file not specified.')

        constraint_file = interpreter.source_strings_to_files(kwargs['constraint_file'])
        if len(constraint_file) != 1:
            raise mesonlib.MesonException('Constraint file must contain one and only one entry.')
        blif_name = proj_name + '_blif'
        blif_fname = proj_name + '.blif'
        asc_name = proj_name + '_asc'
        asc_fname = proj_name + '.asc'
        bin_name = proj_name + '_bin'
        bin_fname = proj_name + '.bin'
        time_name = proj_name + '-time'
        upload_name = proj_name + '-upload'

        blif_target = interpreter.func_custom_target(None, [blif_name], {
            'input': all_sources,
            'output': blif_fname,
            'command': [self.yosys_bin, '-q', '-p', 'synth_ice40 -blif @OUTPUT@', '@INPUT@']})

        asc_target = interpreter.func_custom_target(None, [asc_name], {
            'input': blif_target,
            'output': asc_fname,
            'command': [self.arachne_bin, '-q', '-d', '1k', '-p', constraint_file, '@INPUT@', '-o', '@OUTPUT@']})

        bin_target = interpreter.func_custom_target(None, [bin_name], {
            'input': asc_target,
            'output': bin_fname,
            'command': [self.icepack_bin, '@INPUT@', '@OUTPUT@'],
            'build_by_default': True})

        interpreter.func_run_target(None, [upload_name], {
            'command': [self.iceprog_bin, bin_target]})

        interpreter.func_run_target(None, [time_name], {
            'command': [self.icetime_bin, bin_target]})

def initialize(*args, **kwargs):
    return IceStormModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/unstable_kconfig.py0000644000175000017500000000476713531533273024037 0ustar  jpakkanejpakkane00000000000000# Copyright 2017, 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import ExtensionModule

from .. import mesonlib
from ..mesonlib import typeslistify
from ..interpreterbase import FeatureNew, noKwargs
from ..interpreter import InvalidCode

import os

class KconfigModule(ExtensionModule):

    @FeatureNew('Kconfig Module', '0.51.0')
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.snippets.add('load')

    def _load_file(self, path_to_config):
        result = dict()
        try:
            with open(path_to_config) as f:
                for line in f:
                    if '#' in line:
                        comment_idx = line.index('#')
                        line = line[:comment_idx]
                    line = line.strip()
                    try:
                        name, val = line.split('=', 1)
                    except ValueError:
                        continue
                    result[name.strip()] = val.strip()
        except IOError as e:
            raise mesonlib.MesonException('Failed to load {}: {}'.format(path_to_config, e))

        return result

    @noKwargs
    def load(self, interpreter, state, args, kwargs):
        sources = typeslistify(args, (str, mesonlib.File))
        if len(sources) != 1:
            raise InvalidCode('load takes only one file input.')

        s = sources[0]
        is_built = False
        if isinstance(s, mesonlib.File):
            if s.is_built:
                FeatureNew('kconfig.load() of built files', '0.52.0').use(state.subproject)
                is_built = True
            s = s.absolute_path(interpreter.environment.source_dir, interpreter.environment.build_dir)
        else:
            s = os.path.join(interpreter.environment.source_dir, s)

        if s not in interpreter.build_def_files and not is_built:
            interpreter.build_def_files.append(s)

        return self._load_file(s)


def initialize(*args, **kwargs):
    return KconfigModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/unstable_simd.py0000644000175000017500000000707613571777336023365 0ustar  jpakkanejpakkane00000000000000# Copyright 2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .. import mesonlib, compilers, mlog

from . import ExtensionModule

from ..interpreterbase import FeatureNew

class SimdModule(ExtensionModule):

    @FeatureNew('SIMD module', '0.42.0')
    def __init__(self, interpreter):
        super().__init__(interpreter)
        self.snippets.add('check')
        # FIXME add Altivec and AVX512.
        self.isets = ('mmx',
                      'sse',
                      'sse2',
                      'sse3',
                      'ssse3',
                      'sse41',
                      'sse42',
                      'avx',
                      'avx2',
                      'neon',
                      )

    def check(self, interpreter, state, args, kwargs):
        result = []
        if len(args) != 1:
            raise mesonlib.MesonException('Check requires one argument, a name prefix for checks.')
        prefix = args[0]
        if not isinstance(prefix, str):
            raise mesonlib.MesonException('Argument must be a string.')
        if 'compiler' not in kwargs:
            raise mesonlib.MesonException('Must specify compiler keyword')
        if 'sources' in kwargs:
            raise mesonlib.MesonException('SIMD module does not support the "sources" keyword')
        basic_kwargs = {}
        for key, value in kwargs.items():
            if key not in self.isets and key != 'compiler':
                basic_kwargs[key] = value
        compiler = kwargs['compiler'].compiler
        if not isinstance(compiler, compilers.compilers.Compiler):
            raise mesonlib.MesonException('Compiler argument must be a compiler object.')
        cdata = interpreter.func_configuration_data(None, [], {})
        conf = cdata.held_object
        for iset in self.isets:
            if iset not in kwargs:
                continue
            iset_fname = kwargs[iset] # Might also be an array or Files. static_library will validate.
            args = compiler.get_instruction_set_args(iset)
            if args is None:
                mlog.log('Compiler supports %s:' % iset, mlog.red('NO'))
                continue
            if args:
                if not compiler.has_multi_arguments(args, state.environment)[0]:
                    mlog.log('Compiler supports %s:' % iset, mlog.red('NO'))
                    continue
            mlog.log('Compiler supports %s:' % iset, mlog.green('YES'))
            conf.values['HAVE_' + iset.upper()] = ('1', 'Compiler supports %s.' % iset)
            libname = prefix + '_' + iset
            lib_kwargs = {'sources': iset_fname,
                          }
            lib_kwargs.update(basic_kwargs)
            langarg_key = compiler.get_language() + '_args'
            old_lang_args = mesonlib.extract_as_list(lib_kwargs, langarg_key)
            all_lang_args = old_lang_args + args
            lib_kwargs[langarg_key] = all_lang_args
            result.append(interpreter.func_static_lib(None, [libname], lib_kwargs))
        return [result, cdata]

def initialize(*args, **kwargs):
    return SimdModule(*args, **kwargs)
meson-0.53.2/mesonbuild/modules/windows.py0000644000175000017500000001533713531533273022207 0ustar  jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import enum
import os
import re

from .. import mlog
from .. import mesonlib, build
from ..mesonlib import MachineChoice, MesonException, extract_as_list
from . import get_include_args
from . import ModuleReturnValue
from . import ExtensionModule
from ..interpreter import CustomTargetHolder
from ..interpreterbase import permittedKwargs, FeatureNewKwargs, flatten
from ..dependencies import ExternalProgram

class ResourceCompilerType(enum.Enum):
    windres = 1
    rc = 2

class WindowsModule(ExtensionModule):

    def detect_compiler(self, compilers):
        for l in ('c', 'cpp'):
            if l in compilers:
                return compilers[l]
        raise MesonException('Resource compilation requires a C or C++ compiler.')

    def _find_resource_compiler(self, state):
        # FIXME: Does not handle `native: true` executables, see
        # See https://github.com/mesonbuild/meson/issues/1531
        # Take a parameter instead of the hardcoded definition below
        for_machine = MachineChoice.HOST

        if hasattr(self, '_rescomp'):
            return self._rescomp

        # Will try cross / native file and then env var
        rescomp = ExternalProgram.from_bin_list(state.environment.binaries[for_machine], 'windres')

        if not rescomp or not rescomp.found():
            comp = self.detect_compiler(state.environment.coredata.compilers[for_machine])
            if comp.id in {'msvc', 'clang-cl', 'intel-cl'}:
                rescomp = ExternalProgram('rc', silent=True)
            else:
                rescomp = ExternalProgram('windres', silent=True)

        if not rescomp.found():
            raise MesonException('Could not find Windows resource compiler')

        for (arg, match, rc_type) in [
                ('/?', '^.*Microsoft.*Resource Compiler.*$', ResourceCompilerType.rc),
                ('--version', '^.*GNU windres.*$', ResourceCompilerType.windres),
        ]:
            p, o, e = mesonlib.Popen_safe(rescomp.get_command() + [arg])
            m = re.search(match, o, re.MULTILINE)
            if m:
                mlog.log('Windows resource compiler: %s' % m.group())
                self._rescomp = (rescomp, rc_type)
                break
        else:
            raise MesonException('Could not determine type of Windows resource compiler')

        return self._rescomp

    @FeatureNewKwargs('windows.compile_resources', '0.47.0', ['depend_files', 'depends'])
    @permittedKwargs({'args', 'include_directories', 'depend_files', 'depends'})
    def compile_resources(self, state, args, kwargs):
        extra_args = mesonlib.stringlistify(flatten(kwargs.get('args', [])))
        wrc_depend_files = extract_as_list(kwargs, 'depend_files', pop = True)
        wrc_depends = extract_as_list(kwargs, 'depends', pop = True)
        for d in wrc_depends:
            if isinstance(d, CustomTargetHolder):
                extra_args += get_include_args([d.outdir_include()])
        inc_dirs = extract_as_list(kwargs, 'include_directories', pop = True)
        for incd in inc_dirs:
            if not isinstance(incd.held_object, (str, build.IncludeDirs)):
                raise MesonException('Resource include dirs should be include_directories().')
        extra_args += get_include_args(inc_dirs)

        rescomp, rescomp_type = self._find_resource_compiler(state)
        if rescomp_type == ResourceCompilerType.rc:
            # RC is used to generate .res files, a special binary resource
            # format, which can be passed directly to LINK (apparently LINK uses
            # CVTRES internally to convert this to a COFF object)
            suffix = 'res'
            res_args = extra_args + ['/nologo', '/fo@OUTPUT@', '@INPUT@']
        else:
            # ld only supports object files, so windres is used to generate a
            # COFF object
            suffix = 'o'
            res_args = extra_args + ['@INPUT@', '@OUTPUT@']

            m = 'Argument {!r} has a space which may not work with windres due to ' \
                'a MinGW bug: https://sourceware.org/bugzilla/show_bug.cgi?id=4933'
            for arg in extra_args:
                if ' ' in arg:
                    mlog.warning(m.format(arg))

        res_targets = []

        def add_target(src):
            if isinstance(src, list):
                for subsrc in src:
                    add_target(subsrc)
                return

            if hasattr(src, 'held_object'):
                src = src.held_object

            if isinstance(src, str):
                name_format = 'file {!r}'
                name = os.path.join(state.subdir, src)
            elif isinstance(src, mesonlib.File):
                name_format = 'file {!r}'
                name = src.relative_name()
            elif isinstance(src, build.CustomTarget):
                if len(src.get_outputs()) > 1:
                    raise MesonException('windows.compile_resources does not accept custom targets with more than 1 output.')

                name_format = 'target {!r}'
                name = src.get_id()
            else:
                raise MesonException('Unexpected source type {!r}. windows.compile_resources accepts only strings, files, custom targets, and lists thereof.'.format(src))

            # Path separators are not allowed in target names
            name = name.replace('/', '_').replace('\\', '_')

            res_kwargs = {
                'output': name + '_@BASENAME@.' + suffix,
                'input': [src],
                'command': [rescomp] + res_args,
                'depend_files': wrc_depend_files,
                'depends': wrc_depends,
            }

            # instruct binutils windres to generate a preprocessor depfile
            if rescomp_type == ResourceCompilerType.windres:
                res_kwargs['depfile'] = res_kwargs['output'] + '.d'
                res_kwargs['command'] += ['--preprocessor-arg=-MD', '--preprocessor-arg=-MQ@OUTPUT@', '--preprocessor-arg=-MF@DEPFILE@']

            res_targets.append(build.CustomTarget('Windows resource for ' + name_format.format(name), state.subdir, state.subproject, res_kwargs))

        add_target(args)

        return ModuleReturnValue(res_targets, [res_targets])

def initialize(*args, **kwargs):
    return WindowsModule(*args, **kwargs)
meson-0.53.2/mesonbuild/mparser.py0000644000175000017500000007010613602226377020514 0ustar  jpakkanejpakkane00000000000000# Copyright 2014-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import re
import codecs
import types
from .mesonlib import MesonException
from . import mlog

# This is the regex for the supported escape sequences of a regular string
# literal, like 'abc\x00'
ESCAPE_SEQUENCE_SINGLE_RE = re.compile(r'''
    ( \\U[A-Fa-f0-9]{8}   # 8-digit hex escapes
    | \\u[A-Fa-f0-9]{4}   # 4-digit hex escapes
    | \\x[A-Fa-f0-9]{2}   # 2-digit hex escapes
    | \\[0-7]{1,3}        # Octal escapes
    | \\N\{[^}]+\}        # Unicode characters by name
    | \\[\\'abfnrtv]      # Single-character escapes
    )''', re.UNICODE | re.VERBOSE)

class MesonUnicodeDecodeError(MesonException):
    def __init__(self, match):
        super().__init__("%s" % match)
        self.match = match

def decode_match(match):
    try:
        return codecs.decode(match.group(0), 'unicode_escape')
    except UnicodeDecodeError:
        raise MesonUnicodeDecodeError(match.group(0))

class ParseException(MesonException):
    def __init__(self, text, line, lineno, colno):
        # Format as error message, followed by the line with the error, followed by a caret to show the error column.
        super().__init__("%s\n%s\n%s" % (text, line, '%s^' % (' ' * colno)))
        self.lineno = lineno
        self.colno = colno

class BlockParseException(MesonException):
    def __init__(self, text, line, lineno, colno, start_line, start_lineno, start_colno):
        # This can be formatted in two ways - one if the block start and end are on the same line, and a different way if they are on different lines.

        if lineno == start_lineno:
            # If block start and end are on the same line, it is formatted as:
            # Error message
            # Followed by the line with the error
            # Followed by a caret to show the block start
            # Followed by underscores
            # Followed by a caret to show the block end.
            super().__init__("%s\n%s\n%s" % (text, line, '%s^%s^' % (' ' * start_colno, '_' * (colno - start_colno - 1))))
        else:
            # If block start and end are on different lines, it is formatted as:
            # Error message
            # Followed by the line with the error
            # Followed by a caret to show the error column.
            # Followed by a message saying where the block started.
            # Followed by the line of the block start.
            # Followed by a caret for the block start.
            super().__init__("%s\n%s\n%s\nFor a block that started at %d,%d\n%s\n%s" % (text, line, '%s^' % (' ' * colno), start_lineno, start_colno, start_line, "%s^" % (' ' * start_colno)))
        self.lineno = lineno
        self.colno = colno

class Token:
    def __init__(self, tid, subdir, line_start, lineno, colno, bytespan, value):
        self.tid = tid
        self.subdir = subdir
        self.line_start = line_start
        self.lineno = lineno
        self.colno = colno
        self.bytespan = bytespan
        self.value = value

    def __eq__(self, other):
        if isinstance(other, str):
            return self.tid == other
        return self.tid == other.tid

class Lexer:
    def __init__(self, code):
        self.code = code
        self.keywords = {'true', 'false', 'if', 'else', 'elif',
                         'endif', 'and', 'or', 'not', 'foreach', 'endforeach',
                         'in', 'continue', 'break'}
        self.future_keywords = {'return'}
        self.token_specification = [
            # Need to be sorted longest to shortest.
            ('ignore', re.compile(r'[ \t]')),
            ('id', re.compile('[_a-zA-Z][_0-9a-zA-Z]*')),
            ('number', re.compile(r'0[bB][01]+|0[oO][0-7]+|0[xX][0-9a-fA-F]+|0|[1-9]\d*')),
            ('eol_cont', re.compile(r'\\\n')),
            ('eol', re.compile(r'\n')),
            ('multiline_string', re.compile(r"'''(.|\n)*?'''", re.M)),
            ('comment', re.compile(r'#.*')),
            ('lparen', re.compile(r'\(')),
            ('rparen', re.compile(r'\)')),
            ('lbracket', re.compile(r'\[')),
            ('rbracket', re.compile(r'\]')),
            ('lcurl', re.compile(r'\{')),
            ('rcurl', re.compile(r'\}')),
            ('dblquote', re.compile(r'"')),
            ('string', re.compile(r"'([^'\\]|(\\.))*'")),
            ('comma', re.compile(r',')),
            ('plusassign', re.compile(r'\+=')),
            ('dot', re.compile(r'\.')),
            ('plus', re.compile(r'\+')),
            ('dash', re.compile(r'-')),
            ('star', re.compile(r'\*')),
            ('percent', re.compile(r'%')),
            ('fslash', re.compile(r'/')),
            ('colon', re.compile(r':')),
            ('equal', re.compile(r'==')),
            ('nequal', re.compile(r'!=')),
            ('assign', re.compile(r'=')),
            ('le', re.compile(r'<=')),
            ('lt', re.compile(r'<')),
            ('ge', re.compile(r'>=')),
            ('gt', re.compile(r'>')),
            ('questionmark', re.compile(r'\?')),
        ]

    def getline(self, line_start):
        return self.code[line_start:self.code.find('\n', line_start)]

    def lex(self, subdir):
        line_start = 0
        lineno = 1
        loc = 0
        par_count = 0
        bracket_count = 0
        curl_count = 0
        col = 0
        while loc < len(self.code):
            matched = False
            value = None
            for (tid, reg) in self.token_specification:
                mo = reg.match(self.code, loc)
                if mo:
                    curline = lineno
                    curline_start = line_start
                    col = mo.start() - line_start
                    matched = True
                    span_start = loc
                    loc = mo.end()
                    span_end = loc
                    bytespan = (span_start, span_end)
                    match_text = mo.group()
                    if tid == 'ignore' or tid == 'comment':
                        break
                    elif tid == 'lparen':
                        par_count += 1
                    elif tid == 'rparen':
                        par_count -= 1
                    elif tid == 'lbracket':
                        bracket_count += 1
                    elif tid == 'rbracket':
                        bracket_count -= 1
                    elif tid == 'lcurl':
                        curl_count += 1
                    elif tid == 'rcurl':
                        curl_count -= 1
                    elif tid == 'dblquote':
                        raise ParseException('Double quotes are not supported. Use single quotes.', self.getline(line_start), lineno, col)
                    elif tid == 'string':
                        # Handle here and not on the regexp to give a better error message.
                        if match_text.find("\n") != -1:
                            mlog.warning("""Newline character in a string detected, use ''' (three single quotes) for multiline strings instead.
This will become a hard error in a future Meson release.""", self.getline(line_start), lineno, col)
                        value = match_text[1:-1]
                        try:
                            value = ESCAPE_SEQUENCE_SINGLE_RE.sub(decode_match, value)
                        except MesonUnicodeDecodeError as err:
                            raise MesonException("Failed to parse escape sequence: '{}' in string:\n  {}".format(err.match, match_text))
                    elif tid == 'multiline_string':
                        tid = 'string'
                        value = match_text[3:-3]
                        lines = match_text.split('\n')
                        if len(lines) > 1:
                            lineno += len(lines) - 1
                            line_start = mo.end() - len(lines[-1])
                    elif tid == 'number':
                        value = int(match_text, base=0)
                    elif tid == 'eol_cont':
                        lineno += 1
                        line_start = loc
                        break
                    elif tid == 'eol':
                        lineno += 1
                        line_start = loc
                        if par_count > 0 or bracket_count > 0 or curl_count > 0:
                            break
                    elif tid == 'id':
                        if match_text in self.keywords:
                            tid = match_text
                        else:
                            if match_text in self.future_keywords:
                                mlog.warning("Identifier '{}' will become a reserved keyword in a future release. Please rename it.".format(match_text),
                                             location=types.SimpleNamespace(subdir=subdir, lineno=lineno))
                            value = match_text
                    yield Token(tid, subdir, curline_start, curline, col, bytespan, value)
                    break
            if not matched:
                raise ParseException('lexer', self.getline(line_start), lineno, col)

class BaseNode:
    def accept(self, visitor):
        fname = 'visit_{}'.format(type(self).__name__)
        if hasattr(visitor, fname):
            func = getattr(visitor, fname)
            if callable(func):
                func(self)

class ElementaryNode(BaseNode):
    def __init__(self, token):
        self.lineno = token.lineno
        self.subdir = token.subdir
        self.colno = token.colno
        self.value = token.value
        self.bytespan = token.bytespan

class BooleanNode(ElementaryNode):
    def __init__(self, token, value):
        super().__init__(token)
        self.value = value
        assert(isinstance(self.value, bool))

class IdNode(ElementaryNode):
    def __init__(self, token):
        super().__init__(token)
        assert(isinstance(self.value, str))

    def __str__(self):
        return "Id node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno)

class NumberNode(ElementaryNode):
    def __init__(self, token):
        super().__init__(token)
        assert(isinstance(self.value, int))

class StringNode(ElementaryNode):
    def __init__(self, token):
        super().__init__(token)
        assert(isinstance(self.value, str))

    def __str__(self):
        return "String node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno)

class ContinueNode(ElementaryNode):
    pass

class BreakNode(ElementaryNode):
    pass

class ArrayNode(BaseNode):
    def __init__(self, args, lineno, colno, end_lineno, end_colno):
        self.subdir = args.subdir
        self.lineno = lineno
        self.colno = colno
        self.end_lineno = end_lineno
        self.end_colno = end_colno
        self.args = args

class DictNode(BaseNode):
    def __init__(self, args, lineno, colno, end_lineno, end_colno):
        self.subdir = args.subdir
        self.lineno = lineno
        self.colno = colno
        self.end_lineno = end_lineno
        self.end_colno = end_colno
        self.args = args

class EmptyNode(BaseNode):
    def __init__(self, lineno, colno):
        self.subdir = ''
        self.lineno = lineno
        self.colno = colno
        self.value = None

class OrNode(BaseNode):
    def __init__(self, left, right):
        self.subdir = left.subdir
        self.lineno = left.lineno
        self.colno = left.colno
        self.left = left
        self.right = right

class AndNode(BaseNode):
    def __init__(self, left, right):
        self.subdir = left.subdir
        self.lineno = left.lineno
        self.colno = left.colno
        self.left = left
        self.right = right

class ComparisonNode(BaseNode):
    def __init__(self, ctype, left, right):
        self.lineno = left.lineno
        self.colno = left.colno
        self.subdir = left.subdir
        self.left = left
        self.right = right
        self.ctype = ctype

class ArithmeticNode(BaseNode):
    def __init__(self, operation, left, right):
        self.subdir = left.subdir
        self.lineno = left.lineno
        self.colno = left.colno
        self.left = left
        self.right = right
        self.operation = operation

class NotNode(BaseNode):
    def __init__(self, location_node, value):
        self.subdir = location_node.subdir
        self.lineno = location_node.lineno
        self.colno = location_node.colno
        self.value = value

class CodeBlockNode(BaseNode):
    def __init__(self, location_node):
        self.subdir = location_node.subdir
        self.lineno = location_node.lineno
        self.colno = location_node.colno
        self.lines = []

class IndexNode(BaseNode):
    def __init__(self, iobject, index):
        self.iobject = iobject
        self.index = index
        self.subdir = iobject.subdir
        self.lineno = iobject.lineno
        self.colno = iobject.colno

class MethodNode(BaseNode):
    def __init__(self, subdir, lineno, colno, source_object, name, args):
        self.subdir = subdir
        self.lineno = lineno
        self.colno = colno
        self.source_object = source_object
        self.name = name
        assert(isinstance(self.name, str))
        self.args = args

class FunctionNode(BaseNode):
    def __init__(self, subdir, lineno, colno, end_lineno, end_colno, func_name, args):
        self.subdir = subdir
        self.lineno = lineno
        self.colno = colno
        self.end_lineno = end_lineno
        self.end_colno = end_colno
        self.func_name = func_name
        assert(isinstance(func_name, str))
        self.args = args

class AssignmentNode(BaseNode):
    def __init__(self, subdir, lineno, colno, var_name, value):
        self.subdir = subdir
        self.lineno = lineno
        self.colno = colno
        self.var_name = var_name
        assert(isinstance(var_name, str))
        self.value = value

class PlusAssignmentNode(BaseNode):
    def __init__(self, subdir, lineno, colno, var_name, value):
        self.subdir = subdir
        self.lineno = lineno
        self.colno = colno
        self.var_name = var_name
        assert(isinstance(var_name, str))
        self.value = value

class ForeachClauseNode(BaseNode):
    def __init__(self, lineno, colno, varnames, items, block):
        self.lineno = lineno
        self.colno = colno
        self.varnames = varnames
        self.items = items
        self.block = block

class IfClauseNode(BaseNode):
    def __init__(self, lineno, colno):
        self.lineno = lineno
        self.colno = colno
        self.ifs = []
        self.elseblock = EmptyNode(lineno, colno)

class UMinusNode(BaseNode):
    def __init__(self, current_location, value):
        self.subdir = current_location.subdir
        self.lineno = current_location.lineno
        self.colno = current_location.colno
        self.value = value

class IfNode(BaseNode):
    def __init__(self, lineno, colno, condition, block):
        self.lineno = lineno
        self.colno = colno
        self.condition = condition
        self.block = block

class TernaryNode(BaseNode):
    def __init__(self, subdir, lineno, colno, condition, trueblock, falseblock):
        self.subdir = subdir
        self.lineno = lineno
        self.colno = colno
        self.condition = condition
        self.trueblock = trueblock
        self.falseblock = falseblock

class ArgumentNode(BaseNode):
    def __init__(self, token):
        self.lineno = token.lineno
        self.colno = token.colno
        self.subdir = token.subdir
        self.arguments = []
        self.commas = []
        self.kwargs = {}
        self.order_error = False

    def prepend(self, statement):
        if self.num_kwargs() > 0:
            self.order_error = True
        if not isinstance(statement, EmptyNode):
            self.arguments = [statement] + self.arguments

    def append(self, statement):
        if self.num_kwargs() > 0:
            self.order_error = True
        if not isinstance(statement, EmptyNode):
            self.arguments += [statement]

    def set_kwarg(self, name, value):
        if name in self.kwargs:
            mlog.warning('Keyword argument "{}" defined multiple times.'.format(name), location=self)
            mlog.warning('This will be an error in future Meson releases.')
        self.kwargs[name] = value

    def num_args(self):
        return len(self.arguments)

    def num_kwargs(self):
        return len(self.kwargs)

    def incorrect_order(self):
        return self.order_error

    def __len__(self):
        return self.num_args() # Fixme

comparison_map = {'equal': '==',
                  'nequal': '!=',
                  'lt': '<',
                  'le': '<=',
                  'gt': '>',
                  'ge': '>=',
                  'in': 'in',
                  'notin': 'not in',
                  }

# Recursive descent parser for Meson's definition language.
# Very basic apart from the fact that we have many precedence
# levels so there are not enough words to describe them all.
# Enter numbering:
#
# 1 assignment
# 2 or
# 3 and
# 4 comparison
# 5 arithmetic
# 6 negation
# 7 funcall, method call
# 8 parentheses
# 9 plain token

class Parser:
    def __init__(self, code, subdir):
        self.lexer = Lexer(code)
        self.stream = self.lexer.lex(subdir)
        self.current = Token('eof', '', 0, 0, 0, (0, 0), None)
        self.getsym()
        self.in_ternary = False

    def getsym(self):
        try:
            self.current = next(self.stream)
        except StopIteration:
            self.current = Token('eof', '', self.current.line_start, self.current.lineno, self.current.colno + self.current.bytespan[1] - self.current.bytespan[0], (0, 0), None)

    def getline(self):
        return self.lexer.getline(self.current.line_start)

    def accept(self, s):
        if self.current.tid == s:
            self.getsym()
            return True
        return False

    def expect(self, s):
        if self.accept(s):
            return True
        raise ParseException('Expecting %s got %s.' % (s, self.current.tid), self.getline(), self.current.lineno, self.current.colno)

    def block_expect(self, s, block_start):
        if self.accept(s):
            return True
        raise BlockParseException('Expecting %s got %s.' % (s, self.current.tid), self.getline(), self.current.lineno, self.current.colno, self.lexer.getline(block_start.line_start), block_start.lineno, block_start.colno)

    def parse(self):
        block = self.codeblock()
        self.expect('eof')
        return block

    def statement(self):
        return self.e1()

    def e1(self):
        left = self.e2()
        if self.accept('plusassign'):
            value = self.e1()
            if not isinstance(left, IdNode):
                raise ParseException('Plusassignment target must be an id.', self.getline(), left.lineno, left.colno)
            return PlusAssignmentNode(left.subdir, left.lineno, left.colno, left.value, value)
        elif self.accept('assign'):
            value = self.e1()
            if not isinstance(left, IdNode):
                raise ParseException('Assignment target must be an id.',
                                     self.getline(), left.lineno, left.colno)
            return AssignmentNode(left.subdir, left.lineno, left.colno, left.value, value)
        elif self.accept('questionmark'):
            if self.in_ternary:
                raise ParseException('Nested ternary operators are not allowed.',
                                     self.getline(), left.lineno, left.colno)
            self.in_ternary = True
            trueblock = self.e1()
            self.expect('colon')
            falseblock = self.e1()
            self.in_ternary = False
            return TernaryNode(left.subdir, left.lineno, left.colno, left, trueblock, falseblock)
        return left

    def e2(self):
        left = self.e3()
        while self.accept('or'):
            if isinstance(left, EmptyNode):
                raise ParseException('Invalid or clause.',
                                     self.getline(), left.lineno, left.colno)
            left = OrNode(left, self.e3())
        return left

    def e3(self):
        left = self.e4()
        while self.accept('and'):
            if isinstance(left, EmptyNode):
                raise ParseException('Invalid and clause.',
                                     self.getline(), left.lineno, left.colno)
            left = AndNode(left, self.e4())
        return left

    def e4(self):
        left = self.e5()
        for nodename, operator_type in comparison_map.items():
            if self.accept(nodename):
                return ComparisonNode(operator_type, left, self.e5())
        if self.accept('not') and self.accept('in'):
            return ComparisonNode('notin', left, self.e5())
        return left

    def e5(self):
        return self.e5add()

    def e5add(self):
        left = self.e5sub()
        if self.accept('plus'):
            return ArithmeticNode('add', left, self.e5add())
        return left

    def e5sub(self):
        left = self.e5mod()
        if self.accept('dash'):
            return ArithmeticNode('sub', left, self.e5sub())
        return left

    def e5mod(self):
        left = self.e5mul()
        if self.accept('percent'):
            return ArithmeticNode('mod', left, self.e5mod())
        return left

    def e5mul(self):
        left = self.e5div()
        if self.accept('star'):
            return ArithmeticNode('mul', left, self.e5mul())
        return left

    def e5div(self):
        left = self.e6()
        if self.accept('fslash'):
            return ArithmeticNode('div', left, self.e5div())
        return left

    def e6(self):
        if self.accept('not'):
            return NotNode(self.current, self.e7())
        if self.accept('dash'):
            return UMinusNode(self.current, self.e7())
        return self.e7()

    def e7(self):
        left = self.e8()
        block_start = self.current
        if self.accept('lparen'):
            args = self.args()
            self.block_expect('rparen', block_start)
            if not isinstance(left, IdNode):
                raise ParseException('Function call must be applied to plain id',
                                     self.getline(), left.lineno, left.colno)
            left = FunctionNode(left.subdir, left.lineno, left.colno, self.current.lineno, self.current.colno, left.value, args)
        go_again = True
        while go_again:
            go_again = False
            if self.accept('dot'):
                go_again = True
                left = self.method_call(left)
            if self.accept('lbracket'):
                go_again = True
                left = self.index_call(left)
        return left

    def e8(self):
        block_start = self.current
        if self.accept('lparen'):
            e = self.statement()
            self.block_expect('rparen', block_start)
            return e
        elif self.accept('lbracket'):
            args = self.args()
            self.block_expect('rbracket', block_start)
            return ArrayNode(args, block_start.lineno, block_start.colno, self.current.lineno, self.current.colno)
        elif self.accept('lcurl'):
            key_values = self.key_values()
            self.block_expect('rcurl', block_start)
            return DictNode(key_values, block_start.lineno, block_start.colno, self.current.lineno, self.current.colno)
        else:
            return self.e9()

    def e9(self):
        t = self.current
        if self.accept('true'):
            return BooleanNode(t, True)
        if self.accept('false'):
            return BooleanNode(t, False)
        if self.accept('id'):
            return IdNode(t)
        if self.accept('number'):
            return NumberNode(t)
        if self.accept('string'):
            return StringNode(t)
        return EmptyNode(self.current.lineno, self.current.colno)

    def key_values(self):
        s = self.statement()
        a = ArgumentNode(s)

        while not isinstance(s, EmptyNode):
            if self.accept('colon'):
                a.set_kwarg(s, self.statement())
                potential = self.current
                if not self.accept('comma'):
                    return a
                a.commas.append(potential)
            else:
                raise ParseException('Only key:value pairs are valid in dict construction.',
                                     self.getline(), s.lineno, s.colno)
            s = self.statement()
        return a

    def args(self):
        s = self.statement()
        a = ArgumentNode(s)

        while not isinstance(s, EmptyNode):
            potential = self.current
            if self.accept('comma'):
                a.commas.append(potential)
                a.append(s)
            elif self.accept('colon'):
                if not isinstance(s, IdNode):
                    raise ParseException('Dictionary key must be a plain identifier.',
                                         self.getline(), s.lineno, s.colno)
                a.set_kwarg(s.value, self.statement())
                potential = self.current
                if not self.accept('comma'):
                    return a
                a.commas.append(potential)
            else:
                a.append(s)
                return a
            s = self.statement()
        return a

    def method_call(self, source_object):
        methodname = self.e9()
        if not(isinstance(methodname, IdNode)):
            raise ParseException('Method name must be plain id',
                                 self.getline(), self.current.lineno, self.current.colno)
        self.expect('lparen')
        args = self.args()
        self.expect('rparen')
        method = MethodNode(methodname.subdir, methodname.lineno, methodname.colno, source_object, methodname.value, args)
        if self.accept('dot'):
            return self.method_call(method)
        return method

    def index_call(self, source_object):
        index_statement = self.statement()
        self.expect('rbracket')
        return IndexNode(source_object, index_statement)

    def foreachblock(self):
        t = self.current
        self.expect('id')
        varname = t
        varnames = [t]

        if self.accept('comma'):
            t = self.current
            self.expect('id')
            varnames.append(t)

        self.expect('colon')
        items = self.statement()
        block = self.codeblock()
        return ForeachClauseNode(varname.lineno, varname.colno, varnames, items, block)

    def ifblock(self):
        condition = self.statement()
        clause = IfClauseNode(condition.lineno, condition.colno)
        self.expect('eol')
        block = self.codeblock()
        clause.ifs.append(IfNode(clause.lineno, clause.colno, condition, block))
        self.elseifblock(clause)
        clause.elseblock = self.elseblock()
        return clause

    def elseifblock(self, clause):
        while self.accept('elif'):
            s = self.statement()
            self.expect('eol')
            b = self.codeblock()
            clause.ifs.append(IfNode(s.lineno, s.colno, s, b))

    def elseblock(self):
        if self.accept('else'):
            self.expect('eol')
            return self.codeblock()

    def line(self):
        block_start = self.current
        if self.current == 'eol':
            return EmptyNode(self.current.lineno, self.current.colno)
        if self.accept('if'):
            block = self.ifblock()
            self.block_expect('endif', block_start)
            return block
        if self.accept('foreach'):
            block = self.foreachblock()
            self.block_expect('endforeach', block_start)
            return block
        if self.accept('continue'):
            return ContinueNode(self.current)
        if self.accept('break'):
            return BreakNode(self.current)
        return self.statement()

    def codeblock(self):
        block = CodeBlockNode(self.current)
        cond = True
        while cond:
            curline = self.line()
            if not isinstance(curline, EmptyNode):
                block.lines.append(curline)
            cond = self.accept('eol')
        return block
meson-0.53.2/mesonbuild/msetup.py0000644000175000017500000003047213612313307020351 0ustar  jpakkanejpakkane00000000000000# Copyright 2016-2018 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import typing as T
import time
import sys, stat
import datetime
import os.path
import platform
import cProfile as profile
import argparse
import tempfile
import shutil
import glob

from . import environment, interpreter, mesonlib
from . import build
from . import mlog, coredata
from . import mintro
from .mconf import make_lower_case
from .mesonlib import MesonException

def add_arguments(parser):
    coredata.register_builtin_arguments(parser)
    parser.add_argument('--native-file',
                        default=[],
                        action='append',
                        help='File containing overrides for native compilation environment.')
    parser.add_argument('--cross-file',
                        default=[],
                        action='append',
                        help='File describing cross compilation environment.')
    parser.add_argument('-v', '--version', action='version',
                        version=coredata.version)
    parser.add_argument('--profile-self', action='store_true', dest='profile',
                        help=argparse.SUPPRESS)
    parser.add_argument('--fatal-meson-warnings', action='store_true', dest='fatal_warnings',
                        help='Make all Meson warnings fatal')
    parser.add_argument('--reconfigure', action='store_true',
                        help='Set options and reconfigure the project. Useful when new ' +
                             'options have been added to the project and the default value ' +
                             'is not working.')
    parser.add_argument('--wipe', action='store_true',
                        help='Wipe build directory and reconfigure using previous command line options. ' +
                             'Userful when build directory got corrupted, or when rebuilding with a ' +
                             'newer version of meson.')
    parser.add_argument('builddir', nargs='?', default=None)
    parser.add_argument('sourcedir', nargs='?', default=None)

class MesonApp:
    def __init__(self, options):
        (self.source_dir, self.build_dir) = self.validate_dirs(options.builddir,
                                                               options.sourcedir,
                                                               options.reconfigure,
                                                               options.wipe)
        if options.wipe:
            # Make a copy of the cmd line file to make sure we can always
            # restore that file if anything bad happens. For example if
            # configuration fails we need to be able to wipe again.
            restore = []
            with tempfile.TemporaryDirectory() as d:
                for filename in [coredata.get_cmd_line_file(self.build_dir)] + glob.glob(os.path.join(self.build_dir, environment.Environment.private_dir, '*.ini')):
                    try:
                        restore.append((shutil.copy(filename, d), filename))
                    except FileNotFoundError:
                        raise MesonException(
                            'Cannot find cmd_line.txt. This is probably because this '
                            'build directory was configured with a meson version < 0.49.0.')

                coredata.read_cmd_line_file(self.build_dir, options)

                try:
                    # Don't delete the whole tree, just all of the files and
                    # folders in the tree. Otherwise calling wipe form the builddir
                    # will cause a crash
                    for l in os.listdir(self.build_dir):
                        l = os.path.join(self.build_dir, l)
                        if os.path.isdir(l):
                            mesonlib.windows_proof_rmtree(l)
                        else:
                            mesonlib.windows_proof_rm(l)
                finally:
                    for b, f in restore:
                        os.makedirs(os.path.dirname(f), exist_ok=True)
                        shutil.move(b, f)

        self.options = options

    def has_build_file(self, dirname: str) -> bool:
        fname = os.path.join(dirname, environment.build_filename)
        return os.path.exists(fname)

    def validate_core_dirs(self, dir1: str, dir2: str) -> T.Tuple[str, str]:
        if dir1 is None:
            if dir2 is None:
                if not os.path.exists('meson.build') and os.path.exists('../meson.build'):
                    dir2 = '..'
                else:
                    raise MesonException('Must specify at least one directory name.')
            dir1 = os.getcwd()
        if dir2 is None:
            dir2 = os.getcwd()
        ndir1 = os.path.abspath(os.path.realpath(dir1))
        ndir2 = os.path.abspath(os.path.realpath(dir2))
        if not os.path.exists(ndir1):
            os.makedirs(ndir1)
        if not os.path.exists(ndir2):
            os.makedirs(ndir2)
        if not stat.S_ISDIR(os.stat(ndir1).st_mode):
            raise MesonException('%s is not a directory' % dir1)
        if not stat.S_ISDIR(os.stat(ndir2).st_mode):
            raise MesonException('%s is not a directory' % dir2)
        if os.path.samefile(dir1, dir2):
            raise MesonException('Source and build directories must not be the same. Create a pristine build directory.')
        if self.has_build_file(ndir1):
            if self.has_build_file(ndir2):
                raise MesonException('Both directories contain a build file %s.' % environment.build_filename)
            return ndir1, ndir2
        if self.has_build_file(ndir2):
            return ndir2, ndir1
        raise MesonException('Neither directory contains a build file %s.' % environment.build_filename)

    def validate_dirs(self, dir1: str, dir2: str, reconfigure: bool, wipe: bool) -> T.Tuple[str, str]:
        (src_dir, build_dir) = self.validate_core_dirs(dir1, dir2)
        priv_dir = os.path.join(build_dir, 'meson-private/coredata.dat')
        if os.path.exists(priv_dir):
            if not reconfigure and not wipe:
                print('Directory already configured.\n'
                      '\nJust run your build command (e.g. ninja) and Meson will regenerate as necessary.\n'
                      'If ninja fails, run "ninja reconfigure" or "meson --reconfigure"\n'
                      'to force Meson to regenerate.\n'
                      '\nIf build failures persist, run "meson setup --wipe" to rebuild from scratch\n'
                      'using the same options as passed when configuring the build.'
                      '\nTo change option values, run "meson configure" instead.')
                raise SystemExit
        else:
            has_cmd_line_file = os.path.exists(coredata.get_cmd_line_file(build_dir))
            if (wipe and not has_cmd_line_file) or (not wipe and reconfigure):
                raise SystemExit('Directory does not contain a valid build tree:\n{}'.format(build_dir))
        return src_dir, build_dir

    def generate(self):
        env = environment.Environment(self.source_dir, self.build_dir, self.options)
        mlog.initialize(env.get_log_dir(), self.options.fatal_warnings)
        if self.options.profile:
            mlog.set_timestamp_start(time.monotonic())
        with mesonlib.BuildDirLock(self.build_dir):
            self._generate(env)

    def _generate(self, env):
        mlog.debug('Build started at', datetime.datetime.now().isoformat())
        mlog.debug('Main binary:', sys.executable)
        mlog.debug('Build Options:', coredata.get_cmd_line_options(self.build_dir, self.options))
        mlog.debug('Python system:', platform.system())
        mlog.log(mlog.bold('The Meson build system'))
        mlog.log('Version:', coredata.version)
        mlog.log('Source dir:', mlog.bold(self.source_dir))
        mlog.log('Build dir:', mlog.bold(self.build_dir))
        if env.is_cross_build():
            mlog.log('Build type:', mlog.bold('cross build'))
        else:
            mlog.log('Build type:', mlog.bold('native build'))
        b = build.Build(env)

        intr = interpreter.Interpreter(b)
        if env.is_cross_build():
            logger_fun = mlog.log
        else:
            logger_fun = mlog.debug
        logger_fun('Build machine cpu family:', mlog.bold(intr.builtin['build_machine'].cpu_family_method([], {})))
        logger_fun('Build machine cpu:', mlog.bold(intr.builtin['build_machine'].cpu_method([], {})))
        mlog.log('Host machine cpu family:', mlog.bold(intr.builtin['host_machine'].cpu_family_method([], {})))
        mlog.log('Host machine cpu:', mlog.bold(intr.builtin['host_machine'].cpu_method([], {})))
        logger_fun('Target machine cpu family:', mlog.bold(intr.builtin['target_machine'].cpu_family_method([], {})))
        logger_fun('Target machine cpu:', mlog.bold(intr.builtin['target_machine'].cpu_method([], {})))
        try:
            if self.options.profile:
                fname = os.path.join(self.build_dir, 'meson-private', 'profile-interpreter.log')
                profile.runctx('intr.run()', globals(), locals(), filename=fname)
            else:
                intr.run()
        except Exception as e:
            mintro.write_meson_info_file(b, [e])
            raise
        # Print all default option values that don't match the current value
        for def_opt_name, def_opt_value, cur_opt_value in intr.get_non_matching_default_options():
            mlog.log('Option', mlog.bold(def_opt_name), 'is:',
                     mlog.bold('{}'.format(make_lower_case(cur_opt_value.printable_value()))),
                     '[default: {}]'.format(make_lower_case(def_opt_value)))
        try:
            dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat')
            # We would like to write coredata as late as possible since we use the existence of
            # this file to check if we generated the build file successfully. Since coredata
            # includes settings, the build files must depend on it and appear newer. However, due
            # to various kernel caches, we cannot guarantee that any time in Python is exactly in
            # sync with the time that gets applied to any files. Thus, we dump this file as late as
            # possible, but before build files, and if any error occurs, delete it.
            cdf = env.dump_coredata()
            if self.options.profile:
                fname = 'profile-{}-backend.log'.format(intr.backend.name)
                fname = os.path.join(self.build_dir, 'meson-private', fname)
                profile.runctx('intr.backend.generate(intr)', globals(), locals(), filename=fname)
            else:
                intr.backend.generate(intr)
            build.save(b, dumpfile)
            if env.first_invocation:
                coredata.write_cmd_line_file(self.build_dir, self.options)
            else:
                coredata.update_cmd_line_file(self.build_dir, self.options)

            # Generate an IDE introspection file with the same syntax as the already existing API
            if self.options.profile:
                fname = os.path.join(self.build_dir, 'meson-private', 'profile-introspector.log')
                profile.runctx('mintro.generate_introspection_file(b, intr.backend)', globals(), locals(), filename=fname)
            else:
                mintro.generate_introspection_file(b, intr.backend)
            mintro.write_meson_info_file(b, [], True)

            # Post-conf scripts must be run after writing coredata or else introspection fails.
            intr.backend.run_postconf_scripts()
        except Exception as e:
            mintro.write_meson_info_file(b, [e])
            if 'cdf' in locals():
                old_cdf = cdf + '.prev'
                if os.path.exists(old_cdf):
                    os.replace(old_cdf, cdf)
                else:
                    os.unlink(cdf)
            raise

def run(options) -> int:
    coredata.parse_cmd_line_options(options)
    app = MesonApp(options)
    app.generate()
    return 0
meson-0.53.2/mesonbuild/msubprojects.py0000755000175000017500000002577413612313307021570 0ustar  jpakkanejpakkane00000000000000import os, subprocess
import argparse

from . import mlog
from .mesonlib import git, Popen_safe
from .wrap.wrap import API_ROOT, PackageDefinition, Resolver, WrapException
from .wrap import wraptool

def update_wrapdb_file(wrap, repo_dir, options):
    patch_url = wrap.get('patch_url')
    branch, revision = wraptool.parse_patch_url(patch_url)
    new_branch, new_revision = wraptool.get_latest_version(wrap.name)
    if new_branch == branch and new_revision == revision:
        mlog.log('  -> Up to date.')
        return
    wraptool.update_wrap_file(wrap.filename, wrap.name, new_branch, new_revision)
    msg = ['  -> New wrap file downloaded.']
    # Meson reconfigure won't use the new wrap file as long as the source
    # directory exists. We don't delete it ourself to avoid data loss in case
    # user has changes in their copy.
    if os.path.isdir(repo_dir):
        msg += ['To use it, delete', mlog.bold(repo_dir), 'and run', mlog.bold('meson --reconfigure')]
    mlog.log(*msg)

def update_file(wrap, repo_dir, options):
    patch_url = wrap.values.get('patch_url', '')
    if patch_url.startswith(API_ROOT):
        update_wrapdb_file(wrap, repo_dir, options)
    elif not os.path.isdir(repo_dir):
        # The subproject is not needed, or it is a tarball extracted in
        # 'libfoo-1.0' directory and the version has been bumped and the new
        # directory is 'libfoo-2.0'. In that case forcing a meson
        # reconfigure will download and use the new tarball.
        mlog.log('  -> Subproject has not been checked out. Run', mlog.bold('meson --reconfigure'), 'to fetch it if needed.')
    else:
        # The subproject has not changed, or the new source and/or patch
        # tarballs should be extracted in the same directory than previous
        # version.
        mlog.log('  -> Subproject has not changed, or the new source/patch needs to be extracted on the same location.\n' +
                 '     In that case, delete', mlog.bold(repo_dir), 'and run', mlog.bold('meson --reconfigure'))

def git_output(cmd, workingdir):
    return git(cmd, workingdir, check=True, universal_newlines=True,
               stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout

def git_show(repo_dir):
    commit_message = git_output(['show', '--quiet', '--pretty=format:%h%n%d%n%s%n[%an]'], repo_dir)
    parts = [s.strip() for s in commit_message.split('\n')]
    mlog.log('  ->', mlog.yellow(parts[0]), mlog.red(parts[1]), parts[2], mlog.blue(parts[3]))

def update_git(wrap, repo_dir, options):
    if not os.path.isdir(repo_dir):
        mlog.log('  -> Not used.')
        return
    revision = wrap.get('revision')
    ret = git_output(['rev-parse', '--abbrev-ref', 'HEAD'], repo_dir).strip()
    if ret == 'HEAD':
        try:
            # We are currently in detached mode, just checkout the new revision
            git_output(['fetch'], repo_dir)
            git_output(['checkout', revision], repo_dir)
        except subprocess.CalledProcessError as e:
            out = e.output.decode().strip()
            mlog.log('  -> Could not checkout revision', mlog.cyan(revision))
            mlog.log(mlog.red(out))
            mlog.log(mlog.red(str(e)))
            return
    elif ret == revision:
        try:
            # We are in the same branch, pull latest commits
            git_output(['-c', 'rebase.autoStash=true', 'pull', '--rebase'], repo_dir)
        except subprocess.CalledProcessError as e:
            out = e.output.decode().strip()
            mlog.log('  -> Could not rebase', mlog.bold(repo_dir), 'please fix and try again.')
            mlog.log(mlog.red(out))
            mlog.log(mlog.red(str(e)))
            return
    else:
        # We are in another branch, probably user created their own branch and
        # we should rebase it on top of wrap's branch.
        if options.rebase:
            try:
                git_output(['fetch'], repo_dir)
                git_output(['-c', 'rebase.autoStash=true', 'rebase', revision], repo_dir)
            except subprocess.CalledProcessError as e:
                out = e.output.decode().strip()
                mlog.log('  -> Could not rebase', mlog.bold(repo_dir), 'please fix and try again.')
                mlog.log(mlog.red(out))
                mlog.log(mlog.red(str(e)))
                return
        else:
            mlog.log('  -> Target revision is', mlog.bold(revision), 'but currently in branch is', mlog.bold(ret), '\n' +
                     '     To rebase your branch on top of', mlog.bold(revision), 'use', mlog.bold('--rebase'), 'option.')
            return

    git_output(['submodule', 'update', '--checkout', '--recursive'], repo_dir)
    git_show(repo_dir)

def update_hg(wrap, repo_dir, options):
    if not os.path.isdir(repo_dir):
        mlog.log('  -> Not used.')
        return
    revno = wrap.get('revision')
    if revno.lower() == 'tip':
        # Failure to do pull is not a fatal error,
        # because otherwise you can't develop without
        # a working net connection.
        subprocess.call(['hg', 'pull'], cwd=repo_dir)
    else:
        if subprocess.call(['hg', 'checkout', revno], cwd=repo_dir) != 0:
            subprocess.check_call(['hg', 'pull'], cwd=repo_dir)
            subprocess.check_call(['hg', 'checkout', revno], cwd=repo_dir)

def update_svn(wrap, repo_dir, options):
    if not os.path.isdir(repo_dir):
        mlog.log('  -> Not used.')
        return
    revno = wrap.get('revision')
    p, out, _ = Popen_safe(['svn', 'info', '--show-item', 'revision', repo_dir])
    current_revno = out
    if current_revno == revno:
        return
    if revno.lower() == 'head':
        # Failure to do pull is not a fatal error,
        # because otherwise you can't develop without
        # a working net connection.
        subprocess.call(['svn', 'update'], cwd=repo_dir)
    else:
        subprocess.check_call(['svn', 'update', '-r', revno], cwd=repo_dir)

def update(wrap, repo_dir, options):
    mlog.log('Updating %s...' % wrap.name)
    if wrap.type == 'file':
        update_file(wrap, repo_dir, options)
    elif wrap.type == 'git':
        update_git(wrap, repo_dir, options)
    elif wrap.type == 'hg':
        update_hg(wrap, repo_dir, options)
    elif wrap.type == 'svn':
        update_svn(wrap, repo_dir, options)
    else:
        mlog.log('  -> Cannot update', wrap.type, 'subproject')

def checkout(wrap, repo_dir, options):
    if wrap.type != 'git' or not os.path.isdir(repo_dir):
        return
    branch_name = options.branch_name if options.branch_name else wrap.get('revision')
    cmd = ['checkout', branch_name, '--']
    if options.b:
        cmd.insert(1, '-b')
    mlog.log('Checkout %s in %s...' % (branch_name, wrap.name))
    try:
        git_output(cmd, repo_dir)
        git_show(repo_dir)
    except subprocess.CalledProcessError as e:
        out = e.output.decode().strip()
        mlog.log('  -> ', mlog.red(out))

def download(wrap, repo_dir, options):
    mlog.log('Download %s...' % wrap.name)
    if os.path.isdir(repo_dir):
        mlog.log('  -> Already downloaded')
        return
    try:
        r = Resolver(os.path.dirname(repo_dir))
        r.resolve(wrap.name, 'meson')
        mlog.log('  -> done')
    except WrapException as e:
        mlog.log('  ->', mlog.red(str(e)))

def foreach(wrap, repo_dir, options):
    mlog.log('Executing command in %s' % repo_dir)
    if not os.path.isdir(repo_dir):
        mlog.log('  -> Not downloaded yet')
        return
    try:
        out = subprocess.check_output([options.command] + options.args,
                                      stderr=subprocess.STDOUT,
                                      cwd=repo_dir).decode()
        mlog.log(out, end='')
    except subprocess.CalledProcessError as e:
        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='.',
                   help='Path to source directory')
    p.add_argument('subprojects', nargs='*',
                   help='List of subprojects (default: all)')

def add_arguments(parser):
    subparsers = parser.add_subparsers(title='Commands', dest='command')
    subparsers.required = True

    p = subparsers.add_parser('update', help='Update all subprojects from wrap files')
    p.add_argument('--rebase', default=False, action='store_true',
                   help='Rebase your branch on top of wrap\'s revision (git only)')
    add_common_arguments(p)
    p.set_defaults(subprojects_func=update)

    p = subparsers.add_parser('checkout', help='Checkout a branch (git only)')
    p.add_argument('-b', default=False, action='store_true',
                   help='Create a new branch')
    p.add_argument('branch_name', nargs='?',
                   help='Name of the branch to checkout or create (default: revision set in wrap file)')
    add_common_arguments(p)
    p.set_defaults(subprojects_func=checkout)

    p = subparsers.add_parser('download', help='Ensure subprojects are fetched, even if not in use. ' +
                                               'Already downloaded subprojects are not modified. ' +
                                               'This can be used to pre-fetch all subprojects and avoid downloads during configure.')
    add_common_arguments(p)
    p.set_defaults(subprojects_func=download)

    p = subparsers.add_parser('foreach', help='Execute a command in each subproject directory.')
    p.add_argument('command', metavar='command ...',
                   help='Command to execute in each subproject directory')
    p.add_argument('args', nargs=argparse.REMAINDER,
                   help=argparse.SUPPRESS)
    p.add_argument('--sourcedir', default='.',
                   help='Path to source directory')
    p.set_defaults(subprojects_func=foreach)

def run(options):
    src_dir = os.path.relpath(os.path.realpath(options.sourcedir))
    if not os.path.isfile(os.path.join(src_dir, 'meson.build')):
        mlog.error('Directory', mlog.bold(src_dir), 'does not seem to be a Meson source directory.')
        return 1
    subprojects_dir = os.path.join(src_dir, 'subprojects')
    if not os.path.isdir(subprojects_dir):
        mlog.log('Directory', mlog.bold(src_dir), 'does not seem to have subprojects.')
        return 0
    files = []
    if hasattr(options, 'subprojects'):
        for name in options.subprojects:
            f = os.path.join(subprojects_dir, name + '.wrap')
            if not os.path.isfile(f):
                mlog.error('Subproject', mlog.bold(name), 'not found.')
                return 1
            else:
                files.append(f)
    if not files:
        for f in os.listdir(subprojects_dir):
            if f.endswith('.wrap'):
                files.append(os.path.join(subprojects_dir, f))
    for f in files:
        wrap = PackageDefinition(f)
        directory = wrap.values.get('directory', wrap.name)
        repo_dir = os.path.join(subprojects_dir, directory)
        options.subprojects_func(wrap, repo_dir, options)
    return 0
meson-0.53.2/mesonbuild/mtest.py0000644000175000017500000012407413612313307020172 0ustar  jpakkanejpakkane00000000000000# Copyright 2016-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# A tool to run tests in many different ways.

from pathlib import Path
from collections import namedtuple
from copy import deepcopy
import argparse
import concurrent.futures as conc
import datetime
import enum
import io
import json
import multiprocessing
import os
import pickle
import platform
import random
import re
import signal
import subprocess
import sys
import tempfile
import time
import typing as T

from . import build
from . import environment
from . import mlog
from .dependencies import ExternalProgram
from .mesonlib import MesonException, get_wine_shortpath, split_args

if T.TYPE_CHECKING:
    from .backend.backends import TestSerialisation

# GNU autotools interprets a return code of 77 from tests it executes to
# mean that the test should be skipped.
GNU_SKIP_RETURNCODE = 77

# GNU autotools interprets a return code of 99 from tests it executes to
# mean that the test failed even before testing what it is supposed to test.
GNU_ERROR_RETURNCODE = 99

def is_windows() -> bool:
    platname = platform.system().lower()
    return platname == 'windows' or 'mingw' in platname

def is_cygwin() -> bool:
    platname = platform.system().lower()
    return 'cygwin' in platname

def determine_worker_count() -> int:
    varname = 'MESON_TESTTHREADS'
    if varname in os.environ:
        try:
            num_workers = int(os.environ[varname])
        except ValueError:
            print('Invalid value in %s, using 1 thread.' % varname)
            num_workers = 1
    else:
        try:
            # Fails in some weird environments such as Debian
            # reproducible build.
            num_workers = multiprocessing.cpu_count()
        except Exception:
            num_workers = 1
    return num_workers

def add_arguments(parser: argparse.ArgumentParser) -> None:
    parser.add_argument('--repeat', default=1, dest='repeat', type=int,
                        help='Number of times to run the tests.')
    parser.add_argument('--no-rebuild', default=False, action='store_true',
                        help='Do not rebuild before running tests.')
    parser.add_argument('--gdb', default=False, dest='gdb', action='store_true',
                        help='Run test under gdb.')
    parser.add_argument('--gdb-path', default='gdb', dest='gdb_path',
                        help='Path to the gdb binary (default: gdb).')
    parser.add_argument('--list', default=False, dest='list', action='store_true',
                        help='List available tests.')
    parser.add_argument('--wrapper', default=None, dest='wrapper', type=split_args,
                        help='wrapper to run tests with (e.g. Valgrind)')
    parser.add_argument('-C', default='.', dest='wd',
                        help='directory to cd into before running')
    parser.add_argument('--suite', default=[], dest='include_suites', action='append', metavar='SUITE',
                        help='Only run tests belonging to the given suite.')
    parser.add_argument('--no-suite', default=[], dest='exclude_suites', action='append', metavar='SUITE',
                        help='Do not run tests belonging to the given suite.')
    parser.add_argument('--no-stdsplit', default=True, dest='split', action='store_false',
                        help='Do not split stderr and stdout in test logs.')
    parser.add_argument('--print-errorlogs', default=False, action='store_true',
                        help="Whether to print failing tests' logs.")
    parser.add_argument('--benchmark', default=False, action='store_true',
                        help="Run benchmarks instead of tests.")
    parser.add_argument('--logbase', default='testlog',
                        help="Base name for log file.")
    parser.add_argument('--num-processes', default=determine_worker_count(), type=int,
                        help='How many parallel processes to use.')
    parser.add_argument('-v', '--verbose', default=False, action='store_true',
                        help='Do not redirect stdout and stderr')
    parser.add_argument('-q', '--quiet', default=False, action='store_true',
                        help='Produce less output to the terminal.')
    parser.add_argument('-t', '--timeout-multiplier', type=float, default=None,
                        help='Define a multiplier for test timeout, for example '
                        ' when running tests in particular conditions they might take'
                        ' more time to execute.')
    parser.add_argument('--setup', default=None, dest='setup',
                        help='Which test setup to use.')
    parser.add_argument('--test-args', default=[], type=split_args,
                        help='Arguments to pass to the specified test(s) or all tests')
    parser.add_argument('args', nargs='*',
                        help='Optional list of tests to run')


def returncode_to_status(retcode: int) -> str:
    # Note: We can't use `os.WIFSIGNALED(result.returncode)` and the related
    # functions here because the status returned by subprocess is munged. It
    # returns a negative value if the process was killed by a signal rather than
    # the raw status returned by `wait()`. Also, If a shell sits between Meson
    # the the actual unit test that shell is likely to convert a termination due
    # to a signal into an exit status of 128 plus the signal number.
    if retcode < 0:
        signum = -retcode
        try:
            signame = signal.Signals(signum).name
        except ValueError:
            signame = 'SIGinvalid'
        return '(killed by signal %d %s)' % (signum, signame)

    if retcode <= 128:
        return '(exit status %d)' % (retcode,)

    signum = retcode - 128
    try:
        signame = signal.Signals(signum).name
    except ValueError:
        signame = 'SIGinvalid'
    return '(exit status %d or signal %d %s)' % (retcode, signum, signame)

def env_tuple_to_str(env: T.Iterable[T.Tuple[str, str]]) -> str:
    return ''.join(["%s='%s' " % (k, v) for k, v in env])


class TestException(MesonException):
    pass


@enum.unique
class TestResult(enum.Enum):

    OK = 'OK'
    TIMEOUT = 'TIMEOUT'
    SKIP = 'SKIP'
    FAIL = 'FAIL'
    EXPECTEDFAIL = 'EXPECTEDFAIL'
    UNEXPECTEDPASS = 'UNEXPECTEDPASS'
    ERROR = 'ERROR'


class TAPParser:
    Plan = namedtuple('Plan', ['count', 'late', 'skipped', 'explanation'])
    Bailout = namedtuple('Bailout', ['message'])
    Test = namedtuple('Test', ['number', 'name', 'result', 'explanation'])
    Error = namedtuple('Error', ['message'])
    Version = namedtuple('Version', ['version'])

    _MAIN = 1
    _AFTER_TEST = 2
    _YAML = 3

    _RE_BAILOUT = re.compile(r'Bail out!\s*(.*)')
    _RE_DIRECTIVE = re.compile(r'(?:\s*\#\s*([Ss][Kk][Ii][Pp]\S*|[Tt][Oo][Dd][Oo])\b\s*(.*))?')
    _RE_PLAN = re.compile(r'1\.\.([0-9]+)' + _RE_DIRECTIVE.pattern)
    _RE_TEST = re.compile(r'((?:not )?ok)\s*(?:([0-9]+)\s*)?([^#]*)' + _RE_DIRECTIVE.pattern)
    _RE_VERSION = re.compile(r'TAP version ([0-9]+)')
    _RE_YAML_START = re.compile(r'(\s+)---.*')
    _RE_YAML_END = re.compile(r'\s+\.\.\.\s*')

    def __init__(self, io: T.Iterator[str]):
        self.io = io

    def parse_test(self, ok: bool, num: int, name: str, directive: T.Optional[str], explanation: T.Optional[str]) -> \
            T.Generator[T.Union['TAPParser.Test', 'TAPParser.Error'], None, None]:
        name = name.strip()
        explanation = explanation.strip() if explanation else None
        if directive is not None:
            directive = directive.upper()
            if directive == 'SKIP':
                if ok:
                    yield self.Test(num, name, TestResult.SKIP, explanation)
                    return
            elif directive == 'TODO':
                yield self.Test(num, name, TestResult.UNEXPECTEDPASS if ok else TestResult.EXPECTEDFAIL, explanation)
                return
            else:
                yield self.Error('invalid directive "%s"' % (directive,))

        yield self.Test(num, name, TestResult.OK if ok else TestResult.FAIL, explanation)

    def parse(self) -> T.Generator[T.Union['TAPParser.Test', 'TAPParser.Error', 'TAPParser.Version', 'TAPParser.Plan', 'TAPParser.Bailout'], None, None]:
        found_late_test = False
        bailed_out = False
        plan = None
        lineno = 0
        num_tests = 0
        yaml_lineno = None
        yaml_indent = ''
        state = self._MAIN
        version = 12
        while True:
            lineno += 1
            try:
                line = next(self.io).rstrip()
            except StopIteration:
                break

            # YAML blocks are only accepted after a test
            if state == self._AFTER_TEST:
                if version >= 13:
                    m = self._RE_YAML_START.match(line)
                    if m:
                        state = self._YAML
                        yaml_lineno = lineno
                        yaml_indent = m.group(1)
                        continue
                state = self._MAIN

            elif state == self._YAML:
                if self._RE_YAML_END.match(line):
                    state = self._MAIN
                    continue
                if line.startswith(yaml_indent):
                    continue
                yield self.Error('YAML block not terminated (started on line {})'.format(yaml_lineno))
                state = self._MAIN

            assert state == self._MAIN
            if line.startswith('#'):
                continue

            m = self._RE_TEST.match(line)
            if m:
                if plan and plan.late and not found_late_test:
                    yield self.Error('unexpected test after late plan')
                    found_late_test = True
                num_tests += 1
                num = num_tests if m.group(2) is None else int(m.group(2))
                if num != num_tests:
                    yield self.Error('out of order test numbers')
                yield from self.parse_test(m.group(1) == 'ok', num,
                                           m.group(3), m.group(4), m.group(5))
                state = self._AFTER_TEST
                continue

            m = self._RE_PLAN.match(line)
            if m:
                if plan:
                    yield self.Error('more than one plan found')
                else:
                    count = int(m.group(1))
                    skipped = (count == 0)
                    if m.group(2):
                        if m.group(2).upper().startswith('SKIP'):
                            if count > 0:
                                yield self.Error('invalid SKIP directive for plan')
                            skipped = True
                        else:
                            yield self.Error('invalid directive for plan')
                    plan = self.Plan(count=count, late=(num_tests > 0),
                                     skipped=skipped, explanation=m.group(3))
                    yield plan
                continue

            m = self._RE_BAILOUT.match(line)
            if m:
                yield self.Bailout(m.group(1))
                bailed_out = True
                continue

            m = self._RE_VERSION.match(line)
            if m:
                # The TAP version is only accepted as the first line
                if lineno != 1:
                    yield self.Error('version number must be on the first line')
                    continue
                version = int(m.group(1))
                if version < 13:
                    yield self.Error('version number should be at least 13')
                else:
                    yield self.Version(version=version)
                continue

            if len(line) == 0:
                continue

            yield self.Error('unexpected input at line %d' % (lineno,))

        if state == self._YAML:
            yield self.Error('YAML block not terminated (started on line {})'.format(yaml_lineno))

        if not bailed_out and plan and num_tests != plan.count:
            if num_tests < plan.count:
                yield self.Error('Too few tests run (expected %d, got %d)' % (plan.count, num_tests))
            else:
                yield self.Error('Too many tests run (expected %d, got %d)' % (plan.count, num_tests))


class TestRun:

    @classmethod
    def make_exitcode(cls, test: 'TestSerialisation', test_env: T.Dict[str, str],
                      returncode: int, starttime: float, duration: float,
                      stdo: T.Optional[str], stde: T.Optional[str],
                      cmd: T.Optional[T.List[str]]) -> 'TestRun':
        if returncode == GNU_SKIP_RETURNCODE:
            res = TestResult.SKIP
        elif returncode == GNU_ERROR_RETURNCODE:
            res = TestResult.ERROR
        elif test.should_fail:
            res = TestResult.EXPECTEDFAIL if bool(returncode) else TestResult.UNEXPECTEDPASS
        else:
            res = TestResult.FAIL if bool(returncode) else TestResult.OK
        return cls(test, test_env, res, returncode, starttime, duration, stdo, stde, cmd)

    @classmethod
    def make_tap(cls, test: 'TestSerialisation', test_env: T.Dict[str, str],
                 returncode: int, starttime: float, duration: float,
                 stdo: str, stde: str,
                 cmd: T.Optional[T.List[str]]) -> 'TestRun':
        res = None
        num_tests = 0
        failed = False
        num_skipped = 0

        for i in TAPParser(io.StringIO(stdo)).parse():
            if isinstance(i, TAPParser.Bailout):
                res = TestResult.ERROR
            elif isinstance(i, TAPParser.Test):
                if i.result == TestResult.SKIP:
                    num_skipped += 1
                elif i.result in (TestResult.FAIL, TestResult.UNEXPECTEDPASS):
                    failed = True
                num_tests += 1
            elif isinstance(i, TAPParser.Error):
                res = TestResult.ERROR
                stde += '\nTAP parsing error: ' + i.message

        if returncode != 0:
            res = TestResult.ERROR
            stde += '\n(test program exited with status code %d)' % (returncode,)

        if res is None:
            # Now determine the overall result of the test based on the outcome of the subcases
            if num_skipped == num_tests:
                # This includes the case where num_tests is zero
                res = TestResult.SKIP
            elif test.should_fail:
                res = TestResult.EXPECTEDFAIL if failed else TestResult.UNEXPECTEDPASS
            else:
                res = TestResult.FAIL if failed else TestResult.OK

        return cls(test, test_env, res, returncode, starttime, duration, stdo, stde, cmd)

    def __init__(self, test: 'TestSerialisation', test_env: T.Dict[str, str],
                 res: TestResult, returncode: int, starttime: float, duration: float,
                 stdo: T.Optional[str], stde: T.Optional[str],
                 cmd: T.Optional[T.List[str]]):
        assert isinstance(res, TestResult)
        self.res = res
        self.returncode = returncode
        self.starttime = starttime
        self.duration = duration
        self.stdo = stdo
        self.stde = stde
        self.cmd = cmd
        self.env = test_env
        self.should_fail = test.should_fail

    def get_log(self) -> str:
        res = '--- command ---\n'
        if self.cmd is None:
            res += 'NONE\n'
        else:
            test_only_env = set(self.env.items()) - set(os.environ.items())
            starttime_str = time.strftime("%H:%M:%S", time.gmtime(self.starttime))
            res += '{} {}{}\n'.format(
                starttime_str, env_tuple_to_str(test_only_env), ' '.join(self.cmd)
            )
        if self.stdo:
            res += '--- stdout ---\n'
            res += self.stdo
        if self.stde:
            if res[-1:] != '\n':
                res += '\n'
            res += '--- stderr ---\n'
            res += self.stde
        if res[-1:] != '\n':
            res += '\n'
        res += '-------\n\n'
        return res

def decode(stream: T.Union[None, bytes]) -> str:
    if stream is None:
        return ''
    try:
        return stream.decode('utf-8')
    except UnicodeDecodeError:
        return stream.decode('iso-8859-1', errors='ignore')

def write_json_log(jsonlogfile: T.TextIO, test_name: str, result: TestRun) -> None:
    jresult = {'name': test_name,
               'stdout': result.stdo,
               'result': result.res.value,
               'starttime': result.starttime,
               'duration': result.duration,
               'returncode': result.returncode,
               'env': result.env,
               'command': result.cmd}  # type: T.Dict[str, T.Any]
    if result.stde:
        jresult['stderr'] = result.stde
    jsonlogfile.write(json.dumps(jresult) + '\n')

def run_with_mono(fname: str) -> bool:
    if fname.endswith('.exe') and not (is_windows() or is_cygwin()):
        return True
    return False

def load_benchmarks(build_dir: str) -> T.List['TestSerialisation']:
    datafile = Path(build_dir) / 'meson-private' / 'meson_benchmark_setup.dat'
    if not datafile.is_file():
        raise TestException('Directory {!r} does not seem to be a Meson build directory.'.format(build_dir))
    with datafile.open('rb') as f:
        obj = T.cast(T.List['TestSerialisation'], pickle.load(f))
    return obj

def load_tests(build_dir: str) -> T.List['TestSerialisation']:
    datafile = Path(build_dir) / 'meson-private' / 'meson_test_setup.dat'
    if not datafile.is_file():
        raise TestException('Directory {!r} does not seem to be a Meson build directory.'.format(build_dir))
    with datafile.open('rb') as f:
        obj = T.cast(T.List['TestSerialisation'], pickle.load(f))
    return obj


class SingleTestRunner:

    def __init__(self, test: 'TestSerialisation', test_env: T.Dict[str, str],
                 env: T.Dict[str, str], options: argparse.Namespace):
        self.test = test
        self.test_env = test_env
        self.env = env
        self.options = options

    def _get_cmd(self) -> T.Optional[T.List[str]]:
        if self.test.fname[0].endswith('.jar'):
            return ['java', '-jar'] + self.test.fname
        elif not self.test.is_cross_built and run_with_mono(self.test.fname[0]):
            return ['mono'] + self.test.fname
        else:
            if self.test.is_cross_built and self.test.needs_exe_wrapper:
                if self.test.exe_runner is None:
                    # Can not run test on cross compiled executable
                    # because there is no execute wrapper.
                    return None
                else:
                    if not self.test.exe_runner.found():
                        msg = 'The exe_wrapper defined in the cross file {!r} was not ' \
                              'found. Please check the command and/or add it to PATH.'
                        raise TestException(msg.format(self.test.exe_runner.name))
                    return self.test.exe_runner.get_command() + self.test.fname
            else:
                return self.test.fname

    def run(self) -> TestRun:
        cmd = self._get_cmd()
        if cmd is None:
            skip_stdout = 'Not run because can not execute cross compiled binaries.'
            return TestRun(self.test, self.test_env, TestResult.SKIP, GNU_SKIP_RETURNCODE, time.time(), 0.0, skip_stdout, None, None)
        else:
            wrap = TestHarness.get_wrapper(self.options)
            if self.options.gdb:
                self.test.timeout = None
            return self._run_cmd(wrap + cmd + self.test.cmd_args + self.options.test_args)

    def _run_cmd(self, cmd: T.List[str]) -> TestRun:
        starttime = time.time()

        if len(self.test.extra_paths) > 0:
            self.env['PATH'] = os.pathsep.join(self.test.extra_paths + ['']) + self.env['PATH']
            winecmd = []
            for c in cmd:
                winecmd.append(c)
                if os.path.basename(c).startswith('wine'):
                    self.env['WINEPATH'] = get_wine_shortpath(
                        winecmd,
                        ['Z:' + p for p in self.test.extra_paths] + self.env.get('WINEPATH', '').split(';')
                    )
                    break

        # If MALLOC_PERTURB_ is not set, or if it is set to an empty value,
        # (i.e., the test or the environment don't explicitly set it), set
        # it ourselves. We do this unconditionally for regular tests
        # because it is extremely useful to have.
        # Setting MALLOC_PERTURB_="0" will completely disable this feature.
        if ('MALLOC_PERTURB_' not in self.env or not self.env['MALLOC_PERTURB_']) and not self.options.benchmark:
            self.env['MALLOC_PERTURB_'] = str(random.randint(1, 255))

        stdout = None
        stderr = None
        if not self.options.verbose:
            stdout = tempfile.TemporaryFile("wb+")
            stderr = tempfile.TemporaryFile("wb+") if self.options.split else stdout
        if self.test.protocol == 'tap' and stderr is stdout:
            stdout = tempfile.TemporaryFile("wb+")

        # Let gdb handle ^C instead of us
        if self.options.gdb:
            previous_sigint_handler = signal.getsignal(signal.SIGINT)
            # Make the meson executable ignore SIGINT while gdb is running.
            signal.signal(signal.SIGINT, signal.SIG_IGN)

        def preexec_fn() -> None:
            if self.options.gdb:
                # Restore the SIGINT handler for the child process to
                # ensure it can handle it.
                signal.signal(signal.SIGINT, signal.SIG_DFL)
            else:
                # We don't want setsid() in gdb because gdb needs the
                # terminal in order to handle ^C and not show tcsetpgrp()
                # errors avoid not being able to use the terminal.
                os.setsid()  # type: ignore

        p = subprocess.Popen(cmd,
                             stdout=stdout,
                             stderr=stderr,
                             env=self.env,
                             cwd=self.test.workdir,
                             preexec_fn=preexec_fn if not is_windows() else None)
        timed_out = False
        kill_test = False
        if self.test.timeout is None:
            timeout = None
        elif self.options.timeout_multiplier is not None:
            timeout = self.test.timeout * self.options.timeout_multiplier
        else:
            timeout = self.test.timeout
        try:
            p.communicate(timeout=timeout)
        except subprocess.TimeoutExpired:
            if self.options.verbose:
                print('{} time out (After {} seconds)'.format(self.test.name, timeout))
            timed_out = True
        except KeyboardInterrupt:
            mlog.warning('CTRL-C detected while running %s' % (self.test.name))
            kill_test = True
        finally:
            if self.options.gdb:
                # Let us accept ^C again
                signal.signal(signal.SIGINT, previous_sigint_handler)

        additional_error = None

        if kill_test or timed_out:
            # Python does not provide multiplatform support for
            # killing a process and all its children so we need
            # to roll our own.
            if is_windows():
                subprocess.run(['taskkill', '/F', '/T', '/PID', str(p.pid)])
            else:
                try:
                    # Kill the process group that setsid() created.
                    os.killpg(p.pid, signal.SIGKILL)  # type: ignore
                except ProcessLookupError:
                    # Sometimes (e.g. with Wine) this happens.
                    # There's nothing we can do (maybe the process
                    # already died) so carry on.
                    pass
            try:
                p.communicate(timeout=1)
            except subprocess.TimeoutExpired:
                # An earlier kill attempt has not worked for whatever reason.
                # Try to kill it one last time with a direct call.
                # If the process has spawned children, they will remain around.
                p.kill()
                try:
                    p.communicate(timeout=1)
                except subprocess.TimeoutExpired:
                    additional_error = 'Test process could not be killed.'
            except ValueError:
                additional_error = 'Could not read output. Maybe the process has redirected its stdout/stderr?'
        endtime = time.time()
        duration = endtime - starttime
        if additional_error is None:
            if stdout is None:
                stdo = ''
            else:
                stdout.seek(0)
                stdo = decode(stdout.read())
            if stderr is None or stderr is stdout:
                stde = ''
            else:
                stderr.seek(0)
                stde = decode(stderr.read())
        else:
            stdo = ""
            stde = additional_error
        if timed_out:
            return TestRun(self.test, self.test_env, TestResult.TIMEOUT, p.returncode, starttime, duration, stdo, stde, cmd)
        else:
            if self.test.protocol == 'exitcode':
                return TestRun.make_exitcode(self.test, self.test_env, p.returncode, starttime, duration, stdo, stde, cmd)
            else:
                if self.options.verbose:
                    print(stdo, end='')
                return TestRun.make_tap(self.test, self.test_env, p.returncode, starttime, duration, stdo, stde, cmd)


class TestHarness:
    def __init__(self, options: argparse.Namespace):
        self.options = options
        self.collected_logs = []  # type: T.List[str]
        self.fail_count = 0
        self.expectedfail_count = 0
        self.unexpectedpass_count = 0
        self.success_count = 0
        self.skip_count = 0
        self.timeout_count = 0
        self.is_run = False
        self.tests = None
        self.logfilename = None   # type: T.Optional[str]
        self.logfile = None       # type: T.Optional[T.TextIO]
        self.jsonlogfile = None   # type: T.Optional[T.TextIO]
        if self.options.benchmark:
            self.tests = load_benchmarks(options.wd)
        else:
            self.tests = load_tests(options.wd)
        ss = set()
        for t in self.tests:
            for s in t.suite:
                ss.add(s)
        self.suites = list(ss)

    def __del__(self) -> None:
        self.close_logfiles()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback) -> None:
        self.close_logfiles()

    def close_logfiles(self) -> None:
        if self.logfile:
            self.logfile.close()
            self.logfile = None
        if self.jsonlogfile:
            self.jsonlogfile.close()
            self.jsonlogfile = None

    def merge_suite_options(self, options: argparse.Namespace, test: 'TestSerialisation') -> T.Dict[str, str]:
        if ':' in options.setup:
            if options.setup not in self.build_data.test_setups:
                sys.exit("Unknown test setup '%s'." % options.setup)
            current = self.build_data.test_setups[options.setup]
        else:
            full_name = test.project_name + ":" + options.setup
            if full_name not in self.build_data.test_setups:
                sys.exit("Test setup '%s' not found from project '%s'." % (options.setup, test.project_name))
            current = self.build_data.test_setups[full_name]
        if not options.gdb:
            options.gdb = current.gdb
        if options.gdb:
            options.verbose = True
        if options.timeout_multiplier is None:
            options.timeout_multiplier = current.timeout_multiplier
    #    if options.env is None:
    #        options.env = current.env # FIXME, should probably merge options here.
        if options.wrapper is not None and current.exe_wrapper is not None:
            sys.exit('Conflict: both test setup and command line specify an exe wrapper.')
        if options.wrapper is None:
            options.wrapper = current.exe_wrapper
        return current.env.get_env(os.environ.copy())

    def get_test_runner(self, test: 'TestSerialisation') -> SingleTestRunner:
        options = deepcopy(self.options)
        if not options.setup:
            options.setup = self.build_data.test_setup_default_name
        if options.setup:
            env = self.merge_suite_options(options, test)
        else:
            env = os.environ.copy()
        test_env = test.env.get_env(env)
        env.update(test_env)
        return SingleTestRunner(test, test_env, env, options)

    def process_test_result(self, result: TestRun) -> None:
        if result.res is TestResult.TIMEOUT:
            self.timeout_count += 1
        elif result.res is TestResult.SKIP:
            self.skip_count += 1
        elif result.res is TestResult.OK:
            self.success_count += 1
        elif result.res is TestResult.FAIL or result.res is TestResult.ERROR:
            self.fail_count += 1
        elif result.res is TestResult.EXPECTEDFAIL:
            self.expectedfail_count += 1
        elif result.res is TestResult.UNEXPECTEDPASS:
            self.unexpectedpass_count += 1
        else:
            sys.exit('Unknown test result encountered: {}'.format(result.res))

    def print_stats(self, numlen: int, tests: T.List['TestSerialisation'],
                    name: str, result: TestRun, i: int) -> None:
        startpad = ' ' * (numlen - len('%d' % (i + 1)))
        num = '%s%d/%d' % (startpad, i + 1, len(tests))
        padding1 = ' ' * (38 - len(name))
        padding2 = ' ' * (8 - len(result.res.value))
        status = ''

        if result.res is TestResult.FAIL:
            status = returncode_to_status(result.returncode)
        result_str = '%s %s  %s%s%s%5.2f s %s' % \
            (num, name, padding1, result.res.value, padding2, result.duration,
             status)
        ok_statuses = (TestResult.OK, TestResult.EXPECTEDFAIL)
        bad_statuses = (TestResult.FAIL, TestResult.TIMEOUT, TestResult.UNEXPECTEDPASS,
                        TestResult.ERROR)
        if not self.options.quiet or result.res not in ok_statuses:
            if result.res not in ok_statuses and mlog.colorize_console:
                if result.res in bad_statuses:
                    decorator = mlog.red
                elif result.res is TestResult.SKIP:
                    decorator = mlog.yellow
                else:
                    sys.exit('Unreachable code was ... well ... reached.')
                print(decorator(result_str).get_text(True))
            else:
                print(result_str)
        result_str += "\n\n" + result.get_log()
        if result.res in bad_statuses:
            if self.options.print_errorlogs:
                self.collected_logs.append(result_str)
        if self.logfile:
            self.logfile.write(result_str)
        if self.jsonlogfile:
            write_json_log(self.jsonlogfile, name, result)

    def print_summary(self) -> None:
        msg = '''
Ok:                 %4d
Expected Fail:      %4d
Fail:               %4d
Unexpected Pass:    %4d
Skipped:            %4d
Timeout:            %4d
''' % (self.success_count, self.expectedfail_count, self.fail_count,
            self.unexpectedpass_count, self.skip_count, self.timeout_count)
        print(msg)
        if self.logfile:
            self.logfile.write(msg)

    def print_collected_logs(self) -> None:
        if len(self.collected_logs) > 0:
            if len(self.collected_logs) > 10:
                print('\nThe output from 10 first failed tests:\n')
            else:
                print('\nThe output from the failed tests:\n')
            for log in self.collected_logs[:10]:
                lines = log.splitlines()
                if len(lines) > 104:
                    print('\n'.join(lines[0:4]))
                    print('--- Listing only the last 100 lines from a long log. ---')
                    lines = lines[-100:]
                for line in lines:
                    try:
                        print(line)
                    except UnicodeEncodeError:
                        line = line.encode('ascii', errors='replace').decode()
                        print(line)

    def total_failure_count(self) -> int:
        return self.fail_count + self.unexpectedpass_count + self.timeout_count

    def doit(self) -> int:
        if self.is_run:
            raise RuntimeError('Test harness object can only be used once.')
        self.is_run = True
        tests = self.get_tests()
        if not tests:
            return 0
        self.run_tests(tests)
        return self.total_failure_count()

    @staticmethod
    def split_suite_string(suite: str) -> T.Tuple[str, str]:
        if ':' in suite:
            # mypy can't figure out that str.split(n, 1) will return a list of
            # length 2, so we have to help it.
            return T.cast(T.Tuple[str, str], tuple(suite.split(':', 1)))
        else:
            return suite, ""

    @staticmethod
    def test_in_suites(test: 'TestSerialisation', suites: T.List[str]) -> bool:
        for suite in suites:
            (prj_match, st_match) = TestHarness.split_suite_string(suite)
            for prjst in test.suite:
                (prj, st) = TestHarness.split_suite_string(prjst)

                # the SUITE can be passed as
                #     suite_name
                # or
                #     project_name:suite_name
                # so we need to select only the test belonging to project_name

                # this if handle the first case (i.e., SUITE == suite_name)

                # in this way we can run tests belonging to different
                # (sub)projects which share the same suite_name
                if not st_match and st == prj_match:
                    return True

                # these two conditions are needed to handle the second option
                # i.e., SUITE == project_name:suite_name

                # in this way we select the only the tests of
                # project_name with suite_name
                if prj_match and prj != prj_match:
                    continue
                if st_match and st != st_match:
                    continue
                return True
        return False

    def test_suitable(self, test: 'TestSerialisation') -> bool:
        return ((not self.options.include_suites or
                TestHarness.test_in_suites(test, self.options.include_suites)) and not
                TestHarness.test_in_suites(test, self.options.exclude_suites))

    def get_tests(self) -> T.List['TestSerialisation']:
        if not self.tests:
            print('No tests defined.')
            return []

        if len(self.options.include_suites) or len(self.options.exclude_suites):
            tests = []
            for tst in self.tests:
                if self.test_suitable(tst):
                    tests.append(tst)
        else:
            tests = self.tests

        # allow specifying test names like "meson test foo1 foo2", where test('foo1', ...)
        if self.options.args:
            tests = [t for t in tests if t.name in self.options.args]

        if not tests:
            print('No suitable tests defined.')
            return []

        return tests

    def open_log_files(self) -> None:
        if not self.options.logbase or self.options.verbose:
            return

        namebase = None
        logfile_base = os.path.join(self.options.wd, 'meson-logs', self.options.logbase)

        if self.options.wrapper:
            namebase = os.path.basename(self.get_wrapper(self.options)[0])
        elif self.options.setup:
            namebase = self.options.setup.replace(":", "_")

        if namebase:
            logfile_base += '-' + namebase.replace(' ', '_')
        self.logfilename = logfile_base + '.txt'
        self.jsonlogfilename = logfile_base + '.json'

        self.jsonlogfile = open(self.jsonlogfilename, 'w', encoding='utf-8', errors='replace')
        self.logfile = open(self.logfilename, 'w', encoding='utf-8', errors='surrogateescape')

        self.logfile.write('Log of Meson test suite run on %s\n\n'
                           % datetime.datetime.now().isoformat())
        inherit_env = env_tuple_to_str(os.environ.items())
        self.logfile.write('Inherited environment: {}\n\n'.format(inherit_env))

    @staticmethod
    def get_wrapper(options: argparse.Namespace) -> T.List[str]:
        wrap = []  # type: T.List[str]
        if options.gdb:
            wrap = [options.gdb_path, '--quiet', '--nh']
            if options.repeat > 1:
                wrap += ['-ex', 'run', '-ex', 'quit']
            # Signal the end of arguments to gdb
            wrap += ['--args']
        if options.wrapper:
            wrap += options.wrapper
        return wrap

    def get_pretty_suite(self, test: 'TestSerialisation') -> str:
        if len(self.suites) > 1 and test.suite:
            rv = TestHarness.split_suite_string(test.suite[0])[0]
            s = "+".join(TestHarness.split_suite_string(s)[1] for s in test.suite)
            if len(s):
                rv += ":"
            return rv + s + " / " + test.name
        else:
            return test.name

    def run_tests(self, tests: T.List['TestSerialisation']) -> None:
        executor = None
        futures = []  # type: T.List[T.Tuple[conc.Future[TestRun], int, T.List[TestSerialisation], str, int]]
        numlen = len('%d' % len(tests))
        self.open_log_files()
        startdir = os.getcwd()
        if self.options.wd:
            os.chdir(self.options.wd)
        self.build_data = build.load(os.getcwd())

        try:
            for _ in range(self.options.repeat):
                for i, test in enumerate(tests):
                    visible_name = self.get_pretty_suite(test)
                    single_test = self.get_test_runner(test)

                    if not test.is_parallel or self.options.num_processes == 1 or single_test.options.gdb:
                        self.drain_futures(futures)
                        futures = []
                        res = single_test.run()
                        self.process_test_result(res)
                        self.print_stats(numlen, tests, visible_name, res, i)
                    else:
                        if not executor:
                            executor = conc.ThreadPoolExecutor(max_workers=self.options.num_processes)
                        f = executor.submit(single_test.run)
                        futures.append((f, numlen, tests, visible_name, i))
                    if self.options.repeat > 1 and self.fail_count:
                        break
                if self.options.repeat > 1 and self.fail_count:
                    break

            self.drain_futures(futures)
            self.print_summary()
            self.print_collected_logs()

            if self.logfilename:
                print('Full log written to %s' % self.logfilename)
        finally:
            os.chdir(startdir)

    def drain_futures(self, futures: T.List[T.Tuple['conc.Future[TestRun]', int, T.List['TestSerialisation'], str, int]]) -> None:
        for x in futures:
            (result, numlen, tests, name, i) = x
            if self.options.repeat > 1 and self.fail_count:
                result.cancel()
            if self.options.verbose:
                result.result()
            self.process_test_result(result.result())
            self.print_stats(numlen, tests, name, result.result(), i)

    def run_special(self) -> int:
        '''Tests run by the user, usually something like "under gdb 1000 times".'''
        if self.is_run:
            raise RuntimeError('Can not use run_special after a full run.')
        tests = self.get_tests()
        if not tests:
            return 0
        self.run_tests(tests)
        return self.total_failure_count()


def list_tests(th: TestHarness) -> bool:
    tests = th.get_tests()
    for t in tests:
        print(th.get_pretty_suite(t))
    return not tests

def rebuild_all(wd: str) -> bool:
    if not (Path(wd) / 'build.ninja').is_file():
        print('Only ninja backend is supported to rebuild tests before running them.')
        return True

    ninja = environment.detect_ninja()
    if not ninja:
        print("Can't find ninja, can't rebuild test.")
        return False

    ret = subprocess.run([ninja, '-C', wd]).returncode
    if ret != 0:
        print('Could not rebuild {}'.format(wd))
        return False

    return True

def run(options: argparse.Namespace) -> int:
    if options.benchmark:
        options.num_processes = 1

    if options.verbose and options.quiet:
        print('Can not be both quiet and verbose at the same time.')
        return 1

    check_bin = None
    if options.gdb:
        options.verbose = True
        if options.wrapper:
            print('Must not specify both a wrapper and gdb at the same time.')
            return 1
        check_bin = 'gdb'

    if options.wrapper:
        check_bin = options.wrapper[0]

    if check_bin is not None:
        exe = ExternalProgram(check_bin, silent=True)
        if not exe.found():
            print('Could not find requested program: {!r}'.format(check_bin))
            return 1
    options.wd = os.path.abspath(options.wd)

    if not options.list and not options.no_rebuild:
        if not rebuild_all(options.wd):
            # We return 125 here in case the build failed.
            # The reason is that exit code 125 tells `git bisect run` that the current commit should be skipped.
            # Thus users can directly use `meson test` to bisect without needing to handle the does-not-build case separately in a wrapper script.
            return 125

    with TestHarness(options) as th:
        try:
            if options.list:
                return list_tests(th)
            if not options.args:
                return th.doit()
            return th.run_special()
        except TestException as e:
            print('Meson test encountered an error:\n')
            if os.environ.get('MESON_FORCE_BACKTRACE'):
                raise e
            else:
                print(e)
            return 1

def run_with_args(args: T.List[str]) -> int:
    parser = argparse.ArgumentParser(prog='meson test')
    add_arguments(parser)
    options = parser.parse_args(args)
    return run(options)
meson-0.53.2/mesonbuild/munstable_coredata.py0000644000175000017500000001074413571777336022714 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


from . import coredata as cdata
from .mesonlib import MachineChoice

import os.path
import pprint
import textwrap

def add_arguments(parser):
    parser.add_argument('--all', action='store_true', dest='all', default=False,
                        help='Show data not used by current backend.')

    parser.add_argument('builddir', nargs='?', default='.', help='The build directory')


def dump_compilers(compilers):
    for lang, compiler in compilers.items():
        print('  ' + lang + ':')
        print('      Id: ' + compiler.id)
        print('      Command: ' + ' '.join(compiler.exelist))
        if compiler.full_version:
            print('      Full version: ' + compiler.full_version)
        if compiler.version:
            print('      Detected version: ' + compiler.version)


def dump_guids(d):
    for name, value in d.items():
        print('  ' + name + ': ' + value)


def run(options):
    datadir = 'meson-private'
    if options.builddir is not None:
        datadir = os.path.join(options.builddir, datadir)
    if not os.path.isdir(datadir):
        print('Current directory is not a build dir. Please specify it or '
              'change the working directory to it.')
        return 1

    all_backends = options.all

    print('This is a dump of the internal unstable cache of meson. This is for debugging only.')
    print('Do NOT parse, this will change from version to version in incompatible ways')
    print('')

    coredata = cdata.load(options.builddir)
    backend = coredata.get_builtin_option('backend')
    for k, v in sorted(coredata.__dict__.items()):
        if k in ('backend_options', 'base_options', 'builtins', 'compiler_options', 'user_options'):
            # use `meson configure` to view these
            pass
        elif k in ['install_guid', 'test_guid', 'regen_guid']:
            if all_backends or backend.startswith('vs'):
                print(k + ': ' + v)
        elif k == 'target_guids':
            if all_backends or backend.startswith('vs'):
                print(k + ':')
                dump_guids(v)
        elif k in ['lang_guids']:
            if all_backends or backend.startswith('vs') or backend == 'xcode':
                print(k + ':')
                dump_guids(v)
        elif k == 'meson_command':
            if all_backends or backend.startswith('vs'):
                print('Meson command used in build file regeneration: ' + ' '.join(v))
        elif k == 'pkgconf_envvar':
            print('Last seen PKGCONFIG environment variable value: ' + v)
        elif k == 'version':
            print('Meson version: ' + v)
        elif k == 'cross_files':
            if v:
                print('Cross File: ' + ' '.join(v))
        elif k == 'config_files':
            if v:
                print('Native File: ' + ' '.join(v))
        elif k == 'compilers':
            for for_machine in MachineChoice:
                print('Cached {} machine compilers:'.format(
                    for_machine.get_lower_case_name()))
                dump_compilers(v[for_machine])
        elif k == 'deps':
            def print_dep(dep_key, dep):
                print('  ' + dep_key[0] + ": ")
                print('      compile args: ' + repr(dep.get_compile_args()))
                print('      link args: ' + repr(dep.get_link_args()))
                if dep.get_sources():
                    print('      sources: ' + repr(dep.get_sources()))
                print('      version: ' + repr(dep.get_version()))

            for for_machine in iter(MachineChoice):
                items_list = list(sorted(v[for_machine].items()))
                if items_list:
                    print('Cached dependencies for {} machine' % for_machine.get_lower_case_name())
                    for dep_key, deps in items_list:
                        for dep in deps:
                            print_dep(dep_key, dep)
        else:
            print(k + ':')
            print(textwrap.indent(pprint.pformat(v), '  '))
meson-0.53.2/mesonbuild/optinterpreter.py0000644000175000017500000002201613612313307022115 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2014 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os, re
import functools
import typing as T

from . import mparser
from . import coredata
from . import mesonlib
from . import compilers

forbidden_option_names = set(coredata.builtin_options.keys())
forbidden_prefixes = [lang + '_' for lang in compilers.all_languages] + ['b_', 'backend_']
reserved_prefixes = ['cross_']

def is_invalid_name(name: str, *, log: bool = True) -> bool:
    if name in forbidden_option_names:
        return True
    pref = name.split('_')[0] + '_'
    if pref in forbidden_prefixes:
        return True
    if pref in reserved_prefixes:
        if log:
            from . import mlog
            mlog.deprecation('Option uses prefix "%s", which is reserved for Meson. This will become an error in the future.' % pref)
    return False

class OptionException(mesonlib.MesonException):
    pass


def permitted_kwargs(permitted):
    """Function that validates kwargs for options."""
    def _wraps(func):
        @functools.wraps(func)
        def _inner(name, description, kwargs):
            bad = [a for a in kwargs.keys() if a not in permitted]
            if bad:
                raise OptionException('Invalid kwargs for option "{}": "{}"'.format(
                    name, ' '.join(bad)))
            return func(description, kwargs)
        return _inner
    return _wraps


optname_regex = re.compile('[^a-zA-Z0-9_-]')

@permitted_kwargs({'value', 'yield'})
def StringParser(description, kwargs):
    return coredata.UserStringOption(description,
                                     kwargs.get('value', ''),
                                     kwargs.get('choices', []),
                                     kwargs.get('yield', coredata.default_yielding))

@permitted_kwargs({'value', 'yield'})
def BooleanParser(description, kwargs):
    return coredata.UserBooleanOption(description,
                                      kwargs.get('value', True),
                                      kwargs.get('yield', coredata.default_yielding))

@permitted_kwargs({'value', 'yield', 'choices'})
def ComboParser(description, kwargs):
    if 'choices' not in kwargs:
        raise OptionException('Combo option missing "choices" keyword.')
    choices = kwargs['choices']
    if not isinstance(choices, list):
        raise OptionException('Combo choices must be an array.')
    for i in choices:
        if not isinstance(i, str):
            raise OptionException('Combo choice elements must be strings.')
    return coredata.UserComboOption(description,
                                    choices,
                                    kwargs.get('value', choices[0]),
                                    kwargs.get('yield', coredata.default_yielding),)


@permitted_kwargs({'value', 'min', 'max', 'yield'})
def IntegerParser(description, kwargs):
    if 'value' not in kwargs:
        raise OptionException('Integer option must contain value argument.')
    return coredata.UserIntegerOption(description,
                                      kwargs.get('min', None),
                                      kwargs.get('max', None),
                                      kwargs['value'],
                                      kwargs.get('yield', coredata.default_yielding))

# FIXME: Cannot use FeatureNew while parsing options because we parse it before
# reading options in project(). See func_project() in interpreter.py
#@FeatureNew('array type option()', '0.44.0')
@permitted_kwargs({'value', 'yield', 'choices'})
def string_array_parser(description, kwargs):
    if 'choices' in kwargs:
        choices = kwargs['choices']
        if not isinstance(choices, list):
            raise OptionException('Array choices must be an array.')
        for i in choices:
            if not isinstance(i, str):
                raise OptionException('Array choice elements must be strings.')
            value = kwargs.get('value', choices)
    else:
        choices = None
        value = kwargs.get('value', [])
    if not isinstance(value, list):
        raise OptionException('Array choices must be passed as an array.')
    return coredata.UserArrayOption(description,
                                    value,
                                    choices=choices,
                                    yielding=kwargs.get('yield', coredata.default_yielding))

@permitted_kwargs({'value', 'yield'})
def FeatureParser(description, kwargs):
    return coredata.UserFeatureOption(description,
                                      kwargs.get('value', 'auto'),
                                      yielding=kwargs.get('yield', coredata.default_yielding))

option_types = {'string': StringParser,
                'boolean': BooleanParser,
                'combo': ComboParser,
                'integer': IntegerParser,
                'array': string_array_parser,
                'feature': FeatureParser,
                } # type: T.Dict[str, T.Callable[[str, T.Dict], coredata.UserOption]]

class OptionInterpreter:
    def __init__(self, subproject):
        self.options = {}
        self.subproject = subproject

    def process(self, option_file):
        try:
            with open(option_file, 'r', encoding='utf8') as f:
                ast = mparser.Parser(f.read(), '').parse()
        except mesonlib.MesonException as me:
            me.file = option_file
            raise me
        if not isinstance(ast, mparser.CodeBlockNode):
            e = OptionException('Option file is malformed.')
            e.lineno = ast.lineno()
            raise e
        for cur in ast.lines:
            try:
                self.evaluate_statement(cur)
            except Exception as e:
                e.lineno = cur.lineno
                e.colno = cur.colno
                e.file = os.path.join('meson_options.txt')
                raise e

    def reduce_single(self, arg):
        if isinstance(arg, str):
            return arg
        elif isinstance(arg, (mparser.StringNode, mparser.BooleanNode,
                              mparser.NumberNode)):
            return arg.value
        elif isinstance(arg, mparser.ArrayNode):
            return [self.reduce_single(curarg) for curarg in arg.args.arguments]
        else:
            raise OptionException('Arguments may only be string, int, bool, or array of those.')

    def reduce_arguments(self, args):
        assert(isinstance(args, mparser.ArgumentNode))
        if args.incorrect_order():
            raise OptionException('All keyword arguments must be after positional arguments.')
        reduced_pos = [self.reduce_single(arg) for arg in args.arguments]
        reduced_kw = {}
        for key in args.kwargs.keys():
            if not isinstance(key, str):
                raise OptionException('Keyword argument name is not a string.')
            a = args.kwargs[key]
            reduced_kw[key] = self.reduce_single(a)
        return reduced_pos, reduced_kw

    def evaluate_statement(self, node):
        if not isinstance(node, mparser.FunctionNode):
            raise OptionException('Option file may only contain option definitions')
        func_name = node.func_name
        if func_name != 'option':
            raise OptionException('Only calls to option() are allowed in option files.')
        (posargs, kwargs) = self.reduce_arguments(node.args)

        # FIXME: Cannot use FeatureNew while parsing options because we parse
        # it before reading options in project(). See func_project() in
        # interpreter.py
        #if 'yield' in kwargs:
        #    FeatureNew('option yield', '0.45.0').use(self.subproject)

        if 'type' not in kwargs:
            raise OptionException('Option call missing mandatory "type" keyword argument')
        opt_type = kwargs.pop('type')
        if opt_type not in option_types:
            raise OptionException('Unknown type %s.' % opt_type)
        if len(posargs) != 1:
            raise OptionException('Option() must have one (and only one) positional argument')
        opt_name = posargs[0]
        if not isinstance(opt_name, str):
            raise OptionException('Positional argument must be a string.')
        if optname_regex.search(opt_name) is not None:
            raise OptionException('Option names can only contain letters, numbers or dashes.')
        if is_invalid_name(opt_name):
            raise OptionException('Option name %s is reserved.' % opt_name)
        if self.subproject != '':
            opt_name = self.subproject + ':' + opt_name
        opt = option_types[opt_type](opt_name, kwargs.pop('description', ''), kwargs)
        if opt.description == '':
            opt.description = opt_name
        self.options[opt_name] = opt
meson-0.53.2/mesonbuild/rewriter.py0000644000175000017500000011220513612313307020672 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3
# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This class contains the basic functionality needed to run any interpreter
# or an interpreter-based tool.

# This tool is used to manipulate an existing Meson build definition.
#
# - add a file to a target
# - remove files from a target
# - move targets
# - reindent?

from .ast import IntrospectionInterpreter, build_target_functions, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstPrinter
from mesonbuild.mesonlib import MesonException
from . import mlog, environment
from functools import wraps
from .mparser import Token, ArrayNode, ArgumentNode, AssignmentNode, BaseNode, BooleanNode, ElementaryNode, IdNode, FunctionNode, StringNode
import json, os, re, sys
import typing as T

class RewriterException(MesonException):
    pass

def add_arguments(parser, formatter=None):
    parser.add_argument('-s', '--sourcedir', type=str, default='.', metavar='SRCDIR', help='Path to source directory.')
    parser.add_argument('-V', '--verbose', action='store_true', default=False, help='Enable verbose output')
    parser.add_argument('-S', '--skip-errors', dest='skip', action='store_true', default=False, help='Skip errors instead of aborting')
    subparsers = parser.add_subparsers(dest='type', title='Rewriter commands', description='Rewrite command to execute')

    # Target
    tgt_parser = subparsers.add_parser('target', help='Modify a target', formatter_class=formatter)
    tgt_parser.add_argument('-s', '--subdir', default='', dest='subdir', help='Subdirectory of the new target (only for the "add_target" action)')
    tgt_parser.add_argument('--type', dest='tgt_type', choices=rewriter_keys['target']['target_type'][2], default='executable',
                            help='Type of the target to add (only for the "add_target" action)')
    tgt_parser.add_argument('target', help='Name or ID of the target')
    tgt_parser.add_argument('operation', choices=['add', 'rm', 'add_target', 'rm_target', 'info'],
                            help='Action to execute')
    tgt_parser.add_argument('sources', nargs='*', help='Sources to add/remove')

    # KWARGS
    kw_parser = subparsers.add_parser('kwargs', help='Modify keyword arguments', formatter_class=formatter)
    kw_parser.add_argument('operation', choices=rewriter_keys['kwargs']['operation'][2],
                           help='Action to execute')
    kw_parser.add_argument('function', choices=list(rewriter_func_kwargs.keys()),
                           help='Function type to modify')
    kw_parser.add_argument('id', help='ID of the function to modify (can be anything for "project")')
    kw_parser.add_argument('kwargs', nargs='*', help='Pairs of keyword and value')

    # Default options
    def_parser = subparsers.add_parser('default-options', help='Modify the project default options', formatter_class=formatter)
    def_parser.add_argument('operation', choices=rewriter_keys['default_options']['operation'][2],
                            help='Action to execute')
    def_parser.add_argument('options', nargs='*', help='Key, value pairs of configuration option')

    # JSON file/command
    cmd_parser = subparsers.add_parser('command', help='Execute a JSON array of commands', formatter_class=formatter)
    cmd_parser.add_argument('json', help='JSON string or file to execute')

class RequiredKeys:
    def __init__(self, keys):
        self.keys = keys

    def __call__(self, f):
        @wraps(f)
        def wrapped(*wrapped_args, **wrapped_kwargs):
            assert(len(wrapped_args) >= 2)
            cmd = wrapped_args[1]
            for key, val in self.keys.items():
                typ = val[0] # The type of the value
                default = val[1] # The default value -- None is required
                choices = val[2] # Valid choices -- None is for everything
                if key not in cmd:
                    if default is not None:
                        cmd[key] = default
                    else:
                        raise RewriterException('Key "{}" is missing in object for {}'
                                                .format(key, f.__name__))
                if not isinstance(cmd[key], typ):
                    raise RewriterException('Invalid type of "{}". Required is {} but provided was {}'
                                            .format(key, typ.__name__, type(cmd[key]).__name__))
                if choices is not None:
                    assert(isinstance(choices, list))
                    if cmd[key] not in choices:
                        raise RewriterException('Invalid value of "{}": Possible values are {} but provided was "{}"'
                                                .format(key, choices, cmd[key]))
            return f(*wrapped_args, **wrapped_kwargs)

        return wrapped

class MTypeBase:
    def __init__(self, node: T.Optional[BaseNode] = None):
        if node is None:
            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():  # lgtm [py/init-calls-subclass] (listing nodes does not depend on base class state)
            if isinstance(self.node, i):
                self.node_type = i

    def _new_node(self):
        # Overwrite in derived class
        return BaseNode()

    def can_modify(self):
        return self.node_type is not None

    def get_node(self):
        return self.node

    def supported_nodes(self):
        # Overwrite in derived class
        return []

    def set_value(self, value):
        # Overwrite in derived class
        mlog.warning('Cannot set the value of type', mlog.bold(type(self).__name__), '--> skipping')

    def add_value(self, value):
        # Overwrite in derived class
        mlog.warning('Cannot add a value of type', mlog.bold(type(self).__name__), '--> skipping')

    def remove_value(self, value):
        # Overwrite in derived class
        mlog.warning('Cannot remove a value of type', mlog.bold(type(self).__name__), '--> skipping')

    def remove_regex(self, value):
        # Overwrite in derived class
        mlog.warning('Cannot remove a regex in type', mlog.bold(type(self).__name__), '--> skipping')

class MTypeStr(MTypeBase):
    def __init__(self, node: T.Optional[BaseNode] = None):
        super().__init__(node)

    def _new_node(self):
        return StringNode(Token('', '', 0, 0, 0, None, ''))

    def supported_nodes(self):
        return [StringNode]

    def set_value(self, value):
        self.node.value = str(value)

class MTypeBool(MTypeBase):
    def __init__(self, node: T.Optional[BaseNode] = None):
        super().__init__(node)

    def _new_node(self):
        return StringNode(Token('', '', 0, 0, 0, None, False))

    def supported_nodes(self):
        return [BooleanNode]

    def set_value(self, value):
        self.node.value = bool(value)

class MTypeID(MTypeBase):
    def __init__(self, node: T.Optional[BaseNode] = None):
        super().__init__(node)

    def _new_node(self):
        return StringNode(Token('', '', 0, 0, 0, None, ''))

    def supported_nodes(self):
        return [IdNode]

    def set_value(self, value):
        self.node.value = str(value)

class MTypeList(MTypeBase):
    def __init__(self, node: T.Optional[BaseNode] = None):
        super().__init__(node)

    def _new_node(self):
        return ArrayNode(ArgumentNode(Token('', '', 0, 0, 0, None, '')), 0, 0, 0, 0)

    def _new_element_node(self, value):
        # Overwrite in derived class
        return BaseNode()

    def _ensure_array_node(self):
        if not isinstance(self.node, ArrayNode):
            tmp = self.node
            self.node = self._new_node()
            self.node.args.arguments += [tmp]

    def _check_is_equal(self, node, value) -> bool:
        # Overwrite in derived class
        return False

    def _check_regex_matches(self, node, regex: str) -> bool:
        # Overwrite in derived class
        return False

    def get_node(self):
        if isinstance(self.node, ArrayNode):
            if len(self.node.args.arguments) == 1:
                return self.node.args.arguments[0]
        return self.node

    def supported_element_nodes(self):
        # Overwrite in derived class
        return []

    def supported_nodes(self):
        return [ArrayNode] + self.supported_element_nodes()

    def set_value(self, value):
        if not isinstance(value, list):
            value = [value]
        self._ensure_array_node()
        self.node.args.arguments = [] # Remove all current nodes
        for i in value:
            self.node.args.arguments += [self._new_element_node(i)]

    def add_value(self, value):
        if not isinstance(value, list):
            value = [value]
        self._ensure_array_node()
        for i in value:
            self.node.args.arguments += [self._new_element_node(i)]

    def _remove_helper(self, value, equal_func):
        def check_remove_node(node):
            for j in value:
                if equal_func(i, j):
                    return True
            return False

        if not isinstance(value, list):
            value = [value]
        self._ensure_array_node()
        removed_list = []
        for i in self.node.args.arguments:
            if not check_remove_node(i):
                removed_list += [i]
        self.node.args.arguments = removed_list

    def remove_value(self, value):
        self._remove_helper(value, self._check_is_equal)

    def remove_regex(self, regex: str):
        self._remove_helper(regex, self._check_regex_matches)

class MTypeStrList(MTypeList):
    def __init__(self, node: T.Optional[BaseNode] = None):
        super().__init__(node)

    def _new_element_node(self, value):
        return StringNode(Token('', '', 0, 0, 0, None, str(value)))

    def _check_is_equal(self, node, value) -> bool:
        if isinstance(node, StringNode):
            return node.value == value
        return False

    def _check_regex_matches(self, node, regex: str) -> bool:
        if isinstance(node, StringNode):
            return re.match(regex, node.value) is not None
        return False

    def supported_element_nodes(self):
        return [StringNode]

class MTypeIDList(MTypeList):
    def __init__(self, node: T.Optional[BaseNode] = None):
        super().__init__(node)

    def _new_element_node(self, value):
        return IdNode(Token('', '', 0, 0, 0, None, str(value)))

    def _check_is_equal(self, node, value) -> bool:
        if isinstance(node, IdNode):
            return node.value == value
        return False

    def _check_regex_matches(self, node, regex: str) -> bool:
        if isinstance(node, StringNode):
            return re.match(regex, node.value) is not None
        return False

    def supported_element_nodes(self):
        return [IdNode]

rewriter_keys = {
    'default_options': {
        'operation': (str, None, ['set', 'delete']),
        'options': (dict, {}, None)
    },
    'kwargs': {
        'function': (str, None, None),
        'id': (str, None, None),
        'operation': (str, None, ['set', 'delete', 'add', 'remove', 'remove_regex', 'info']),
        'kwargs': (dict, {}, None)
    },
    'target': {
        'target': (str, None, None),
        'operation': (str, None, ['src_add', 'src_rm', 'target_rm', 'target_add', 'info']),
        'sources': (list, [], None),
        'subdir': (str, '', None),
        'target_type': (str, 'executable', ['both_libraries', 'executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library']),
    }
}

rewriter_func_kwargs = {
    'dependency': {
        'language': MTypeStr,
        'method': MTypeStr,
        'native': MTypeBool,
        'not_found_message': MTypeStr,
        'required': MTypeBool,
        'static': MTypeBool,
        'version': MTypeStrList,
        'modules': MTypeStrList
    },
    'target': {
        'build_by_default': MTypeBool,
        'build_rpath': MTypeStr,
        'dependencies': MTypeIDList,
        'gui_app': MTypeBool,
        'link_with': MTypeIDList,
        'export_dynamic': MTypeBool,
        'implib': MTypeBool,
        'install': MTypeBool,
        'install_dir': MTypeStr,
        'install_rpath': MTypeStr,
        'pie': MTypeBool
    },
    'project': {
        'default_options': MTypeStrList,
        'meson_version': MTypeStr,
        'license': MTypeStrList,
        'subproject_dir': MTypeStr,
        'version': MTypeStr
    }
}

class Rewriter:
    def __init__(self, sourcedir: str, generator: str = 'ninja', skip_errors: bool = False):
        self.sourcedir = sourcedir
        self.interpreter = IntrospectionInterpreter(sourcedir, '', generator, visitors = [AstIDGenerator(), AstIndentationGenerator(), AstConditionLevel()])
        self.skip_errors = skip_errors
        self.modefied_nodes = []
        self.to_remove_nodes = []
        self.to_add_nodes = []
        self.functions = {
            'default_options': self.process_default_options,
            'kwargs': self.process_kwargs,
            'target': self.process_target,
        }
        self.info_dump = None

    def analyze_meson(self):
        mlog.log('Analyzing meson file:', mlog.bold(os.path.join(self.sourcedir, environment.build_filename)))
        self.interpreter.analyze()
        mlog.log('  -- Project:', mlog.bold(self.interpreter.project_data['descriptive_name']))
        mlog.log('  -- Version:', mlog.cyan(self.interpreter.project_data['version']))

    def add_info(self, cmd_type: str, cmd_id: str, data: dict):
        if self.info_dump is None:
            self.info_dump = {}
        if cmd_type not in self.info_dump:
            self.info_dump[cmd_type] = {}
        self.info_dump[cmd_type][cmd_id] = data

    def print_info(self):
        if self.info_dump is None:
            return
        sys.stderr.write(json.dumps(self.info_dump, indent=2))

    def on_error(self):
        if self.skip_errors:
            return mlog.cyan('-->'), mlog.yellow('skipping')
        return mlog.cyan('-->'), mlog.red('aborting')

    def handle_error(self):
        if self.skip_errors:
            return None
        raise MesonException('Rewriting the meson.build failed')

    def find_target(self, target: str):
        def check_list(name: str) -> T.List[BaseNode]:
            result = []
            for i in self.interpreter.targets:
                if name == i['name'] or name == i['id']:
                    result += [i]
            return result

        targets = check_list(target)
        if targets:
            if len(targets) == 1:
                return targets[0]
            else:
                mlog.error('There are multiple targets matching', mlog.bold(target))
                for i in targets:
                    mlog.error('  -- Target name', mlog.bold(i['name']), 'with ID', mlog.bold(i['id']))
                mlog.error('Please try again with the unique ID of the target', *self.on_error())
                self.handle_error()
                return None

        # Check the assignments
        tgt = None
        if target in self.interpreter.assignments:
            node = self.interpreter.assignments[target][0]
            if isinstance(node, FunctionNode):
                if node.func_name in ['executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries']:
                    tgt = self.interpreter.assign_vals[target][0]

        return tgt

    def find_dependency(self, dependency: str):
        def check_list(name: str):
            for i in self.interpreter.dependencies:
                if name == i['name']:
                    return i
            return None

        dep = check_list(dependency)
        if dep is not None:
            return dep

        # Check the assignments
        if dependency in self.interpreter.assignments:
            node = self.interpreter.assignments[dependency][0]
            if isinstance(node, FunctionNode):
                if node.func_name in ['dependency']:
                    name = self.interpreter.flatten_args(node.args)[0]
                    dep = check_list(name)

        return dep

    @RequiredKeys(rewriter_keys['default_options'])
    def process_default_options(self, cmd):
        # First, remove the old values
        kwargs_cmd = {
            'function': 'project',
            'id': "/",
            'operation': 'remove_regex',
            'kwargs': {
                'default_options': ['{}=.*'.format(x) for x in cmd['options'].keys()]
            }
        }
        self.process_kwargs(kwargs_cmd)

        # Then add the new values
        if cmd['operation'] != 'set':
            return

        kwargs_cmd['operation'] = 'add'
        kwargs_cmd['kwargs']['default_options'] = []

        cdata = self.interpreter.coredata
        options = {
            **cdata.builtins,
            **cdata.builtins_per_machine.host,
            **{'build.' + k: o for k, o in cdata.builtins_per_machine.build.items()},
            **cdata.backend_options,
            **cdata.base_options,
            **cdata.compiler_options.host,
            **{'build.' + k: o for k, o in cdata.compiler_options.build.items()},
            **cdata.user_options,
        }

        for key, val in sorted(cmd['options'].items()):
            if key not in options:
                mlog.error('Unknown options', mlog.bold(key), *self.on_error())
                self.handle_error()
                continue

            try:
                val = options[key].validate_value(val)
            except MesonException as e:
                mlog.error('Unable to set', mlog.bold(key), mlog.red(str(e)), *self.on_error())
                self.handle_error()
                continue

            kwargs_cmd['kwargs']['default_options'] += ['{}={}'.format(key, val)]

        self.process_kwargs(kwargs_cmd)

    @RequiredKeys(rewriter_keys['kwargs'])
    def process_kwargs(self, cmd):
        mlog.log('Processing function type', mlog.bold(cmd['function']), 'with id', mlog.cyan("'" + cmd['id'] + "'"))
        if cmd['function'] not in rewriter_func_kwargs:
            mlog.error('Unknown function type', cmd['function'], *self.on_error())
            return self.handle_error()
        kwargs_def = rewriter_func_kwargs[cmd['function']]

        # Find the function node to modify
        node = None
        arg_node = None
        if cmd['function'] == 'project':
            if cmd['id'] != '/':
                mlog.error('The ID for the function type project must be "/"', *self.on_error())
                return self.handle_error()
            node = self.interpreter.project_node
            arg_node = node.args
        elif cmd['function'] == 'target':
            tmp = self.find_target(cmd['id'])
            if tmp:
                node = tmp['node']
                arg_node = node.args
        elif cmd['function'] == 'dependency':
            tmp = self.find_dependency(cmd['id'])
            if tmp:
                node = tmp['node']
                arg_node = node.args
        if not node:
            mlog.error('Unable to find the function node')
        assert(isinstance(node, FunctionNode))
        assert(isinstance(arg_node, ArgumentNode))

        # Print kwargs info
        if cmd['operation'] == 'info':
            info_data = {}
            for key, val in sorted(arg_node.kwargs.items()):
                info_data[key] = None
                if isinstance(val, ElementaryNode):
                    info_data[key] = val.value
                elif isinstance(val, ArrayNode):
                    data_list = []
                    for i in val.args.arguments:
                        element = None
                        if isinstance(i, ElementaryNode):
                            element = i.value
                        data_list += [element]
                    info_data[key] = data_list

            self.add_info('kwargs', '{}#{}'.format(cmd['function'], cmd['id']), info_data)
            return # Nothing else to do

        # Modify the kwargs
        num_changed = 0
        for key, val in sorted(cmd['kwargs'].items()):
            if key not in kwargs_def:
                mlog.error('Cannot modify unknown kwarg', mlog.bold(key), *self.on_error())
                self.handle_error()
                continue

            # Remove the key from the kwargs
            if cmd['operation'] == 'delete':
                if key in arg_node.kwargs:
                    mlog.log('  -- Deleting', mlog.bold(key), 'from the kwargs')
                    del arg_node.kwargs[key]
                    num_changed += 1
                else:
                    mlog.log('  -- Key', mlog.bold(key), 'is already deleted')
                continue

            if key not in arg_node.kwargs:
                arg_node.kwargs[key] = None
            modifyer = kwargs_def[key](arg_node.kwargs[key])
            if not modifyer.can_modify():
                mlog.log('  -- Skipping', mlog.bold(key), 'because it is to complex to modify')

            # Apply the operation
            val_str = str(val)
            if cmd['operation'] == 'set':
                mlog.log('  -- Setting', mlog.bold(key), 'to', mlog.yellow(val_str))
                modifyer.set_value(val)
            elif cmd['operation'] == 'add':
                mlog.log('  -- Adding', mlog.yellow(val_str), 'to', mlog.bold(key))
                modifyer.add_value(val)
            elif cmd['operation'] == 'remove':
                mlog.log('  -- Removing', mlog.yellow(val_str), 'from', mlog.bold(key))
                modifyer.remove_value(val)
            elif cmd['operation'] == 'remove_regex':
                mlog.log('  -- Removing all values matching', mlog.yellow(val_str), 'from', mlog.bold(key))
                modifyer.remove_regex(val)

            # Write back the result
            arg_node.kwargs[key] = modifyer.get_node()
            num_changed += 1

        if num_changed > 0 and node not in self.modefied_nodes:
            self.modefied_nodes += [node]

    def find_assignment_node(self, node: BaseNode) -> AssignmentNode:
        if hasattr(node, 'ast_id') and node.ast_id in self.interpreter.reverse_assignment:
            return self.interpreter.reverse_assignment[node.ast_id]
        return None

    @RequiredKeys(rewriter_keys['target'])
    def process_target(self, cmd):
        mlog.log('Processing target', mlog.bold(cmd['target']), 'operation', mlog.cyan(cmd['operation']))
        target = self.find_target(cmd['target'])
        if target is None and cmd['operation'] != 'target_add':
            mlog.error('Unknown target', mlog.bold(cmd['target']), *self.on_error())
            return self.handle_error()

        # Make source paths relative to the current subdir
        def rel_source(src: str) -> str:
            subdir = os.path.abspath(os.path.join(self.sourcedir, target['subdir']))
            if os.path.isabs(src):
                return os.path.relpath(src, subdir)
            elif not os.path.exists(src):
                return src # Trust the user when the source doesn't exist
            # Make sure that the path is relative to the subdir
            return os.path.relpath(os.path.abspath(src), subdir)

        if target is not None:
            cmd['sources'] = [rel_source(x) for x in cmd['sources']]

        # Utility function to get a list of the sources from a node
        def arg_list_from_node(n):
            args = []
            if isinstance(n, FunctionNode):
                args = list(n.args.arguments)
                if n.func_name in build_target_functions:
                    args.pop(0)
            elif isinstance(n, ArrayNode):
                args = n.args.arguments
            elif isinstance(n, ArgumentNode):
                args = n.arguments
            return args

        to_sort_nodes = []

        if cmd['operation'] == 'src_add':
            node = None
            if target['sources']:
                node = target['sources'][0]
            else:
                node = target['node']
            assert(node is not None)

            # Generate the current source list
            src_list = []
            for i in target['sources']:
                for j in arg_list_from_node(i):
                    if isinstance(j, StringNode):
                        src_list += [j.value]

            # Generate the new String nodes
            to_append = []
            for i in sorted(set(cmd['sources'])):
                if i in src_list:
                    mlog.log('  -- Source', mlog.green(i), 'is already defined for the target --> skipping')
                    continue
                mlog.log('  -- Adding source', mlog.green(i), 'at',
                         mlog.yellow('{}:{}'.format(os.path.join(node.subdir, environment.build_filename), node.lineno)))
                token = Token('string', node.subdir, 0, 0, 0, None, i)
                to_append += [StringNode(token)]

            # Append to the AST at the right place
            arg_node = None
            if isinstance(node, (FunctionNode, ArrayNode)):
                arg_node = node.args
            elif isinstance(node, ArgumentNode):
                arg_node = node
            assert(arg_node is not None)
            arg_node.arguments += to_append

            # Mark the node as modified
            if arg_node not in to_sort_nodes and not isinstance(node, FunctionNode):
                to_sort_nodes += [arg_node]
            if node not in self.modefied_nodes:
                self.modefied_nodes += [node]

        elif cmd['operation'] == 'src_rm':
            # Helper to find the exact string node and its parent
            def find_node(src):
                for i in target['sources']:
                    for j in arg_list_from_node(i):
                        if isinstance(j, StringNode):
                            if j.value == src:
                                return i, j
                return None, None

            for i in cmd['sources']:
                # Try to find the node with the source string
                root, string_node = find_node(i)
                if root is None:
                    mlog.warning('  -- Unable to find source', mlog.green(i), 'in the target')
                    continue

                # Remove the found string node from the argument list
                arg_node = None
                if isinstance(root, (FunctionNode, ArrayNode)):
                    arg_node = root.args
                elif isinstance(root, ArgumentNode):
                    arg_node = root
                assert(arg_node is not None)
                mlog.log('  -- Removing source', mlog.green(i), 'from',
                         mlog.yellow('{}:{}'.format(os.path.join(string_node.subdir, environment.build_filename), string_node.lineno)))
                arg_node.arguments.remove(string_node)

                # Mark the node as modified
                if arg_node not in to_sort_nodes and not isinstance(root, FunctionNode):
                    to_sort_nodes += [arg_node]
                if root not in self.modefied_nodes:
                    self.modefied_nodes += [root]

        elif cmd['operation'] == 'target_add':
            if target is not None:
                mlog.error('Can not add target', mlog.bold(cmd['target']), 'because it already exists', *self.on_error())
                return self.handle_error()

            id_base = re.sub(r'[- ]', '_', cmd['target'])
            target_id = id_base + '_exe' if cmd['target_type'] == 'executable' else '_lib'
            source_id = id_base + '_sources'

            # Build src list
            src_arg_node = ArgumentNode(Token('string', cmd['subdir'], 0, 0, 0, None, ''))
            src_arr_node = ArrayNode(src_arg_node, 0, 0, 0, 0)
            src_far_node = ArgumentNode(Token('string', cmd['subdir'], 0, 0, 0, None, ''))
            src_fun_node = FunctionNode(cmd['subdir'], 0, 0, 0, 0, 'files', src_far_node)
            src_ass_node = AssignmentNode(cmd['subdir'], 0, 0, source_id, src_fun_node)
            src_arg_node.arguments = [StringNode(Token('string', cmd['subdir'], 0, 0, 0, None, x)) for x in cmd['sources']]
            src_far_node.arguments = [src_arr_node]

            # Build target
            tgt_arg_node = ArgumentNode(Token('string', cmd['subdir'], 0, 0, 0, None, ''))
            tgt_fun_node = FunctionNode(cmd['subdir'], 0, 0, 0, 0, cmd['target_type'], tgt_arg_node)
            tgt_ass_node = AssignmentNode(cmd['subdir'], 0, 0, target_id, tgt_fun_node)
            tgt_arg_node.arguments = [
                StringNode(Token('string', cmd['subdir'], 0, 0, 0, None, cmd['target'])),
                IdNode(Token('string', cmd['subdir'], 0, 0, 0, None, source_id))
            ]

            src_ass_node.accept(AstIndentationGenerator())
            tgt_ass_node.accept(AstIndentationGenerator())
            self.to_add_nodes += [src_ass_node, tgt_ass_node]

        elif cmd['operation'] == 'target_rm':
            to_remove = self.find_assignment_node(target['node'])
            if to_remove is None:
                to_remove = target['node']
            self.to_remove_nodes += [to_remove]
            mlog.log('  -- Removing target', mlog.green(cmd['target']), 'at',
                     mlog.yellow('{}:{}'.format(os.path.join(to_remove.subdir, environment.build_filename), to_remove.lineno)))

        elif cmd['operation'] == 'info':
            # T.List all sources in the target
            src_list = []
            for i in target['sources']:
                for j in arg_list_from_node(i):
                    if isinstance(j, StringNode):
                        src_list += [j.value]
            test_data = {
                'name': target['name'],
                'sources': src_list
            }
            self.add_info('target', target['id'], test_data)

        # Sort files
        for i in to_sort_nodes:
            convert = lambda text: int(text) if text.isdigit() else text.lower()
            alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
            path_sorter = lambda key: ([(key.count('/') <= idx, alphanum_key(x)) for idx, x in enumerate(key.split('/'))])

            unknown = [x for x in i.arguments if not isinstance(x, StringNode)]
            sources = [x for x in i.arguments if isinstance(x, StringNode)]
            sources = sorted(sources, key=lambda x: path_sorter(x.value))
            i.arguments = unknown + sources

    def process(self, cmd):
        if 'type' not in cmd:
            raise RewriterException('Command has no key "type"')
        if cmd['type'] not in self.functions:
            raise RewriterException('Unknown command "{}". Supported commands are: {}'
                                    .format(cmd['type'], list(self.functions.keys())))
        self.functions[cmd['type']](cmd)

    def apply_changes(self):
        assert(all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'subdir') for x in self.modefied_nodes))
        assert(all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'subdir') for x in self.to_remove_nodes))
        assert(all(isinstance(x, (ArrayNode, FunctionNode)) for x in self.modefied_nodes))
        assert(all(isinstance(x, (ArrayNode, AssignmentNode, FunctionNode)) for x in self.to_remove_nodes))
        # Sort based on line and column in reversed order
        work_nodes = [{'node': x, 'action': 'modify'} for x in self.modefied_nodes]
        work_nodes += [{'node': x, 'action': 'rm'} for x in self.to_remove_nodes]
        work_nodes = list(sorted(work_nodes, key=lambda x: (x['node'].lineno, x['node'].colno), reverse=True))
        work_nodes += [{'node': x, 'action': 'add'} for x in self.to_add_nodes]

        # Generating the new replacement string
        str_list = []
        for i in work_nodes:
            new_data = ''
            if i['action'] == 'modify' or i['action'] == 'add':
                printer = AstPrinter()
                i['node'].accept(printer)
                printer.post_process()
                new_data = printer.result.strip()
            data = {
                'file': os.path.join(i['node'].subdir, environment.build_filename),
                'str': new_data,
                'node': i['node'],
                'action': i['action']
            }
            str_list += [data]

        # Load build files
        files = {}
        for i in str_list:
            if i['file'] in files:
                continue
            fpath = os.path.realpath(os.path.join(self.sourcedir, i['file']))
            fdata = ''
            # Create an empty file if it does not exist
            if not os.path.exists(fpath):
                with open(fpath, 'w'):
                    pass
            with open(fpath, 'r') as fp:
                fdata = fp.read()

            # Generate line offsets numbers
            m_lines = fdata.splitlines(True)
            offset = 0
            line_offsets = []
            for j in m_lines:
                line_offsets += [offset]
                offset += len(j)

            files[i['file']] = {
                'path': fpath,
                'raw': fdata,
                'offsets': line_offsets
            }

        # Replace in source code
        def remove_node(i):
            offsets = files[i['file']]['offsets']
            raw = files[i['file']]['raw']
            node = i['node']
            line = node.lineno - 1
            col = node.colno
            start = offsets[line] + col
            end = start
            if isinstance(node, (ArrayNode, FunctionNode)):
                end = offsets[node.end_lineno - 1] + node.end_colno

            # Only removal is supported for assignments
            elif isinstance(node, AssignmentNode) and i['action'] == 'rm':
                if isinstance(node.value, (ArrayNode, FunctionNode)):
                    remove_node({'file': i['file'], 'str': '', 'node': node.value, 'action': 'rm'})
                    raw = files[i['file']]['raw']
                while raw[end] != '=':
                    end += 1
                end += 1 # Handle the '='
                while raw[end] in [' ', '\n', '\t']:
                    end += 1

            files[i['file']]['raw'] = raw[:start] + i['str'] + raw[end:]

        for i in str_list:
            if i['action'] in ['modify', 'rm']:
                remove_node(i)
            elif i['action'] in ['add']:
                files[i['file']]['raw'] += i['str'] + '\n'

        # Write the files back
        for key, val in files.items():
            mlog.log('Rewriting', mlog.yellow(key))
            with open(val['path'], 'w') as fp:
                fp.write(val['raw'])

target_operation_map = {
    'add': 'src_add',
    'rm': 'src_rm',
    'add_target': 'target_add',
    'rm_target': 'target_rm',
    'info': 'info',
}

def list_to_dict(in_list: T.List[str]) -> T.Dict[str, str]:
    result = {}
    it = iter(in_list)
    try:
        for i in it:
            # calling next(it) is not a mistake, we're taking the next element from
            # the iterator, avoiding the need to preprocess it into a sequence of
            # key value pairs.
            result[i] = next(it)
    except StopIteration:
        raise TypeError('in_list parameter of list_to_dict must have an even length.')
    return result

def generate_target(options) -> T.List[dict]:
    return [{
        'type': 'target',
        'target': options.target,
        'operation': target_operation_map[options.operation],
        'sources': options.sources,
        'subdir': options.subdir,
        'target_type': options.tgt_type,
    }]

def generate_kwargs(options) -> T.List[dict]:
    return [{
        'type': 'kwargs',
        'function': options.function,
        'id': options.id,
        'operation': options.operation,
        'kwargs': list_to_dict(options.kwargs),
    }]

def generate_def_opts(options) -> T.List[dict]:
    return [{
        'type': 'default_options',
        'operation': options.operation,
        'options': list_to_dict(options.options),
    }]

def genreate_cmd(options) -> T.List[dict]:
    if os.path.exists(options.json):
        with open(options.json, 'r') as fp:
            return json.load(fp)
    else:
        return json.loads(options.json)

# Map options.type to the actual type name
cli_type_map = {
    'target': generate_target,
    'tgt': generate_target,
    'kwargs': generate_kwargs,
    'default-options': generate_def_opts,
    'def': generate_def_opts,
    'command': genreate_cmd,
    'cmd': genreate_cmd,
}

def run(options):
    if not options.verbose:
        mlog.set_quiet()

    try:
        rewriter = Rewriter(options.sourcedir, skip_errors=options.skip)
        rewriter.analyze_meson()

        if options.type is None:
            mlog.error('No command specified')
            return 1

        commands = cli_type_map[options.type](options)

        if not isinstance(commands, list):
            raise TypeError('Command is not a list')

        for i in commands:
            if not isinstance(i, object):
                raise TypeError('Command is not an object')
            rewriter.process(i)

        rewriter.apply_changes()
        rewriter.print_info()
        return 0
    except Exception as e:
        raise e
    finally:
        mlog.set_verbose()
meson-0.53.2/mesonbuild/scripts/0000755000175000017500000000000013625242354020152 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/scripts/__init__.py0000644000175000017500000000144413035766234022271 0ustar  jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

def destdir_join(d1, d2):
    # c:\destdir + c:\prefix must produce c:\destdir\prefix
    if len(d1) > 1 and d1[1] == ':' \
            and len(d2) > 1 and d2[1] == ':':
        return d1 + d2[2:]
    return d1 + d2
meson-0.53.2/mesonbuild/scripts/clangformat.py0000644000175000017500000000310113546416757023030 0ustar  jpakkanejpakkane00000000000000# Copyright 2018 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pathlib
import subprocess
from concurrent.futures import ThreadPoolExecutor

from ..environment import detect_clangformat
from ..compilers import lang_suffixes

def clangformat(exelist, srcdir_name, builddir_name):
    srcdir = pathlib.Path(srcdir_name)
    suffixes = set(lang_suffixes['c']).union(set(lang_suffixes['cpp']))
    suffixes.add('h')
    futures = []
    with ThreadPoolExecutor() as e:
        for f in (x for suff in suffixes for x in srcdir.glob('**/*.' + suff)):
            strf = str(f)
            if strf.startswith(builddir_name):
                continue
            futures.append(e.submit(subprocess.check_call, exelist + ['-style=file', '-i', strf]))
        [x.result() for x in futures]
    return 0

def run(args):
    srcdir_name = args[0]
    builddir_name = args[1]

    exelist = detect_clangformat()
    if not exelist:
        print('Could not execute clang-format "%s"' % ' '.join(exelist))
        return 1

    return clangformat(exelist, srcdir_name, builddir_name)
meson-0.53.2/mesonbuild/scripts/clangtidy.py0000644000175000017500000000357313571777336022527 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pathlib
import subprocess
import shutil
from concurrent.futures import ThreadPoolExecutor

from ..compilers import lang_suffixes

def manual_clangformat(srcdir_name, builddir_name):
    srcdir = pathlib.Path(srcdir_name)
    suffixes = set(lang_suffixes['c']).union(set(lang_suffixes['cpp']))
    suffixes.add('h')
    futures = []
    returncode = 0
    with ThreadPoolExecutor() as e:
        for f in (x for suff in suffixes for x in srcdir.glob('**/*.' + suff)):
            strf = str(f)
            if strf.startswith(builddir_name):
                continue
            futures.append(e.submit(subprocess.run, ['clang-tidy', '-p', builddir_name, strf]))
        [max(returncode, x.result().returncode) for x in futures]
    return returncode

def clangformat(srcdir_name, builddir_name):
    run_clang_tidy = None
    for rct in ('run-clang-tidy', 'run-clang-tidy.py'):
        if shutil.which(rct):
            run_clang_tidy = rct
            break
    if run_clang_tidy:
        return subprocess.run([run_clang_tidy, '-p', builddir_name]).returncode
    else:
        print('Could not find run-clang-tidy, running checks manually.')
        manual_clangformat(srcdir_name, builddir_name)

def run(args):
    srcdir_name = args[0]
    builddir_name = args[1]
    return clangformat(srcdir_name, builddir_name)
meson-0.53.2/mesonbuild/scripts/cleantrees.py0000644000175000017500000000261013026303756022647 0ustar  jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
import shutil
import pickle

def rmtrees(build_dir, trees):
    for t in trees:
        # Never delete trees outside of the builddir
        if os.path.isabs(t):
            print('Cannot delete dir with absolute path {!r}'.format(t))
            continue
        bt = os.path.join(build_dir, t)
        # Skip if it doesn't exist, or if it is not a directory
        if os.path.isdir(bt):
            shutil.rmtree(bt, ignore_errors=True)

def run(args):
    if len(args) != 1:
        print('Cleaner script for Meson. Do not run on your own please.')
        print('cleantrees.py ')
        return 1
    with open(args[0], 'rb') as f:
        data = pickle.load(f)
    rmtrees(data.build_dir, data.trees)
    # Never fail cleaning
    return 0

if __name__ == '__main__':
    run(sys.argv[1:])
meson-0.53.2/mesonbuild/scripts/commandrunner.py0000644000175000017500000000570313571777336023416 0ustar  jpakkanejpakkane00000000000000# Copyright 2014 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This program is a wrapper to run external commands. It determines
what to run, sets up the environment and executes the command."""

import sys, os, subprocess, shutil, shlex
import re

def run_command(source_dir, build_dir, subdir, meson_command, command, arguments):
    env = {'MESON_SOURCE_ROOT': source_dir,
           'MESON_BUILD_ROOT': build_dir,
           'MESON_SUBDIR': subdir,
           'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in meson_command + ['introspect']]),
           }
    cwd = os.path.join(source_dir, subdir)
    child_env = os.environ.copy()
    child_env.update(env)

    # Is the command an executable in path?
    exe = shutil.which(command)
    if exe is not None:
        command_array = [exe] + arguments
    else:# No? Maybe it is a script in the source tree.
        fullpath = os.path.join(source_dir, subdir, command)
        command_array = [fullpath] + arguments
    try:
        return subprocess.Popen(command_array, env=child_env, cwd=cwd)
    except FileNotFoundError:
        print('Could not execute command "%s". File not found.' % command)
        sys.exit(1)
    except PermissionError:
        print('Could not execute command "%s". File not executable.' % command)
        sys.exit(1)
    except OSError as err:
        print('Could not execute command "{}": {}'.format(command, err))
        sys.exit(1)
    except subprocess.SubprocessError as err:
        print('Could not execute command "{}": {}'.format(command, err))
        sys.exit(1)

def is_python_command(cmdname):
    end_py_regex = r'python(3|3\.\d+)?(\.exe)?$'
    return re.search(end_py_regex, cmdname) is not None

def run(args):
    if len(args) < 4:
        print('commandrunner.py     [arguments]')
        return 1
    src_dir = args[0]
    build_dir = args[1]
    subdir = args[2]
    meson_command = args[3]
    if is_python_command(meson_command):
        meson_command = [meson_command, args[4]]
        command = args[5]
        arguments = args[6:]
    else:
        meson_command = [meson_command]
        command = args[4]
        arguments = args[5:]
    pc = run_command(src_dir, build_dir, subdir, meson_command, command, arguments)
    while True:
        try:
            pc.wait()
            break
        except KeyboardInterrupt:
            pass
    return pc.returncode

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
meson-0.53.2/mesonbuild/scripts/coverage.py0000644000175000017500000001545213462637046022333 0ustar  jpakkanejpakkane00000000000000# Copyright 2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from mesonbuild import environment

import argparse, sys, os, subprocess, pathlib

def coverage(outputs, source_root, subproject_root, build_root, log_dir):
    outfiles = []
    exitcode = 0

    (gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe) = environment.find_coverage_tools()

    # gcovr >= 4.2 requires a different syntax for out of source builds
    if gcovr_new_rootdir:
        gcovr_base_cmd = [gcovr_exe, '-r', source_root, build_root]
    else:
        gcovr_base_cmd = [gcovr_exe, '-r', build_root]

    if not outputs or 'xml' in outputs:
        if gcovr_exe:
            subprocess.check_call(gcovr_base_cmd +
                                  ['-x',
                                   '-e', subproject_root,
                                   '-o', os.path.join(log_dir, 'coverage.xml'),
                                   ])
            outfiles.append(('Xml', pathlib.Path(log_dir, 'coverage.xml')))
        elif outputs:
            print('gcovr >= 3.3 needed to generate Xml coverage report')
            exitcode = 1

    if not outputs or 'text' in outputs:
        if gcovr_exe:
            subprocess.check_call(gcovr_base_cmd +
                                  ['-e', subproject_root,
                                   '-o', os.path.join(log_dir, 'coverage.txt'),
                                   ])
            outfiles.append(('Text', pathlib.Path(log_dir, 'coverage.txt')))
        elif outputs:
            print('gcovr >= 3.3 needed to generate text coverage report')
            exitcode = 1

    if not outputs or 'html' in outputs:
        if lcov_exe and genhtml_exe:
            htmloutdir = os.path.join(log_dir, 'coveragereport')
            covinfo = os.path.join(log_dir, 'coverage.info')
            initial_tracefile = covinfo + '.initial'
            run_tracefile = covinfo + '.run'
            raw_tracefile = covinfo + '.raw'
            subprocess.check_call([lcov_exe,
                                   '--directory', build_root,
                                   '--capture',
                                   '--initial',
                                   '--output-file',
                                   initial_tracefile])
            subprocess.check_call([lcov_exe,
                                   '--directory', build_root,
                                   '--capture',
                                   '--output-file', run_tracefile,
                                   '--no-checksum',
                                   '--rc', 'lcov_branch_coverage=1',
                                   ])
            # Join initial and test results.
            subprocess.check_call([lcov_exe,
                                   '-a', initial_tracefile,
                                   '-a', run_tracefile,
                                   '--rc', 'lcov_branch_coverage=1',
                                   '-o', raw_tracefile])
            # Remove all directories outside the source_root from the covinfo
            subprocess.check_call([lcov_exe,
                                   '--extract', raw_tracefile,
                                   os.path.join(source_root, '*'),
                                   '--rc', 'lcov_branch_coverage=1',
                                   '--output-file', covinfo])
            # Remove all directories inside subproject dir
            subprocess.check_call([lcov_exe,
                                   '--remove', covinfo,
                                   os.path.join(subproject_root, '*'),
                                   '--rc', 'lcov_branch_coverage=1',
                                   '--output-file', covinfo])
            subprocess.check_call([genhtml_exe,
                                   '--prefix', build_root,
                                   '--prefix', source_root,
                                   '--output-directory', htmloutdir,
                                   '--title', 'Code coverage',
                                   '--legend',
                                   '--show-details',
                                   '--branch-coverage',
                                   covinfo])
            outfiles.append(('Html', pathlib.Path(htmloutdir, 'index.html')))
        elif gcovr_exe:
            htmloutdir = os.path.join(log_dir, 'coveragereport')
            if not os.path.isdir(htmloutdir):
                os.mkdir(htmloutdir)
            subprocess.check_call(gcovr_base_cmd +
                                  ['--html',
                                   '--html-details',
                                   '--print-summary',
                                   '-e', subproject_root,
                                   '-o', os.path.join(htmloutdir, 'index.html'),
                                   ])
            outfiles.append(('Html', pathlib.Path(htmloutdir, 'index.html')))
        elif outputs:
            print('lcov/genhtml or gcovr >= 3.3 needed to generate Html coverage report')
            exitcode = 1

    if not outputs and not outfiles:
        print('Need gcovr or lcov/genhtml to generate any coverage reports')
        exitcode = 1

    if outfiles:
        print('')
        for (filetype, path) in outfiles:
            print(filetype + ' coverage report can be found at', path.as_uri())

    return exitcode

def run(args):
    if not os.path.isfile('build.ninja'):
        print('Coverage currently only works with the Ninja backend.')
        return 1
    parser = argparse.ArgumentParser(description='Generate coverage reports')
    parser.add_argument('--text', dest='outputs', action='append_const',
                        const='text', help='generate Text report')
    parser.add_argument('--xml', dest='outputs', action='append_const',
                        const='xml', help='generate Xml report')
    parser.add_argument('--html', dest='outputs', action='append_const',
                        const='html', help='generate Html report')
    parser.add_argument('source_root')
    parser.add_argument('subproject_root')
    parser.add_argument('build_root')
    parser.add_argument('log_dir')
    options = parser.parse_args(args)
    return coverage(options.outputs, options.source_root,
                    options.subproject_root, options.build_root,
                    options.log_dir)

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
meson-0.53.2/mesonbuild/scripts/delwithsuffix.py0000644000175000017500000000210613110002662023371 0ustar  jpakkanejpakkane00000000000000# Copyright 2013 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os, sys

def run(args):
    if len(args) != 2:
        print('delwithsuffix.py  ')
        sys.exit(1)

    topdir = args[0]
    suffix = args[1]
    if suffix[0] != '.':
        suffix = '.' + suffix

    for (root, _, files) in os.walk(topdir):
        for f in files:
            if f.endswith(suffix):
                fullname = os.path.join(root, f)
                os.unlink(fullname)
    return 0

if __name__ == '__main__':
    run(sys.argv[1:])
meson-0.53.2/mesonbuild/scripts/depfixer.py0000644000175000017500000004067413571777336022362 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import sys, struct
import shutil, subprocess

from ..mesonlib import OrderedSet

SHT_STRTAB = 3
DT_NEEDED = 1
DT_RPATH = 15
DT_RUNPATH = 29
DT_STRTAB = 5
DT_SONAME = 14
DT_MIPS_RLD_MAP_REL = 1879048245

class DataSizes:
    def __init__(self, ptrsize, is_le):
        if is_le:
            p = '<'
        else:
            p = '>'
        self.Half = p + 'h'
        self.HalfSize = 2
        self.Word = p + 'I'
        self.WordSize = 4
        self.Sword = p + 'i'
        self.SwordSize = 4
        if ptrsize == 64:
            self.Addr = p + 'Q'
            self.AddrSize = 8
            self.Off = p + 'Q'
            self.OffSize = 8
            self.XWord = p + 'Q'
            self.XWordSize = 8
            self.Sxword = p + 'q'
            self.SxwordSize = 8
        else:
            self.Addr = p + 'I'
            self.AddrSize = 4
            self.Off = p + 'I'
            self.OffSize = 4

class DynamicEntry(DataSizes):
    def __init__(self, ifile, ptrsize, is_le):
        super().__init__(ptrsize, is_le)
        self.ptrsize = ptrsize
        if ptrsize == 64:
            self.d_tag = struct.unpack(self.Sxword, ifile.read(self.SxwordSize))[0]
            self.val = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
        else:
            self.d_tag = struct.unpack(self.Sword, ifile.read(self.SwordSize))[0]
            self.val = struct.unpack(self.Word, ifile.read(self.WordSize))[0]

    def write(self, ofile):
        if self.ptrsize == 64:
            ofile.write(struct.pack(self.Sxword, self.d_tag))
            ofile.write(struct.pack(self.XWord, self.val))
        else:
            ofile.write(struct.pack(self.Sword, self.d_tag))
            ofile.write(struct.pack(self.Word, self.val))

class SectionHeader(DataSizes):
    def __init__(self, ifile, ptrsize, is_le):
        super().__init__(ptrsize, is_le)
        if ptrsize == 64:
            is_64 = True
        else:
            is_64 = False
# Elf64_Word
        self.sh_name = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
# Elf64_Word
        self.sh_type = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
# Elf64_Xword
        if is_64:
            self.sh_flags = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
        else:
            self.sh_flags = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
# Elf64_Addr
        self.sh_addr = struct.unpack(self.Addr, ifile.read(self.AddrSize))[0]
# Elf64_Off
        self.sh_offset = struct.unpack(self.Off, ifile.read(self.OffSize))[0]
# Elf64_Xword
        if is_64:
            self.sh_size = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
        else:
            self.sh_size = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
# Elf64_Word
        self.sh_link = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
# Elf64_Word
        self.sh_info = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
# Elf64_Xword
        if is_64:
            self.sh_addralign = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
        else:
            self.sh_addralign = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
# Elf64_Xword
        if is_64:
            self.sh_entsize = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
        else:
            self.sh_entsize = struct.unpack(self.Word, ifile.read(self.WordSize))[0]

class Elf(DataSizes):
    def __init__(self, bfile, verbose=True):
        self.bfile = bfile
        self.verbose = verbose
        self.bf = open(bfile, 'r+b')
        try:
            (self.ptrsize, self.is_le) = self.detect_elf_type()
            super().__init__(self.ptrsize, self.is_le)
            self.parse_header()
            self.parse_sections()
            self.parse_dynamic()
        except (struct.error, RuntimeError):
            self.bf.close()
            raise

    def __enter__(self):
        return self

    def __del__(self):
        if self.bf:
            self.bf.close()

    def __exit__(self, exc_type, exc_value, traceback):
        self.bf.close()
        self.bf = None

    def detect_elf_type(self):
        data = self.bf.read(6)
        if data[1:4] != b'ELF':
            # This script gets called to non-elf targets too
            # so just ignore them.
            if self.verbose:
                print('File "%s" is not an ELF file.' % self.bfile)
            sys.exit(0)
        if data[4] == 1:
            ptrsize = 32
        elif data[4] == 2:
            ptrsize = 64
        else:
            sys.exit('File "%s" has unknown ELF class.' % self.bfile)
        if data[5] == 1:
            is_le = True
        elif data[5] == 2:
            is_le = False
        else:
            sys.exit('File "%s" has unknown ELF endianness.' % self.bfile)
        return ptrsize, is_le

    def parse_header(self):
        self.bf.seek(0)
        self.e_ident = struct.unpack('16s', self.bf.read(16))[0]
        self.e_type = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
        self.e_machine = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
        self.e_version = struct.unpack(self.Word, self.bf.read(self.WordSize))[0]
        self.e_entry = struct.unpack(self.Addr, self.bf.read(self.AddrSize))[0]
        self.e_phoff = struct.unpack(self.Off, self.bf.read(self.OffSize))[0]
        self.e_shoff = struct.unpack(self.Off, self.bf.read(self.OffSize))[0]
        self.e_flags = struct.unpack(self.Word, self.bf.read(self.WordSize))[0]
        self.e_ehsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
        self.e_phentsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
        self.e_phnum = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
        self.e_shentsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
        self.e_shnum = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
        self.e_shstrndx = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]

    def parse_sections(self):
        self.bf.seek(self.e_shoff)
        self.sections = []
        for _ in range(self.e_shnum):
            self.sections.append(SectionHeader(self.bf, self.ptrsize, self.is_le))

    def read_str(self):
        arr = []
        x = self.bf.read(1)
        while x != b'\0':
            arr.append(x)
            x = self.bf.read(1)
            if x == b'':
                raise RuntimeError('Tried to read past the end of the file')
        return b''.join(arr)

    def find_section(self, target_name):
        section_names = self.sections[self.e_shstrndx]
        for i in self.sections:
            self.bf.seek(section_names.sh_offset + i.sh_name)
            name = self.read_str()
            if name == target_name:
                return i

    def parse_dynamic(self):
        sec = self.find_section(b'.dynamic')
        self.dynamic = []
        if sec is None:
            return
        self.bf.seek(sec.sh_offset)
        while True:
            e = DynamicEntry(self.bf, self.ptrsize, self.is_le)
            self.dynamic.append(e)
            if e.d_tag == 0:
                break

    def print_section_names(self):
        section_names = self.sections[self.e_shstrndx]
        for i in self.sections:
            self.bf.seek(section_names.sh_offset + i.sh_name)
            name = self.read_str()
            print(name.decode())

    def print_soname(self):
        soname = None
        strtab = None
        for i in self.dynamic:
            if i.d_tag == DT_SONAME:
                soname = i
            if i.d_tag == DT_STRTAB:
                strtab = i
        if soname is None or strtab is None:
            print("This file does not have a soname")
            return
        self.bf.seek(strtab.val + soname.val)
        print(self.read_str())

    def get_entry_offset(self, entrynum):
        sec = self.find_section(b'.dynstr')
        for i in self.dynamic:
            if i.d_tag == entrynum:
                return sec.sh_offset + i.val
        return None

    def print_rpath(self):
        offset = self.get_entry_offset(DT_RPATH)
        if offset is None:
            print("This file does not have an rpath.")
        else:
            self.bf.seek(offset)
            print(self.read_str())

    def print_runpath(self):
        offset = self.get_entry_offset(DT_RUNPATH)
        if offset is None:
            print("This file does not have a runpath.")
        else:
            self.bf.seek(offset)
            print(self.read_str())

    def print_deps(self):
        sec = self.find_section(b'.dynstr')
        deps = []
        for i in self.dynamic:
            if i.d_tag == DT_NEEDED:
                deps.append(i)
        for i in deps:
            offset = sec.sh_offset + i.val
            self.bf.seek(offset)
            name = self.read_str()
            print(name)

    def fix_deps(self, prefix):
        sec = self.find_section(b'.dynstr')
        deps = []
        for i in self.dynamic:
            if i.d_tag == DT_NEEDED:
                deps.append(i)
        for i in deps:
            offset = sec.sh_offset + i.val
            self.bf.seek(offset)
            name = self.read_str()
            if name.startswith(prefix):
                basename = name.split(b'/')[-1]
                padding = b'\0' * (len(name) - len(basename))
                newname = basename + padding
                assert(len(newname) == len(name))
                self.bf.seek(offset)
                self.bf.write(newname)

    def fix_rpath(self, new_rpath):
        # The path to search for can be either rpath or runpath.
        # Fix both of them to be sure.
        self.fix_rpathtype_entry(new_rpath, DT_RPATH)
        self.fix_rpathtype_entry(new_rpath, DT_RUNPATH)

    def fix_rpathtype_entry(self, new_rpath, entrynum):
        if isinstance(new_rpath, str):
            new_rpath = new_rpath.encode('utf8')
        rp_off = self.get_entry_offset(entrynum)
        if rp_off is None:
            if self.verbose:
                print('File does not have rpath. It should be a fully static executable.')
            return
        self.bf.seek(rp_off)
        old_rpath = self.read_str()
        if len(old_rpath) < len(new_rpath):
            sys.exit("New rpath must not be longer than the old one.")
        # The linker does read-only string deduplication. If there is a
        # string that shares a suffix with the rpath, they might get
        # dedupped. This means changing the rpath string might break something
        # completely unrelated. This has already happened once with X.org.
        # Thus we want to keep this change as small as possible to minimize
        # the chance of obliterating other strings. It might still happen
        # but our behavior is identical to what chrpath does and it has
        # been in use for ages so based on that this should be rare.
        if not new_rpath:
            self.remove_rpath_entry(entrynum)
        else:
            self.bf.seek(rp_off)
            self.bf.write(new_rpath)
            self.bf.write(b'\0')

    def remove_rpath_entry(self, entrynum):
        sec = self.find_section(b'.dynamic')
        if sec is None:
            return None
        for (i, entry) in enumerate(self.dynamic):
            if entry.d_tag == entrynum:
                rpentry = self.dynamic[i]
                rpentry.d_tag = 0
                self.dynamic = self.dynamic[:i] + self.dynamic[i + 1:] + [rpentry]
                break
        # DT_MIPS_RLD_MAP_REL is relative to the offset of the tag. Adjust it consequently.
        for entry in self.dynamic[i:]:
            if entry.d_tag == DT_MIPS_RLD_MAP_REL:
                entry.val += 2 * (self.ptrsize // 8)
                break
        self.bf.seek(sec.sh_offset)
        for entry in self.dynamic:
            entry.write(self.bf)
        return None

def fix_elf(fname, new_rpath, verbose=True):
    with Elf(fname, verbose) as e:
        if new_rpath is None:
            e.print_rpath()
            e.print_runpath()
        else:
            e.fix_rpath(new_rpath)

def get_darwin_rpaths_to_remove(fname):
    out = subprocess.check_output(['otool', '-l', fname],
                                  universal_newlines=True,
                                  stderr=subprocess.DEVNULL)
    result = []
    current_cmd = 'FOOBAR'
    for line in out.split('\n'):
        line = line.strip()
        if ' ' not in line:
            continue
        key, value = line.strip().split(' ', 1)
        if key == 'cmd':
            current_cmd = value
        if key == 'path' and current_cmd == 'LC_RPATH':
            rp = value.split('(', 1)[0].strip()
            result.append(rp)
    return result

def fix_darwin(fname, new_rpath, final_path, install_name_mappings):
    try:
        rpaths = get_darwin_rpaths_to_remove(fname)
    except subprocess.CalledProcessError:
        # Otool failed, which happens when invoked on a
        # non-executable target. Just return.
        return
    try:
        args = []
        if rpaths:
            # TODO: fix this properly, not totally clear how
            #
            # removing rpaths from binaries on macOS has tons of
            # weird edge cases. For instance, if the user provided
            # a '-Wl,-rpath' argument in LDFLAGS that happens to
            # coincide with an rpath generated from a dependency,
            # this would cause installation failures, as meson would
            # generate install_name_tool calls with two identical
            # '-delete_rpath' arguments, which install_name_tool
            # fails on. Because meson itself ensures that it never
            # adds duplicate rpaths, duplicate rpaths necessarily
            # come from user variables. The idea of using OrderedSet
            # is to remove *at most one* duplicate RPATH entry. This
            # is not optimal, as it only respects the user's choice
            # partially: if they provided a non-duplicate '-Wl,-rpath'
            # argument, it gets removed, if they provided a duplicate
            # one, it remains in the final binary. A potentially optimal
            # solution would split all user '-Wl,-rpath' arguments from
            # LDFLAGS, and later add them back with '-add_rpath'.
            for rp in OrderedSet(rpaths):
                args += ['-delete_rpath', rp]
            subprocess.check_call(['install_name_tool', fname] + args,
                                  stdout=subprocess.DEVNULL,
                                  stderr=subprocess.DEVNULL)
        args = []
        if new_rpath:
            args += ['-add_rpath', new_rpath]
        # Rewrite -install_name @rpath/libfoo.dylib to /path/to/libfoo.dylib
        if fname.endswith('dylib'):
            args += ['-id', final_path]
        if install_name_mappings:
            for old, new in install_name_mappings.items():
                args += ['-change', old, new]
        if args:
            subprocess.check_call(['install_name_tool', fname] + args,
                                  stdout=subprocess.DEVNULL,
                                  stderr=subprocess.DEVNULL)
    except Exception as err:
        raise SystemExit(err)

def fix_jar(fname):
    subprocess.check_call(['jar', 'xfv', fname, 'META-INF/MANIFEST.MF'])
    with open('META-INF/MANIFEST.MF', 'r+') as f:
        lines = f.readlines()
        f.seek(0)
        for line in lines:
            if not line.startswith('Class-Path:'):
                f.write(line)
        f.truncate()
    subprocess.check_call(['jar', 'ufm', fname, 'META-INF/MANIFEST.MF'])

def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True):
    # Static libraries never have rpaths
    if fname.endswith('.a'):
        return
    # DLLs and EXE never have rpaths
    if fname.endswith('.dll') or fname.endswith('.exe'):
        return
    try:
        if fname.endswith('.jar'):
            fix_jar(fname)
            return
        fix_elf(fname, new_rpath, verbose)
        return
    except SystemExit as e:
        if isinstance(e.code, int) and e.code == 0:
            pass
        else:
            raise
    if shutil.which('install_name_tool'):
        fix_darwin(fname, new_rpath, final_path, install_name_mappings)
meson-0.53.2/mesonbuild/scripts/dirchanger.py0000644000175000017500000000160713025554726022641 0ustar  jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

'''CD into dir given as first argument and execute
the command given in the rest of the arguments.'''

import os, subprocess, sys

def run(args):
    dirname = args[0]
    command = args[1:]

    os.chdir(dirname)
    return subprocess.call(command)

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
meson-0.53.2/mesonbuild/scripts/gettext.py0000644000175000017500000001132313455557413022216 0ustar  jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import shutil
import argparse
import subprocess
from . import destdir_join

parser = argparse.ArgumentParser()
parser.add_argument('command')
parser.add_argument('--pkgname', default='')
parser.add_argument('--datadirs', default='')
parser.add_argument('--langs', default='')
parser.add_argument('--localedir', default='')
parser.add_argument('--subdir', default='')
parser.add_argument('--extra-args', default='')

def read_linguas(src_sub):
    # Syntax of this file is documented here:
    # https://www.gnu.org/software/gettext/manual/html_node/po_002fLINGUAS.html
    linguas = os.path.join(src_sub, 'LINGUAS')
    try:
        langs = []
        with open(linguas) as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith('#'):
                    langs += line.split()
        return langs
    except (FileNotFoundError, PermissionError):
        print('Could not find file LINGUAS in {}'.format(src_sub))
        return []

def run_potgen(src_sub, pkgname, datadirs, args):
    listfile = os.path.join(src_sub, 'POTFILES.in')
    if not os.path.exists(listfile):
        listfile = os.path.join(src_sub, 'POTFILES')
        if not os.path.exists(listfile):
            print('Could not find file POTFILES in %s' % src_sub)
            return 1

    child_env = os.environ.copy()
    if datadirs:
        child_env['GETTEXTDATADIRS'] = datadirs

    ofile = os.path.join(src_sub, pkgname + '.pot')
    return subprocess.call(['xgettext', '--package-name=' + pkgname, '-p', src_sub, '-f', listfile,
                            '-D', os.environ['MESON_SOURCE_ROOT'], '-k_', '-o', ofile] + args,
                           env=child_env)

def gen_gmo(src_sub, bld_sub, langs):
    for l in langs:
        subprocess.check_call(['msgfmt', os.path.join(src_sub, l + '.po'),
                               '-o', os.path.join(bld_sub, l + '.gmo')])
    return 0

def update_po(src_sub, pkgname, langs):
    potfile = os.path.join(src_sub, pkgname + '.pot')
    for l in langs:
        pofile = os.path.join(src_sub, l + '.po')
        if os.path.exists(pofile):
            subprocess.check_call(['msgmerge', '-q', '-o', pofile, pofile, potfile])
        else:
            subprocess.check_call(['msginit', '--input', potfile, '--output-file', pofile, '--locale', l, '--no-translator'])
    return 0

def do_install(src_sub, bld_sub, dest, pkgname, langs):
    for l in langs:
        srcfile = os.path.join(bld_sub, l + '.gmo')
        outfile = os.path.join(dest, l, 'LC_MESSAGES',
                               pkgname + '.mo')
        tempfile = outfile + '.tmp'
        os.makedirs(os.path.dirname(outfile), exist_ok=True)
        shutil.copyfile(srcfile, tempfile)
        shutil.copystat(srcfile, tempfile)
        os.replace(tempfile, outfile)
        print('Installing %s to %s' % (srcfile, outfile))
    return 0

def run(args):
    options = parser.parse_args(args)
    subcmd = options.command
    langs = options.langs.split('@@') if options.langs else None
    extra_args = options.extra_args.split('@@') if options.extra_args else []
    subdir = os.environ.get('MESON_SUBDIR', '')
    if options.subdir:
        subdir = options.subdir
    src_sub = os.path.join(os.environ['MESON_SOURCE_ROOT'], subdir)
    bld_sub = os.path.join(os.environ['MESON_BUILD_ROOT'], subdir)

    if not langs:
        langs = read_linguas(src_sub)

    if subcmd == 'pot':
        return run_potgen(src_sub, options.pkgname, options.datadirs, extra_args)
    elif subcmd == 'gen_gmo':
        return gen_gmo(src_sub, bld_sub, langs)
    elif subcmd == 'update_po':
        if run_potgen(src_sub, options.pkgname, options.datadirs, extra_args) != 0:
            return 1
        return update_po(src_sub, options.pkgname, langs)
    elif subcmd == 'install':
        destdir = os.environ.get('DESTDIR', '')
        dest = destdir_join(destdir, os.path.join(os.environ['MESON_INSTALL_PREFIX'],
                                                  options.localedir))
        if gen_gmo(src_sub, bld_sub, langs) != 0:
            return 1
        do_install(src_sub, bld_sub, dest, options.pkgname, langs)
    else:
        print('Unknown subcommand.')
        return 1
meson-0.53.2/mesonbuild/scripts/gtkdochelper.py0000644000175000017500000002514413537776255023223 0ustar  jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys, os
import subprocess
import shutil
import argparse
from ..mesonlib import MesonException, Popen_safe, is_windows, split_args
from . import destdir_join

parser = argparse.ArgumentParser()

parser.add_argument('--sourcedir', dest='sourcedir')
parser.add_argument('--builddir', dest='builddir')
parser.add_argument('--subdir', dest='subdir')
parser.add_argument('--headerdirs', dest='headerdirs')
parser.add_argument('--mainfile', dest='mainfile')
parser.add_argument('--modulename', dest='modulename')
parser.add_argument('--moduleversion', dest='moduleversion')
parser.add_argument('--htmlargs', dest='htmlargs', default='')
parser.add_argument('--scanargs', dest='scanargs', default='')
parser.add_argument('--scanobjsargs', dest='scanobjsargs', default='')
parser.add_argument('--gobjects-types-file', dest='gobject_typesfile', default='')
parser.add_argument('--fixxrefargs', dest='fixxrefargs', default='')
parser.add_argument('--mkdbargs', dest='mkdbargs', default='')
parser.add_argument('--ld', dest='ld', default='')
parser.add_argument('--cc', dest='cc', default='')
parser.add_argument('--ldflags', dest='ldflags', default='')
parser.add_argument('--cflags', dest='cflags', default='')
parser.add_argument('--content-files', dest='content_files', default='')
parser.add_argument('--expand-content-files', dest='expand_content_files', default='')
parser.add_argument('--html-assets', dest='html_assets', default='')
parser.add_argument('--ignore-headers', dest='ignore_headers', default='')
parser.add_argument('--namespace', dest='namespace', default='')
parser.add_argument('--mode', dest='mode', default='')
parser.add_argument('--installdir', dest='install_dir')
parser.add_argument('--run', dest='run', default='')
for tool in ['scan', 'scangobj', 'mkdb', 'mkhtml', 'fixxref']:
    program_name = 'gtkdoc-' + tool
    parser.add_argument('--' + program_name, dest=program_name.replace('-', '_'))

def gtkdoc_run_check(cmd, cwd, library_paths=None):
    if library_paths is None:
        library_paths = []

    env = dict(os.environ)
    if is_windows():
        if 'PATH' in env:
            library_paths.extend(env['PATH'].split(os.pathsep))
        env['PATH'] = os.pathsep.join(library_paths)
    else:
        if 'LD_LIBRARY_PATH' in env:
            library_paths.extend(env['LD_LIBRARY_PATH'].split(os.pathsep))
        env['LD_LIBRARY_PATH'] = os.pathsep.join(library_paths)

    # Put stderr into stdout since we want to print it out anyway.
    # This preserves the order of messages.
    p, out = Popen_safe(cmd, cwd=cwd, env=env, stderr=subprocess.STDOUT)[0:2]
    if p.returncode != 0:
        err_msg = ["{!r} failed with status {:d}".format(cmd, p.returncode)]
        if out:
            err_msg.append(out)
        raise MesonException('\n'.join(err_msg))
    elif out:
        print(out)

def build_gtkdoc(source_root, build_root, doc_subdir, src_subdirs,
                 main_file, module, module_version,
                 html_args, scan_args, fixxref_args, mkdb_args,
                 gobject_typesfile, scanobjs_args, run, ld, cc, ldflags, cflags,
                 html_assets, content_files, ignore_headers, namespace,
                 expand_content_files, mode, options):
    print("Building documentation for %s" % module)

    src_dir_args = []
    for src_dir in src_subdirs:
        if not os.path.isabs(src_dir):
            dirs = [os.path.join(source_root, src_dir),
                    os.path.join(build_root, src_dir)]
        else:
            dirs = [src_dir]
        src_dir_args += ['--source-dir=' + d for d in dirs]

    doc_src = os.path.join(source_root, doc_subdir)
    abs_out = os.path.join(build_root, doc_subdir)
    htmldir = os.path.join(abs_out, 'html')

    content_files += [main_file]
    sections = os.path.join(doc_src, module + "-sections.txt")
    if os.path.exists(sections):
        content_files.append(sections)

    overrides = os.path.join(doc_src, module + "-overrides.txt")
    if os.path.exists(overrides):
        content_files.append(overrides)

    # Copy files to build directory
    for f in content_files:
        # FIXME: Use mesonlib.File objects so we don't need to do this
        if not os.path.isabs(f):
            f = os.path.join(doc_src, f)
        elif os.path.commonpath([f, build_root]) == build_root:
            continue
        shutil.copyfile(f, os.path.join(abs_out, os.path.basename(f)))

    shutil.rmtree(htmldir, ignore_errors=True)
    try:
        os.mkdir(htmldir)
    except Exception:
        pass

    for f in html_assets:
        f_abs = os.path.join(doc_src, f)
        shutil.copyfile(f_abs, os.path.join(htmldir, os.path.basename(f_abs)))

    scan_cmd = [options.gtkdoc_scan, '--module=' + module] + src_dir_args
    if ignore_headers:
        scan_cmd.append('--ignore-headers=' + ' '.join(ignore_headers))
    # Add user-specified arguments
    scan_cmd += scan_args
    gtkdoc_run_check(scan_cmd, abs_out)

    # Use the generated types file when available, otherwise gobject_typesfile
    # would often be a path to source dir instead of build dir.
    if '--rebuild-types' in scan_args:
        gobject_typesfile = os.path.join(abs_out, module + '.types')

    if gobject_typesfile:
        scanobjs_cmd = [options.gtkdoc_scangobj] + scanobjs_args
        scanobjs_cmd += ['--types=' + gobject_typesfile,
                         '--module=' + module,
                         '--run=' + run,
                         '--cflags=' + cflags,
                         '--ldflags=' + ldflags,
                         '--cc=' + cc,
                         '--ld=' + ld,
                         '--output-dir=' + abs_out]

        library_paths = []
        for ldflag in split_args(ldflags):
            if ldflag.startswith('-Wl,-rpath,'):
                library_paths.append(ldflag[11:])

        gtkdoc_run_check(scanobjs_cmd, build_root, library_paths)

    # Make docbook files
    if mode == 'auto':
        # Guessing is probably a poor idea but these keeps compat
        # with previous behavior
        if main_file.endswith('sgml'):
            modeflag = '--sgml-mode'
        else:
            modeflag = '--xml-mode'
    elif mode == 'xml':
        modeflag = '--xml-mode'
    elif mode == 'sgml':
        modeflag = '--sgml-mode'
    else: # none
        modeflag = None

    mkdb_cmd = [options.gtkdoc_mkdb,
                '--module=' + module,
                '--output-format=xml',
                '--expand-content-files=' + ' '.join(expand_content_files),
                ] + src_dir_args
    if namespace:
        mkdb_cmd.append('--name-space=' + namespace)
    if modeflag:
        mkdb_cmd.append(modeflag)
    if main_file:
        # Yes, this is the flag even if the file is in xml.
        mkdb_cmd.append('--main-sgml-file=' + main_file)
    # Add user-specified arguments
    mkdb_cmd += mkdb_args
    gtkdoc_run_check(mkdb_cmd, abs_out)

    # Make HTML documentation
    mkhtml_cmd = [options.gtkdoc_mkhtml,
                  '--path=' + ':'.join((doc_src, abs_out)),
                  module,
                  ] + html_args
    if main_file:
        mkhtml_cmd.append('../' + main_file)
    else:
        mkhtml_cmd.append('%s-docs.xml' % module)
    # html gen must be run in the HTML dir
    gtkdoc_run_check(mkhtml_cmd, htmldir)

    # Fix cross-references in HTML files
    fixref_cmd = [options.gtkdoc_fixxref,
                  '--module=' + module,
                  '--module-dir=html'] + fixxref_args
    gtkdoc_run_check(fixref_cmd, abs_out)

    if module_version:
        shutil.move(os.path.join(htmldir, '{}.devhelp2'.format(module)),
                    os.path.join(htmldir, '{}-{}.devhelp2'.format(module, module_version)))

def install_gtkdoc(build_root, doc_subdir, install_prefix, datadir, module):
    source = os.path.join(build_root, doc_subdir, 'html')
    final_destination = os.path.join(install_prefix, datadir, module)
    shutil.rmtree(final_destination, ignore_errors=True)
    shutil.copytree(source, final_destination)

def run(args):
    options = parser.parse_args(args)
    if options.htmlargs:
        htmlargs = options.htmlargs.split('@@')
    else:
        htmlargs = []
    if options.scanargs:
        scanargs = options.scanargs.split('@@')
    else:
        scanargs = []
    if options.scanobjsargs:
        scanobjsargs = options.scanobjsargs.split('@@')
    else:
        scanobjsargs = []
    if options.fixxrefargs:
        fixxrefargs = options.fixxrefargs.split('@@')
    else:
        fixxrefargs = []
    if options.mkdbargs:
        mkdbargs = options.mkdbargs.split('@@')
    else:
        mkdbargs = []
    build_gtkdoc(
        options.sourcedir,
        options.builddir,
        options.subdir,
        options.headerdirs.split('@@'),
        options.mainfile,
        options.modulename,
        options.moduleversion,
        htmlargs,
        scanargs,
        fixxrefargs,
        mkdbargs,
        options.gobject_typesfile,
        scanobjsargs,
        options.run,
        options.ld,
        options.cc,
        options.ldflags,
        options.cflags,
        options.html_assets.split('@@') if options.html_assets else [],
        options.content_files.split('@@') if options.content_files else [],
        options.ignore_headers.split('@@') if options.ignore_headers else [],
        options.namespace,
        options.expand_content_files.split('@@') if options.expand_content_files else [],
        options.mode,
        options)

    if 'MESON_INSTALL_PREFIX' in os.environ:
        destdir = os.environ.get('DESTDIR', '')
        install_prefix = destdir_join(destdir, os.environ['MESON_INSTALL_PREFIX'])
        if options.install_dir:
            install_dir = options.install_dir
        else:
            install_dir = options.modulename
            if options.moduleversion:
                install_dir += '-' + options.moduleversion
        if os.path.isabs(install_dir):
            install_dir = destdir_join(destdir, install_dir)
        install_gtkdoc(options.builddir,
                       options.subdir,
                       install_prefix,
                       'share/gtk-doc/html',
                       install_dir)
    return 0

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
meson-0.53.2/mesonbuild/scripts/hotdochelper.py0000644000175000017500000000213713366273150023207 0ustar  jpakkanejpakkane00000000000000import os
import shutil
import subprocess

from . import destdir_join

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--install')
parser.add_argument('--extra-extension-path', action="append", default=[])
parser.add_argument('--name')
parser.add_argument('--builddir')
parser.add_argument('--project-version')


def run(argv):
    options, args = parser.parse_known_args(argv)
    subenv = os.environ.copy()

    for ext_path in options.extra_extension_path:
        subenv['PYTHONPATH'] = subenv.get('PYTHONPATH', '') + ':' + ext_path

    res = subprocess.call(args, cwd=options.builddir, env=subenv)
    if res != 0:
        exit(res)

    if options.install:
        source_dir = os.path.join(options.builddir, options.install)
        destdir = os.environ.get('DESTDIR', '')
        installdir = destdir_join(destdir,
                                  os.path.join(os.environ['MESON_INSTALL_PREFIX'],
                                               'share/doc/', options.name, "html"))

        shutil.rmtree(installdir, ignore_errors=True)
        shutil.copytree(source_dir, installdir)
meson-0.53.2/mesonbuild/scripts/meson_exe.py0000644000175000017500000000746213537776255022535 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
import argparse
import pickle
import platform
import subprocess

from .. import mesonlib
from ..backend.backends import ExecutableSerialisation

options = None

def buildparser():
    parser = argparse.ArgumentParser(description='Custom executable wrapper for Meson. Do not run on your own, mmm\'kay?')
    parser.add_argument('--unpickle')
    parser.add_argument('--capture')
    return parser

def is_windows():
    platname = platform.system().lower()
    return platname == 'windows' or 'mingw' in platname

def is_cygwin():
    platname = platform.system().lower()
    return 'cygwin' in platname

def run_exe(exe):
    if exe.exe_runner:
        if not exe.exe_runner.found():
            raise AssertionError('BUG: Can\'t run cross-compiled exe {!r} with not-found '
                                 'wrapper {!r}'.format(exe.cmd_args[0], exe.exe_runner.get_path()))
        cmd_args = exe.exe_runner.get_command() + exe.cmd_args
    else:
        cmd_args = exe.cmd_args
    child_env = os.environ.copy()
    child_env.update(exe.env)
    if exe.extra_paths:
        child_env['PATH'] = (os.pathsep.join(exe.extra_paths + ['']) +
                             child_env['PATH'])
        if exe.exe_runner and mesonlib.substring_is_in_list('wine', exe.exe_runner.get_command()):
            child_env['WINEPATH'] = mesonlib.get_wine_shortpath(
                exe.exe_runner.get_command(),
                ['Z:' + p for p in exe.extra_paths] + child_env.get('WINEPATH', '').split(';')
            )

    p = subprocess.Popen(cmd_args, env=child_env, cwd=exe.workdir,
                         close_fds=False,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()

    if p.returncode == 0xc0000135:
        # STATUS_DLL_NOT_FOUND on Windows indicating a common problem that is otherwise hard to diagnose
        raise FileNotFoundError('Missing DLLs on calling {!r}'.format(exe.name))

    if exe.capture and p.returncode == 0:
        skip_write = False
        try:
            with open(exe.capture, 'rb') as cur:
                skip_write = cur.read() == stdout
        except IOError:
            pass
        if not skip_write:
            with open(exe.capture, 'wb') as output:
                output.write(stdout)
    else:
        sys.stdout.buffer.write(stdout)
    if stderr:
        sys.stderr.buffer.write(stderr)
    return p.returncode

def run(args):
    global options
    parser = buildparser()
    options, cmd_args = parser.parse_known_args(args)
    # argparse supports double dash to separate options and positional arguments,
    # but the user has to remove it manually.
    if cmd_args and cmd_args[0] == '--':
        cmd_args = cmd_args[1:]
    if not options.unpickle and not cmd_args:
        parser.error('either --unpickle or executable and arguments are required')
    if options.unpickle:
        if cmd_args or options.capture:
            parser.error('no other arguments can be used with --unpickle')
        with open(options.unpickle, 'rb') as f:
            exe = pickle.load(f)
    else:
        exe = ExecutableSerialisation(cmd_args, capture=options.capture)

    return run_exe(exe)

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
meson-0.53.2/mesonbuild/scripts/msgfmthelper.py0000644000175000017500000000243713462637046023234 0ustar  jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import subprocess
import os

parser = argparse.ArgumentParser()
parser.add_argument('input')
parser.add_argument('output')
parser.add_argument('type')
parser.add_argument('podir')
parser.add_argument('--datadirs', default='')
parser.add_argument('args', default=[], metavar='extra msgfmt argument', nargs='*')


def run(args):
    options = parser.parse_args(args)
    env = None
    if options.datadirs:
        env = os.environ.copy()
        env.update({'GETTEXTDATADIRS': options.datadirs})
    return subprocess.call(['msgfmt', '--' + options.type, '-d', options.podir,
                            '--template', options.input,  '-o', options.output] + options.args,
                           env=env)
meson-0.53.2/mesonbuild/scripts/regen_checker.py0000644000175000017500000000432213340206727023307 0ustar  jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys, os
import pickle, subprocess

# This could also be used for XCode.

def need_regen(regeninfo, regen_timestamp):
    for i in regeninfo.depfiles:
        curfile = os.path.join(regeninfo.build_dir, i)
        curtime = os.stat(curfile).st_mtime
        if curtime > regen_timestamp:
            return True
    # The timestamp file gets automatically deleted by MSBuild during a 'Clean' build.
    # We must make sure to recreate it, even if we do not regenerate the solution.
    # Otherwise, Visual Studio will always consider the REGEN project out of date.
    print("Everything is up-to-date, regeneration of build files is not needed.")
    from ..backend.vs2010backend import Vs2010Backend
    Vs2010Backend.touch_regen_timestamp(regeninfo.build_dir)
    return False

def regen(regeninfo, meson_command, backend):
    cmd = meson_command + ['--internal',
                           'regenerate',
                           regeninfo.build_dir,
                           regeninfo.source_dir,
                           '--backend=' + backend]
    subprocess.check_call(cmd)

def run(args):
    private_dir = args[0]
    dumpfile = os.path.join(private_dir, 'regeninfo.dump')
    coredata = os.path.join(private_dir, 'coredata.dat')
    with open(dumpfile, 'rb') as f:
        regeninfo = pickle.load(f)
    with open(coredata, 'rb') as f:
        coredata = pickle.load(f)
    backend = coredata.get_builtin_option('backend')
    regen_timestamp = os.stat(dumpfile).st_mtime
    if need_regen(regeninfo, regen_timestamp):
        regen(regeninfo, coredata.meson_command, backend)
    sys.exit(0)

if __name__ == '__main__':
    run(sys.argv[1:])
meson-0.53.2/mesonbuild/scripts/scanbuild.py0000644000175000017500000000300613571777336022504 0ustar  jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import subprocess
import shutil
import tempfile
from ..environment import detect_ninja, detect_scanbuild


def scanbuild(exelist, srcdir, blddir, privdir, logdir, args):
    with tempfile.TemporaryDirectory(dir=privdir) as scandir:
        meson_cmd = exelist + args
        build_cmd = exelist + ['-o', logdir, detect_ninja(), '-C', scandir]
        rc = subprocess.call(meson_cmd + [srcdir, scandir])
        if rc != 0:
            return rc
        return subprocess.call(build_cmd)


def run(args):
    srcdir = args[0]
    blddir = args[1]
    meson_cmd = args[2:]
    privdir = os.path.join(blddir, 'meson-private')
    logdir = os.path.join(blddir, 'meson-logs/scanbuild')
    shutil.rmtree(logdir, ignore_errors=True)

    exelist = detect_scanbuild()
    if not exelist:
        print('Could not execute scan-build "%s"' % ' '.join(exelist))
        return 1

    return scanbuild(exelist, srcdir, blddir, privdir, logdir, meson_cmd)
meson-0.53.2/mesonbuild/scripts/symbolextractor.py0000644000175000017500000001034413462637046023774 0ustar  jpakkanejpakkane00000000000000# Copyright 2013-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This script extracts the symbols of a given shared library
# into a file. If the symbols have not changed, the file is not
# touched. This information is used to skip link steps if the
# ABI has not changed.

# This file is basically a reimplementation of
# http://cgit.freedesktop.org/libreoffice/core/commit/?id=3213cd54b76bc80a6f0516aac75a48ff3b2ad67c

import os, sys
from .. import mesonlib
from ..mesonlib import Popen_safe
import argparse

parser = argparse.ArgumentParser()

parser.add_argument('--cross-host', default=None, dest='cross_host',
                    help='cross compilation host platform')
parser.add_argument('args', nargs='+')

def dummy_syms(outfilename):
    """Just touch it so relinking happens always."""
    with open(outfilename, 'w'):
        pass

def write_if_changed(text, outfilename):
    try:
        with open(outfilename, 'r') as f:
            oldtext = f.read()
        if text == oldtext:
            return
    except FileNotFoundError:
        pass
    with open(outfilename, 'w') as f:
        f.write(text)

def linux_syms(libfilename, outfilename):
    evar = 'READELF'
    if evar in os.environ:
        readelfbin = os.environ[evar].strip()
    else:
        readelfbin = 'readelf'
    evar = 'NM'
    if evar in os.environ:
        nmbin = os.environ[evar].strip()
    else:
        nmbin = 'nm'
    pe, output = Popen_safe([readelfbin, '-d', libfilename])[0:2]
    if pe.returncode != 0:
        raise RuntimeError('Readelf does not work')
    result = [x for x in output.split('\n') if 'SONAME' in x]
    assert(len(result) <= 1)
    pnm, output = Popen_safe([nmbin, '--dynamic', '--extern-only',
                              '--defined-only', '--format=posix',
                              libfilename])[0:2]
    if pnm.returncode != 0:
        raise RuntimeError('nm does not work.')
    for line in output.split('\n'):
        if not line:
            continue
        line_split = line.split()
        entry = line_split[0:2]
        if len(line_split) >= 4:
            entry += [line_split[3]]
        result += [' '.join(entry)]
    write_if_changed('\n'.join(result) + '\n', outfilename)

def osx_syms(libfilename, outfilename):
    pe, output = Popen_safe(['otool', '-l', libfilename])[0:2]
    if pe.returncode != 0:
        raise RuntimeError('Otool does not work.')
    arr = output.split('\n')
    for (i, val) in enumerate(arr):
        if 'LC_ID_DYLIB' in val:
            match = i
            break
    result = [arr[match + 2], arr[match + 5]] # Libreoffice stores all 5 lines but the others seem irrelevant.
    pnm, output = Popen_safe(['nm', '-g', '-P', libfilename])[0:2]
    if pnm.returncode != 0:
        raise RuntimeError('nm does not work.')
    result += [' '.join(x.split()[0:2]) for x in output.split('\n') if x and not x.endswith('U')]
    write_if_changed('\n'.join(result) + '\n', outfilename)

def gen_symbols(libfilename, outfilename, cross_host):
    if cross_host is not None:
        # In case of cross builds just always relink.
        # In theory we could determine the correct
        # toolset but there are more important things
        # to do.
        dummy_syms(outfilename)
    elif mesonlib.is_linux():
        linux_syms(libfilename, outfilename)
    elif mesonlib.is_osx():
        osx_syms(libfilename, outfilename)
    else:
        dummy_syms(outfilename)

def run(args):
    options = parser.parse_args(args)
    if len(options.args) != 2:
        print('symbolextractor.py  ')
        sys.exit(1)
    libfile = options.args[0]
    outfile = options.args[1]
    gen_symbols(libfile, outfile, options.cross_host)
    return 0

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
meson-0.53.2/mesonbuild/scripts/tags.py0000644000175000017500000000307213571777336021501 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import subprocess
from pathlib import Path


def ls_as_bytestream():
    if os.path.exists('.git'):
        return subprocess.run(['git', 'ls-tree', '-r', '--name-only', 'HEAD'],
                              stdout=subprocess.PIPE).stdout

    files = [str(p) for p in Path('.').glob('**/*')
             if not p.is_dir() and
             not next((x for x in p.parts if x.startswith('.')), None)]
    return '\n'.join(files).encode()


def cscope():
    ls = b'\n'.join([b'"%s"' % f for f in ls_as_bytestream().split()])
    return subprocess.run(['cscope', '-v', '-b', '-i-'], input=ls).returncode


def ctags():
    ls = ls_as_bytestream()
    return subprocess.run(['ctags', '-L-'], input=ls).returncode


def etags():
    ls = ls_as_bytestream()
    return subprocess.run(['etags', '-'], input=ls).returncode


def run(args):
    tool_name = args[0]
    srcdir_name = args[1]
    os.chdir(srcdir_name)
    assert tool_name in ['cscope', 'ctags', 'etags']
    return globals()[tool_name]()
meson-0.53.2/mesonbuild/scripts/uninstall.py0000644000175000017500000000305013140423077022526 0ustar  jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os

logfile = 'meson-logs/install-log.txt'

def do_uninstall(log):
    failures = 0
    successes = 0
    for line in open(log):
        if line.startswith('#'):
            continue
        fname = line.strip()
        try:
            if os.path.isdir(fname) and not os.path.islink(fname):
                os.rmdir(fname)
            else:
                os.unlink(fname)
            print('Deleted:', fname)
            successes += 1
        except Exception as e:
            print('Could not delete %s: %s.' % (fname, e))
            failures += 1
    print('\nUninstall finished.\n')
    print('Deleted:', successes)
    print('Failed:', failures)
    print('\nRemember that files created by custom scripts have not been removed.')

def run(args):
    if args:
        print('Weird error.')
        return 1
    if not os.path.exists(logfile):
        print('Log file does not exist, no installation has been done.')
        return 0
    do_uninstall(logfile)
    return 0
meson-0.53.2/mesonbuild/scripts/vcstagger.py0000644000175000017500000000311213455557413022514 0ustar  jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys, os, subprocess, re


def config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_selector, cmd):
    try:
        output = subprocess.check_output(cmd, cwd=source_dir)
        new_string = re.search(regex_selector, output.decode()).group(1).strip()
    except Exception:
        new_string = fallback

    with open(infile, encoding='utf8') as f:
        new_data = f.read().replace(replace_string, new_string)
    if os.path.exists(outfile):
        with open(outfile, encoding='utf8') as f:
            needs_update = (f.read() != new_data)
    else:
        needs_update = True
    if needs_update:
        with open(outfile, 'w', encoding='utf8') as f:
            f.write(new_data)


def run(args):
    infile, outfile, fallback, source_dir, replace_string, regex_selector = args[0:6]
    command = args[6:]
    config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_selector, command)
    return 0

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
meson-0.53.2/mesonbuild/scripts/yelphelper.py0000644000175000017500000001327013501510132022661 0ustar  jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import subprocess
import shutil
import argparse
from .. import mlog
from ..mesonlib import has_path_sep
from . import destdir_join
from .gettext import read_linguas

parser = argparse.ArgumentParser()
parser.add_argument('command')
parser.add_argument('--id', dest='project_id')
parser.add_argument('--subdir', dest='subdir')
parser.add_argument('--installdir', dest='install_dir')
parser.add_argument('--sources', dest='sources')
parser.add_argument('--media', dest='media', default='')
parser.add_argument('--langs', dest='langs', default='')
parser.add_argument('--symlinks', type=bool, dest='symlinks', default=False)

def build_pot(srcdir, project_id, sources):
    # Must be relative paths
    sources = [os.path.join('C', source) for source in sources]
    outfile = os.path.join(srcdir, project_id + '.pot')
    subprocess.call(['itstool', '-o', outfile] + sources)

def update_po(srcdir, project_id, langs):
    potfile = os.path.join(srcdir, project_id + '.pot')
    for lang in langs:
        pofile = os.path.join(srcdir, lang, lang + '.po')
        subprocess.call(['msgmerge', '-q', '-o', pofile, pofile, potfile])

def build_translations(srcdir, blddir, langs):
    for lang in langs:
        outdir = os.path.join(blddir, lang)
        os.makedirs(outdir, exist_ok=True)
        subprocess.call([
            'msgfmt', os.path.join(srcdir, lang, lang + '.po'),
            '-o', os.path.join(outdir, lang + '.gmo')
        ])

def merge_translations(blddir, sources, langs):
    for lang in langs:
        subprocess.call([
            'itstool', '-m', os.path.join(blddir, lang, lang + '.gmo'),
            '-o', os.path.join(blddir, lang)
        ] + sources)

def install_help(srcdir, blddir, sources, media, langs, install_dir, destdir, project_id, symlinks):
    c_install_dir = os.path.join(install_dir, 'C', project_id)
    for lang in langs + ['C']:
        indir = destdir_join(destdir, os.path.join(install_dir, lang, project_id))
        os.makedirs(indir, exist_ok=True)
        for source in sources:
            infile = os.path.join(srcdir if lang == 'C' else blddir, lang, source)
            outfile = os.path.join(indir, source)
            mlog.log('Installing %s to %s' % (infile, outfile))
            shutil.copyfile(infile, outfile)
            shutil.copystat(infile, outfile)
        for m in media:
            infile = os.path.join(srcdir, lang, m)
            outfile = os.path.join(indir, m)
            c_infile = os.path.join(srcdir, 'C', m)
            if not os.path.exists(infile):
                if not os.path.exists(c_infile):
                    mlog.warning('Media file "%s" did not exist in C directory' % m)
                    continue
                elif symlinks:
                    srcfile = os.path.join(c_install_dir, m)
                    mlog.log('Symlinking %s to %s.' % (outfile, srcfile))
                    if has_path_sep(m):
                        os.makedirs(os.path.dirname(outfile), exist_ok=True)
                    try:
                        try:
                            os.symlink(srcfile, outfile)
                        except FileExistsError:
                            os.remove(outfile)
                            os.symlink(srcfile, outfile)
                        continue
                    except (NotImplementedError, OSError):
                        mlog.warning('Symlinking not supported, falling back to copying')
                        infile = c_infile
                else:
                    # Lang doesn't have media file so copy it over 'C' one
                    infile = c_infile
            mlog.log('Installing %s to %s' % (infile, outfile))
            if has_path_sep(m):
                os.makedirs(os.path.dirname(outfile), exist_ok=True)
            shutil.copyfile(infile, outfile)
            shutil.copystat(infile, outfile)

def run(args):
    options = parser.parse_args(args)
    langs = options.langs.split('@@') if options.langs else []
    media = options.media.split('@@') if options.media else []
    sources = options.sources.split('@@')
    destdir = os.environ.get('DESTDIR', '')
    src_subdir = os.path.join(os.environ['MESON_SOURCE_ROOT'], options.subdir)
    build_subdir = os.path.join(os.environ['MESON_BUILD_ROOT'], options.subdir)
    abs_sources = [os.path.join(src_subdir, 'C', source) for source in sources]

    if not langs:
        langs = read_linguas(src_subdir)

    if options.command == 'pot':
        build_pot(src_subdir, options.project_id, sources)
    elif options.command == 'update-po':
        build_pot(src_subdir, options.project_id, sources)
        update_po(src_subdir, options.project_id, langs)
    elif options.command == 'build':
        if langs:
            build_translations(src_subdir, build_subdir, langs)
    elif options.command == 'install':
        install_dir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], options.install_dir)
        if langs:
            build_translations(src_subdir, build_subdir, langs)
            merge_translations(build_subdir, abs_sources, langs)
        install_help(src_subdir, build_subdir, sources, media, langs, install_dir,
                     destdir, options.project_id, options.symlinks)
meson-0.53.2/mesonbuild/templates/0000755000175000017500000000000013625242354020461 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/templates/__init__.py0000644000175000017500000000000013571777336022575 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/templates/cpptemplates.py0000644000175000017500000001176013571777336023556 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re


hello_cpp_template = '''#include 

#define PROJECT_NAME "{project_name}"

int main(int argc, char **argv) {{
    if(argc != 1) {{
        std::cout << argv[0] <<  "takes no arguments.\\n";
        return 1;
    }}
    std::cout << "This is project " << PROJECT_NAME << ".\\n";
    return 0;
}}
'''

hello_cpp_meson_template = '''project('{project_name}', 'cpp',
  version : '{version}',
  default_options : ['warning_level=3',
                     'cpp_std=c++14'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''

lib_hpp_template = '''#pragma once
#if defined _WIN32 || defined __CYGWIN__
  #ifdef BUILDING_{utoken}
    #define {utoken}_PUBLIC __declspec(dllexport)
  #else
    #define {utoken}_PUBLIC __declspec(dllimport)
  #endif
#else
  #ifdef BUILDING_{utoken}
      #define {utoken}_PUBLIC __attribute__ ((visibility ("default")))
  #else
      #define {utoken}_PUBLIC
  #endif
#endif

namespace {namespace} {{

class {utoken}_PUBLIC {class_name} {{

public:
  {class_name}();
  int get_number() const;

private:

  int number;

}};

}}

'''

lib_cpp_template = '''#include <{header_file}>

namespace {namespace} {{

{class_name}::{class_name}() {{
    number = 6;
}}

int {class_name}::get_number() const {{
  return number;
}}

}}
'''

lib_cpp_test_template = '''#include <{header_file}>
#include 

int main(int argc, char **argv) {{
    if(argc != 1) {{
        std::cout << argv[0] << " takes no arguments.\\n";
        return 1;
    }}
    {namespace}::{class_name} c;
    return c.get_number() != 6;
}}
'''

lib_cpp_meson_template = '''project('{project_name}', 'cpp',
  version : '{version}',
  default_options : ['warning_level=3', 'cpp_std=c++14'])

# These arguments are only used to build the shared library
# not the executables that use the library.
lib_args = ['-DBUILDING_{utoken}']

shlib = shared_library('{lib_name}', '{source_file}',
  install : true,
  cpp_args : lib_args,
  gnu_symbol_visibility : 'hidden',
)

test_exe = executable('{test_exe_name}', '{test_source_file}',
  link_with : shlib)
test('{test_name}', test_exe)

# Make this library usable as a Meson subproject.
{ltoken}_dep = declare_dependency(
  include_directories: include_directories('.'),
  link_with : shlib)

# Make this library usable from the system's
# package manager.
install_headers('{header_file}', subdir : '{header_dir}')

pkg_mod = import('pkgconfig')
pkg_mod.generate(
  name : '{project_name}',
  filebase : '{ltoken}',
  description : 'Meson sample project.',
  subdirs : '{header_dir}',
  libraries : shlib,
  version : '{version}',
)
'''


def create_exe_cpp_sample(project_name, project_version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    source_name = lowercase_token + '.cpp'
    open(source_name, 'w').write(hello_cpp_template.format(project_name=project_name))
    open('meson.build', 'w').write(hello_cpp_meson_template.format(project_name=project_name,
                                                                   exe_name=lowercase_token,
                                                                   source_name=source_name,
                                                                   version=project_version))


def create_lib_cpp_sample(project_name, version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    uppercase_token = lowercase_token.upper()
    class_name = uppercase_token[0] + lowercase_token[1:]
    namespace = lowercase_token
    lib_hpp_name = lowercase_token + '.hpp'
    lib_cpp_name = lowercase_token + '.cpp'
    test_cpp_name = lowercase_token + '_test.cpp'
    kwargs = {'utoken': uppercase_token,
              'ltoken': lowercase_token,
              'header_dir': lowercase_token,
              'class_name': class_name,
              'namespace': namespace,
              'header_file': lib_hpp_name,
              'source_file': lib_cpp_name,
              'test_source_file': test_cpp_name,
              'test_exe_name': lowercase_token,
              'project_name': project_name,
              'lib_name': lowercase_token,
              'test_name': lowercase_token,
              'version': version,
              }
    open(lib_hpp_name, 'w').write(lib_hpp_template.format(**kwargs))
    open(lib_cpp_name, 'w').write(lib_cpp_template.format(**kwargs))
    open(test_cpp_name, 'w').write(lib_cpp_test_template.format(**kwargs))
    open('meson.build', 'w').write(lib_cpp_meson_template.format(**kwargs))
meson-0.53.2/mesonbuild/templates/ctemplates.py0000644000175000017500000001130313571777336023207 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re


lib_h_template = '''#pragma once
#if defined _WIN32 || defined __CYGWIN__
  #ifdef BUILDING_{utoken}
    #define {utoken}_PUBLIC __declspec(dllexport)
  #else
    #define {utoken}_PUBLIC __declspec(dllimport)
  #endif
#else
  #ifdef BUILDING_{utoken}
      #define {utoken}_PUBLIC __attribute__ ((visibility ("default")))
  #else
      #define {utoken}_PUBLIC
  #endif
#endif

int {utoken}_PUBLIC {function_name}();

'''

lib_c_template = '''#include <{header_file}>

/* This function will not be exported and is not
 * directly callable by users of this library.
 */
int internal_function() {{
    return 0;
}}

int {function_name}() {{
    return internal_function();
}}
'''

lib_c_test_template = '''#include <{header_file}>
#include 

int main(int argc, char **argv) {{
    if(argc != 1) {{
        printf("%s takes no arguments.\\n", argv[0]);
        return 1;
    }}
    return {function_name}();
}}
'''

lib_c_meson_template = '''project('{project_name}', 'c',
  version : '{version}',
  default_options : ['warning_level=3'])

# These arguments are only used to build the shared library
# not the executables that use the library.
lib_args = ['-DBUILDING_{utoken}']

shlib = shared_library('{lib_name}', '{source_file}',
  install : true,
  c_args : lib_args,
  gnu_symbol_visibility : 'hidden',
)

test_exe = executable('{test_exe_name}', '{test_source_file}',
  link_with : shlib)
test('{test_name}', test_exe)

# Make this library usable as a Meson subproject.
{ltoken}_dep = declare_dependency(
  include_directories: include_directories('.'),
  link_with : shlib)

# Make this library usable from the system's
# package manager.
install_headers('{header_file}', subdir : '{header_dir}')

pkg_mod = import('pkgconfig')
pkg_mod.generate(
  name : '{project_name}',
  filebase : '{ltoken}',
  description : 'Meson sample project.',
  subdirs : '{header_dir}',
  libraries : shlib,
  version : '{version}',
)
'''

hello_c_template = '''#include 

#define PROJECT_NAME "{project_name}"

int main(int argc, char **argv) {{
    if(argc != 1) {{
        printf("%s takes no arguments.\\n", argv[0]);
        return 1;
    }}
    printf("This is project %s.\\n", PROJECT_NAME);
    return 0;
}}
'''

hello_c_meson_template = '''project('{project_name}', 'c',
  version : '{version}',
  default_options : ['warning_level=3'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''

def create_exe_c_sample(project_name, project_version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    source_name = lowercase_token + '.c'
    open(source_name, 'w').write(hello_c_template.format(project_name=project_name))
    open('meson.build', 'w').write(hello_c_meson_template.format(project_name=project_name,
                                                                 exe_name=lowercase_token,
                                                                 source_name=source_name,
                                                                 version=project_version))

def create_lib_c_sample(project_name, version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    uppercase_token = lowercase_token.upper()
    function_name = lowercase_token[0:3] + '_func'
    lib_h_name = lowercase_token + '.h'
    lib_c_name = lowercase_token + '.c'
    test_c_name = lowercase_token + '_test.c'
    kwargs = {'utoken': uppercase_token,
              'ltoken': lowercase_token,
              'header_dir': lowercase_token,
              'function_name': function_name,
              'header_file': lib_h_name,
              'source_file': lib_c_name,
              'test_source_file': test_c_name,
              'test_exe_name': lowercase_token,
              'project_name': project_name,
              'lib_name': lowercase_token,
              'test_name': lowercase_token,
              'version': version,
              }
    open(lib_h_name, 'w').write(lib_h_template.format(**kwargs))
    open(lib_c_name, 'w').write(lib_c_template.format(**kwargs))
    open(test_c_name, 'w').write(lib_c_test_template.format(**kwargs))
    open('meson.build', 'w').write(lib_c_meson_template.format(**kwargs))
meson-0.53.2/mesonbuild/templates/dlangtemplates.py0000644000175000017500000001023513605156067024043 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re


hello_d_template = '''module main;
import std.stdio;

enum PROJECT_NAME = "{project_name}";

int main(string[] args) {{
    if (args.length != 1){{
        writefln("%s takes no arguments.\\n", args[0]);
        return 1;
    }}
    writefln("This is project %s.\\n", PROJECT_NAME);
    return 0;
}}
'''

hello_d_meson_template = '''project('{project_name}', 'd',
    version : '{version}',
    default_options: ['warning_level=3'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''

lib_d_template = '''module {module_file};

/* This function will not be exported and is not
 * directly callable by users of this library.
 */
int internal_function() {{
    return 0;
}}

int {function_name}() {{
    return internal_function();
}}
'''

lib_d_test_template = '''module {module_file}_test;
import std.stdio;
import {module_file};


int main(string[] args) {{
    if (args.length != 1){{
        writefln("%s takes no arguments.\\n", args[0]);
        return 1;
    }}
    return {function_name}();
}}
'''

lib_d_meson_template = '''project('{project_name}', 'd',
  version : '{version}',
  default_options : ['warning_level=3'])

stlib = static_library('{lib_name}', '{source_file}',
  install : true,
  gnu_symbol_visibility : 'hidden',
)

test_exe = executable('{test_exe_name}', '{test_source_file}',
  link_with : stlib)
test('{test_name}', test_exe)

# Make this library usable as a Meson subproject.
{ltoken}_dep = declare_dependency(
  include_directories: include_directories('.'),
  link_with : stlib)

# Make this library usable from the Dlang
# build system.
dlang_mod = import('dlang')
if find_program('dub', required: false).found()
  dlang_mod.generate_dub_file(meson.project_name().to_lower(), meson.source_root(),
    name : meson.project_name(),
    license: meson.project_license(),
    sourceFiles : '{source_file}',
    description : 'Meson sample project.',
    version : '{version}',
  )
endif
'''

def create_exe_d_sample(project_name, project_version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    source_name = lowercase_token + '.d'
    open(source_name, 'w').write(hello_d_template.format(project_name=project_name))
    open('meson.build', 'w').write(hello_d_meson_template.format(project_name=project_name,
                                                                 exe_name=lowercase_token,
                                                                 source_name=source_name,
                                                                 version=project_version))


def create_lib_d_sample(project_name, version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    uppercase_token = lowercase_token.upper()
    function_name = lowercase_token[0:3] + '_func'
    lib_m_name = lowercase_token
    lib_d_name = lowercase_token + '.d'
    test_d_name = lowercase_token + '_test.d'
    kwargs = {'utoken': uppercase_token,
              'ltoken': lowercase_token,
              'header_dir': lowercase_token,
              'function_name': function_name,
              'module_file': lib_m_name,
              'source_file': lib_d_name,
              'test_source_file': test_d_name,
              'test_exe_name': lowercase_token,
              'project_name': project_name,
              'lib_name': lowercase_token,
              'test_name': lowercase_token,
              'version': version,
              }
    open(lib_d_name, 'w').write(lib_d_template.format(**kwargs))
    open(test_d_name, 'w').write(lib_d_test_template.format(**kwargs))
    open('meson.build', 'w').write(lib_d_meson_template.format(**kwargs))
meson-0.53.2/mesonbuild/templates/fortrantemplates.py0000644000175000017500000001004313571777336024440 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re

lib_fortran_template = '''
! This procedure will not be exported and is not
! directly callable by users of this library.

module modfoo

implicit none
private
public :: {function_name}

contains

integer function internal_function()
    internal_function = 0
end function internal_function

integer function {function_name}()
    {function_name} = internal_function()
end function {function_name}

end module modfoo
'''

lib_fortran_test_template = '''
use modfoo

print *,{function_name}()

end program
'''

lib_fortran_meson_template = '''project('{project_name}', 'fortran',
  version : '{version}',
  default_options : ['warning_level=3'])

# These arguments are only used to build the shared library
# not the executables that use the library.
lib_args = ['-DBUILDING_{utoken}']

shlib = shared_library('{lib_name}', '{source_file}',
  install : true,
  fortran_args : lib_args,
  gnu_symbol_visibility : 'hidden',
)

test_exe = executable('{test_exe_name}', '{test_source_file}',
  link_with : shlib)
test('{test_name}', test_exe)

# Make this library usable as a Meson subproject.
{ltoken}_dep = declare_dependency(
  include_directories: include_directories('.'),
  link_with : shlib)

pkg_mod = import('pkgconfig')
pkg_mod.generate(
  name : '{project_name}',
  filebase : '{ltoken}',
  description : 'Meson sample project.',
  subdirs : '{header_dir}',
  libraries : shlib,
  version : '{version}',
)
'''

hello_fortran_template = '''
implicit none

character(len=*), parameter :: PROJECT_NAME = "{project_name}"

print *,"This is project ", PROJECT_NAME

end program
'''

hello_fortran_meson_template = '''project('{project_name}', 'fortran',
  version : '{version}',
  default_options : ['warning_level=3'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''

def create_exe_fortran_sample(project_name, project_version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    source_name = lowercase_token + '.f90'
    open(source_name, 'w').write(hello_fortran_template.format(project_name=project_name))
    open('meson.build', 'w').write(hello_fortran_meson_template.format(project_name=project_name,
                                                                       exe_name=lowercase_token,
                                                                       source_name=source_name,
                                                                       version=project_version))

def create_lib_fortran_sample(project_name, version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    uppercase_token = lowercase_token.upper()
    function_name = lowercase_token[0:3] + '_func'
    lib_fortran_name = lowercase_token + '.f90'
    test_fortran_name = lowercase_token + '_test.f90'
    kwargs = {'utoken': uppercase_token,
              'ltoken': lowercase_token,
              'header_dir': lowercase_token,
              'function_name': function_name,
              'source_file': lib_fortran_name,
              'test_source_file': test_fortran_name,
              'test_exe_name': lowercase_token,
              'project_name': project_name,
              'lib_name': lowercase_token,
              'test_name': lowercase_token,
              'version': version,
              }
    open(lib_fortran_name, 'w').write(lib_fortran_template.format(**kwargs))
    open(test_fortran_name, 'w').write(lib_fortran_test_template.format(**kwargs))
    open('meson.build', 'w').write(lib_fortran_meson_template.format(**kwargs))
meson-0.53.2/mesonbuild/templates/objctemplates.py0000644000175000017500000001140713571777336023707 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re


lib_h_template = '''#pragma once
#if defined _WIN32 || defined __CYGWIN__
  #ifdef BUILDING_{utoken}
    #define {utoken}_PUBLIC __declspec(dllexport)
  #else
    #define {utoken}_PUBLIC __declspec(dllimport)
  #endif
#else
  #ifdef BUILDING_{utoken}
      #define {utoken}_PUBLIC __attribute__ ((visibility ("default")))
  #else
      #define {utoken}_PUBLIC
  #endif
#endif

int {utoken}_PUBLIC {function_name}();

'''

lib_objc_template = '''#import <{header_file}>

/* This function will not be exported and is not
 * directly callable by users of this library.
 */
int internal_function() {{
    return 0;
}}

int {function_name}() {{
    return internal_function();
}}
'''

lib_objc_test_template = '''#import <{header_file}>
#import 

int main(int argc, char **argv) {{
    if(argc != 1) {{
        printf("%s takes no arguments.\\n", argv[0]);
        return 1;
    }}
    return {function_name}();
}}
'''

lib_objc_meson_template = '''project('{project_name}', 'objc',
  version : '{version}',
  default_options : ['warning_level=3'])

# These arguments are only used to build the shared library
# not the executables that use the library.
lib_args = ['-DBUILDING_{utoken}']

shlib = shared_library('{lib_name}', '{source_file}',
  install : true,
  objc_args : lib_args,
  gnu_symbol_visibility : 'hidden',
)

test_exe = executable('{test_exe_name}', '{test_source_file}',
  link_with : shlib)
test('{test_name}', test_exe)

# Make this library usable as a Meson subproject.
{ltoken}_dep = declare_dependency(
  include_directories: include_directories('.'),
  link_with : shlib)

# Make this library usable from the system's
# package manager.
install_headers('{header_file}', subdir : '{header_dir}')

pkg_mod = import('pkgconfig')
pkg_mod.generate(
  name : '{project_name}',
  filebase : '{ltoken}',
  description : 'Meson sample project.',
  subdirs : '{header_dir}',
  libraries : shlib,
  version : '{version}',
)
'''

hello_objc_template = '''#import 

#define PROJECT_NAME "{project_name}"

int main(int argc, char **argv) {{
    if(argc != 1) {{
        printf("%s takes no arguments.\\n", argv[0]);
        return 1;
    }}
    printf("This is project %s.\\n", PROJECT_NAME);
    return 0;
}}
'''

hello_objc_meson_template = '''project('{project_name}', 'objc',
  version : '{version}',
  default_options : ['warning_level=3'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''

def create_exe_objc_sample(project_name, project_version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    source_name = lowercase_token + '.m'
    open(source_name, 'w').write(hello_objc_template.format(project_name=project_name))
    open('meson.build', 'w').write(hello_objc_meson_template.format(project_name=project_name,
                                                                    exe_name=lowercase_token,
                                                                    source_name=source_name,
                                                                    version=project_version))

def create_lib_objc_sample(project_name, version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    uppercase_token = lowercase_token.upper()
    function_name = lowercase_token[0:3] + '_func'
    lib_h_name = lowercase_token + '.h'
    lib_objc_name = lowercase_token + '.m'
    test_objc_name = lowercase_token + '_test.m'
    kwargs = {'utoken': uppercase_token,
              'ltoken': lowercase_token,
              'header_dir': lowercase_token,
              'function_name': function_name,
              'header_file': lib_h_name,
              'source_file': lib_objc_name,
              'test_source_file': test_objc_name,
              'test_exe_name': lowercase_token,
              'project_name': project_name,
              'lib_name': lowercase_token,
              'test_name': lowercase_token,
              'version': version,
              }
    open(lib_h_name, 'w').write(lib_h_template.format(**kwargs))
    open(lib_objc_name, 'w').write(lib_objc_template.format(**kwargs))
    open(test_objc_name, 'w').write(lib_objc_test_template.format(**kwargs))
    open('meson.build', 'w').write(lib_objc_meson_template.format(**kwargs))
meson-0.53.2/mesonbuild/templates/rusttemplates.py0000644000175000017500000000702513571777336023770 0ustar  jpakkanejpakkane00000000000000# Copyright 2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re


lib_rust_template = '''#![crate_name = "{crate_file}"]

/* This function will not be exported and is not
 * directly callable by users of this library.
 */
fn internal_function() -> i32 {{
    return 0;
}}

pub fn {function_name}() -> i32 {{
    return internal_function();
}}
'''

lib_rust_test_template = '''extern crate {crate_file};

fn main() {{
    println!("printing: {{}}", {crate_file}::{function_name}());
}}
'''


lib_rust_meson_template = '''project('{project_name}', 'rust',
  version : '{version}',
  default_options : ['warning_level=3'])

shlib = static_library('{lib_name}', '{source_file}', install : true)

test_exe = executable('{test_exe_name}', '{test_source_file}',
  link_with : shlib)
test('{test_name}', test_exe)

# Make this library usable as a Meson subproject.
{ltoken}_dep = declare_dependency(
  include_directories: include_directories('.'),
  link_with : shlib)
'''

hello_rust_template = '''
fn main() {{
    let project_name = "{project_name}";
    println!("This is project {{}}.\\n", project_name);
}}
'''

hello_rust_meson_template = '''project('{project_name}', 'rust',
  version : '{version}',
  default_options : ['warning_level=3'])

exe = executable('{exe_name}', '{source_name}',
  install : true)

test('basic', exe)
'''

def create_exe_rust_sample(project_name, project_version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    source_name = lowercase_token + '.rs'
    open(source_name, 'w').write(hello_rust_template.format(project_name=project_name))
    open('meson.build', 'w').write(hello_rust_meson_template.format(project_name=project_name,
                                                                    exe_name=lowercase_token,
                                                                    source_name=source_name,
                                                                    version=project_version))

def create_lib_rust_sample(project_name, version):
    lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
    uppercase_token = lowercase_token.upper()
    function_name = lowercase_token[0:3] + '_func'
    lib_crate_name = lowercase_token
    lib_rs_name = lowercase_token + '.rs'
    test_rs_name = lowercase_token + '_test.rs'
    kwargs = {'utoken': uppercase_token,
              'ltoken': lowercase_token,
              'header_dir': lowercase_token,
              'function_name': function_name,
              'crate_file': lib_crate_name,
              'source_file': lib_rs_name,
              'test_source_file': test_rs_name,
              'test_exe_name': lowercase_token,
              'project_name': project_name,
              'lib_name': lowercase_token,
              'test_name': lowercase_token,
              'version': version,
              }
    open(lib_rs_name, 'w').write(lib_rust_template.format(**kwargs))
    open(test_rs_name, 'w').write(lib_rust_test_template.format(**kwargs))
    open('meson.build', 'w').write(lib_rust_meson_template.format(**kwargs))
meson-0.53.2/mesonbuild/wrap/0000755000175000017500000000000013625242354017434 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/mesonbuild/wrap/__init__.py0000644000175000017500000000372313571777336021567 0ustar  jpakkanejpakkane00000000000000from enum import Enum

# Used for the --wrap-mode command-line argument
#
# Special wrap modes:
#   nofallback: Don't download wraps for dependency() fallbacks
#   nodownload: Don't download wraps for all subproject() calls
#
# subprojects are used for two purposes:
# 1. To download and build dependencies by using .wrap
#    files if they are not provided by the system. This is
#    usually expressed via dependency(..., fallback: ...).
# 2. To download and build 'copylibs' which are meant to be
#    used by copying into your project. This is always done
#    with an explicit subproject() call.
#
# --wrap-mode=nofallback will never do (1)
# --wrap-mode=nodownload will do neither (1) nor (2)
#
# If you are building from a release tarball, you should be
# able to safely use 'nodownload' since upstream is
# expected to ship all required sources with the tarball.
#
# If you are building from a git repository, you will want
# to use 'nofallback' so that any 'copylib' wraps will be
# download as subprojects.
#
# --wrap-mode=forcefallback will ignore external dependencies,
# even if they match the version requirements, and automatically
# use the fallback if one was provided. This is useful for example
# to make sure a project builds when using the fallbacks.
#
# Note that these options do not affect subprojects that
# are git submodules since those are only usable in git
# repositories, and you almost always want to download them.

# This did _not_ work when inside the WrapMode class.
# I don't know why. If you can fix this, patches welcome.
string_to_value = {'default': 1,
                   'nofallback': 2,
                   'nodownload': 3,
                   'forcefallback': 4,
                   }

class WrapMode(Enum):
    default = 1
    nofallback = 2
    nodownload = 3
    forcefallback = 4

    def __str__(self) -> str:
        return self.name

    @staticmethod
    def from_string(mode_name: str):
        g = string_to_value[mode_name]
        return WrapMode(g)
meson-0.53.2/mesonbuild/wrap/wrap.py0000644000175000017500000004341313625260316020762 0ustar  jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .. import mlog
import contextlib
import urllib.request
import urllib.error
import urllib.parse
import os
import hashlib
import shutil
import tempfile
import stat
import subprocess
import sys
import configparser
import typing as T

from . import WrapMode
from ..mesonlib import git, GIT, ProgressBar, MesonException

if T.TYPE_CHECKING:
    import http.client

try:
    # 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:
    has_ssl = False
    API_ROOT = 'http://wrapdb.mesonbuild.com/v1/'

REQ_TIMEOUT = 600.0
SSL_WARNING_PRINTED = False
WHITELIST_SUBDOMAIN = 'wrapdb.mesonbuild.com'

def quiet_git(cmd: T.List[str], workingdir: str) -> T.Tuple[bool, str]:
    if not GIT:
        return False, 'Git program not found.'
    pc = git(cmd, workingdir, universal_newlines=True,
             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if pc.returncode != 0:
        return False, pc.stderr
    return True, pc.stdout

def verbose_git(cmd: T.List[str], workingdir: str, check: bool = False) -> bool:
    if not GIT:
        return False
    return git(cmd, workingdir, check=check).returncode == 0

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(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:
        mlog.warning('SSL module not available in {}: WrapDB traffic not authenticated.'.format(sys.executable))
        SSL_WARNING_PRINTED = True
    try:
        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):
    pass

class WrapNotFoundException(WrapException):
    pass

class PackageDefinition:
    def __init__(self, fname: str):
        self.filename = fname
        self.basename = os.path.basename(fname)
        self.name = self.basename[:-5]
        try:
            self.config = configparser.ConfigParser(interpolation=None)
            self.config.read(fname)
        except configparser.Error:
            raise WrapException('Failed to parse {}'.format(self.basename))
        if len(self.config.sections()) < 1:
            raise WrapException('Missing sections in {}'.format(self.basename))
        self.wrap_section = self.config.sections()[0]
        if not self.wrap_section.startswith('wrap-'):
            m = '{!r} is not a valid first section in {}'
            raise WrapException(m.format(self.wrap_section, self.basename))
        self.type = self.wrap_section[5:]
        self.values = dict(self.config[self.wrap_section])

    def get(self, key: str) -> str:
        try:
            return self.values[key]
        except KeyError:
            m = 'Missing key {!r} in {}'
            raise WrapException(m.format(key, self.basename))

    def has_patch(self) -> bool:
        return 'patch_url' in self.values

def load_wrap(subdir_root: str, packagename: str) -> PackageDefinition:
    fname = os.path.join(subdir_root, packagename + '.wrap')
    if os.path.isfile(fname):
        return PackageDefinition(fname)
    return None

def get_directory(subdir_root: str, packagename: str):
    directory = packagename
    # We always have to load the wrap file, if it exists, because it could
    # override the default directory name.
    wrap = load_wrap(subdir_root, packagename)
    if wrap and 'directory' in wrap.values:
        directory = wrap.get('directory')
        if os.path.dirname(directory):
            raise WrapException('Directory key must be a name and not a path')
    return wrap, directory

class Resolver:
    def __init__(self, subdir_root: str, wrap_mode=WrapMode.default):
        self.wrap_mode = wrap_mode
        self.subdir_root = subdir_root
        self.cachedir = os.path.join(self.subdir_root, 'packagecache')

    def resolve(self, packagename: str, method: str) -> str:
        self.packagename = packagename
        self.wrap, self.directory = get_directory(self.subdir_root, self.packagename)
        self.dirname = os.path.join(self.subdir_root, self.directory)
        meson_file = os.path.join(self.dirname, 'meson.build')
        cmake_file = os.path.join(self.dirname, 'CMakeLists.txt')

        if method not in ['meson', 'cmake']:
            raise WrapException('Only the methods "meson" and "cmake" are supported')

        # The directory is there and has meson.build? Great, use it.
        if method == 'meson' and os.path.exists(meson_file):
            return self.directory
        if method == 'cmake' and os.path.exists(cmake_file):
            return self.directory

        # Check if the subproject is a git submodule
        self.resolve_git_submodule()

        if os.path.exists(self.dirname):
            if not os.path.isdir(self.dirname):
                raise WrapException('Path already exists but is not a directory')
        else:
            # A wrap file is required to download
            if not self.wrap:
                m = 'Subproject directory not found and {}.wrap file not found'
                raise WrapNotFoundException(m.format(self.packagename))

            if self.wrap.type == 'file':
                self.get_file()
            else:
                self.check_can_download()
                if self.wrap.type == 'git':
                    self.get_git()
                elif self.wrap.type == "hg":
                    self.get_hg()
                elif self.wrap.type == "svn":
                    self.get_svn()
                else:
                    raise WrapException('Unknown wrap type {!r}'.format(self.wrap.type))

        # A meson.build or CMakeLists.txt file is required in the directory
        if method == 'meson' and not os.path.exists(meson_file):
            raise WrapException('Subproject exists but has no meson.build file')
        if method == 'cmake' and not os.path.exists(cmake_file):
            raise WrapException('Subproject exists but has no CMakeLists.txt file')

        return self.directory

    def check_can_download(self) -> None:
        # Don't download subproject data based on wrap file if requested.
        # Git submodules are ok (see above)!
        if self.wrap_mode is WrapMode.nodownload:
            m = 'Automatic wrap-based subproject downloading is disabled'
            raise WrapException(m)

    def resolve_git_submodule(self) -> bool:
        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:
            return False
        # Is `dirname` a submodule?
        ret, out = quiet_git(['submodule', 'status', self.dirname], self.subdir_root)
        if not ret:
            return False
        # Submodule has not been added, add it
        if out.startswith('+'):
            mlog.warning('git submodule might be out of date')
            return True
        elif out.startswith('U'):
            raise WrapException('git submodule has merge conflicts')
        # Submodule exists, but is deinitialized or wasn't initialized
        elif out.startswith('-'):
            if verbose_git(['submodule', 'update', '--init', self.dirname], self.subdir_root):
                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(' '):
            verbose_git(['checkout', '.'], self.dirname)
            # Even if checkout failed, try building it anyway and let the user
            # handle any problems manually.
            return True
        elif out == '':
            # It is not a submodule, just a folder that exists in the main repository.
            return False
        m = 'Unknown git submodule output: {!r}'
        raise WrapException(m.format(out))

    def get_file(self) -> None:
        path = self.get_file_internal('source')
        extract_dir = self.subdir_root
        # Some upstreams ship packages that do not have a leading directory.
        # Create one for them.
        if 'lead_directory_missing' in self.wrap.values:
            os.mkdir(self.dirname)
            extract_dir = self.dirname
        shutil.unpack_archive(path, extract_dir)
        if self.wrap.has_patch():
            self.apply_patch()

    def get_git(self) -> None:
        if not GIT:
            raise WrapException('Git program not found.')
        revno = self.wrap.get('revision')
        is_shallow = False
        depth_option = []    # type: T.List[str]
        if self.wrap.values.get('depth', '') != '':
            is_shallow = True
            depth_option = ['--depth', self.wrap.values.get('depth')]
        # for some reason git only allows commit ids to be shallowly fetched by fetch not with clone
        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
            verbose_git(['init', self.directory], self.subdir_root, check=True)
            verbose_git(['remote', 'add', 'origin', self.wrap.get('url')], self.dirname, check=True)
            revno = self.wrap.get('revision')
            verbose_git(['fetch', *depth_option, 'origin', revno], self.dirname, check=True)
            verbose_git(['checkout', revno], self.dirname, check=True)
            if self.wrap.values.get('clone-recursive', '').lower() == 'true':
                verbose_git(['submodule', 'update', '--init', '--checkout',
                             '--recursive', *depth_option], self.dirname, check=True)
            push_url = self.wrap.values.get('push-url')
            if push_url:
                verbose_git(['remote', 'set-url', '--push', 'origin', push_url], self.dirname, check=True)
        else:
            if not is_shallow:
                verbose_git(['clone', self.wrap.get('url'), self.directory], self.subdir_root, check=True)
                if revno.lower() != 'head':
                    if not verbose_git(['checkout', revno], self.dirname):
                        verbose_git(['fetch', self.wrap.get('url'), revno], self.dirname, check=True)
                        verbose_git(['checkout', revno], self.dirname, check=True)
            else:
                verbose_git(['clone', *depth_option, '--branch', revno, self.wrap.get('url'),
                             self.directory], self.subdir_root, check=True)
            if self.wrap.values.get('clone-recursive', '').lower() == 'true':
                verbose_git(['submodule', 'update', '--init', '--checkout', '--recursive', *depth_option],
                            self.dirname, check=True)
            push_url = self.wrap.values.get('push-url')
            if push_url:
                verbose_git(['remote', 'set-url', '--push', 'origin', push_url], self.dirname, check=True)

    def is_git_full_commit_id(self, revno: str) -> bool:
        result = False
        if len(revno) in (40, 64): # 40 for sha1, 64 for upcoming sha256
            result = all((ch in '0123456789AaBbCcDdEeFf' for ch in revno))
        return result

    def get_hg(self) -> None:
        revno = self.wrap.get('revision')
        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],
                                  cwd=self.dirname)

    def get_svn(self) -> None:
        revno = self.wrap.get('revision')
        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, urlstring: str) -> T.Tuple[str, str]:
        blocksize = 10 * 1024
        h = hashlib.sha256()
        tmpfile = tempfile.NamedTemporaryFile(mode='wb', dir=self.cachedir, delete=False)
        url = urllib.parse.urlparse(urlstring)
        if url.hostname and 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(urlstring, timeout=REQ_TIMEOUT)
            except urllib.error.URLError:
                raise WrapException('could not get {} is the internet available?'.format(urlstring))
        with contextlib.closing(resp) as resp:
            try:
                dlsize = int(resp.info()['Content-Length'])
            except TypeError:
                dlsize = None
            if dlsize is None:
                print('Downloading file of unknown size.')
                while True:
                    block = resp.read(blocksize)
                    if block == b'':
                        break
                    h.update(block)
                    tmpfile.write(block)
                hashvalue = h.hexdigest()
                return hashvalue, tmpfile.name
            sys.stdout.flush()
            progress_bar = ProgressBar(bar_type='download', total=dlsize,
                                       desc='Downloading')
            while True:
                block = resp.read(blocksize)
                if block == b'':
                    break
                h.update(block)
                tmpfile.write(block)
                progress_bar.update(len(block))
            progress_bar.close()
            hashvalue = h.hexdigest()
        return hashvalue, tmpfile.name

    def check_hash(self, what: str, path: str) -> None:
        expected = self.wrap.get(what + '_hash')
        h = hashlib.sha256()
        with open(path, 'rb') as f:
            h.update(f.read())
        dhash = h.hexdigest()
        if dhash != expected:
            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()
        srcurl = self.wrap.get(what + '_url')
        mlog.log('Downloading', mlog.bold(self.packagename), what, 'from', mlog.bold(srcurl))
        dhash, tmpfile = self.get_data(srcurl)
        expected = self.wrap.get(what + '_hash')
        if dhash != expected:
            os.remove(tmpfile)
            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:
        filename = self.wrap.get(what + '_filename')
        cache_path = os.path.join(self.cachedir, filename)

        if os.path.exists(cache_path):
            self.check_hash(what, cache_path)
            mlog.log('Using', mlog.bold(self.packagename), what, 'from cache.')
            return cache_path

        if not os.path.isdir(self.cachedir):
            os.mkdir(self.cachedir)
        self.download(what, cache_path)
        return cache_path

    def apply_patch(self) -> None:
        path = self.get_file_internal('patch')
        try:
            shutil.unpack_archive(path, self.subdir_root)
        except Exception:
            with tempfile.TemporaryDirectory() as workdir:
                shutil.unpack_archive(path, workdir)
                self.copy_tree(workdir, self.subdir_root)

    def copy_tree(self, root_src_dir: str, root_dst_dir: str) -> None:
        """
        Copy directory tree. Overwrites also read only files.
        """
        for src_dir, _, files in os.walk(root_src_dir):
            dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
            if not os.path.exists(dst_dir):
                os.makedirs(dst_dir)
            for file_ in files:
                src_file = os.path.join(src_dir, file_)
                dst_file = os.path.join(dst_dir, file_)
                if os.path.exists(dst_file):
                    try:
                        os.remove(dst_file)
                    except PermissionError:
                        os.chmod(dst_file, stat.S_IWUSR)
                        os.remove(dst_file)
                shutil.copy2(src_file, dst_dir)
meson-0.53.2/mesonbuild/wrap/wraptool.py0000644000175000017500000001754513602226377021673 0ustar  jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import sys, os
import configparser
import shutil

from glob import glob

from .wrap import API_ROOT, open_wrapdburl

from .. import mesonlib

def add_arguments(parser):
    subparsers = parser.add_subparsers(title='Commands', dest='command')
    subparsers.required = True

    p = subparsers.add_parser('list', help='show all available projects')
    p.set_defaults(wrap_func=list_projects)

    p = subparsers.add_parser('search', help='search the db by name')
    p.add_argument('name')
    p.set_defaults(wrap_func=search)

    p = subparsers.add_parser('install', help='install the specified project')
    p.add_argument('name')
    p.set_defaults(wrap_func=install)

    p = subparsers.add_parser('update', help='update the project to its newest available release')
    p.add_argument('name')
    p.set_defaults(wrap_func=update)

    p = subparsers.add_parser('info', help='show available versions of a project')
    p.add_argument('name')
    p.set_defaults(wrap_func=info)

    p = subparsers.add_parser('status', help='show installed and available versions of your projects')
    p.set_defaults(wrap_func=status)

    p = subparsers.add_parser('promote', help='bring a subsubproject up to the master project')
    p.add_argument('project_path')
    p.set_defaults(wrap_func=promote)

def get_result(urlstring):
    u = open_wrapdburl(urlstring)
    data = u.read().decode('utf-8')
    jd = json.loads(data)
    if jd['output'] != 'ok':
        print('Got bad output from server.', file=sys.stderr)
        raise SystemExit(data)
    return jd

def get_projectlist():
    jd = get_result(API_ROOT + 'projects')
    projects = jd['projects']
    return projects

def list_projects(options):
    projects = get_projectlist()
    for p in projects:
        print(p)

def search(options):
    name = options.name
    jd = get_result(API_ROOT + 'query/byname/' + name)
    for p in jd['projects']:
        print(p)

def get_latest_version(name: str) -> tuple:
    jd = get_result(API_ROOT + 'query/get_latest/' + name)
    branch = jd['branch']
    revision = jd['revision']
    return branch, revision

def install(options):
    name = options.name
    if not os.path.isdir('subprojects'):
        raise SystemExit('Subprojects dir not found. Run this script in your source root directory.')
    if os.path.isdir(os.path.join('subprojects', name)):
        raise SystemExit('Subproject directory for this project already exists.')
    wrapfile = os.path.join('subprojects', name + '.wrap')
    if os.path.exists(wrapfile):
        raise SystemExit('Wrap file already exists.')
    (branch, revision) = get_latest_version(name)
    u = open_wrapdburl(API_ROOT + 'projects/{}/{}/{}/get_wrap'.format(name, branch, revision))
    data = u.read()
    with open(wrapfile, 'wb') as f:
        f.write(data)
    print('Installed', name, 'branch', branch, 'revision', revision)

def parse_patch_url(patch_url):
    arr = patch_url.split('/')
    return arr[-3], int(arr[-2])

def get_current_version(wrapfile):
    cp = configparser.ConfigParser()
    cp.read(wrapfile)
    cp = cp['wrap-file']
    patch_url = cp['patch_url']
    branch, revision = parse_patch_url(patch_url)
    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/{}/{}/{}/get_wrap'.format(name, new_branch, new_revision))
    data = u.read()
    with open(wrapfile, 'wb') as f:
        f.write(data)

def update(options):
    name = options.name
    if not os.path.isdir('subprojects'):
        raise SystemExit('Subprojects dir not found. Run this command in your source root directory.')
    wrapfile = os.path.join('subprojects', name + '.wrap')
    if not os.path.exists(wrapfile):
        raise SystemExit('Project ' + name + ' is not in use.')
    (branch, revision, subdir, src_file, patch_file) = get_current_version(wrapfile)
    (new_branch, new_revision) = get_latest_version(name)
    if new_branch == branch and new_revision == revision:
        print('Project ' + name + ' is already up to date.')
        raise SystemExit
    update_wrap_file(wrapfile, name, new_branch, new_revision)
    shutil.rmtree(os.path.join('subprojects', subdir), ignore_errors=True)
    try:
        os.unlink(os.path.join('subprojects/packagecache', src_file))
    except FileNotFoundError:
        pass
    try:
        os.unlink(os.path.join('subprojects/packagecache', patch_file))
    except FileNotFoundError:
        pass
    print('Updated', name, 'to branch', new_branch, 'revision', new_revision)

def info(options):
    name = options.name
    jd = get_result(API_ROOT + 'projects/' + name)
    versions = jd['versions']
    if not versions:
        raise SystemExit('No available versions of' + name)
    print('Available versions of {}:'.format(name))
    for v in versions:
        print(' ', v['branch'], v['revision'])

def do_promotion(from_path, spdir_name):
    if os.path.isfile(from_path):
        assert(from_path.endswith('.wrap'))
        shutil.copy(from_path, spdir_name)
    elif os.path.isdir(from_path):
        sproj_name = os.path.basename(from_path)
        outputdir = os.path.join(spdir_name, sproj_name)
        if os.path.exists(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):
    argument = options.project_path
    spdir_name = 'subprojects'
    sprojs = mesonlib.detect_subprojects(spdir_name)

    # check if the argument is a full path to a subproject directory or wrap file
    system_native_path_argument = argument.replace('/', os.sep)
    for matches in sprojs.values():
        if system_native_path_argument in matches:
            do_promotion(system_native_path_argument, spdir_name)
            return

    # otherwise the argument is just a subproject basename which must be unambiguous
    if argument not in sprojs:
        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 {} 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)
    do_promotion(matches[0], spdir_name)

def status(options):
    print('Subproject status')
    for w in glob('subprojects/*.wrap'):
        name = os.path.basename(w)[:-5]
        try:
            (latest_branch, latest_revision) = get_latest_version(name)
        except Exception:
            print('', name, 'not available in wrapdb.', file=sys.stderr)
            continue
        try:
            (current_branch, current_revision, _, _, _) = get_current_version(w)
        except Exception:
            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 {}, revision {}.'.format(current_branch, current_revision))
        else:
            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)
    return 0
meson-0.53.2/pyproject.toml0000644000175000017500000000006213571777336017251 0ustar  jpakkanejpakkane00000000000000[build-system]
requires = ["setuptools", "wheel"]
meson-0.53.2/run_cross_test.py0000755000175000017500000000402213455557413017757 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# Copyright 2013-2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

'''Runs the basic test suite through a cross compiler.
Not part of the main test suite because of two reasons:

1) setup of the cross build is platform specific
2) it can be slow (e.g. when invoking test apps via wine)

Eventually migrate to something fancier.'''

import sys
import os
from pathlib import Path
import argparse

from run_project_tests import gather_tests, run_tests, StopException, setup_commands
from run_project_tests import failing_logs

def runtests(cross_file, failfast):
    commontests = [('common', gather_tests(Path('test cases', 'common')), False)]
    try:
        (passing_tests, failing_tests, skipped_tests) = \
            run_tests(commontests, 'meson-cross-test-run', failfast, ['--cross-file', cross_file])
    except StopException:
        pass
    print('\nTotal passed cross tests:', passing_tests)
    print('Total failed cross tests:', failing_tests)
    print('Total skipped cross tests:', skipped_tests)
    if failing_tests > 0 and ('CI' in os.environ):
        print('\nMesonlogs of failing tests\n')
        for log in failing_logs:
            print(log, '\n')
    return failing_tests

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--failfast', action='store_true')
    parser.add_argument('cross_file')
    options = parser.parse_args()
    setup_commands('ninja')
    return runtests(options.cross_file, options.failfast)

if __name__ == '__main__':
    sys.exit(main())
meson-0.53.2/run_meson_command_tests.py0000755000175000017500000002040113531533273021620 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# Copyright 2018 The Meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys
import os
import tempfile
import unittest
import subprocess
import zipapp
from pathlib import Path

from mesonbuild.mesonlib import windows_proof_rmtree, python_command, is_windows

def get_pypath():
    import sysconfig
    pypath = sysconfig.get_path('purelib', vars={'base': ''})
    # Ensure that / is the path separator and not \, then strip /
    return Path(pypath).as_posix().strip('/')

def get_pybindir():
    import sysconfig
    # 'Scripts' on Windows and 'bin' on other platforms including MSYS
    return sysconfig.get_path('scripts', vars={'base': ''}).strip('\\/')

class CommandTests(unittest.TestCase):
    '''
    Test that running meson in various ways works as expected by checking the
    value of mesonlib.meson_command that was set during configuration.
    '''

    def setUp(self):
        super().setUp()
        self.orig_env = os.environ.copy()
        self.orig_dir = os.getcwd()
        os.environ['MESON_COMMAND_TESTS'] = '1'
        self.tmpdir = Path(tempfile.mkdtemp()).resolve()
        self.src_root = Path(__file__).resolve().parent
        self.testdir = str(self.src_root / 'test cases/common/1 trivial')
        self.meson_args = ['--backend=ninja']

    def tearDown(self):
        try:
            windows_proof_rmtree(str(self.tmpdir))
        except FileNotFoundError:
            pass
        os.environ.clear()
        os.environ.update(self.orig_env)
        os.chdir(str(self.orig_dir))
        super().tearDown()

    def _run(self, command, workdir=None):
        '''
        Run a command while printing the stdout, and also return a copy of it
        '''
        # If this call hangs CI will just abort. It is very hard to distinguish
        # between CI issue and test bug in that case. Set timeout and fail loud
        # instead.
        p = subprocess.run(command, stdout=subprocess.PIPE,
                           env=os.environ.copy(), universal_newlines=True,
                           cwd=workdir, timeout=60 * 5)
        print(p.stdout)
        if p.returncode != 0:
            raise subprocess.CalledProcessError(p.returncode, command)
        return p.stdout

    def assertMesonCommandIs(self, line, cmd):
        self.assertTrue(line.startswith('meson_command '), msg=line)
        self.assertEqual(line, 'meson_command is {!r}'.format(cmd))

    def test_meson_uninstalled(self):
        # This is what the meson command must be for all these cases
        resolved_meson_command = python_command + [str(self.src_root / 'meson.py')]
        # Absolute path to meson.py
        os.chdir('/')
        builddir = str(self.tmpdir / 'build1')
        meson_py = str(self.src_root / 'meson.py')
        meson_setup = [meson_py, 'setup']
        meson_command = python_command + meson_setup + self.meson_args
        stdo = self._run(meson_command + [self.testdir, builddir])
        self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
        # ./meson.py
        os.chdir(str(self.src_root))
        builddir = str(self.tmpdir / 'build2')
        meson_py = './meson.py'
        meson_setup = [meson_py, 'setup']
        meson_command = python_command + meson_setup + self.meson_args
        stdo = self._run(meson_command + [self.testdir, builddir])
        self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
        # Symlink to meson.py
        if is_windows():
            # Symlinks require admin perms
            return
        os.chdir(str(self.src_root))
        builddir = str(self.tmpdir / 'build3')
        # Create a symlink to meson.py in bindir, and add it to PATH
        bindir = (self.tmpdir / 'bin')
        bindir.mkdir()
        (bindir / 'meson').symlink_to(self.src_root / 'meson.py')
        os.environ['PATH'] = str(bindir) + os.pathsep + os.environ['PATH']
        # See if it works!
        meson_py = 'meson'
        meson_setup = [meson_py, 'setup']
        meson_command = meson_setup + self.meson_args
        stdo = self._run(meson_command + [self.testdir, builddir])
        self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)

    def test_meson_installed(self):
        # Install meson
        prefix = self.tmpdir / 'prefix'
        pylibdir = prefix / get_pypath()
        bindir = prefix / get_pybindir()
        pylibdir.mkdir(parents=True)
        # XXX: join with empty name so it always ends with os.sep otherwise
        # distutils complains that prefix isn't contained in PYTHONPATH
        os.environ['PYTHONPATH'] = os.path.join(str(pylibdir), '')
        os.environ['PATH'] = str(bindir) + os.pathsep + os.environ['PATH']
        self._run(python_command + ['setup.py', 'install', '--prefix', str(prefix)])
        # Check that all the files were installed correctly
        self.assertTrue(bindir.is_dir())
        self.assertTrue(pylibdir.is_dir())
        from setup import packages
        # Extract list of expected python module files
        expect = set()
        for pkg in packages:
            expect.update([p.as_posix() for p in Path(pkg.replace('.', '/')).glob('*.py')])
        # Check what was installed, only count files that are inside 'mesonbuild'
        have = set()
        for p in Path(pylibdir).glob('**/*.py'):
            s = p.as_posix()
            if 'mesonbuild' not in s:
                continue
            if '/data/' in s:
                continue
            have.add(s[s.rfind('mesonbuild'):])
        self.assertEqual(have, expect)
        # Run `meson`
        os.chdir('/')
        resolved_meson_command = [str(bindir / 'meson')]
        builddir = str(self.tmpdir / 'build1')
        meson_setup = ['meson', 'setup']
        meson_command = meson_setup + self.meson_args
        stdo = self._run(meson_command + [self.testdir, builddir])
        self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
        # Run `/path/to/meson`
        builddir = str(self.tmpdir / 'build2')
        meson_setup = [str(bindir / 'meson'), 'setup']
        meson_command = meson_setup + self.meson_args
        stdo = self._run(meson_command + [self.testdir, builddir])
        self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
        # Run `python3 -m mesonbuild.mesonmain`
        resolved_meson_command = python_command + ['-m', 'mesonbuild.mesonmain']
        builddir = str(self.tmpdir / 'build3')
        meson_setup = ['-m', 'mesonbuild.mesonmain', 'setup']
        meson_command = python_command + meson_setup + self.meson_args
        stdo = self._run(meson_command + [self.testdir, builddir])
        self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
        if is_windows():
            # Next part requires a shell
            return
        # `meson` is a wrapper to `meson.real`
        resolved_meson_command = [str(bindir / 'meson.real')]
        builddir = str(self.tmpdir / 'build4')
        (bindir / 'meson').rename(bindir / 'meson.real')
        wrapper = (bindir / 'meson')
        wrapper.open('w').write('#!/bin/sh\n\nmeson.real "$@"')
        wrapper.chmod(0o755)
        meson_setup = [str(wrapper), 'setup']
        meson_command = meson_setup + self.meson_args
        stdo = self._run(meson_command + [self.testdir, builddir])
        self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)

    def test_meson_exe_windows(self):
        raise unittest.SkipTest('NOT IMPLEMENTED')

    def test_meson_zipapp(self):
        if is_windows():
            raise unittest.SkipTest('NOT IMPLEMENTED')
        source = Path(__file__).resolve().parent.as_posix()
        target = self.tmpdir / 'meson.pyz'
        zipapp.create_archive(source=source, target=target, interpreter=python_command[0], main=None)
        self._run([target.as_posix(), '--help'])


if __name__ == '__main__':
    sys.exit(unittest.main(buffer=True))
meson-0.53.2/run_project_tests.py0000755000175000017500000012271513625260316020461 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# Copyright 2012-2019 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import typing as T
import itertools
import os
import subprocess
import shutil
import sys
import signal
import shlex
from io import StringIO
from ast import literal_eval
from enum import Enum
import tempfile
from pathlib import Path, PurePath
from mesonbuild import build
from mesonbuild import environment
from mesonbuild import compilers
from mesonbuild import mesonlib
from mesonbuild import mlog
from mesonbuild import mtest
from mesonbuild.mesonlib import MachineChoice, stringlistify, Popen_safe
from mesonbuild.coredata import backendlist
import argparse
import json
import xml.etree.ElementTree as ET
import time
import multiprocessing
from concurrent.futures import ProcessPoolExecutor, CancelledError
import re
from run_tests import get_fake_options, run_configure, get_meson_script
from run_tests import get_backend_commands, get_backend_args_for_dir, Backend
from run_tests import ensure_backend_detects_changes
from run_tests import guess_backend

ALL_TESTS = ['cmake', 'common', 'warning-meson', 'failing-meson', 'failing-build', 'failing-test',
             'kconfig', 'platform-osx', 'platform-windows', 'platform-linux',
             'java', 'C#', 'vala',  'rust', 'd', 'objective c', 'objective c++',
             'fortran', 'swift', 'cuda', 'python3', 'python', 'fpga', 'frameworks', 'nasm', 'wasm'
             ]


class BuildStep(Enum):
    configure = 1
    build = 2
    test = 3
    install = 4
    clean = 5
    validate = 6


class TestResult:
    def __init__(self, msg, step, stdo, stde, mlog, cicmds, conftime=0, buildtime=0, testtime=0):
        self.msg = msg
        self.step = step
        self.stdo = stdo
        self.stde = stde
        self.mlog = mlog
        self.cicmds = cicmds
        self.conftime = conftime
        self.buildtime = buildtime
        self.testtime = testtime


class TestDef:
    def __init__(self, path: Path, name: T.Optional[str], args: T.List[str], skip: bool = False):
        self.path = path
        self.name = name
        self.args = args
        self.skip = skip

    def __repr__(self) -> str:
        return '<{}: {:<48} [{}: {}] -- {}>'.format(type(self).__name__, str(self.path), self.name, self.args, self.skip)

    def display_name(self) -> str:
        if self.name:
            return '{}   ({})'.format(self.path.as_posix(), self.name)
        return self.path.as_posix()

class AutoDeletedDir:
    def __init__(self, d):
        self.dir = d

    def __enter__(self):
        os.makedirs(self.dir, exist_ok=True)
        return self.dir

    def __exit__(self, _type, value, traceback):
        # We don't use tempfile.TemporaryDirectory, but wrap the
        # deletion in the AutoDeletedDir class because
        # it fails on Windows due antivirus programs
        # holding files open.
        mesonlib.windows_proof_rmtree(self.dir)

failing_logs = []
print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
under_ci = 'CI' in os.environ
under_old_os_ci = 'OLD_OS_CI' in os.environ
do_debug = under_ci or print_debug
no_meson_log_msg = 'No meson-log.txt found.'

system_compiler = None

class StopException(Exception):
    def __init__(self):
        super().__init__('Stopped by user')

stop = False
def stop_handler(signal, frame):
    global stop
    stop = True
signal.signal(signal.SIGINT, stop_handler)
signal.signal(signal.SIGTERM, stop_handler)

def setup_commands(optbackend):
    global do_debug, backend, backend_flags
    global compile_commands, clean_commands, test_commands, install_commands, uninstall_commands
    backend, backend_flags = guess_backend(optbackend, shutil.which('msbuild'))
    compile_commands, clean_commands, test_commands, install_commands, \
        uninstall_commands = get_backend_commands(backend, do_debug)

def get_relative_files_list_from_dir(fromdir: Path) -> T.List[Path]:
    return [file.relative_to(fromdir) for file in fromdir.rglob('*') if file.is_file()]

def platform_fix_name(fname: str, compiler, env) -> str:
    # canonicalize compiler
    if (compiler in {'clang-cl', 'intel-cl'} or
       (env.machines.host.is_windows() and compiler == 'pgi')):
        canonical_compiler = 'msvc'
    else:
        canonical_compiler = compiler

    if '?lib' in fname:
        if env.machines.host.is_windows() and canonical_compiler == 'msvc':
            fname = re.sub(r'lib/\?lib(.*)\.', r'bin/\1.', fname)
            fname = re.sub(r'/\?lib/', r'/bin/', fname)
        elif env.machines.host.is_windows():
            fname = re.sub(r'lib/\?lib(.*)\.', r'bin/lib\1.', fname)
            fname = re.sub(r'\?lib(.*)\.dll$', r'lib\1.dll', fname)
            fname = re.sub(r'/\?lib/', r'/bin/', fname)
        elif env.machines.host.is_cygwin():
            fname = re.sub(r'lib/\?lib(.*)\.so$', r'bin/cyg\1.dll', fname)
            fname = re.sub(r'lib/\?lib(.*)\.', r'bin/cyg\1.', fname)
            fname = re.sub(r'\?lib(.*)\.dll$', r'cyg\1.dll', fname)
            fname = re.sub(r'/\?lib/', r'/bin/', fname)
        else:
            fname = re.sub(r'\?lib', 'lib', fname)

    if fname.endswith('?exe'):
        fname = fname[:-4]
        if env.machines.host.is_windows() or env.machines.host.is_cygwin():
            return fname + '.exe'

    if fname.startswith('?msvc:'):
        fname = fname[6:]
        if canonical_compiler != 'msvc':
            return None

    if fname.startswith('?gcc:'):
        fname = fname[5:]
        if canonical_compiler == 'msvc':
            return None

    if fname.startswith('?cygwin:'):
        fname = fname[8:]
        if not env.machines.host.is_cygwin():
            return None

    if fname.startswith('?!cygwin:'):
        fname = fname[9:]
        if env.machines.host.is_cygwin():
            return None

    if fname.endswith('?so'):
        if env.machines.host.is_windows() and canonical_compiler == 'msvc':
            fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname)
            fname = re.sub(r'/(?:lib|)([^/]*?)\?so$', r'/\1.dll', fname)
            return fname
        elif env.machines.host.is_windows():
            fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname)
            fname = re.sub(r'/([^/]*?)\?so$', r'/\1.dll', fname)
            return fname
        elif env.machines.host.is_cygwin():
            fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname)
            fname = re.sub(r'/lib([^/]*?)\?so$', r'/cyg\1.dll', fname)
            fname = re.sub(r'/([^/]*?)\?so$', r'/\1.dll', fname)
            return fname
        elif env.machines.host.is_darwin():
            return fname[:-3] + '.dylib'
        else:
            return fname[:-3] + '.so'

    if fname.endswith('?implib') or fname.endswith('?implibempty'):
        if env.machines.host.is_windows() and canonical_compiler == 'msvc':
            # only MSVC doesn't generate empty implibs
            if fname.endswith('?implibempty') and compiler == 'msvc':
                return None
            return re.sub(r'/(?:lib|)([^/]*?)\?implib(?:empty|)$', r'/\1.lib', fname)
        elif env.machines.host.is_windows() or env.machines.host.is_cygwin():
            return re.sub(r'\?implib(?:empty|)$', r'.dll.a', fname)
        else:
            return None

    return fname

def validate_install(srcdir: str, installdir: Path, compiler, env) -> str:
    # List of installed files
    info_file = Path(srcdir) / 'installed_files.txt'
    installdir = Path(installdir)
    # If this exists, the test does not install any other files
    noinst_file = Path('usr/no-installed-files')
    expected = {}  # type: T.Dict[Path, bool]
    ret_msg = ''
    # Generate list of expected files
    if (installdir / noinst_file).is_file():
        expected[noinst_file] = False
    elif info_file.is_file():
        with info_file.open() as f:
            for line in f:
                line = platform_fix_name(line.strip(), compiler, env)
                if line:
                    expected[Path(line)] = False
    # Check if expected files were found
    for fname in expected:
        file_path = installdir / fname
        if file_path.is_file() or file_path.is_symlink():
            expected[fname] = True
    for (fname, found) in expected.items():
        if not found:
            ret_msg += 'Expected file {} missing.\n'.format(fname)
    # Check if there are any unexpected files
    found = get_relative_files_list_from_dir(installdir)
    for fname in found:
        if fname not in expected:
            ret_msg += 'Extra file {} found.\n'.format(fname)
    if ret_msg != '':
        ret_msg += '\nInstall dir contents:\n'
        for i in found:
            ret_msg += '  - {}'.format(i)
    return ret_msg

def log_text_file(logfile, testdir, stdo, stde):
    global stop, executor, futures
    logfile.write('%s\nstdout\n\n---\n' % testdir.as_posix())
    logfile.write(stdo)
    logfile.write('\n\n---\n\nstderr\n\n---\n')
    logfile.write(stde)
    logfile.write('\n\n---\n\n')
    if print_debug:
        try:
            print(stdo)
        except UnicodeError:
            sanitized_out = stdo.encode('ascii', errors='replace').decode()
            print(sanitized_out)
        try:
            print(stde, file=sys.stderr)
        except UnicodeError:
            sanitized_err = stde.encode('ascii', errors='replace').decode()
            print(sanitized_err, file=sys.stderr)
    if stop:
        print("Aborting..")
        for f in futures:
            f[2].cancel()
        executor.shutdown()
        raise StopException()


def bold(text):
    return mlog.bold(text).get_text(mlog.colorize_console)


def green(text):
    return mlog.green(text).get_text(mlog.colorize_console)


def red(text):
    return mlog.red(text).get_text(mlog.colorize_console)


def yellow(text):
    return mlog.yellow(text).get_text(mlog.colorize_console)


def _run_ci_include(args: T.List[str]) -> str:
    if not args:
        return 'At least one parameter required'
    try:
        file_path = Path(args[0])
        data = file_path.open(errors='ignore', encoding='utf-8').read()
        return 'Included file {}:\n{}\n'.format(args[0], data)
    except Exception:
        return 'Failed to open {} ({})'.format(args[0])

ci_commands = {
    'ci_include': _run_ci_include
}

def run_ci_commands(raw_log: str) -> T.List[str]:
    res = []
    for l in raw_log.splitlines():
        if not l.startswith('!meson_ci!/'):
            continue
        cmd = shlex.split(l[11:])
        if not cmd or cmd[0] not in ci_commands:
            continue
        res += ['CI COMMAND {}:\n{}\n'.format(cmd[0], ci_commands[cmd[0]](cmd[1:]))]
    return res


def run_test_inprocess(testdir):
    old_stdout = sys.stdout
    sys.stdout = mystdout = StringIO()
    old_stderr = sys.stderr
    sys.stderr = mystderr = StringIO()
    old_cwd = os.getcwd()
    os.chdir(testdir)
    test_log_fname = Path('meson-logs', 'testlog.txt')
    try:
        returncode_test = mtest.run_with_args(['--no-rebuild'])
        if test_log_fname.exists():
            test_log = test_log_fname.open(errors='ignore').read()
        else:
            test_log = ''
        returncode_benchmark = mtest.run_with_args(['--no-rebuild', '--benchmark', '--logbase', 'benchmarklog'])
    finally:
        sys.stdout = old_stdout
        sys.stderr = old_stderr
        os.chdir(old_cwd)
    return max(returncode_test, returncode_benchmark), mystdout.getvalue(), mystderr.getvalue(), test_log

def parse_test_args(testdir):
    args = []
    try:
        with open(os.path.join(testdir, 'test_args.txt'), 'r') as f:
            content = f.read()
            try:
                args = literal_eval(content)
            except Exception:
                raise Exception('Malformed test_args file.')
            args = stringlistify(args)
    except FileNotFoundError:
        pass
    return args

# Build directory name must be the same so Ccache works over
# consecutive invocations.
def create_deterministic_builddir(src_dir, name):
    import hashlib
    if name:
        src_dir += name
    rel_dirname = 'b ' + hashlib.sha256(src_dir.encode(errors='ignore')).hexdigest()[0:10]
    os.mkdir(rel_dirname)
    abs_pathname = os.path.join(os.getcwd(), rel_dirname)
    return abs_pathname

def run_test(skipped, testdir, name, extra_args, compiler, backend, flags, commands, should_fail):
    if skipped:
        return None
    with AutoDeletedDir(create_deterministic_builddir(testdir, name)) as build_dir:
        with AutoDeletedDir(tempfile.mkdtemp(prefix='i ', dir=os.getcwd())) as install_dir:
            try:
                return _run_test(testdir, build_dir, install_dir, extra_args, compiler, backend, flags, commands, should_fail)
            finally:
                mlog.shutdown() # Close the log file because otherwise Windows wets itself.

def pass_prefix_to_test(dirname):
    if '39 prefix absolute' in dirname:
        return False
    return True

def pass_libdir_to_test(dirname):
    if '8 install' in dirname:
        return False
    if '38 libdir must be inside prefix' in dirname:
        return False
    if '195 install_mode' in dirname:
        return False
    return True

def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backend, flags, commands, should_fail):
    compile_commands, clean_commands, install_commands, uninstall_commands = commands
    test_args = parse_test_args(testdir)
    gen_start = time.time()
    setup_env = None
    # Configure in-process
    if pass_prefix_to_test(testdir):
        gen_args = ['--prefix', '/usr']
    else:
        gen_args = []
    if pass_libdir_to_test(testdir):
        gen_args += ['--libdir', 'lib']
    gen_args += [testdir, test_build_dir] + flags + test_args + extra_args
    nativefile = os.path.join(testdir, 'nativefile.ini')
    if os.path.exists(nativefile):
        gen_args.extend(['--native-file', nativefile])
    crossfile = os.path.join(testdir, 'crossfile.ini')
    if os.path.exists(crossfile):
        gen_args.extend(['--cross-file', crossfile])
    setup_env_file = os.path.join(testdir, 'setup_env.json')
    if os.path.exists(setup_env_file):
        setup_env = os.environ.copy()
        with open(setup_env_file, 'r') as fp:
            data = json.load(fp)
            for key, val in data.items():
                val = val.replace('@ROOT@', os.path.abspath(testdir))
                setup_env[key] = val
    (returncode, stdo, stde) = run_configure(gen_args, env=setup_env)
    try:
        logfile = Path(test_build_dir, 'meson-logs', 'meson-log.txt')
        mesonlog = logfile.open(errors='ignore', encoding='utf-8').read()
    except Exception:
        mesonlog = no_meson_log_msg
    cicmds = run_ci_commands(mesonlog)
    gen_time = time.time() - gen_start
    if should_fail == 'meson':
        if returncode == 1:
            return TestResult('', BuildStep.configure, stdo, stde, mesonlog, cicmds, gen_time)
        elif returncode != 0:
            return TestResult('Test exited with unexpected status {}'.format(returncode), BuildStep.configure, stdo, stde, mesonlog, cicmds, gen_time)
        else:
            return TestResult('Test that should have failed succeeded', BuildStep.configure, stdo, stde, mesonlog, cicmds, gen_time)
    if returncode != 0:
        return TestResult('Generating the build system failed.', BuildStep.configure, stdo, stde, mesonlog, cicmds, gen_time)
    builddata = build.load(test_build_dir)
    # Touch the meson.build file to force a regenerate so we can test that
    # regeneration works before a build is run.
    ensure_backend_detects_changes(backend)
    os.utime(os.path.join(testdir, 'meson.build'))
    # Build with subprocess
    dir_args = get_backend_args_for_dir(backend, test_build_dir)
    build_start = time.time()
    pc, o, e = Popen_safe(compile_commands + dir_args, cwd=test_build_dir)
    build_time = time.time() - build_start
    stdo += o
    stde += e
    if should_fail == 'build':
        if pc.returncode != 0:
            return TestResult('', BuildStep.build, stdo, stde, mesonlog, cicmds, gen_time)
        return TestResult('Test that should have failed to build succeeded', BuildStep.build, stdo, stde, mesonlog, cicmds, gen_time)
    if pc.returncode != 0:
        return TestResult('Compiling source code failed.', BuildStep.build, stdo, stde, mesonlog, cicmds, gen_time, build_time)
    # Touch the meson.build file to force a regenerate so we can test that
    # regeneration works after a build is complete.
    ensure_backend_detects_changes(backend)
    os.utime(os.path.join(testdir, 'meson.build'))
    test_start = time.time()
    # Test in-process
    (returncode, tstdo, tstde, test_log) = run_test_inprocess(test_build_dir)
    test_time = time.time() - test_start
    stdo += tstdo
    stde += tstde
    mesonlog += test_log
    if should_fail == 'test':
        if returncode != 0:
            return TestResult('', BuildStep.test, stdo, stde, mesonlog, cicmds, gen_time)
        return TestResult('Test that should have failed to run unit tests succeeded', BuildStep.test, stdo, stde, mesonlog, cicmds, gen_time)
    if returncode != 0:
        return TestResult('Running unit tests failed.', BuildStep.test, stdo, stde, mesonlog, cicmds, gen_time, build_time, test_time)
    # Do installation, if the backend supports it
    if install_commands:
        env = os.environ.copy()
        env['DESTDIR'] = install_dir
        # Install with subprocess
        pi, o, e = Popen_safe(install_commands, cwd=test_build_dir, env=env)
        stdo += o
        stde += e
        if pi.returncode != 0:
            return TestResult('Running install failed.', BuildStep.install, stdo, stde, mesonlog, cicmds, gen_time, build_time, test_time)
    # Clean with subprocess
    env = os.environ.copy()
    pi, o, e = Popen_safe(clean_commands + dir_args, cwd=test_build_dir, env=env)
    stdo += o
    stde += e
    if pi.returncode != 0:
        return TestResult('Running clean failed.', BuildStep.clean, stdo, stde, mesonlog, cicmds, gen_time, build_time, test_time)
    if not install_commands:
        return TestResult('', BuildStep.install, '', '', mesonlog, cicmds, gen_time, build_time, test_time)
    return TestResult(validate_install(testdir, install_dir, compiler, builddata.environment),
                      BuildStep.validate, stdo, stde, mesonlog, cicmds, gen_time, build_time, test_time)

def gather_tests(testdir: Path) -> T.List[TestDef]:
    tests = [t.name for t in testdir.glob('*') if t.is_dir()]
    tests = [t for t in tests if not t.startswith('.')]  # Filter non-tests files (dot files, etc)
    tests = [TestDef(testdir / t, None, []) for t in tests]
    all_tests = []
    for t in tests:
        matrix_file = t.path / 'test_matrix.json'
        if not matrix_file.is_file():
            all_tests += [t]
            continue

        # Build multiple tests from matrix definition
        opt_list = []  # type: T.List[T.List[T.Tuple[str, bool]]]
        matrix = json.loads(matrix_file.read_text())
        assert "options" in matrix
        for key, val in matrix["options"].items():
            assert isinstance(val, list)
            tmp_opts = []  # type: T.List[T.Tuple[str, bool]]
            for i in val:
                assert isinstance(i, dict)
                assert "val" in i
                skip = False

                # Skip the matrix entry if environment variable is present
                if 'skip_on_env' in i:
                    for env in i['skip_on_env']:
                        if env in os.environ:
                            skip = True

                tmp_opts += [('{}={}'.format(key, i['val']), skip)]

            if opt_list:
                new_opt_list = []  # type: T.List[T.List[T.Tuple[str, bool]]]
                for i in opt_list:
                    for j in tmp_opts:
                        new_opt_list += [[*i, j]]
                opt_list = new_opt_list
            else:
                opt_list = [[x] for x in tmp_opts]

        for i in opt_list:
            name = ' '.join([x[0] for x in i])
            opts = ['-D' + x[0] for x in i]
            skip = any([x[1] for x in i])
            all_tests += [TestDef(t.path, name, opts, skip)]

    all_tests = [(int(t.path.name.split()[0]), t.name or '', t) for t in all_tests]
    all_tests.sort()
    all_tests = [t[2] for t in all_tests]
    return all_tests

def have_d_compiler():
    if shutil.which("ldc2"):
        return True
    elif shutil.which("ldc"):
        return True
    elif shutil.which("gdc"):
        return True
    elif shutil.which("dmd"):
        # The Windows installer sometimes produces a DMD install
        # that exists but segfaults every time the compiler is run.
        # Don't know why. Don't know how to fix. Skip in this case.
        cp = subprocess.run(['dmd', '--version'],
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
        if cp.stdout == b'':
            return False
        return True
    return False

def have_objc_compiler():
    with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir:
        env = environment.Environment(None, build_dir, get_fake_options('/'))
        try:
            objc_comp = env.detect_objc_compiler(MachineChoice.HOST)
        except mesonlib.MesonException:
            return False
        if not objc_comp:
            return False
        env.coredata.process_new_compiler('objc', objc_comp, env)
        try:
            objc_comp.sanity_check(env.get_scratch_dir(), env)
        except mesonlib.MesonException:
            return False
    return True

def have_objcpp_compiler():
    with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir:
        env = environment.Environment(None, build_dir, get_fake_options('/'))
        try:
            objcpp_comp = env.detect_objcpp_compiler(MachineChoice.HOST)
        except mesonlib.MesonException:
            return False
        if not objcpp_comp:
            return False
        env.coredata.process_new_compiler('objcpp', objcpp_comp, env)
        try:
            objcpp_comp.sanity_check(env.get_scratch_dir(), env)
        except mesonlib.MesonException:
            return False
    return True

def have_java():
    if shutil.which('javac') and shutil.which('java'):
        return True
    return False

def skippable(suite, test):
    # Everything is optional when not running on CI, or on Ubuntu 16.04 CI
    if not under_ci or under_old_os_ci:
        return True

    if not suite.endswith('frameworks'):
        return True

    # gtk-doc test may be skipped, pending upstream fixes for spaces in
    # filenames landing in the distro used for CI
    if test.endswith('10 gtk-doc'):
        return True

    # NetCDF is not in the CI Docker image
    if test.endswith('netcdf'):
        return True

    # MSVC doesn't link with GFortran
    if test.endswith('14 fortran links c'):
        return True

    # Blocks are not supported on all compilers
    if test.endswith('29 blocks'):
        return True

    # No frameworks test should be skipped on linux CI, as we expect all
    # prerequisites to be installed
    if mesonlib.is_linux():
        return False

    # Boost test should only be skipped for windows CI build matrix entries
    # which don't define BOOST_ROOT
    if test.endswith('1 boost'):
        if mesonlib.is_windows():
            return 'BOOST_ROOT' not in os.environ
        return False

    # Qt is provided on macOS by Homebrew
    if test.endswith('4 qt') and mesonlib.is_osx():
        return False

    # Other framework tests are allowed to be skipped on other platforms
    return True

def skip_csharp(backend) -> bool:
    if backend is not Backend.ninja:
        return True
    if not shutil.which('resgen'):
        return True
    if shutil.which('mcs'):
        return False
    if shutil.which('csc'):
        # Only support VS2017 for now. Earlier versions fail
        # under CI in mysterious ways.
        try:
            stdo = subprocess.check_output(['csc', '/version'])
        except subprocess.CalledProcessError:
            return True
        # Having incrementing version numbers would be too easy.
        # Microsoft reset the versioning back to 1.0 (from 4.x)
        # when they got the Roslyn based compiler. Thus there
        # is NO WAY to reliably do version number comparisons.
        # Only support the version that ships with VS2017.
        return not stdo.startswith(b'2.')
    return True

# In Azure some setups have a broken rustc that will error out
# on all compilation attempts.

def has_broken_rustc() -> bool:
    dirname = 'brokenrusttest'
    if os.path.exists(dirname):
        mesonlib.windows_proof_rmtree(dirname)
    os.mkdir(dirname)
    open(dirname + '/sanity.rs', 'w').write('''fn main() {
}
''')
    pc = subprocess.run(['rustc', '-o', 'sanity.exe', 'sanity.rs'],
                        cwd=dirname,
                        stdout = subprocess.DEVNULL,
                        stderr = subprocess.DEVNULL)
    mesonlib.windows_proof_rmtree(dirname)
    return pc.returncode != 0

def should_skip_rust(backend: Backend) -> bool:
    if not shutil.which('rustc'):
        return True
    if backend is not Backend.ninja:
        return True
    if mesonlib.is_windows() and has_broken_rustc():
        return True
    return False

def detect_tests_to_run(only: T.List[str]) -> T.List[T.Tuple[str, T.List[TestDef], bool]]:
    """
    Parameters
    ----------
    only: list of str, optional
        specify names of tests to run

    Returns
    -------
    gathered_tests: list of tuple of str, list of TestDef, bool
        tests to run
    """

    skip_fortran = not(shutil.which('gfortran') or
                       shutil.which('flang') or
                       shutil.which('pgfortran') or
                       shutil.which('ifort'))

    # Name, subdirectory, skip condition.
    all_tests = [
        ('cmake', 'cmake', not shutil.which('cmake') or (os.environ.get('compiler') == 'msvc2015' and under_ci)),
        ('common', 'common', False),
        ('warning-meson', 'warning', False),
        ('failing-meson', 'failing', False),
        ('failing-build', 'failing build', False),
        ('failing-test',  'failing test', False),
        ('kconfig', 'kconfig', False),

        ('platform-osx', 'osx', not mesonlib.is_osx()),
        ('platform-windows', 'windows', not mesonlib.is_windows() and not mesonlib.is_cygwin()),
        ('platform-linux', 'linuxlike', mesonlib.is_osx() or mesonlib.is_windows()),

        ('java', 'java', backend is not Backend.ninja or mesonlib.is_osx() or not have_java()),
        ('C#', 'csharp', skip_csharp(backend)),
        ('vala', 'vala', backend is not Backend.ninja or not shutil.which(os.environ.get('VALAC', 'valac'))),
        ('rust', 'rust', should_skip_rust(backend)),
        ('d', 'd', backend is not Backend.ninja or not have_d_compiler()),
        ('objective c', 'objc', backend not in (Backend.ninja, Backend.xcode) or not have_objc_compiler()),
        ('objective c++', 'objcpp', backend not in (Backend.ninja, Backend.xcode) or not have_objcpp_compiler()),
        ('fortran', 'fortran', skip_fortran or backend != Backend.ninja),
        ('swift', 'swift', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('swiftc')),
        # CUDA tests on Windows: use Ninja backend:  python run_project_tests.py --only cuda --backend ninja
        ('cuda', 'cuda', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('nvcc')),
        ('python3', 'python3', backend is not Backend.ninja),
        ('python', 'python', backend is not Backend.ninja),
        ('fpga', 'fpga', shutil.which('yosys') is None),
        ('frameworks', 'frameworks', False),
        ('nasm', 'nasm', False),
        ('wasm', 'wasm', shutil.which('emcc') is None or backend is not Backend.ninja),
    ]

    names = [t[0] for t in all_tests]
    assert names == ALL_TESTS, 'argparse("--only", choices=ALL_TESTS) need to be updated to match all_tests names'
    if only:
        ind = [names.index(o) for o in only]
        all_tests = [all_tests[i] for i in ind]
    gathered_tests = [(name, gather_tests(Path('test cases', subdir)), skip) for name, subdir, skip in all_tests]
    return gathered_tests

def run_tests(all_tests: T.List[T.Tuple[str, T.List[TestDef], bool]],
              log_name_base: str, failfast: bool,
              extra_args: T.List[str]) -> T.Tuple[int, int, int]:
    global logfile
    txtname = log_name_base + '.txt'
    with open(txtname, 'w', encoding='utf-8', errors='ignore') as lf:
        logfile = lf
        return _run_tests(all_tests, log_name_base, failfast, extra_args)

def _run_tests(all_tests: T.List[T.Tuple[str, T.List[TestDef], bool]],
               log_name_base: str, failfast: bool,
               extra_args: T.List[str]) -> T.Tuple[int, int, int]:
    global stop, executor, futures, system_compiler
    xmlname = log_name_base + '.xml'
    junit_root = ET.Element('testsuites')
    conf_time = 0
    build_time = 0
    test_time = 0
    passing_tests = 0
    failing_tests = 0
    skipped_tests = 0
    commands = (compile_commands, clean_commands, install_commands, uninstall_commands)

    try:
        # This fails in some CI environments for unknown reasons.
        num_workers = multiprocessing.cpu_count()
    except Exception as e:
        print('Could not determine number of CPUs due to the following reason:' + str(e))
        print('Defaulting to using only one process')
        num_workers = 1
    # Due to Ninja deficiency, almost 50% of build time
    # is spent waiting. Do something useful instead.
    #
    # Remove this once the following issue has been resolved:
    # https://github.com/mesonbuild/meson/pull/2082
    if not mesonlib.is_windows():  # twice as fast on Windows by *not* multiplying by 2.
        num_workers *= 2
    executor = ProcessPoolExecutor(max_workers=num_workers)

    for name, test_cases, skipped in all_tests:
        current_suite = ET.SubElement(junit_root, 'testsuite', {'name': name, 'tests': str(len(test_cases))})
        print()
        if skipped:
            print(bold('Not running %s tests.' % name))
        else:
            print(bold('Running %s tests.' % name))
        print()
        futures = []
        for t in test_cases:
            # Jenkins screws us over by automatically sorting test cases by name
            # and getting it wrong by not doing logical number sorting.
            (testnum, testbase) = t.path.name.split(' ', 1)
            testname = '%.3d %s' % (int(testnum), testbase)
            if t.name:
                testname += ' ({})'.format(t.name)
            should_fail = False
            suite_args = []
            if name.startswith('failing'):
                should_fail = name.split('failing-')[1]
            if name.startswith('warning'):
                suite_args = ['--fatal-meson-warnings']
                should_fail = name.split('warning-')[1]

            result = executor.submit(run_test, skipped or t.skip, t.path.as_posix(), t.name, extra_args + suite_args + t.args,
                                     system_compiler, backend, backend_flags, commands, should_fail)
            futures.append((testname, t, result))
        for (testname, t, result) in futures:
            sys.stdout.flush()
            try:
                result = result.result()
            except CancelledError:
                continue
            if (result is None) or (('MESON_SKIP_TEST' in result.stdo) and (skippable(name, t.path.as_posix()))):
                print(yellow('Skipping:'), t.display_name())
                current_test = ET.SubElement(current_suite, 'testcase', {'name': testname,
                                                                         'classname': name})
                ET.SubElement(current_test, 'skipped', {})
                skipped_tests += 1
            else:
                without_install = "" if len(install_commands) > 0 else " (without install)"
                if result.msg != '':
                    print(red('Failed test{} during {}: {!r}'.format(without_install, result.step.name, t.display_name())))
                    print('Reason:', result.msg)
                    failing_tests += 1
                    if result.step == BuildStep.configure and result.mlog != no_meson_log_msg:
                        # For configure failures, instead of printing stdout,
                        # print the meson log if available since it's a superset
                        # of stdout and often has very useful information.
                        failing_logs.append(result.mlog)
                    elif under_ci:
                        # Always print the complete meson log when running in
                        # a CI. This helps debugging issues that only occur in
                        # a hard to reproduce environment
                        failing_logs.append(result.mlog)
                        failing_logs.append(result.stdo)
                    else:
                        failing_logs.append(result.stdo)
                    for cmd_res in result.cicmds:
                        failing_logs.append(cmd_res)
                    failing_logs.append(result.stde)
                    if failfast:
                        print("Cancelling the rest of the tests")
                        for (_, _, res) in futures:
                            res.cancel()
                else:
                    print('Succeeded test%s: %s' % (without_install, t.display_name()))
                    passing_tests += 1
                conf_time += result.conftime
                build_time += result.buildtime
                test_time += result.testtime
                total_time = conf_time + build_time + test_time
                log_text_file(logfile, t.path, result.stdo, result.stde)
                current_test = ET.SubElement(current_suite, 'testcase', {'name': testname,
                                                                         'classname': name,
                                                                         'time': '%.3f' % total_time})
                if result.msg != '':
                    ET.SubElement(current_test, 'failure', {'message': result.msg})
                stdoel = ET.SubElement(current_test, 'system-out')
                stdoel.text = result.stdo
                stdeel = ET.SubElement(current_test, 'system-err')
                stdeel.text = result.stde

            if failfast and failing_tests > 0:
                break

    print("\nTotal configuration time: %.2fs" % conf_time)
    print("Total build time: %.2fs" % build_time)
    print("Total test time: %.2fs" % test_time)
    ET.ElementTree(element=junit_root).write(xmlname, xml_declaration=True, encoding='UTF-8')
    return passing_tests, failing_tests, skipped_tests

def check_file(file: Path):
    lines = file.read_bytes().split(b'\n')
    tabdetector = re.compile(br' *\t')
    for i, line in enumerate(lines):
        if re.match(tabdetector, line):
            raise SystemExit("File {} contains a tab indent on line {:d}. Only spaces are permitted.".format(file, i + 1))
        if line.endswith(b'\r'):
            raise SystemExit("File {} contains DOS line ending on line {:d}. Only unix-style line endings are permitted.".format(file, i + 1))

def check_format():
    check_suffixes = {'.c',
                      '.cpp',
                      '.cxx',
                      '.cc',
                      '.rs',
                      '.f90',
                      '.vala',
                      '.d',
                      '.s',
                      '.m',
                      '.mm',
                      '.asm',
                      '.java',
                      '.txt',
                      '.py',
                      '.swift',
                      '.build',
                      '.md',
                      }
    for (root, _, filenames) in os.walk('.'):
        if '.dub' in root: # external deps are here
            continue
        if '.pytest_cache' in root:
            continue
        if 'meson-logs' in root or 'meson-private' in root:
            continue
        if '.eggs' in root or '_cache' in root:  # e.g. .mypy_cache
            continue
        for fname in filenames:
            file = Path(fname)
            if file.suffix.lower() in check_suffixes:
                if file.name in ('sitemap.txt', 'meson-test-run.txt'):
                    continue
                check_file(root / file)

def check_meson_commands_work():
    global backend, compile_commands, test_commands, install_commands
    testdir = PurePath('test cases', 'common', '1 trivial').as_posix()
    meson_commands = mesonlib.python_command + [get_meson_script()]
    with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir:
        print('Checking that configuring works...')
        gen_cmd = meson_commands + [testdir, build_dir] + backend_flags
        pc, o, e = Popen_safe(gen_cmd)
        if pc.returncode != 0:
            raise RuntimeError('Failed to configure {!r}:\n{}\n{}'.format(testdir, e, o))
        print('Checking that building works...')
        dir_args = get_backend_args_for_dir(backend, build_dir)
        pc, o, e = Popen_safe(compile_commands + dir_args, cwd=build_dir)
        if pc.returncode != 0:
            raise RuntimeError('Failed to build {!r}:\n{}\n{}'.format(testdir, e, o))
        print('Checking that testing works...')
        pc, o, e = Popen_safe(test_commands, cwd=build_dir)
        if pc.returncode != 0:
            raise RuntimeError('Failed to test {!r}:\n{}\n{}'.format(testdir, e, o))
        if install_commands:
            print('Checking that installing works...')
            pc, o, e = Popen_safe(install_commands, cwd=build_dir)
            if pc.returncode != 0:
                raise RuntimeError('Failed to install {!r}:\n{}\n{}'.format(testdir, e, o))


def detect_system_compiler():
    global system_compiler

    with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir:
        env = environment.Environment(None, build_dir, get_fake_options('/'))
        print()
        for lang in sorted(compilers.all_languages):
            try:
                comp = env.compiler_from_language(lang, MachineChoice.HOST)
                details = '%s %s' % (' '.join(comp.get_exelist()), comp.get_version_string())
            except mesonlib.MesonException:
                comp = None
                details = 'not found'
            print('%-7s: %s' % (lang, details))

            # note C compiler for later use by platform_fix_name()
            if lang == 'c':
                if comp:
                    system_compiler = comp.get_id()
                else:
                    raise RuntimeError("Could not find C compiler.")
        print()

def print_tool_versions():
    tools = [
        {
            'tool': 'cmake',
            'args': ['--version'],
            'regex': re.compile(r'^cmake version ([0-9]+(\.[0-9]+)*)$'),
            'match_group': 1,
        },
    ]

    def get_version(t: dict) -> str:
        exe = shutil.which(t['tool'])
        if not exe:
            return 'not found'

        args = [t['tool']] + t['args']
        pc, o, e = Popen_safe(args)
        if pc.returncode != 0:
            return '{} (invalid {} executable)'.format(exe, t['tool'])
        for i in o.split('\n'):
            i = i.strip('\n\r\t ')
            m = t['regex'].match(i)
            if m is not None:
                return '{} ({})'.format(exe, m.group(t['match_group']))

        return '{} (unknown)'.format(exe)

    max_width = max([len(x['tool']) for x in tools] + [7])
    for tool in tools:
        print('{0:<{2}}: {1}'.format(tool['tool'], get_version(tool), max_width))
    print()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
    parser.add_argument('extra_args', nargs='*',
                        help='arguments that are passed directly to Meson (remember to have -- before these).')
    parser.add_argument('--backend', dest='backend', choices=backendlist)
    parser.add_argument('--failfast', action='store_true',
                        help='Stop running if test case fails')
    parser.add_argument('--no-unittests', action='store_true',
                        help='Not used, only here to simplify run_tests.py')
    parser.add_argument('--only', help='name of test(s) to run', nargs='+', choices=ALL_TESTS)
    options = parser.parse_args()
    setup_commands(options.backend)

    detect_system_compiler()
    print_tool_versions()
    script_dir = os.path.split(__file__)[0]
    if script_dir != '':
        os.chdir(script_dir)
    check_format()
    check_meson_commands_work()
    try:
        all_tests = detect_tests_to_run(options.only)
        (passing_tests, failing_tests, skipped_tests) = run_tests(all_tests, 'meson-test-run', options.failfast, options.extra_args)
    except StopException:
        pass
    print('\nTotal passed tests:', green(str(passing_tests)))
    print('Total failed tests:', red(str(failing_tests)))
    print('Total skipped tests:', yellow(str(skipped_tests)))
    if failing_tests > 0:
        print('\nMesonlogs of failing tests\n')
        for l in failing_logs:
            try:
                print(l, '\n')
            except UnicodeError:
                print(l.encode('ascii', errors='replace').decode(), '\n')
    for name, dirs, _ in all_tests:
        dir_names = list(set(x.path.name for x in dirs))
        for k, g in itertools.groupby(dir_names, key=lambda x: x.split()[0]):
            tests = list(g)
            if len(tests) != 1:
                print('WARNING: The %s suite contains duplicate "%s" tests: "%s"' % (name, k, '", "'.join(tests)))
    raise SystemExit(failing_tests)
meson-0.53.2/run_tests.py0000755000175000017500000003677313625260316016743 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
import time
import shutil
import subprocess
import tempfile
import platform
import argparse
from io import StringIO
from enum import Enum
from glob import glob
from pathlib import Path
from mesonbuild import compilers
from mesonbuild import dependencies
from mesonbuild import mesonlib
from mesonbuild import mesonmain
from mesonbuild import mtest
from mesonbuild import mlog
from mesonbuild.environment import Environment, detect_ninja
from mesonbuild.coredata import backendlist

NINJA_1_9_OR_NEWER = False

def guess_backend(backend, msbuild_exe: str):
    # Auto-detect backend if unspecified
    backend_flags = []
    if backend is None:
        if msbuild_exe is not None and (mesonlib.is_windows() and not _using_intelcl()):
            backend = 'vs' # Meson will auto-detect VS version to use
        else:
            backend = 'ninja'
    # Set backend arguments for Meson
    if backend.startswith('vs'):
        backend_flags = ['--backend=' + backend]
        backend = Backend.vs
    elif backend == 'xcode':
        backend_flags = ['--backend=xcode']
        backend = Backend.xcode
    elif backend == 'ninja':
        backend_flags = ['--backend=ninja']
        backend = Backend.ninja
    else:
        raise RuntimeError('Unknown backend: {!r}'.format(backend))
    return (backend, backend_flags)


def _using_intelcl() -> bool:
    """
    detect if intending to using Intel-Cl compilers (Intel compilers on Windows)
    Sufficient evidence of intent is that user is working in the Intel compiler
    shell environment, otherwise this function returns False
    """
    if not mesonlib.is_windows():
        return False
    # handle where user tried to "blank" MKLROOT and left space(s)
    if not os.environ.get('MKLROOT', '').strip():
        return False
    if (os.environ.get('CC') == 'icl' or
            os.environ.get('CXX') == 'icl' or
            os.environ.get('FC') == 'ifort'):
        return True
    # Intel-Cl users might not have the CC,CXX,FC envvars set,
    # but because they're in Intel shell, the exe's below are on PATH
    if shutil.which('icl') or shutil.which('ifort'):
        return True
    mlog.warning('It appears you might be intending to use Intel compiler on Windows '
                 'since non-empty environment variable MKLROOT is set to {} '
                 'However, Meson cannot find the Intel WIndows compiler executables (icl,ifort).'
                 'Please try using the Intel shell.'.format(os.environ.get('MKLROOT')))
    return False


# Fake classes and objects for mocking
class FakeBuild:
    def __init__(self, env):
        self.environment = env

class FakeCompilerOptions:
    def __init__(self):
        self.value = []

def get_fake_options(prefix=''):
    opts = argparse.Namespace()
    opts.native_file = []
    opts.cross_file = None
    opts.wrap_mode = None
    opts.prefix = prefix
    opts.cmd_line_options = {}
    return opts

def get_fake_env(sdir='', bdir=None, prefix='', opts=None):
    if opts is None:
        opts = get_fake_options(prefix)
    env = Environment(sdir, bdir, opts)
    env.coredata.compiler_options.host['c_args'] = FakeCompilerOptions()
    env.machines.host.cpu_family = 'x86_64' # Used on macOS inside find_library
    return env


Backend = Enum('Backend', 'ninja vs xcode')

if 'MESON_EXE' in os.environ:
    meson_exe = mesonlib.split_args(os.environ['MESON_EXE'])
else:
    meson_exe = None

if mesonlib.is_windows() or mesonlib.is_cygwin():
    exe_suffix = '.exe'
else:
    exe_suffix = ''

def get_meson_script():
    '''
    Guess the meson that corresponds to the `mesonbuild` that has been imported
    so we can run configure and other commands in-process, since mesonmain.run
    needs to know the meson_command to use.

    Also used by run_unittests.py to determine what meson to run when not
    running in-process (which is the default).
    '''
    # Is there a meson.py next to the mesonbuild currently in use?
    mesonbuild_dir = Path(mesonmain.__file__).resolve().parent.parent
    meson_script = mesonbuild_dir / 'meson.py'
    if meson_script.is_file():
        return str(meson_script)
    # Then if mesonbuild is in PYTHONPATH, meson must be in PATH
    mlog.warning('Could not find meson.py next to the mesonbuild module. '
                 'Trying system meson...')
    meson_cmd = shutil.which('meson')
    if meson_cmd:
        return meson_cmd
    raise RuntimeError('Could not find {!r} or a meson in PATH'.format(meson_script))

def get_backend_args_for_dir(backend, builddir):
    '''
    Visual Studio backend needs to be given the solution to build
    '''
    if backend is Backend.vs:
        sln_name = glob(os.path.join(builddir, '*.sln'))[0]
        return [os.path.split(sln_name)[-1]]
    return []

def find_vcxproj_with_target(builddir, target):
    import re, fnmatch
    t, ext = os.path.splitext(target)
    if ext:
        p = r'{}\s*\{}'.format(t, ext)
    else:
        p = r'{}'.format(t)
    for _, _, files in os.walk(builddir):
        for f in fnmatch.filter(files, '*.vcxproj'):
            f = os.path.join(builddir, f)
            with open(f, 'r', encoding='utf-8') as o:
                if re.search(p, o.read(), flags=re.MULTILINE):
                    return f
    raise RuntimeError('No vcxproj matching {!r} in {!r}'.format(p, builddir))

def get_builddir_target_args(backend, builddir, target):
    dir_args = []
    if not target:
        dir_args = get_backend_args_for_dir(backend, builddir)
    if target is None:
        return dir_args
    if backend is Backend.vs:
        vcxproj = find_vcxproj_with_target(builddir, target)
        target_args = [vcxproj]
    elif backend is Backend.xcode:
        target_args = ['-target', target]
    elif backend is Backend.ninja:
        target_args = [target]
    else:
        raise AssertionError('Unknown backend: {!r}'.format(backend))
    return target_args + dir_args

def get_backend_commands(backend, debug=False):
    install_cmd = []
    uninstall_cmd = []
    if backend is Backend.vs:
        cmd = ['msbuild']
        clean_cmd = cmd + ['/target:Clean']
        test_cmd = cmd + ['RUN_TESTS.vcxproj']
    elif backend is Backend.xcode:
        cmd = ['xcodebuild']
        # In Xcode9 new build system's clean command fails when using a custom build directory.
        # Maybe use it when CI uses Xcode10 we can remove '-UseNewBuildSystem=FALSE'
        clean_cmd = cmd + ['-alltargets', 'clean', '-UseNewBuildSystem=FALSE']
        test_cmd = cmd + ['-target', 'RUN_TESTS']
    elif backend is Backend.ninja:
        global NINJA_1_9_OR_NEWER
        # Look for 1.9 to see if https://github.com/ninja-build/ninja/issues/1219
        # is fixed, else require 1.6 for -w dupbuild=err
        for v in ('1.9', '1.6'):
            ninja_cmd = detect_ninja(v)
            if ninja_cmd is not None:
                if v == '1.9':
                    NINJA_1_9_OR_NEWER = True
                else:
                    mlog.warning('Found ninja <1.9, tests will run slower', once=True)
                    if 'CI' in os.environ and 'OLD_OS_CI' not in os.environ:
                        raise RuntimeError('Require ninja >= 1.9 when running on Meson CI')
                break
        cmd = [ninja_cmd, '-w', 'dupbuild=err', '-d', 'explain']
        if cmd[0] is None:
            raise RuntimeError('Could not find Ninja v1.6 or newer')
        if debug:
            cmd += ['-v']
        clean_cmd = cmd + ['clean']
        test_cmd = cmd + ['test', 'benchmark']
        install_cmd = cmd + ['install']
        uninstall_cmd = cmd + ['uninstall']
    else:
        raise AssertionError('Unknown backend: {!r}'.format(backend))
    return cmd, clean_cmd, test_cmd, install_cmd, uninstall_cmd

def ensure_backend_detects_changes(backend):
    global NINJA_1_9_OR_NEWER
    if backend is not Backend.ninja:
        return
    need_workaround = False
    # We're not running on HFS+ which only stores dates in seconds:
    # https://developer.apple.com/legacy/library/technotes/tn/tn1150.html#HFSPlusDates
    # XXX: Upgrade Travis image to Apple FS when that becomes available
    # TODO: Detect HFS+ vs APFS
    if mesonlib.is_osx():
        mlog.warning('Running on HFS+, enabling timestamp resolution workaround', once=True)
        need_workaround = True
    # We're using ninja >= 1.9 which has QuLogic's patch for sub-1s resolution
    # timestamps
    if not NINJA_1_9_OR_NEWER:
        mlog.warning('Don\'t have ninja >= 1.9, enabling timestamp resolution workaround', once=True)
        need_workaround = True
    # Increase the difference between build.ninja's timestamp and the timestamp
    # of whatever you changed: https://github.com/ninja-build/ninja/issues/371
    if need_workaround:
        time.sleep(1)

def run_mtest_inprocess(commandlist):
    old_stdout = sys.stdout
    sys.stdout = mystdout = StringIO()
    old_stderr = sys.stderr
    sys.stderr = mystderr = StringIO()
    try:
        returncode = mtest.run_with_args(commandlist)
    finally:
        sys.stdout = old_stdout
        sys.stderr = old_stderr
    return returncode, mystdout.getvalue(), mystderr.getvalue()

def clear_meson_configure_class_caches():
    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
    sys.stdout = mystdout = StringIO()
    old_stderr = sys.stderr
    sys.stderr = mystderr = StringIO()
    old_environ = os.environ.copy()
    if env is not None:
        os.environ.update(env)
    try:
        returncode = mesonmain.run(commandlist, get_meson_script())
    finally:
        sys.stdout = old_stdout
        sys.stderr = old_stderr
        clear_meson_configure_class_caches()
        os.environ.clear()
        os.environ.update(old_environ)
    return returncode, mystdout.getvalue(), mystderr.getvalue()

def run_configure_external(full_command, env=None):
    pc, o, e = mesonlib.Popen_safe(full_command, env=env)
    return pc.returncode, o, e

def run_configure(commandlist, env=None):
    global meson_exe
    if meson_exe:
        return run_configure_external(meson_exe + commandlist, env=env)
    return run_configure_inprocess(commandlist, env=env)

def print_system_info():
    print(mlog.bold('System information.').get_text(mlog.colorize_console))
    print('Architecture:', platform.architecture())
    print('Machine:', platform.machine())
    print('Platform:', platform.system())
    print('Processor:', platform.processor())
    print('System:', platform.system())
    print('')

def main():
    print_system_info()
    parser = argparse.ArgumentParser()
    parser.add_argument('--cov', action='store_true')
    parser.add_argument('--backend', default=None, dest='backend',
                        choices=backendlist)
    parser.add_argument('--cross', default=False, dest='cross', action='store_true')
    parser.add_argument('--failfast', action='store_true')
    parser.add_argument('--no-unittests', action='store_true', default=False)
    (options, _) = parser.parse_known_args()
    # Enable coverage early...
    enable_coverage = options.cov
    if enable_coverage:
        os.makedirs('.coverage', exist_ok=True)
        sys.argv.remove('--cov')
        import coverage
        coverage.process_startup()
    returncode = 0
    cross = options.cross
    backend, _ = guess_backend(options.backend, shutil.which('msbuild'))
    no_unittests = options.no_unittests
    # Running on a developer machine? Be nice!
    if not mesonlib.is_windows() and not mesonlib.is_haiku() and 'CI' not in os.environ:
        os.nice(20)
    # Appveyor sets the `platform` environment variable which completely messes
    # up building with the vs2010 and vs2015 backends.
    #
    # Specifically, MSBuild reads the `platform` environment variable to set
    # the configured value for the platform (Win32/x64/arm), which breaks x86
    # builds.
    #
    # Appveyor setting this also breaks our 'native build arch' detection for
    # Windows in environment.py:detect_windows_arch() by overwriting the value
    # of `platform` set by vcvarsall.bat.
    #
    # While building for x86, `platform` should be unset.
    if 'APPVEYOR' in os.environ and os.environ['arch'] == 'x86':
        os.environ.pop('platform')
    # Run tests
    print(mlog.bold('Running unittests.').get_text(mlog.colorize_console))
    print(flush=True)
    # Can't pass arguments to unit tests, so set the backend to use in the environment
    env = os.environ.copy()
    env['MESON_UNIT_TEST_BACKEND'] = backend.name
    with tempfile.TemporaryDirectory() as temp_dir:
        # Enable coverage on all subsequent processes.
        if enable_coverage:
            Path(temp_dir, 'usercustomize.py').open('w').write(
                'import coverage\n'
                'coverage.process_startup()\n')
            env['COVERAGE_PROCESS_START'] = '.coveragerc'
            if 'PYTHONPATH' in env:
                env['PYTHONPATH'] = os.pathsep.join([temp_dir, env.get('PYTHONPATH')])
            else:
                env['PYTHONPATH'] = temp_dir
        if not cross:
            cmd = mesonlib.python_command + ['run_meson_command_tests.py', '-v']
            if options.failfast:
                cmd += ['--failfast']
            returncode += subprocess.call(cmd, env=env)
            if options.failfast and returncode != 0:
                return returncode
            if no_unittests:
                print('Skipping all unit tests.')
                returncode = 0
            else:
                cmd = mesonlib.python_command + ['run_unittests.py', '-v']
                if options.failfast:
                    cmd += ['--failfast']
                returncode += subprocess.call(cmd, env=env)
                if options.failfast and returncode != 0:
                    return returncode
            cmd = mesonlib.python_command + ['run_project_tests.py'] + sys.argv[1:]
            returncode += subprocess.call(cmd, env=env)
        else:
            cross_test_args = mesonlib.python_command + ['run_cross_test.py']
            print(mlog.bold('Running armhf cross tests.').get_text(mlog.colorize_console))
            print(flush=True)
            cmd = cross_test_args + ['cross/ubuntu-armhf.txt']
            if options.failfast:
                cmd += ['--failfast']
            returncode += subprocess.call(cmd, env=env)
            if options.failfast and returncode != 0:
                return returncode
            print(mlog.bold('Running mingw-w64 64-bit cross tests.')
                  .get_text(mlog.colorize_console))
            print(flush=True)
            cmd = cross_test_args + ['cross/linux-mingw-w64-64bit.txt']
            if options.failfast:
                cmd += ['--failfast']
            returncode += subprocess.call(cmd, env=env)
    return returncode

if __name__ == '__main__':
    sys.exit(main())
meson-0.53.2/run_unittests.py0000755000175000017500000121655713625260317017645 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3
# Copyright 2016-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import stat
import subprocess
import re
import json
import tempfile
import textwrap
import os
import shutil
import sys
import unittest
import platform
import pickle
import functools
import io
import operator
import threading
import urllib.error
import urllib.request
import zipfile
import hashlib
from itertools import chain
from unittest import mock
from configparser import ConfigParser
from contextlib import contextmanager
from glob import glob
from pathlib import (PurePath, Path)
from distutils.dir_util import copy_tree

import mesonbuild.mlog
import mesonbuild.depfile
import mesonbuild.compilers
import mesonbuild.envconfig
import mesonbuild.environment
import mesonbuild.mesonlib
import mesonbuild.coredata
import mesonbuild.modules.gnome
from mesonbuild.interpreter import Interpreter, ObjectHolder
from mesonbuild.ast import AstInterpreter
from mesonbuild.mesonlib import (
    BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows,
    is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, is_sunos,
    windows_proof_rmtree, python_command, version_compare, split_args,
    quote_arg
)
from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException
from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram
import mesonbuild.dependencies.base
from mesonbuild.build import Target
import mesonbuild.modules.pkgconfig

from mesonbuild.mtest import TAPParser, TestResult

from run_tests import (
    Backend, FakeBuild, FakeCompilerOptions,
    ensure_backend_detects_changes, exe_suffix, get_backend_commands,
    get_builddir_target_args, get_fake_env, get_fake_options, get_meson_script,
    run_configure_inprocess, run_mtest_inprocess
)


URLOPEN_TIMEOUT = 5


def get_dynamic_section_entry(fname, entry):
    if is_cygwin() or is_osx():
        raise unittest.SkipTest('Test only applicable to ELF platforms')

    try:
        raw_out = subprocess.check_output(['readelf', '-d', fname],
                                          universal_newlines=True)
    except FileNotFoundError:
        # FIXME: Try using depfixer.py:Elf() as a fallback
        raise unittest.SkipTest('readelf not found')
    pattern = re.compile(entry + r': \[(.*?)\]')
    for line in raw_out.split('\n'):
        m = pattern.search(line)
        if m is not None:
            return m.group(1)
    return None # The file did not contain the specified entry.

def get_soname(fname):
    return get_dynamic_section_entry(fname, 'soname')

def get_rpath(fname):
    return get_dynamic_section_entry(fname, r'(?:rpath|runpath)')

def is_tarball():
    if not os.path.isdir('docs'):
        return True
    return False

def is_ci():
    if 'CI' in os.environ:
        return True
    return False

def is_pull():
    # Travis
    if os.environ.get('TRAVIS_PULL_REQUEST', 'false') != 'false':
        return True
    # Azure
    if 'SYSTEM_PULLREQUEST_ISFORK' in os.environ:
        return True
    return False

def _git_init(project_dir):
    subprocess.check_call(['git', 'init'], cwd=project_dir, stdout=subprocess.DEVNULL)
    subprocess.check_call(['git', 'config',
                           'user.name', 'Author Person'], cwd=project_dir)
    subprocess.check_call(['git', 'config',
                           'user.email', 'teh_coderz@example.com'], cwd=project_dir)
    subprocess.check_call('git add *', cwd=project_dir, shell=True,
                          stdout=subprocess.DEVNULL)
    subprocess.check_call(['git', 'commit', '-a', '-m', 'I am a project'], cwd=project_dir,
                          stdout=subprocess.DEVNULL)

@functools.lru_cache()
def is_real_gnu_compiler(path):
    '''
    Check if the gcc we have is a real gcc and not a macOS wrapper around clang
    '''
    if not path:
        return False
    out = subprocess.check_output([path, '--version'], universal_newlines=True, stderr=subprocess.STDOUT)
    return 'Free Software Foundation' in out

def skipIfNoExecutable(exename):
    '''
    Skip this test if the given executable is not found.
    '''
    def wrapper(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            if shutil.which(exename) is None:
                raise unittest.SkipTest(exename + ' not found')
            return func(*args, **kwargs)
        return wrapped
    return wrapper

def skipIfNoPkgconfig(f):
    '''
    Skip this test if no pkg-config is found, unless we're on CI.
    This allows users to run our test suite without having
    pkg-config installed on, f.ex., macOS, while ensuring that our CI does not
    silently skip the test because of misconfiguration.

    Note: Yes, we provide pkg-config even while running Windows CI
    '''
    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        if not is_ci() and shutil.which('pkg-config') is None:
            raise unittest.SkipTest('pkg-config not found')
        return f(*args, **kwargs)
    return wrapped

def skipIfNoPkgconfigDep(depname):
    '''
    Skip this test if the given pkg-config dep is not found, unless we're on CI.
    '''
    def wrapper(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            if not is_ci() and shutil.which('pkg-config') is None:
                raise unittest.SkipTest('pkg-config not found')
            if not is_ci() and subprocess.call(['pkg-config', '--exists', depname]) != 0:
                raise unittest.SkipTest('pkg-config dependency {} not found.'.format(depname))
            return func(*args, **kwargs)
        return wrapped
    return wrapper

def skip_if_no_cmake(f):
    '''
    Skip this test if no cmake is found, unless we're on CI.
    This allows users to run our test suite without having
    cmake installed on, f.ex., macOS, while ensuring that our CI does not
    silently skip the test because of misconfiguration.
    '''
    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        if not is_ci() and shutil.which('cmake') is None:
            raise unittest.SkipTest('cmake not found')
        return f(*args, **kwargs)
    return wrapped

def skip_if_not_language(lang):
    def wrapper(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            try:
                env = get_fake_env()
                f = getattr(env, 'detect_{}_compiler'.format(lang))
                f(MachineChoice.HOST)
            except EnvironmentException:
                raise unittest.SkipTest('No {} compiler found.'.format(lang))
            return func(*args, **kwargs)
        return wrapped
    return wrapper

def skip_if_env_set(key):
    '''
    Skip a test if a particular env is set, except when running under CI
    '''
    def wrapper(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            old = None
            if key in os.environ:
                if not is_ci():
                    raise unittest.SkipTest('Env var {!r} set, skipping'.format(key))
                old = os.environ.pop(key)
            try:
                return func(*args, **kwargs)
            finally:
                if old is not None:
                    os.environ[key] = old
        return wrapped
    return wrapper

def skip_if_not_base_option(feature):
    """Skip tests if The compiler does not support a given base option.

    for example, ICC doesn't currently support b_sanitize.
    """
    def actual(f):
        @functools.wraps(f)
        def wrapped(*args, **kwargs):
            env = get_fake_env()
            cc = env.detect_c_compiler(MachineChoice.HOST)
            if feature not in cc.base_options:
                raise unittest.SkipTest(
                    '{} not available with {}'.format(feature, cc.id))
            return f(*args, **kwargs)
        return wrapped
    return actual


@contextmanager
def temp_filename():
    '''A context manager which provides a filename to an empty temporary file.

    On exit the file will be deleted.
    '''

    fd, filename = tempfile.mkstemp()
    os.close(fd)
    try:
        yield filename
    finally:
        try:
            os.remove(filename)
        except OSError:
            pass

@contextmanager
def no_pkgconfig():
    '''
    A context manager that overrides shutil.which and ExternalProgram to force
    them to return None for pkg-config to simulate it not existing.
    '''
    old_which = shutil.which
    old_search = ExternalProgram._search

    def new_search(self, name, search_dir):
        if name == 'pkg-config':
            return [None]
        return old_search(self, name, search_dir)

    def new_which(cmd, *kwargs):
        if cmd == 'pkg-config':
            return None
        return old_which(cmd, *kwargs)

    shutil.which = new_which
    ExternalProgram._search = new_search
    try:
        yield
    finally:
        shutil.which = old_which
        ExternalProgram._search = old_search


class InternalTests(unittest.TestCase):

    def test_version_number(self):
        searchfunc = mesonbuild.environment.search_version
        self.assertEqual(searchfunc('foobar 1.2.3'), '1.2.3')
        self.assertEqual(searchfunc('1.2.3'), '1.2.3')
        self.assertEqual(searchfunc('foobar 2016.10.28 1.2.3'), '1.2.3')
        self.assertEqual(searchfunc('2016.10.28 1.2.3'), '1.2.3')
        self.assertEqual(searchfunc('foobar 2016.10.128'), 'unknown version')
        self.assertEqual(searchfunc('2016.10.128'), 'unknown version')

    def test_mode_symbolic_to_bits(self):
        modefunc = mesonbuild.mesonlib.FileMode.perms_s_to_bits
        self.assertEqual(modefunc('---------'), 0)
        self.assertEqual(modefunc('r--------'), stat.S_IRUSR)
        self.assertEqual(modefunc('---r-----'), stat.S_IRGRP)
        self.assertEqual(modefunc('------r--'), stat.S_IROTH)
        self.assertEqual(modefunc('-w-------'), stat.S_IWUSR)
        self.assertEqual(modefunc('----w----'), stat.S_IWGRP)
        self.assertEqual(modefunc('-------w-'), stat.S_IWOTH)
        self.assertEqual(modefunc('--x------'), stat.S_IXUSR)
        self.assertEqual(modefunc('-----x---'), stat.S_IXGRP)
        self.assertEqual(modefunc('--------x'), stat.S_IXOTH)
        self.assertEqual(modefunc('--S------'), stat.S_ISUID)
        self.assertEqual(modefunc('-----S---'), stat.S_ISGID)
        self.assertEqual(modefunc('--------T'), stat.S_ISVTX)
        self.assertEqual(modefunc('--s------'), stat.S_ISUID | stat.S_IXUSR)
        self.assertEqual(modefunc('-----s---'), stat.S_ISGID | stat.S_IXGRP)
        self.assertEqual(modefunc('--------t'), stat.S_ISVTX | stat.S_IXOTH)
        self.assertEqual(modefunc('rwx------'), stat.S_IRWXU)
        self.assertEqual(modefunc('---rwx---'), stat.S_IRWXG)
        self.assertEqual(modefunc('------rwx'), stat.S_IRWXO)
        # We could keep listing combinations exhaustively but that seems
        # tedious and pointless. Just test a few more.
        self.assertEqual(modefunc('rwxr-xr-x'),
                         stat.S_IRWXU |
                         stat.S_IRGRP | stat.S_IXGRP |
                         stat.S_IROTH | stat.S_IXOTH)
        self.assertEqual(modefunc('rw-r--r--'),
                         stat.S_IRUSR | stat.S_IWUSR |
                         stat.S_IRGRP |
                         stat.S_IROTH)
        self.assertEqual(modefunc('rwsr-x---'),
                         stat.S_IRWXU | stat.S_ISUID |
                         stat.S_IRGRP | stat.S_IXGRP)

    def test_compiler_args_class(self):
        cargsfunc = mesonbuild.compilers.CompilerArgs
        cc = mesonbuild.compilers.CCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock())
        # Test that empty initialization works
        a = cargsfunc(cc)
        self.assertEqual(a, [])
        # Test that list initialization works
        a = cargsfunc(cc, ['-I.', '-I..'])
        self.assertEqual(a, ['-I.', '-I..'])
        # Test that there is no de-dup on initialization
        self.assertEqual(cargsfunc(cc, ['-I.', '-I.']), ['-I.', '-I.'])

        ## Test that appending works
        a.append('-I..')
        self.assertEqual(a, ['-I..', '-I.'])
        a.append('-O3')
        self.assertEqual(a, ['-I..', '-I.', '-O3'])

        ## Test that in-place addition works
        a += ['-O2', '-O2']
        self.assertEqual(a, ['-I..', '-I.', '-O3', '-O2', '-O2'])
        # Test that removal works
        a.remove('-O2')
        self.assertEqual(a, ['-I..', '-I.', '-O3', '-O2'])
        # Test that de-dup happens on addition
        a += ['-Ifoo', '-Ifoo']
        self.assertEqual(a, ['-Ifoo', '-I..', '-I.', '-O3', '-O2'])

        # .extend() is just +=, so we don't test it

        ## Test that addition works
        # Test that adding a list with just one old arg works and yields the same array
        a = a + ['-Ifoo']
        self.assertEqual(a, ['-Ifoo', '-I..', '-I.', '-O3', '-O2'])
        # Test that adding a list with one arg new and one old works
        a = a + ['-Ifoo', '-Ibaz']
        self.assertEqual(a, ['-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2'])
        # Test that adding args that must be prepended and appended works
        a = a + ['-Ibar', '-Wall']
        self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2', '-Wall'])

        ## Test that reflected addition works
        # Test that adding to a list with just one old arg works and yields the same array
        a = ['-Ifoo'] + a
        self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-O3', '-O2', '-Wall'])
        # Test that adding to a list with just one new arg that is not pre-pended works
        a = ['-Werror'] + a
        self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Werror', '-O3', '-O2', '-Wall'])
        # Test that adding to a list with two new args preserves the order
        a = ['-Ldir', '-Lbah'] + a
        self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall'])
        # Test that adding to a list with old args does nothing
        a = ['-Ibar', '-Ibaz', '-Ifoo'] + a
        self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall'])

        ## Test that adding libraries works
        l = cargsfunc(cc, ['-Lfoodir', '-lfoo'])
        self.assertEqual(l, ['-Lfoodir', '-lfoo'])
        # Adding a library and a libpath appends both correctly
        l += ['-Lbardir', '-lbar']
        self.assertEqual(l, ['-Lbardir', '-Lfoodir', '-lfoo', '-lbar'])
        # Adding the same library again does nothing
        l += ['-lbar']
        self.assertEqual(l, ['-Lbardir', '-Lfoodir', '-lfoo', '-lbar'])

        ## Test that 'direct' append and extend works
        l = cargsfunc(cc, ['-Lfoodir', '-lfoo'])
        self.assertEqual(l, ['-Lfoodir', '-lfoo'])
        # Direct-adding a library and a libpath appends both correctly
        l.extend_direct(['-Lbardir', '-lbar'])
        self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar'])
        # Direct-adding the same library again still adds it
        l.append_direct('-lbar')
        self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar'])
        # Direct-adding with absolute path deduplicates
        l.append_direct('/libbaz.a')
        self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a'])
        # Adding libbaz again does nothing
        l.append_direct('/libbaz.a')
        self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a'])

    def test_compiler_args_class_gnuld(self):
        cargsfunc = mesonbuild.compilers.CompilerArgs
        ## Test --start/end-group
        linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,', [])
        gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock(), linker=linker)
        ## Ensure that the fake compiler is never called by overriding the relevant function
        gcc.get_default_include_dirs = lambda: ['/usr/include', '/usr/share/include', '/usr/local/include']
        ## Test that 'direct' append and extend works
        l = cargsfunc(gcc, ['-Lfoodir', '-lfoo'])
        self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group'])
        # Direct-adding a library and a libpath appends both correctly
        l.extend_direct(['-Lbardir', '-lbar'])
        self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-Wl,--end-group'])
        # Direct-adding the same library again still adds it
        l.append_direct('-lbar')
        self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '-Wl,--end-group'])
        # Direct-adding with absolute path deduplicates
        l.append_direct('/libbaz.a')
        self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group'])
        # Adding libbaz again does nothing
        l.append_direct('/libbaz.a')
        self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group'])
        # Adding a non-library argument doesn't include it in the group
        l += ['-Lfoo', '-Wl,--export-dynamic']
        self.assertEqual(l.to_native(copy=True), ['-Lfoo', '-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group', '-Wl,--export-dynamic'])
        # -Wl,-lfoo is detected as a library and gets added to the group
        l.append('-Wl,-ldl')
        self.assertEqual(l.to_native(copy=True), ['-Lfoo', '-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--export-dynamic', '-Wl,-ldl', '-Wl,--end-group'])

    def test_compiler_args_remove_system(self):
        cargsfunc = mesonbuild.compilers.CompilerArgs
        ## Test --start/end-group
        linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,', [])
        gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock(), linker=linker)
        ## Ensure that the fake compiler is never called by overriding the relevant function
        gcc.get_default_include_dirs = lambda: ['/usr/include', '/usr/share/include', '/usr/local/include']
        ## Test that 'direct' append and extend works
        l = cargsfunc(gcc, ['-Lfoodir', '-lfoo'])
        self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group'])
        ## Test that to_native removes all system includes
        l += ['-isystem/usr/include', '-isystem=/usr/share/include', '-DSOMETHING_IMPORTANT=1', '-isystem', '/usr/local/include']
        self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group', '-DSOMETHING_IMPORTANT=1'])

    def test_string_templates_substitution(self):
        dictfunc = mesonbuild.mesonlib.get_filenames_templates_dict
        substfunc = mesonbuild.mesonlib.substitute_values
        ME = mesonbuild.mesonlib.MesonException

        # Identity
        self.assertEqual(dictfunc([], []), {})

        # One input, no outputs
        inputs = ['bar/foo.c.in']
        outputs = []
        ret = dictfunc(inputs, outputs)
        d = {'@INPUT@': inputs, '@INPUT0@': inputs[0],
             '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c'}
        # Check dictionary
        self.assertEqual(ret, d)
        # Check substitutions
        cmd = ['some', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), cmd)
        cmd = ['@INPUT@.out', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out'] + cmd[1:])
        cmd = ['@INPUT0@.out', '@PLAINNAME@.ok', 'strings']
        self.assertEqual(substfunc(cmd, d),
                         [inputs[0] + '.out'] + [d['@PLAINNAME@'] + '.ok'] + cmd[2:])
        cmd = ['@INPUT@', '@BASENAME@.hah', 'strings']
        self.assertEqual(substfunc(cmd, d),
                         inputs + [d['@BASENAME@'] + '.hah'] + cmd[2:])
        cmd = ['@OUTPUT@']
        self.assertRaises(ME, substfunc, cmd, d)

        # One input, one output
        inputs = ['bar/foo.c.in']
        outputs = ['out.c']
        ret = dictfunc(inputs, outputs)
        d = {'@INPUT@': inputs, '@INPUT0@': inputs[0],
             '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c',
             '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': '.'}
        # Check dictionary
        self.assertEqual(ret, d)
        # Check substitutions
        cmd = ['some', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), cmd)
        cmd = ['@INPUT@.out', '@OUTPUT@', 'strings']
        self.assertEqual(substfunc(cmd, d),
                         [inputs[0] + '.out'] + outputs + cmd[2:])
        cmd = ['@INPUT0@.out', '@PLAINNAME@.ok', '@OUTPUT0@']
        self.assertEqual(substfunc(cmd, d),
                         [inputs[0] + '.out', d['@PLAINNAME@'] + '.ok'] + outputs)
        cmd = ['@INPUT@', '@BASENAME@.hah', 'strings']
        self.assertEqual(substfunc(cmd, d),
                         inputs + [d['@BASENAME@'] + '.hah'] + cmd[2:])

        # One input, one output with a subdir
        outputs = ['dir/out.c']
        ret = dictfunc(inputs, outputs)
        d = {'@INPUT@': inputs, '@INPUT0@': inputs[0],
             '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c',
             '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': 'dir'}
        # Check dictionary
        self.assertEqual(ret, d)

        # Two inputs, no outputs
        inputs = ['bar/foo.c.in', 'baz/foo.c.in']
        outputs = []
        ret = dictfunc(inputs, outputs)
        d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1]}
        # Check dictionary
        self.assertEqual(ret, d)
        # Check substitutions
        cmd = ['some', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), cmd)
        cmd = ['@INPUT@', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), inputs + cmd[1:])
        cmd = ['@INPUT0@.out', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out'] + cmd[1:])
        cmd = ['@INPUT0@.out', '@INPUT1@.ok', 'strings']
        self.assertEqual(substfunc(cmd, d), [inputs[0] + '.out', inputs[1] + '.ok'] + cmd[2:])
        cmd = ['@INPUT0@', '@INPUT1@', 'strings']
        self.assertEqual(substfunc(cmd, d), inputs + cmd[2:])
        # Many inputs, can't use @INPUT@ like this
        cmd = ['@INPUT@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)
        # Not enough inputs
        cmd = ['@INPUT2@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)
        # Too many inputs
        cmd = ['@PLAINNAME@']
        self.assertRaises(ME, substfunc, cmd, d)
        cmd = ['@BASENAME@']
        self.assertRaises(ME, substfunc, cmd, d)
        # No outputs
        cmd = ['@OUTPUT@']
        self.assertRaises(ME, substfunc, cmd, d)
        cmd = ['@OUTPUT0@']
        self.assertRaises(ME, substfunc, cmd, d)
        cmd = ['@OUTDIR@']
        self.assertRaises(ME, substfunc, cmd, d)

        # Two inputs, one output
        outputs = ['dir/out.c']
        ret = dictfunc(inputs, outputs)
        d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1],
             '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': 'dir'}
        # Check dictionary
        self.assertEqual(ret, d)
        # Check substitutions
        cmd = ['some', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), cmd)
        cmd = ['@OUTPUT@', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), outputs + cmd[1:])
        cmd = ['@OUTPUT@.out', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out'] + cmd[1:])
        cmd = ['@OUTPUT0@.out', '@INPUT1@.ok', 'strings']
        self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out', inputs[1] + '.ok'] + cmd[2:])
        # Many inputs, can't use @INPUT@ like this
        cmd = ['@INPUT@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)
        # Not enough inputs
        cmd = ['@INPUT2@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)
        # Not enough outputs
        cmd = ['@OUTPUT2@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)

        # Two inputs, two outputs
        outputs = ['dir/out.c', 'dir/out2.c']
        ret = dictfunc(inputs, outputs)
        d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1],
             '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTPUT1@': outputs[1],
             '@OUTDIR@': 'dir'}
        # Check dictionary
        self.assertEqual(ret, d)
        # Check substitutions
        cmd = ['some', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), cmd)
        cmd = ['@OUTPUT@', 'ordinary', 'strings']
        self.assertEqual(substfunc(cmd, d), outputs + cmd[1:])
        cmd = ['@OUTPUT0@', '@OUTPUT1@', 'strings']
        self.assertEqual(substfunc(cmd, d), outputs + cmd[2:])
        cmd = ['@OUTPUT0@.out', '@INPUT1@.ok', '@OUTDIR@']
        self.assertEqual(substfunc(cmd, d), [outputs[0] + '.out', inputs[1] + '.ok', 'dir'])
        # Many inputs, can't use @INPUT@ like this
        cmd = ['@INPUT@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)
        # Not enough inputs
        cmd = ['@INPUT2@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)
        # Not enough outputs
        cmd = ['@OUTPUT2@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)
        # Many outputs, can't use @OUTPUT@ like this
        cmd = ['@OUTPUT@.out', 'ordinary', 'strings']
        self.assertRaises(ME, substfunc, cmd, d)

    def test_needs_exe_wrapper_override(self):
        config = ConfigParser()
        config['binaries'] = {
            'c': '\'/usr/bin/gcc\'',
        }
        config['host_machine'] = {
            'system': '\'linux\'',
            'cpu_family': '\'arm\'',
            'cpu': '\'armv7\'',
            'endian': '\'little\'',
        }
        # Can not be used as context manager because we need to
        # open it a second time and this is not possible on
        # Windows.
        configfile = tempfile.NamedTemporaryFile(mode='w+', delete=False)
        configfilename = configfile.name
        config.write(configfile)
        configfile.flush()
        configfile.close()
        opts = get_fake_options()
        opts.cross_file = (configfilename,)
        env = get_fake_env(opts=opts)
        detected_value = env.need_exe_wrapper()
        os.unlink(configfilename)

        desired_value = not detected_value
        config['properties'] = {
            'needs_exe_wrapper': 'true' if desired_value else 'false'
        }

        configfile = tempfile.NamedTemporaryFile(mode='w+', delete=False)
        configfilename = configfile.name
        config.write(configfile)
        configfile.close()
        opts = get_fake_options()
        opts.cross_file = (configfilename,)
        env = get_fake_env(opts=opts)
        forced_value = env.need_exe_wrapper()
        os.unlink(configfilename)

        self.assertEqual(forced_value, desired_value)

    def test_listify(self):
        listify = mesonbuild.mesonlib.listify
        # Test sanity
        self.assertEqual([1], listify(1))
        self.assertEqual([], listify([]))
        self.assertEqual([1], listify([1]))
        # Test flattening
        self.assertEqual([1, 2, 3], listify([1, [2, 3]]))
        self.assertEqual([1, 2, 3], listify([1, [2, [3]]]))
        self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False))
        # Test flattening and unholdering
        holder1 = ObjectHolder(1)
        holder3 = ObjectHolder(3)
        self.assertEqual([holder1], listify(holder1))
        self.assertEqual([holder1], listify([holder1]))
        self.assertEqual([holder1, 2], listify([holder1, 2]))
        self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]]))
        self.assertEqual([1], listify(holder1, unholder=True))
        self.assertEqual([1], listify([holder1], unholder=True))
        self.assertEqual([1, 2], listify([holder1, 2], unholder=True))
        self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True))
        # Unholding doesn't work recursively when not flattening
        self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False))

    def test_extract_as_list(self):
        extract = mesonbuild.mesonlib.extract_as_list
        # Test sanity
        kwargs = {'sources': [1, 2, 3]}
        self.assertEqual([1, 2, 3], extract(kwargs, 'sources'))
        self.assertEqual(kwargs, {'sources': [1, 2, 3]})
        self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True))
        self.assertEqual(kwargs, {})
        # Test unholding
        holder3 = ObjectHolder(3)
        kwargs = {'sources': [1, 2, holder3]}
        self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True))
        self.assertEqual(kwargs, {'sources': [1, 2, holder3]})
        self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True))
        self.assertEqual(kwargs, {})
        # Test listification
        kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]}
        self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources'))

    def test_pkgconfig_module(self):

        class Mock:
            pass

        mock = Mock()
        mock.pcdep = Mock()
        mock.pcdep.name = "some_name"
        mock.version_reqs = []

        # pkgconfig dependency as lib
        deps = mesonbuild.modules.pkgconfig.DependenciesHelper("thislib")
        deps.add_pub_libs([mock])
        self.assertEqual(deps.format_reqs(deps.pub_reqs), "some_name")

        # pkgconfig dependency as requires
        deps = mesonbuild.modules.pkgconfig.DependenciesHelper("thislib")
        deps.add_pub_reqs([mock])
        self.assertEqual(deps.format_reqs(deps.pub_reqs), "some_name")

    def _test_all_naming(self, cc, env, patterns, platform):
        shr = patterns[platform]['shared']
        stc = patterns[platform]['static']
        shrstc = shr + tuple([x for x in stc if x not in shr])
        stcshr = stc + tuple([x for x in shr if x not in stc])
        p = cc.get_library_naming(env, LibType.SHARED)
        self.assertEqual(p, shr)
        p = cc.get_library_naming(env, LibType.STATIC)
        self.assertEqual(p, stc)
        p = cc.get_library_naming(env, LibType.PREFER_STATIC)
        self.assertEqual(p, stcshr)
        p = cc.get_library_naming(env, LibType.PREFER_SHARED)
        self.assertEqual(p, shrstc)
        # Test find library by mocking up openbsd
        if platform != 'openbsd':
            return
        with tempfile.TemporaryDirectory() as tmpdir:
            with open(os.path.join(tmpdir, 'libfoo.so.6.0'), 'w') as f:
                f.write('')
            with open(os.path.join(tmpdir, 'libfoo.so.5.0'), 'w') as f:
                f.write('')
            with open(os.path.join(tmpdir, 'libfoo.so.54.0'), 'w') as f:
                f.write('')
            with open(os.path.join(tmpdir, 'libfoo.so.66a.0b'), 'w') as f:
                f.write('')
            with open(os.path.join(tmpdir, 'libfoo.so.70.0.so.1'), 'w') as f:
                f.write('')
            found = cc.find_library_real('foo', env, [tmpdir], '', LibType.PREFER_SHARED)
            self.assertEqual(os.path.basename(found[0]), 'libfoo.so.54.0')

    def test_find_library_patterns(self):
        '''
        Unit test for the library search patterns used by find_library()
        '''
        unix_static = ('lib{}.a', '{}.a')
        msvc_static = ('lib{}.a', 'lib{}.lib', '{}.a', '{}.lib')
        # This is the priority list of pattern matching for library searching
        patterns = {'openbsd': {'shared': ('lib{}.so', '{}.so', 'lib{}.so.[0-9]*.[0-9]*', '{}.so.[0-9]*.[0-9]*'),
                                'static': unix_static},
                    'linux': {'shared': ('lib{}.so', '{}.so'),
                              'static': unix_static},
                    'darwin': {'shared': ('lib{}.dylib', 'lib{}.so', '{}.dylib', '{}.so'),
                               'static': unix_static},
                    'cygwin': {'shared': ('cyg{}.dll', 'cyg{}.dll.a', 'lib{}.dll',
                                          'lib{}.dll.a', '{}.dll', '{}.dll.a'),
                               'static': ('cyg{}.a',) + unix_static},
                    'windows-msvc': {'shared': ('lib{}.lib', '{}.lib'),
                                     'static': msvc_static},
                    'windows-mingw': {'shared': ('lib{}.dll.a', 'lib{}.lib', 'lib{}.dll',
                                                 '{}.dll.a', '{}.lib', '{}.dll'),
                                      'static': msvc_static}}
        env = get_fake_env()
        cc = env.detect_c_compiler(MachineChoice.HOST)
        if is_osx():
            self._test_all_naming(cc, env, patterns, 'darwin')
        elif is_cygwin():
            self._test_all_naming(cc, env, patterns, 'cygwin')
        elif is_windows():
            if cc.get_argument_syntax() == 'msvc':
                self._test_all_naming(cc, env, patterns, 'windows-msvc')
            else:
                self._test_all_naming(cc, env, patterns, 'windows-mingw')
        elif is_openbsd():
            self._test_all_naming(cc, env, patterns, 'openbsd')
        else:
            self._test_all_naming(cc, env, patterns, 'linux')
            env.machines.host.system = 'openbsd'
            self._test_all_naming(cc, env, patterns, 'openbsd')
            env.machines.host.system = 'darwin'
            self._test_all_naming(cc, env, patterns, 'darwin')
            env.machines.host.system = 'cygwin'
            self._test_all_naming(cc, env, patterns, 'cygwin')
            env.machines.host.system = 'windows'
            self._test_all_naming(cc, env, patterns, 'windows-mingw')

    def test_pkgconfig_parse_libs(self):
        '''
        Unit test for parsing of pkg-config output to search for libraries

        https://github.com/mesonbuild/meson/issues/3951
        '''
        def create_static_lib(name):
            if not is_osx():
                name.open('w').close()
                return
            src = name.with_suffix('.c')
            out = name.with_suffix('.o')
            with src.open('w') as f:
                f.write('int meson_foobar (void) { return 0; }')
            subprocess.check_call(['clang', '-c', str(src), '-o', str(out)])
            subprocess.check_call(['ar', 'csr', str(name), str(out)])

        with tempfile.TemporaryDirectory() as tmpdir:
            pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True)
            env = get_fake_env()
            compiler = env.detect_c_compiler(MachineChoice.HOST)
            env.coredata.compilers.host = {'c': compiler}
            env.coredata.compiler_options.host['c_link_args'] = FakeCompilerOptions()
            p1 = Path(tmpdir) / '1'
            p2 = Path(tmpdir) / '2'
            p1.mkdir()
            p2.mkdir()
            # libfoo.a is in one prefix
            create_static_lib(p1 / 'libfoo.a')
            # libbar.a is in both prefixes
            create_static_lib(p1 / 'libbar.a')
            create_static_lib(p2 / 'libbar.a')
            # Ensure that we never statically link to these
            create_static_lib(p1 / 'libpthread.a')
            create_static_lib(p1 / 'libm.a')
            create_static_lib(p1 / 'libc.a')
            create_static_lib(p1 / 'libdl.a')
            create_static_lib(p1 / 'librt.a')

            def fake_call_pkgbin(self, args, env=None):
                if '--libs' not in args:
                    return 0, '', ''
                if args[0] == 'foo':
                    return 0, '-L{} -lfoo -L{} -lbar'.format(p2.as_posix(), p1.as_posix()), ''
                if args[0] == 'bar':
                    return 0, '-L{} -lbar'.format(p2.as_posix()), ''
                if args[0] == 'internal':
                    return 0, '-L{} -lpthread -lm -lc -lrt -ldl'.format(p1.as_posix()), ''

            old_call = PkgConfigDependency._call_pkgbin
            old_check = PkgConfigDependency.check_pkgconfig
            PkgConfigDependency._call_pkgbin = fake_call_pkgbin
            PkgConfigDependency.check_pkgconfig = lambda x, _: pkgbin
            # Test begins
            try:
                kwargs = {'required': True, 'silent': True}
                foo_dep = PkgConfigDependency('foo', env, kwargs)
                self.assertEqual(foo_dep.get_link_args(),
                                 [(p1 / 'libfoo.a').as_posix(), (p2 / 'libbar.a').as_posix()])
                bar_dep = PkgConfigDependency('bar', env, kwargs)
                self.assertEqual(bar_dep.get_link_args(), [(p2 / 'libbar.a').as_posix()])
                internal_dep = PkgConfigDependency('internal', env, kwargs)
                if compiler.get_argument_syntax() == 'msvc':
                    self.assertEqual(internal_dep.get_link_args(), [])
                else:
                    link_args = internal_dep.get_link_args()
                    for link_arg in link_args:
                        for lib in ('pthread', 'm', 'c', 'dl', 'rt'):
                            self.assertNotIn('lib{}.a'.format(lib), link_arg, msg=link_args)
            finally:
                # Test ends
                PkgConfigDependency._call_pkgbin = old_call
                PkgConfigDependency.check_pkgconfig = old_check
                # Reset dependency class to ensure that in-process configure doesn't mess up
                PkgConfigDependency.pkgbin_cache = {}
                PkgConfigDependency.class_pkgbin = PerMachine(None, None)

    def test_version_compare(self):
        comparefunc = mesonbuild.mesonlib.version_compare_many
        for (a, b, result) in [
                ('0.99.beta19', '>= 0.99.beta14', True),
        ]:
            self.assertEqual(comparefunc(a, b)[0], result)

        for (a, b, op) in [
                # examples from https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison
                ("1.0010", "1.9", operator.gt),
                ("1.05", "1.5", operator.eq),
                ("1.0", "1", operator.gt),
                ("2.50", "2.5", operator.gt),
                ("fc4", "fc.4", operator.eq),
                ("FC5", "fc4", operator.lt),
                ("2a", "2.0", operator.lt),
                ("1.0", "1.fc4", operator.gt),
                ("3.0.0_fc", "3.0.0.fc", operator.eq),
                # from RPM tests
                ("1.0", "1.0", operator.eq),
                ("1.0", "2.0", operator.lt),
                ("2.0", "1.0", operator.gt),
                ("2.0.1", "2.0.1", operator.eq),
                ("2.0", "2.0.1", operator.lt),
                ("2.0.1", "2.0", operator.gt),
                ("2.0.1a", "2.0.1a", operator.eq),
                ("2.0.1a", "2.0.1", operator.gt),
                ("2.0.1", "2.0.1a", operator.lt),
                ("5.5p1", "5.5p1", operator.eq),
                ("5.5p1", "5.5p2", operator.lt),
                ("5.5p2", "5.5p1", operator.gt),
                ("5.5p10", "5.5p10", operator.eq),
                ("5.5p1", "5.5p10", operator.lt),
                ("5.5p10", "5.5p1", operator.gt),
                ("10xyz", "10.1xyz", operator.lt),
                ("10.1xyz", "10xyz", operator.gt),
                ("xyz10", "xyz10", operator.eq),
                ("xyz10", "xyz10.1", operator.lt),
                ("xyz10.1", "xyz10", operator.gt),
                ("xyz.4", "xyz.4", operator.eq),
                ("xyz.4", "8", operator.lt),
                ("8", "xyz.4", operator.gt),
                ("xyz.4", "2", operator.lt),
                ("2", "xyz.4", operator.gt),
                ("5.5p2", "5.6p1", operator.lt),
                ("5.6p1", "5.5p2", operator.gt),
                ("5.6p1", "6.5p1", operator.lt),
                ("6.5p1", "5.6p1", operator.gt),
                ("6.0.rc1", "6.0", operator.gt),
                ("6.0", "6.0.rc1", operator.lt),
                ("10b2", "10a1", operator.gt),
                ("10a2", "10b2", operator.lt),
                ("1.0aa", "1.0aa", operator.eq),
                ("1.0a", "1.0aa", operator.lt),
                ("1.0aa", "1.0a", operator.gt),
                ("10.0001", "10.0001", operator.eq),
                ("10.0001", "10.1", operator.eq),
                ("10.1", "10.0001", operator.eq),
                ("10.0001", "10.0039", operator.lt),
                ("10.0039", "10.0001", operator.gt),
                ("4.999.9", "5.0", operator.lt),
                ("5.0", "4.999.9", operator.gt),
                ("20101121", "20101121", operator.eq),
                ("20101121", "20101122", operator.lt),
                ("20101122", "20101121", operator.gt),
                ("2_0", "2_0", operator.eq),
                ("2.0", "2_0", operator.eq),
                ("2_0", "2.0", operator.eq),
                ("a", "a", operator.eq),
                ("a+", "a+", operator.eq),
                ("a+", "a_", operator.eq),
                ("a_", "a+", operator.eq),
                ("+a", "+a", operator.eq),
                ("+a", "_a", operator.eq),
                ("_a", "+a", operator.eq),
                ("+_", "+_", operator.eq),
                ("_+", "+_", operator.eq),
                ("_+", "_+", operator.eq),
                ("+", "_", operator.eq),
                ("_", "+", operator.eq),
                # other tests
                ('0.99.beta19', '0.99.beta14', operator.gt),
                ("1.0.0", "2.0.0", operator.lt),
                (".0.0", "2.0.0", operator.lt),
                ("alpha", "beta", operator.lt),
                ("1.0", "1.0.0", operator.lt),
                ("2.456", "2.1000", operator.lt),
                ("2.1000", "3.111", operator.lt),
                ("2.001", "2.1", operator.eq),
                ("2.34", "2.34", operator.eq),
                ("6.1.2", "6.3.8", operator.lt),
                ("1.7.3.0", "2.0.0", operator.lt),
                ("2.24.51", "2.25", operator.lt),
                ("2.1.5+20120813+gitdcbe778", "2.1.5", operator.gt),
                ("3.4.1", "3.4b1", operator.gt),
                ("041206", "200090325", operator.lt),
                ("0.6.2+git20130413", "0.6.2", operator.gt),
                ("2.6.0+bzr6602", "2.6.0", operator.gt),
                ("2.6.0", "2.6b2", operator.gt),
                ("2.6.0+bzr6602", "2.6b2x", operator.gt),
                ("0.6.7+20150214+git3a710f9", "0.6.7", operator.gt),
                ("15.8b", "15.8.0.1", operator.lt),
                ("1.2rc1", "1.2.0", operator.lt),
        ]:
            ver_a = Version(a)
            ver_b = Version(b)
            if op is operator.eq:
                for o, name in [(op, 'eq'), (operator.ge, 'ge'), (operator.le, 'le')]:
                    self.assertTrue(o(ver_a, ver_b), '{} {} {}'.format(ver_a, name, ver_b))
            if op is operator.lt:
                for o, name in [(op, 'lt'), (operator.le, 'le'), (operator.ne, 'ne')]:
                    self.assertTrue(o(ver_a, ver_b), '{} {} {}'.format(ver_a, name, ver_b))
                for o, name in [(operator.gt, 'gt'), (operator.ge, 'ge'), (operator.eq, 'eq')]:
                    self.assertFalse(o(ver_a, ver_b), '{} {} {}'.format(ver_a, name, ver_b))
            if op is operator.gt:
                for o, name in [(op, 'gt'), (operator.ge, 'ge'), (operator.ne, 'ne')]:
                    self.assertTrue(o(ver_a, ver_b), '{} {} {}'.format(ver_a, name, ver_b))
                for o, name in [(operator.lt, 'lt'), (operator.le, 'le'), (operator.eq, 'eq')]:
                    self.assertFalse(o(ver_a, ver_b), '{} {} {}'.format(ver_a, name, ver_b))

    def test_msvc_toolset_version(self):
        '''
        Ensure that the toolset version returns the correct value for this MSVC
        '''
        env = get_fake_env()
        cc = env.detect_c_compiler(MachineChoice.HOST)
        if cc.get_argument_syntax() != 'msvc':
            raise unittest.SkipTest('Test only applies to MSVC-like compilers')
        toolset_ver = cc.get_toolset_version()
        self.assertIsNotNone(toolset_ver)
        # Visual Studio 2015 and older versions do not define VCToolsVersion
        # TODO: ICL doesn't set this in the VSC2015 profile either
        if cc.id == 'msvc' and int(''.join(cc.version.split('.')[0:2])) < 1910:
            return
        if 'VCToolsVersion' in os.environ:
            vctools_ver = os.environ['VCToolsVersion']
        else:
            self.assertIn('VCINSTALLDIR', os.environ)
            # See https://devblogs.microsoft.com/cppblog/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
            vctools_ver = (Path(os.environ['VCINSTALLDIR']) / 'Auxiliary' / 'Build' / 'Microsoft.VCToolsVersion.default.txt').read_text()
        self.assertTrue(vctools_ver.startswith(toolset_ver),
                        msg='{!r} does not start with {!r}'.format(vctools_ver, toolset_ver))

    def test_split_args(self):
        split_args = mesonbuild.mesonlib.split_args
        join_args = mesonbuild.mesonlib.join_args
        if is_windows():
            test_data = [
                # examples from https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments
                (r'"a b c" d e', ['a b c', 'd', 'e'], True),
                (r'"ab\"c" "\\" d', ['ab"c', '\\', 'd'], False),
                (r'a\\\b d"e f"g h', [r'a\\\b', 'de fg', 'h'], False),
                (r'a\\\"b c d', [r'a\"b', 'c', 'd'], False),
                (r'a\\\\"b c" d e', [r'a\\b c', 'd', 'e'], False),
                # other basics
                (r'""', [''], True),
                (r'a b c d "" e', ['a', 'b', 'c', 'd', '', 'e'], True),
                (r"'a b c' d e", ["'a", 'b', "c'", 'd', 'e'], True),
                (r"'a&b&c' d e", ["'a&b&c'", 'd', 'e'], True),
                (r"a & b & c d e", ['a', '&', 'b', '&', 'c', 'd', 'e'], True),
                (r"'a & b & c d e'", ["'a", '&', 'b', '&', 'c', 'd', "e'"], True),
                ('a  b\nc\rd \n\re', ['a', 'b', 'c', 'd', 'e'], False),
                # more illustrative tests
                (r'cl test.cpp /O1 /Fe:test.exe', ['cl', 'test.cpp', '/O1', '/Fe:test.exe'], True),
                (r'cl "test.cpp /O1 /Fe:test.exe"', ['cl', 'test.cpp /O1 /Fe:test.exe'], True),
                (r'cl /DNAME=\"Bob\" test.cpp', ['cl', '/DNAME="Bob"', 'test.cpp'], False),
                (r'cl "/DNAME=\"Bob\"" test.cpp', ['cl', '/DNAME="Bob"', 'test.cpp'], True),
                (r'cl /DNAME=\"Bob, Alice\" test.cpp', ['cl', '/DNAME="Bob,', 'Alice"', 'test.cpp'], False),
                (r'cl "/DNAME=\"Bob, Alice\"" test.cpp', ['cl', '/DNAME="Bob, Alice"', 'test.cpp'], True),
                (r'cl C:\path\with\backslashes.cpp', ['cl', r'C:\path\with\backslashes.cpp'], True),
                (r'cl C:\\path\\with\\double\\backslashes.cpp', ['cl', r'C:\\path\\with\\double\\backslashes.cpp'], True),
                (r'cl "C:\\path\\with\\double\\backslashes.cpp"', ['cl', r'C:\\path\\with\\double\\backslashes.cpp'], False),
                (r'cl C:\path with spaces\test.cpp', ['cl', r'C:\path', 'with', r'spaces\test.cpp'], False),
                (r'cl "C:\path with spaces\test.cpp"', ['cl', r'C:\path with spaces\test.cpp'], True),
                (r'cl /DPATH="C:\path\with\backslashes test.cpp', ['cl', r'/DPATH=C:\path\with\backslashes test.cpp'], False),
                (r'cl /DPATH=\"C:\\ends\\with\\backslashes\\\" test.cpp', ['cl', r'/DPATH="C:\\ends\\with\\backslashes\"', 'test.cpp'], False),
                (r'cl /DPATH="C:\\ends\\with\\backslashes\\" test.cpp', ['cl', '/DPATH=C:\\\\ends\\\\with\\\\backslashes\\', 'test.cpp'], False),
                (r'cl "/DNAME=\"C:\\ends\\with\\backslashes\\\"" test.cpp', ['cl', r'/DNAME="C:\\ends\\with\\backslashes\"', 'test.cpp'], True),
                (r'cl "/DNAME=\"C:\\ends\\with\\backslashes\\\\"" test.cpp', ['cl', r'/DNAME="C:\\ends\\with\\backslashes\\ test.cpp'], False),
                (r'cl "/DNAME=\"C:\\ends\\with\\backslashes\\\\\"" test.cpp', ['cl', r'/DNAME="C:\\ends\\with\\backslashes\\"', 'test.cpp'], True),
            ]
        else:
            test_data = [
                (r"'a b c' d e", ['a b c', 'd', 'e'], True),
                (r"a/b/c d e", ['a/b/c', 'd', 'e'], True),
                (r"a\b\c d e", [r'abc', 'd', 'e'], False),
                (r"a\\b\\c d e", [r'a\b\c', 'd', 'e'], False),
                (r'"a b c" d e', ['a b c', 'd', 'e'], False),
                (r'"a\\b\\c\\" d e', ['a\\b\\c\\', 'd', 'e'], False),
                (r"'a\b\c\' d e", ['a\\b\\c\\', 'd', 'e'], True),
                (r"'a&b&c' d e", ['a&b&c', 'd', 'e'], True),
                (r"a & b & c d e", ['a', '&', 'b', '&', 'c', 'd', 'e'], False),
                (r"'a & b & c d e'", ['a & b & c d e'], True),
                (r"abd'e f'g h", [r'abde fg', 'h'], False),
                ('a  b\nc\rd \n\re', ['a', 'b', 'c', 'd', 'e'], False),

                ('g++ -DNAME="Bob" test.cpp', ['g++', '-DNAME=Bob', 'test.cpp'], False),
                ("g++ '-DNAME=\"Bob\"' test.cpp", ['g++', '-DNAME="Bob"', 'test.cpp'], True),
                ('g++ -DNAME="Bob, Alice" test.cpp', ['g++', '-DNAME=Bob, Alice', 'test.cpp'], False),
                ("g++ '-DNAME=\"Bob, Alice\"' test.cpp", ['g++', '-DNAME="Bob, Alice"', 'test.cpp'], True),
            ]

        for (cmd, expected, roundtrip) in test_data:
            self.assertEqual(split_args(cmd), expected)
            if roundtrip:
                self.assertEqual(join_args(expected), cmd)

    def test_quote_arg(self):
        split_args = mesonbuild.mesonlib.split_args
        quote_arg = mesonbuild.mesonlib.quote_arg
        if is_windows():
            test_data = [
                ('', '""'),
                ('arg1', 'arg1'),
                ('/option1', '/option1'),
                ('/Ovalue', '/Ovalue'),
                ('/OBob&Alice', '/OBob&Alice'),
                ('/Ovalue with spaces', r'"/Ovalue with spaces"'),
                (r'/O"value with spaces"', r'"/O\"value with spaces\""'),
                (r'/OC:\path with spaces\test.exe', r'"/OC:\path with spaces\test.exe"'),
                ('/LIBPATH:C:\\path with spaces\\ends\\with\\backslashes\\', r'"/LIBPATH:C:\path with spaces\ends\with\backslashes\\"'),
                ('/LIBPATH:"C:\\path with spaces\\ends\\with\\backslashes\\\\"', r'"/LIBPATH:\"C:\path with spaces\ends\with\backslashes\\\\\""'),
                (r'/DMSG="Alice said: \"Let\'s go\""', r'"/DMSG=\"Alice said: \\\"Let\'s go\\\"\""'),
            ]
        else:
            test_data = [
                ('arg1', 'arg1'),
                ('--option1', '--option1'),
                ('-O=value', '-O=value'),
                ('-O=Bob&Alice', "'-O=Bob&Alice'"),
                ('-O=value with spaces', "'-O=value with spaces'"),
                ('-O="value with spaces"', '\'-O=\"value with spaces\"\''),
                ('-O=/path with spaces/test', '\'-O=/path with spaces/test\''),
                ('-DMSG="Alice said: \\"Let\'s go\\""', "'-DMSG=\"Alice said: \\\"Let'\"'\"'s go\\\"\"'"),
            ]

        for (arg, expected) in test_data:
            self.assertEqual(quote_arg(arg), expected)
            self.assertEqual(split_args(expected)[0], arg)

    def test_depfile(self):
        for (f, target, expdeps) in [
                # empty, unknown target
                ([''], 'unknown', set()),
                # simple target & deps
                (['meson/foo.o  : foo.c   foo.h'], 'meson/foo.o', set({'foo.c', 'foo.h'})),
                (['meson/foo.o: foo.c foo.h'], 'foo.c', set()),
                # get all deps
                (['meson/foo.o: foo.c foo.h',
                  'foo.c: gen.py'], 'meson/foo.o', set({'foo.c', 'foo.h', 'gen.py'})),
                (['meson/foo.o: foo.c foo.h',
                  'foo.c: gen.py'], 'foo.c', set({'gen.py'})),
                # linue continuation, multiple targets
                (['foo.o \\', 'foo.h: bar'], 'foo.h', set({'bar'})),
                (['foo.o \\', 'foo.h: bar'], 'foo.o', set({'bar'})),
                # \\ handling
                (['foo: Program\\ F\\iles\\\\X'], 'foo', set({'Program Files\\X'})),
                # $ handling
                (['f$o.o: c/b'], 'f$o.o', set({'c/b'})),
                (['f$$o.o: c/b'], 'f$o.o', set({'c/b'})),
                # cycles
                (['a: b', 'b: a'], 'a', set({'a', 'b'})),
                (['a: b', 'b: a'], 'b', set({'a', 'b'})),
        ]:
            d = mesonbuild.depfile.DepFile(f)
            deps = d.get_all_dependencies(target)
            self.assertEqual(deps, expdeps)

    def test_log_once(self):
        f = io.StringIO()
        with mock.patch('mesonbuild.mlog.log_file', f), \
                mock.patch('mesonbuild.mlog._logged_once', set()):
            mesonbuild.mlog.log_once('foo')
            mesonbuild.mlog.log_once('foo')
            actual = f.getvalue().strip()
            self.assertEqual(actual, 'foo', actual)

    def test_log_once_ansi(self):
        f = io.StringIO()
        with mock.patch('mesonbuild.mlog.log_file', f), \
                mock.patch('mesonbuild.mlog._logged_once', set()):
            mesonbuild.mlog.log_once(mesonbuild.mlog.bold('foo'))
            mesonbuild.mlog.log_once(mesonbuild.mlog.bold('foo'))
            actual = f.getvalue().strip()
            self.assertEqual(actual.count('foo'), 1, actual)

            mesonbuild.mlog.log_once('foo')
            actual = f.getvalue().strip()
            self.assertEqual(actual.count('foo'), 1, actual)

            f.truncate()

            mesonbuild.mlog.warning('bar', once=True)
            mesonbuild.mlog.warning('bar', once=True)
            actual = f.getvalue().strip()
            self.assertEqual(actual.count('bar'), 1, actual)

    def test_sort_libpaths(self):
        sort_libpaths = mesonbuild.dependencies.base.sort_libpaths
        self.assertEqual(sort_libpaths(
            ['/home/mesonuser/.local/lib', '/usr/local/lib', '/usr/lib'],
            ['/home/mesonuser/.local/lib/pkgconfig', '/usr/local/lib/pkgconfig']),
            ['/home/mesonuser/.local/lib', '/usr/local/lib', '/usr/lib'])
        self.assertEqual(sort_libpaths(
            ['/usr/local/lib', '/home/mesonuser/.local/lib', '/usr/lib'],
            ['/home/mesonuser/.local/lib/pkgconfig', '/usr/local/lib/pkgconfig']),
            ['/home/mesonuser/.local/lib', '/usr/local/lib', '/usr/lib'])
        self.assertEqual(sort_libpaths(
            ['/usr/lib', '/usr/local/lib', '/home/mesonuser/.local/lib'],
            ['/home/mesonuser/.local/lib/pkgconfig', '/usr/local/lib/pkgconfig']),
            ['/home/mesonuser/.local/lib', '/usr/local/lib', '/usr/lib'])
        self.assertEqual(sort_libpaths(
            ['/usr/lib', '/usr/local/lib', '/home/mesonuser/.local/lib'],
            ['/home/mesonuser/.local/lib/pkgconfig', '/usr/local/libdata/pkgconfig']),
            ['/home/mesonuser/.local/lib', '/usr/local/lib', '/usr/lib'])


@unittest.skipIf(is_tarball(), 'Skipping because this is a tarball release')
class DataTests(unittest.TestCase):

    def test_snippets(self):
        hashcounter = re.compile('^ *(#)+')
        snippet_dir = Path('docs/markdown/snippets')
        self.assertTrue(snippet_dir.is_dir())
        for f in snippet_dir.glob('*'):
            self.assertTrue(f.is_file())
            if f.parts[-1].endswith('~'):
                continue
            if f.suffix == '.md':
                in_code_block = False
                with f.open() as snippet:
                    for line in snippet:
                        if line.startswith('    '):
                            continue
                        if line.startswith('```'):
                            in_code_block = not in_code_block
                        if in_code_block:
                            continue
                        m = re.match(hashcounter, line)
                        if m:
                            self.assertEqual(len(m.group(0)), 2, 'All headings in snippets must have two hash symbols: ' + f.name)
                self.assertFalse(in_code_block, 'Unclosed code block.')
            else:
                if f.name != 'add_release_note_snippets_here':
                    self.assertTrue(False, 'A file without .md suffix in snippets dir: ' + f.name)

    def test_compiler_options_documented(self):
        '''
        Test that C and C++ compiler options and base options are documented in
        Builtin-Options.md. Only tests the default compiler for the current
        platform on the CI.
        '''
        md = None
        with open('docs/markdown/Builtin-options.md', encoding='utf-8') as f:
            md = f.read()
        self.assertIsNotNone(md)
        env = get_fake_env()
        # FIXME: Support other compilers
        cc = env.detect_c_compiler(MachineChoice.HOST)
        cpp = env.detect_cpp_compiler(MachineChoice.HOST)
        for comp in (cc, cpp):
            for opt in comp.get_options().keys():
                self.assertIn(opt, md)
            for opt in comp.base_options:
                self.assertIn(opt, md)
        self.assertNotIn('b_unknown', md)

    def test_builtin_options_documented(self):
        '''
        Test that universal options and base options are documented in
        Builtin-Options.md.
        '''
        md = None
        with open('docs/markdown/Builtin-options.md', encoding='utf-8') as f:
            md = f.read()
        self.assertIsNotNone(md)

        found_entries = set()
        sections = list(re.finditer(r"^## (.+)$", md, re.MULTILINE)) + [None]

        for s1, s2 in zip(sections[:], sections[1:]):
            if s1.group(1) == "Universal options":
                # Extract the content for this section
                end = s2.start() if s2 is not None else len(md)
                content = md[s1.end():end]
                subsections = list(re.finditer(r"^### (.+)$", content, re.MULTILINE)) + [None]

                for sub1, sub2 in zip(subsections[:], subsections[1:]):
                    if sub1.group(1) == "Directories" or sub1.group(1) == "Core options":
                        # Extract the content for this subsection
                        sub_end = sub2.start() if sub2 is not None else len(content)
                        subcontent = content[sub1.end():sub_end]
                        # Find the list entries
                        arches = [m.group(1) for m in re.finditer(r"^\| (\w+) .* \|", subcontent, re.MULTILINE)]
                        # Drop the header
                        arches = set(arches[1:])

                        self.assertEqual(len(found_entries & arches), 0)
                        found_entries |= arches
            break

        self.assertEqual(found_entries, set([
            *mesonbuild.coredata.builtin_options.keys(),
            *mesonbuild.coredata.builtin_options_per_machine.keys()
        ]))

    def test_cpu_families_documented(self):
        with open("docs/markdown/Reference-tables.md", encoding='utf-8') as f:
            md = f.read()
        self.assertIsNotNone(md)

        sections = list(re.finditer(r"^## (.+)$", md, re.MULTILINE))
        for s1, s2 in zip(sections[::2], sections[1::2]):
            if s1.group(1) == "CPU families":
                # Extract the content for this section
                content = md[s1.end():s2.start()]
                # Find the list entries
                arches = [m.group(1) for m in re.finditer(r"^\| (\w+) +\|", content, re.MULTILINE)]
                # Drop the header
                arches = set(arches[1:])
                self.assertEqual(arches, set(mesonbuild.environment.known_cpu_families))

    def test_markdown_files_in_sitemap(self):
        '''
        Test that each markdown files in docs/markdown is referenced in sitemap.txt
        '''
        with open("docs/sitemap.txt", encoding='utf-8') as f:
            md = f.read()
        self.assertIsNotNone(md)
        toc = list(m.group(1) for m in re.finditer(r"^\s*(\w.*)$", md, re.MULTILINE))
        markdownfiles = [f.name for f in Path("docs/markdown").iterdir() if f.is_file() and f.suffix == '.md']
        exceptions = ['_Sidebar.md']
        for f in markdownfiles:
            if f not in exceptions:
                self.assertIn(f, toc)

    def test_vim_syntax_highlighting(self):
        '''
        Ensure that vim syntax highlighting files were updated for new
        functions in the global namespace in build files.
        '''
        env = get_fake_env()
        interp = Interpreter(FakeBuild(env), mock=True)
        with open('data/syntax-highlighting/vim/syntax/meson.vim') as f:
            res = re.search(r'syn keyword mesonBuiltin(\s+\\\s\w+)+', f.read(), re.MULTILINE)
            defined = set([a.strip() for a in res.group().split('\\')][1:])
            self.assertEqual(defined, set(chain(interp.funcs.keys(), interp.builtin.keys())))

    @unittest.skipIf(is_pull(), 'Skipping because this is a pull request')
    def test_json_grammar_syntax_highlighting(self):
        '''
        Ensure that syntax highlighting JSON grammar written by TingPing was
        updated for new functions in the global namespace in build files.
        https://github.com/TingPing/language-meson/
        '''
        env = get_fake_env()
        interp = Interpreter(FakeBuild(env), mock=True)
        url = 'https://raw.githubusercontent.com/TingPing/language-meson/master/grammars/meson.json'
        try:
            # Use a timeout to avoid blocking forever in case the network is
            # slow or unavailable in a weird way
            r = urllib.request.urlopen(url, timeout=URLOPEN_TIMEOUT)
        except urllib.error.URLError as e:
            # Skip test when network is not available, such as during packaging
            # by a distro or Flatpak
            if not isinstance(e, urllib.error.HTTPError):
                raise unittest.SkipTest('Network unavailable')
            # Don't fail the test if github is down, but do fail if 4xx
            if e.code >= 500:
                raise unittest.SkipTest('Server error ' + str(e.code))
            raise e
        # On Python 3.5, we must decode bytes to string. Newer versions don't require that.
        grammar = json.loads(r.read().decode('utf-8', 'surrogatepass'))
        for each in grammar['patterns']:
            if 'name' in each and each['name'] == 'support.function.builtin.meson':
                # The string is of the form: (?x)\\b(func1|func2|...\n)\\b\\s*(?=\\() and
                # we convert that to [func1, func2, ...] without using regex to parse regex
                funcs = set(each['match'].split('\\b(')[1].split('\n')[0].split('|'))
            if 'name' in each and each['name'] == 'support.variable.meson':
                # \\b(builtin1|builtin2...)\\b
                builtin = set(each['match'].split('\\b(')[1].split(')\\b')[0].split('|'))
        self.assertEqual(builtin, set(interp.builtin.keys()))
        self.assertEqual(funcs, set(interp.funcs.keys()))

    def test_all_functions_defined_in_ast_interpreter(self):
        '''
        Ensure that the all functions defined in the Interpreter are also defined
        in the AstInterpreter (and vice versa).
        '''
        env = get_fake_env()
        interp = Interpreter(FakeBuild(env), mock=True)
        astint = AstInterpreter('.', '')
        self.assertEqual(set(interp.funcs.keys()), set(astint.funcs.keys()))


class BasePlatformTests(unittest.TestCase):
    def setUp(self):
        super().setUp()
        self.maxDiff = None
        src_root = os.path.dirname(__file__)
        src_root = os.path.join(os.getcwd(), src_root)
        self.src_root = src_root
        self.prefix = '/usr'
        self.libdir = 'lib'
        # Get the backend
        # FIXME: Extract this from argv?
        self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja'))
        self.meson_args = ['--backend=' + self.backend.name]
        self.meson_cross_file = None
        self.meson_command = python_command + [get_meson_script()]
        self.setup_command = self.meson_command + self.meson_args
        self.mconf_command = self.meson_command + ['configure']
        self.mintro_command = self.meson_command + ['introspect']
        self.wrap_command = self.meson_command + ['wrap']
        self.rewrite_command = self.meson_command + ['rewrite']
        # Backend-specific build commands
        self.build_command, self.clean_command, self.test_command, self.install_command, \
            self.uninstall_command = get_backend_commands(self.backend)
        # Test directories
        self.common_test_dir = os.path.join(src_root, 'test cases/common')
        self.vala_test_dir = os.path.join(src_root, 'test cases/vala')
        self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks')
        self.unit_test_dir = os.path.join(src_root, 'test cases/unit')
        self.rewrite_test_dir = os.path.join(src_root, 'test cases/rewrite')
        # Misc stuff
        self.orig_env = os.environ.copy()
        if self.backend is Backend.ninja:
            self.no_rebuild_stdout = ['ninja: no work to do.', 'samu: nothing to do']
        else:
            # VS doesn't have a stable output when no changes are done
            # XCode backend is untested with unit tests, help welcome!
            self.no_rebuild_stdout = ['UNKNOWN BACKEND {!r}'.format(self.backend.name)]

        self.builddirs = []
        self.new_builddir()

    def change_builddir(self, newdir):
        self.builddir = newdir
        self.privatedir = os.path.join(self.builddir, 'meson-private')
        self.logdir = os.path.join(self.builddir, 'meson-logs')
        self.installdir = os.path.join(self.builddir, 'install')
        self.distdir = os.path.join(self.builddir, 'meson-dist')
        self.mtest_command = self.meson_command + ['test', '-C', self.builddir]
        self.builddirs.append(self.builddir)

    def new_builddir(self):
        if not is_cygwin():
            # Keep builddirs inside the source tree so that virus scanners
            # don't complain
            newdir = tempfile.mkdtemp(dir=os.getcwd())
        else:
            # But not on Cygwin because that breaks the umask tests. See:
            # https://github.com/mesonbuild/meson/pull/5546#issuecomment-509666523
            newdir = tempfile.mkdtemp()
        # In case the directory is inside a symlinked directory, find the real
        # path otherwise we might not find the srcdir from inside the builddir.
        newdir = os.path.realpath(newdir)
        self.change_builddir(newdir)

    def _print_meson_log(self):
        log = os.path.join(self.logdir, 'meson-log.txt')
        if not os.path.isfile(log):
            print("{!r} doesn't exist".format(log))
            return
        with open(log, 'r', encoding='utf-8') as f:
            print(f.read())

    def tearDown(self):
        for path in self.builddirs:
            try:
                windows_proof_rmtree(path)
            except FileNotFoundError:
                pass
        os.environ.clear()
        os.environ.update(self.orig_env)
        super().tearDown()

    def _run(self, command, *, workdir=None, override_envvars=None):
        '''
        Run a command while printing the stdout and stderr to stdout,
        and also return a copy of it
        '''
        # If this call hangs CI will just abort. It is very hard to distinguish
        # between CI issue and test bug in that case. Set timeout and fail loud
        # instead.
        if override_envvars is None:
            env = None
        else:
            env = os.environ.copy()
            env.update(override_envvars)

        p = subprocess.run(command, stdout=subprocess.PIPE,
                           stderr=subprocess.STDOUT, env=env,
                           universal_newlines=True, cwd=workdir, timeout=60 * 5)
        print(p.stdout)
        if p.returncode != 0:
            if 'MESON_SKIP_TEST' in p.stdout:
                raise unittest.SkipTest('Project requested skipping.')
            raise subprocess.CalledProcessError(p.returncode, command, output=p.stdout)
        return p.stdout

    def init(self, srcdir, *,
             extra_args=None,
             default_args=True,
             inprocess=False,
             override_envvars=None):
        self.assertPathExists(srcdir)
        if extra_args is None:
            extra_args = []
        if not isinstance(extra_args, list):
            extra_args = [extra_args]
        args = [srcdir, self.builddir]
        if default_args:
            args += ['--prefix', self.prefix,
                     '--libdir', self.libdir]
            if self.meson_cross_file:
                args += ['--cross-file', self.meson_cross_file]
        self.privatedir = os.path.join(self.builddir, 'meson-private')
        if inprocess:
            try:
                if override_envvars is not None:
                    old_envvars = os.environ.copy()
                    os.environ.update(override_envvars)
                (returncode, out, err) = run_configure_inprocess(self.meson_args + args + extra_args)
                if override_envvars is not None:
                    os.environ.clear()
                    os.environ.update(old_envvars)
                if 'MESON_SKIP_TEST' in out:
                    raise unittest.SkipTest('Project requested skipping.')
                if returncode != 0:
                    self._print_meson_log()
                    print('Stdout:\n')
                    print(out)
                    print('Stderr:\n')
                    print(err)
                    raise RuntimeError('Configure failed')
            except Exception:
                self._print_meson_log()
                raise
            finally:
                # Close log file to satisfy Windows file locking
                mesonbuild.mlog.shutdown()
                mesonbuild.mlog.log_dir = None
                mesonbuild.mlog.log_file = None
        else:
            try:
                out = self._run(self.setup_command + args + extra_args, override_envvars=override_envvars)
            except unittest.SkipTest:
                raise unittest.SkipTest('Project requested skipping: ' + srcdir)
            except Exception:
                self._print_meson_log()
                raise
        return out

    def build(self, target=None, *, extra_args=None, override_envvars=None):
        if extra_args is None:
            extra_args = []
        # Add arguments for building the target (if specified),
        # and using the build dir (if required, with VS)
        args = get_builddir_target_args(self.backend, self.builddir, target)
        return self._run(self.build_command + args + extra_args, workdir=self.builddir, override_envvars=override_envvars)

    def clean(self, *, override_envvars=None):
        dir_args = get_builddir_target_args(self.backend, self.builddir, None)
        self._run(self.clean_command + dir_args, workdir=self.builddir, override_envvars=override_envvars)

    def run_tests(self, *, inprocess=False, override_envvars=None):
        if not inprocess:
            self._run(self.test_command, workdir=self.builddir, override_envvars=override_envvars)
        else:
            if override_envvars is not None:
                old_envvars = os.environ.copy()
                os.environ.update(override_envvars)
            try:
                run_mtest_inprocess(['-C', self.builddir])
            finally:
                if override_envvars is not None:
                    os.environ.clear()
                    os.environ.update(old_envvars)

    def install(self, *, use_destdir=True, override_envvars=None):
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name))
        if use_destdir:
            destdir = {'DESTDIR': self.installdir}
            if override_envvars is None:
                override_envvars = destdir
            else:
                override_envvars.update(destdir)
        self._run(self.install_command, workdir=self.builddir, override_envvars=override_envvars)

    def uninstall(self, *, override_envvars=None):
        self._run(self.uninstall_command, workdir=self.builddir, override_envvars=override_envvars)

    def run_target(self, target, *, override_envvars=None):
        '''
        Run a Ninja target while printing the stdout and stderr to stdout,
        and also return a copy of it
        '''
        return self.build(target=target, override_envvars=override_envvars)

    def setconf(self, arg, will_build=True):
        if not isinstance(arg, list):
            arg = [arg]
        if will_build:
            ensure_backend_detects_changes(self.backend)
        self._run(self.mconf_command + arg + [self.builddir])

    def wipe(self):
        windows_proof_rmtree(self.builddir)

    def utime(self, f):
        ensure_backend_detects_changes(self.backend)
        os.utime(f)

    def get_compdb(self):
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('Compiler db not available with {} backend'.format(self.backend.name))
        try:
            with open(os.path.join(self.builddir, 'compile_commands.json')) as ifile:
                contents = json.load(ifile)
        except FileNotFoundError:
            raise unittest.SkipTest('Compiler db not found')
        # If Ninja is using .rsp files, generate them, read their contents, and
        # replace it as the command for all compile commands in the parsed json.
        if len(contents) > 0 and contents[0]['command'].endswith('.rsp'):
            # Pretend to build so that the rsp files are generated
            self.build(extra_args=['-d', 'keeprsp', '-n'])
            for each in contents:
                # Extract the actual command from the rsp file
                compiler, rsp = each['command'].split(' @')
                rsp = os.path.join(self.builddir, rsp)
                # Replace the command with its contents
                with open(rsp, 'r', encoding='utf-8') as f:
                    each['command'] = compiler + ' ' + f.read()
        return contents

    def get_meson_log(self):
        with open(os.path.join(self.builddir, 'meson-logs', 'meson-log.txt')) as f:
            return f.readlines()

    def get_meson_log_compiler_checks(self):
        '''
        Fetch a list command-lines run by meson for compiler checks.
        Each command-line is returned as a list of arguments.
        '''
        log = self.get_meson_log()
        prefix = 'Command line:'
        cmds = [l[len(prefix):].split() for l in log if l.startswith(prefix)]
        return cmds

    def introspect(self, args):
        if isinstance(args, str):
            args = [args]
        out = subprocess.check_output(self.mintro_command + args + [self.builddir],
                                      universal_newlines=True)
        return json.loads(out)

    def introspect_directory(self, directory, args):
        if isinstance(args, str):
            args = [args]
        out = subprocess.check_output(self.mintro_command + args + [directory],
                                      universal_newlines=True)
        try:
            obj = json.loads(out)
        except Exception as e:
            print(out)
            raise e
        return obj

    def assertPathEqual(self, path1, path2):
        '''
        Handles a lot of platform-specific quirks related to paths such as
        separator, case-sensitivity, etc.
        '''
        self.assertEqual(PurePath(path1), PurePath(path2))

    def assertPathListEqual(self, pathlist1, pathlist2):
        self.assertEqual(len(pathlist1), len(pathlist2))
        worklist = list(zip(pathlist1, pathlist2))
        for i in worklist:
            if i[0] is None:
                self.assertEqual(i[0], i[1])
            else:
                self.assertPathEqual(i[0], i[1])

    def assertPathBasenameEqual(self, path, basename):
        msg = '{!r} does not end with {!r}'.format(path, basename)
        # We cannot use os.path.basename because it returns '' when the path
        # ends with '/' for some silly reason. This is not how the UNIX utility
        # `basename` works.
        path_basename = PurePath(path).parts[-1]
        self.assertEqual(PurePath(path_basename), PurePath(basename), msg)

    def assertBuildIsNoop(self):
        ret = self.build()
        if self.backend is Backend.ninja:
            self.assertIn(ret.split('\n')[-2], self.no_rebuild_stdout)
        elif self.backend is Backend.vs:
            # Ensure that some target said that no rebuild was done
            self.assertIn('CustomBuild:\n  All outputs are up-to-date.', ret)
            self.assertIn('ClCompile:\n  All outputs are up-to-date.', ret)
            self.assertIn('Link:\n  All outputs are up-to-date.', ret)
            # Ensure that no targets were built
            clre = re.compile('ClCompile:\n [^\n]*cl', flags=re.IGNORECASE)
            linkre = re.compile('Link:\n [^\n]*link', flags=re.IGNORECASE)
            self.assertNotRegex(ret, clre)
            self.assertNotRegex(ret, linkre)
        elif self.backend is Backend.xcode:
            raise unittest.SkipTest('Please help us fix this test on the xcode backend')
        else:
            raise RuntimeError('Invalid backend: {!r}'.format(self.backend.name))

    def assertRebuiltTarget(self, target):
        ret = self.build()
        if self.backend is Backend.ninja:
            self.assertIn('Linking target {}'.format(target), ret)
        elif self.backend is Backend.vs:
            # Ensure that this target was rebuilt
            linkre = re.compile('Link:\n [^\n]*link[^\n]*' + target, flags=re.IGNORECASE)
            self.assertRegex(ret, linkre)
        elif self.backend is Backend.xcode:
            raise unittest.SkipTest('Please help us fix this test on the xcode backend')
        else:
            raise RuntimeError('Invalid backend: {!r}'.format(self.backend.name))

    def assertPathExists(self, path):
        m = 'Path {!r} should exist'.format(path)
        self.assertTrue(os.path.exists(path), msg=m)

    def assertPathDoesNotExist(self, path):
        m = 'Path {!r} should not exist'.format(path)
        self.assertFalse(os.path.exists(path), msg=m)


class AllPlatformTests(BasePlatformTests):
    '''
    Tests that should run on all platforms
    '''

    def test_default_options_prefix(self):
        '''
        Tests that setting a prefix in default_options in project() works.
        Can't be an ordinary test because we pass --prefix to meson there.
        https://github.com/mesonbuild/meson/issues/1349
        '''
        testdir = os.path.join(self.common_test_dir, '90 default options')
        self.init(testdir, default_args=False)
        opts = self.introspect('--buildoptions')
        for opt in opts:
            if opt['name'] == 'prefix':
                prefix = opt['value']
        self.assertEqual(prefix, '/absoluteprefix')

    def test_do_conf_file_preserve_newlines(self):

        def conf_file(in_data, confdata):
            with temp_filename() as fin:
                with open(fin, 'wb') as fobj:
                    fobj.write(in_data.encode('utf-8'))
                with temp_filename() as fout:
                    mesonbuild.mesonlib.do_conf_file(fin, fout, confdata, 'meson')
                    with open(fout, 'rb') as fobj:
                        return fobj.read().decode('utf-8')

        confdata = {'VAR': ('foo', 'bar')}
        self.assertEqual(conf_file('@VAR@\n@VAR@\n', confdata), 'foo\nfoo\n')
        self.assertEqual(conf_file('@VAR@\r\n@VAR@\r\n', confdata), 'foo\r\nfoo\r\n')

    def test_absolute_prefix_libdir(self):
        '''
        Tests that setting absolute paths for --prefix and --libdir work. Can't
        be an ordinary test because these are set via the command-line.
        https://github.com/mesonbuild/meson/issues/1341
        https://github.com/mesonbuild/meson/issues/1345
        '''
        testdir = os.path.join(self.common_test_dir, '90 default options')
        prefix = '/someabs'
        libdir = 'libdir'
        extra_args = ['--prefix=' + prefix,
                      # This can just be a relative path, but we want to test
                      # that passing this as an absolute path also works
                      '--libdir=' + prefix + '/' + libdir]
        self.init(testdir, extra_args=extra_args, default_args=False)
        opts = self.introspect('--buildoptions')
        for opt in opts:
            if opt['name'] == 'prefix':
                self.assertEqual(prefix, opt['value'])
            elif opt['name'] == 'libdir':
                self.assertEqual(libdir, opt['value'])

    def test_libdir_must_be_inside_prefix(self):
        '''
        Tests that libdir is forced to be inside prefix no matter how it is set.
        Must be a unit test for obvious reasons.
        '''
        testdir = os.path.join(self.common_test_dir, '1 trivial')
        # libdir being inside prefix is ok
        args = ['--prefix', '/opt', '--libdir', '/opt/lib32']
        self.init(testdir, extra_args=args)
        self.wipe()
        # libdir not being inside prefix is not ok
        args = ['--prefix', '/usr', '--libdir', '/opt/lib32']
        self.assertRaises(subprocess.CalledProcessError, self.init, testdir, extra_args=args)
        self.wipe()
        # libdir must be inside prefix even when set via mesonconf
        self.init(testdir)
        self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False)

    def test_prefix_dependent_defaults(self):
        '''
        Tests that configured directory paths are set to prefix dependent
        defaults.
        '''
        testdir = os.path.join(self.common_test_dir, '1 trivial')
        expected = {
            '/opt': {'prefix': '/opt',
                     'bindir': 'bin', 'datadir': 'share', 'includedir': 'include',
                     'infodir': 'share/info',
                     'libexecdir': 'libexec', 'localedir': 'share/locale',
                     'localstatedir': 'var', 'mandir': 'share/man',
                     'sbindir': 'sbin', 'sharedstatedir': 'com',
                     'sysconfdir': 'etc'},
            '/usr': {'prefix': '/usr',
                     'bindir': 'bin', 'datadir': 'share', 'includedir': 'include',
                     'infodir': 'share/info',
                     'libexecdir': 'libexec', 'localedir': 'share/locale',
                     'localstatedir': '/var', 'mandir': 'share/man',
                     'sbindir': 'sbin', 'sharedstatedir': '/var/lib',
                     'sysconfdir': '/etc'},
            '/usr/local': {'prefix': '/usr/local',
                           'bindir': 'bin', 'datadir': 'share',
                           'includedir': 'include', 'infodir': 'share/info',
                           'libexecdir': 'libexec',
                           'localedir': 'share/locale',
                           'localstatedir': '/var/local', 'mandir': 'share/man',
                           'sbindir': 'sbin', 'sharedstatedir': '/var/local/lib',
                           'sysconfdir': 'etc'},
            # N.B. We don't check 'libdir' as it's platform dependent, see
            # default_libdir():
        }

        if mesonbuild.mesonlib.default_prefix() == '/usr/local':
            expected[None] = expected['/usr/local']

        for prefix in expected:
            args = []
            if prefix:
                args += ['--prefix', prefix]
            self.init(testdir, extra_args=args, default_args=False)
            opts = self.introspect('--buildoptions')
            for opt in opts:
                name = opt['name']
                value = opt['value']
                if name in expected[prefix]:
                    self.assertEqual(value, expected[prefix][name])
            self.wipe()

    def test_default_options_prefix_dependent_defaults(self):
        '''
        Tests that setting a prefix in default_options in project() sets prefix
        dependent defaults for other options, and that those defaults can
        be overridden in default_options or by the command line.
        '''
        testdir = os.path.join(self.common_test_dir, '168 default options prefix dependent defaults')
        expected = {
            '':
            {'prefix':         '/usr',
             'sysconfdir':     '/etc',
             'localstatedir':  '/var',
             'sharedstatedir': '/sharedstate'},
            '--prefix=/usr':
            {'prefix':         '/usr',
             'sysconfdir':     '/etc',
             'localstatedir':  '/var',
             'sharedstatedir': '/sharedstate'},
            '--sharedstatedir=/var/state':
            {'prefix':         '/usr',
             'sysconfdir':     '/etc',
             'localstatedir':  '/var',
             'sharedstatedir': '/var/state'},
            '--sharedstatedir=/var/state --prefix=/usr --sysconfdir=sysconf':
            {'prefix':         '/usr',
             'sysconfdir':     'sysconf',
             'localstatedir':  '/var',
             'sharedstatedir': '/var/state'},
        }
        for args in expected:
            self.init(testdir, extra_args=args.split(), default_args=False)
            opts = self.introspect('--buildoptions')
            for opt in opts:
                name = opt['name']
                value = opt['value']
                if name in expected[args]:
                    self.assertEqual(value, expected[args][name])
            self.wipe()

    def test_clike_get_library_dirs(self):
        env = get_fake_env()
        cc = env.detect_c_compiler(MachineChoice.HOST)
        for d in cc.get_library_dirs(env):
            self.assertTrue(os.path.exists(d))
            self.assertTrue(os.path.isdir(d))
            self.assertTrue(os.path.isabs(d))

    def test_static_library_overwrite(self):
        '''
        Tests that static libraries are never appended to, always overwritten.
        Has to be a unit test because this involves building a project,
        reconfiguring, and building it again so that `ar` is run twice on the
        same static library.
        https://github.com/mesonbuild/meson/issues/1355
        '''
        testdir = os.path.join(self.common_test_dir, '3 static')
        env = get_fake_env(testdir, self.builddir, self.prefix)
        cc = env.detect_c_compiler(MachineChoice.HOST)
        static_linker = env.detect_static_linker(cc)
        if is_windows():
            raise unittest.SkipTest('https://github.com/mesonbuild/meson/issues/1526')
        if not isinstance(static_linker, mesonbuild.linkers.ArLinker):
            raise unittest.SkipTest('static linker is not `ar`')
        # Configure
        self.init(testdir)
        # Get name of static library
        targets = self.introspect('--targets')
        self.assertEqual(len(targets), 1)
        libname = targets[0]['filename'][0]
        # Build and get contents of static library
        self.build()
        before = self._run(['ar', 't', os.path.join(self.builddir, libname)]).split()
        # Filter out non-object-file contents
        before = [f for f in before if f.endswith(('.o', '.obj'))]
        # Static library should contain only one object
        self.assertEqual(len(before), 1, msg=before)
        # Change the source to be built into the static library
        self.setconf('-Dsource=libfile2.c')
        self.build()
        after = self._run(['ar', 't', os.path.join(self.builddir, libname)]).split()
        # Filter out non-object-file contents
        after = [f for f in after if f.endswith(('.o', '.obj'))]
        # Static library should contain only one object
        self.assertEqual(len(after), 1, msg=after)
        # and the object must have changed
        self.assertNotEqual(before, after)

    def test_static_compile_order(self):
        '''
        Test that the order of files in a compiler command-line while compiling
        and linking statically is deterministic. This can't be an ordinary test
        case because we need to inspect the compiler database.
        https://github.com/mesonbuild/meson/pull/951
        '''
        testdir = os.path.join(self.common_test_dir, '5 linkstatic')
        self.init(testdir)
        compdb = self.get_compdb()
        # Rules will get written out in this order
        self.assertTrue(compdb[0]['file'].endswith("libfile.c"))
        self.assertTrue(compdb[1]['file'].endswith("libfile2.c"))
        self.assertTrue(compdb[2]['file'].endswith("libfile3.c"))
        self.assertTrue(compdb[3]['file'].endswith("libfile4.c"))
        # FIXME: We don't have access to the linker command

    def test_run_target_files_path(self):
        '''
        Test that run_targets are run from the correct directory
        https://github.com/mesonbuild/meson/issues/957
        '''
        testdir = os.path.join(self.common_test_dir, '54 run target')
        self.init(testdir)
        self.run_target('check_exists')

    def test_install_introspection(self):
        '''
        Tests that the Meson introspection API exposes install filenames correctly
        https://github.com/mesonbuild/meson/issues/829
        '''
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name))
        testdir = os.path.join(self.common_test_dir, '8 install')
        self.init(testdir)
        intro = self.introspect('--targets')
        if intro[0]['type'] == 'executable':
            intro = intro[::-1]
        self.assertPathListEqual(intro[0]['install_filename'], ['/usr/lib/libstat.a'])
        self.assertPathListEqual(intro[1]['install_filename'], ['/usr/bin/prog' + exe_suffix])

    def test_install_subdir_introspection(self):
        '''
        Test that the Meson introspection API also contains subdir install information
        https://github.com/mesonbuild/meson/issues/5556
        '''
        testdir = os.path.join(self.common_test_dir, '62 install subdir')
        self.init(testdir)
        intro = self.introspect('--installed')
        expected = {
            'sub2': 'share/sub2',
            'subdir/sub1': 'share/sub1',
            'subdir/sub_elided': 'share',
            'sub1': 'share/sub1',
            'sub/sub1': 'share/sub1',
            'sub_elided': 'share',
            'nested_elided/sub': 'share',
        }

        self.assertEqual(len(intro), len(expected))

        # Convert expected to PurePath
        expected_converted = {PurePath(os.path.join(testdir, key)): PurePath(os.path.join(self.prefix, val)) for key, val in expected.items()}
        intro_converted = {PurePath(key): PurePath(val) for key, val in intro.items()}

        for src, dst in expected_converted.items():
            self.assertIn(src, intro_converted)
            self.assertEqual(dst, intro_converted[src])

    def test_install_introspection_multiple_outputs(self):
        '''
        Tests that the Meson introspection API exposes multiple install filenames correctly without crashing
        https://github.com/mesonbuild/meson/pull/4555

        Reverted to the first file only because of https://github.com/mesonbuild/meson/pull/4547#discussion_r244173438
        TODO Change the format to a list officially in a followup PR
        '''
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name))
        testdir = os.path.join(self.common_test_dir, '144 custom target multiple outputs')
        self.init(testdir)
        intro = self.introspect('--targets')
        if intro[0]['type'] == 'executable':
            intro = intro[::-1]
        self.assertPathListEqual(intro[0]['install_filename'], ['/usr/include/diff.h', '/usr/bin/diff.sh'])
        self.assertPathListEqual(intro[1]['install_filename'], ['/opt/same.h', '/opt/same.sh'])
        self.assertPathListEqual(intro[2]['install_filename'], ['/usr/include/first.h', None])
        self.assertPathListEqual(intro[3]['install_filename'], [None, '/usr/bin/second.sh'])

    def test_install_log_content(self):
        '''
        Tests that the install-log.txt is consistent with the installed files and directories.
        Specifically checks that the log file only contains one entry per file/directory.
        https://github.com/mesonbuild/meson/issues/4499
        '''
        testdir = os.path.join(self.common_test_dir, '62 install subdir')
        self.init(testdir)
        self.install()
        installpath = Path(self.installdir)
        # Find installed files and directories
        expected = {installpath: 0}
        for name in installpath.rglob('*'):
            expected[name] = 0
        # Find logged files and directories
        with Path(self.builddir, 'meson-logs', 'install-log.txt').open() as f:
            logged = list(map(lambda l: Path(l.strip()),
                              filter(lambda l: not l.startswith('#'),
                                     f.readlines())))
        for name in logged:
            self.assertTrue(name in expected, 'Log contains extra entry {}'.format(name))
            expected[name] += 1

        for name, count in expected.items():
            self.assertGreater(count, 0, 'Log is missing entry for {}'.format(name))
            self.assertLess(count, 2, 'Log has multiple entries for {}'.format(name))

    def test_uninstall(self):
        exename = os.path.join(self.installdir, 'usr/bin/prog' + exe_suffix)
        testdir = os.path.join(self.common_test_dir, '8 install')
        self.init(testdir)
        self.assertPathDoesNotExist(exename)
        self.install()
        self.assertPathExists(exename)
        self.uninstall()
        self.assertPathDoesNotExist(exename)

    def test_forcefallback(self):
        testdir = os.path.join(self.unit_test_dir, '31 forcefallback')
        self.init(testdir, extra_args=['--wrap-mode=forcefallback'])
        self.build()
        self.run_tests()

    def test_env_ops_dont_stack(self):
        '''
        Test that env ops prepend/append do not stack, and that this usage issues a warning
        '''
        testdir = os.path.join(self.unit_test_dir, '63 test env does not stack')
        out = self.init(testdir)
        self.assertRegex(out, r'WARNING: Overriding.*TEST_VAR_APPEND')
        self.assertRegex(out, r'WARNING: Overriding.*TEST_VAR_PREPEND')
        self.assertNotRegex(out, r'WARNING: Overriding.*TEST_VAR_SET')
        self.run_tests()

    def test_testsetups(self):
        if not shutil.which('valgrind'):
            raise unittest.SkipTest('Valgrind not installed.')
        testdir = os.path.join(self.unit_test_dir, '2 testsetups')
        self.init(testdir)
        self.build()
        # Run tests without setup
        self.run_tests()
        with open(os.path.join(self.logdir, 'testlog.txt')) as f:
            basic_log = f.read()
        # Run buggy test with setup that has env that will make it fail
        self.assertRaises(subprocess.CalledProcessError,
                          self._run, self.mtest_command + ['--setup=valgrind'])
        with open(os.path.join(self.logdir, 'testlog-valgrind.txt')) as f:
            vg_log = f.read()
        self.assertFalse('TEST_ENV is set' in basic_log)
        self.assertFalse('Memcheck' in basic_log)
        self.assertTrue('TEST_ENV is set' in vg_log)
        self.assertTrue('Memcheck' in vg_log)
        # Run buggy test with setup without env that will pass
        self._run(self.mtest_command + ['--setup=wrapper'])
        # Setup with no properties works
        self._run(self.mtest_command + ['--setup=empty'])
        # Setup with only env works
        self._run(self.mtest_command + ['--setup=onlyenv'])
        self._run(self.mtest_command + ['--setup=onlyenv2'])
        self._run(self.mtest_command + ['--setup=onlyenv3'])
        # Setup with only a timeout works
        self._run(self.mtest_command + ['--setup=timeout'])

    def test_testsetup_selection(self):
        testdir = os.path.join(self.unit_test_dir, '14 testsetup selection')
        self.init(testdir)
        self.build()

        # Run tests without setup
        self.run_tests()

        self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['--setup=missingfromfoo'])
        self._run(self.mtest_command + ['--setup=missingfromfoo', '--no-suite=foo:'])

        self._run(self.mtest_command + ['--setup=worksforall'])
        self._run(self.mtest_command + ['--setup=main:worksforall'])

        self.assertRaises(subprocess.CalledProcessError, self._run,
                          self.mtest_command + ['--setup=onlyinbar'])
        self.assertRaises(subprocess.CalledProcessError, self._run,
                          self.mtest_command + ['--setup=onlyinbar', '--no-suite=main:'])
        self._run(self.mtest_command + ['--setup=onlyinbar', '--no-suite=main:', '--no-suite=foo:'])
        self._run(self.mtest_command + ['--setup=bar:onlyinbar'])
        self.assertRaises(subprocess.CalledProcessError, self._run,
                          self.mtest_command + ['--setup=foo:onlyinbar'])
        self.assertRaises(subprocess.CalledProcessError, self._run,
                          self.mtest_command + ['--setup=main:onlyinbar'])

    def test_testsetup_default(self):
        testdir = os.path.join(self.unit_test_dir, '49 testsetup default')
        self.init(testdir)
        self.build()

        # Run tests without --setup will cause the default setup to be used
        self.run_tests()
        with open(os.path.join(self.logdir, 'testlog.txt')) as f:
            default_log = f.read()

        # Run tests with explicitly using the same setup that is set as default
        self._run(self.mtest_command + ['--setup=mydefault'])
        with open(os.path.join(self.logdir, 'testlog-mydefault.txt')) as f:
            mydefault_log = f.read()

        # Run tests with another setup
        self._run(self.mtest_command + ['--setup=other'])
        with open(os.path.join(self.logdir, 'testlog-other.txt')) as f:
            other_log = f.read()

        self.assertTrue('ENV_A is 1' in default_log)
        self.assertTrue('ENV_B is 2' in default_log)
        self.assertTrue('ENV_C is 2' in default_log)

        self.assertTrue('ENV_A is 1' in mydefault_log)
        self.assertTrue('ENV_B is 2' in mydefault_log)
        self.assertTrue('ENV_C is 2' in mydefault_log)

        self.assertTrue('ENV_A is 1' in other_log)
        self.assertTrue('ENV_B is 3' in other_log)
        self.assertTrue('ENV_C is 2' in other_log)

    def assertFailedTestCount(self, failure_count, command):
        try:
            self._run(command)
            self.assertEqual(0, failure_count, 'Expected %d tests to fail.' % failure_count)
        except subprocess.CalledProcessError as e:
            self.assertEqual(e.returncode, failure_count)

    def test_suite_selection(self):
        testdir = os.path.join(self.unit_test_dir, '4 suite selection')
        self.init(testdir)
        self.build()

        self.assertFailedTestCount(4, self.mtest_command)

        self.assertFailedTestCount(0, self.mtest_command + ['--suite', ':success'])
        self.assertFailedTestCount(3, self.mtest_command + ['--suite', ':fail'])
        self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', ':success'])
        self.assertFailedTestCount(1, self.mtest_command + ['--no-suite', ':fail'])

        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj'])
        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc'])
        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail'])
        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix'])
        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj'])
        self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjsucc'])
        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail'])
        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix'])

        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj:fail'])
        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'mainprj:success'])
        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj:fail'])
        self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'mainprj:success'])

        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail:fail'])
        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjfail:success'])
        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail:fail'])
        self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjfail:success'])

        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:fail'])
        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:success'])
        self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjsucc:fail'])
        self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjsucc:success'])

        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix:fail'])
        self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjmix:success'])
        self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix:fail'])
        self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjmix:success'])

        self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix:fail'])
        self.assertFailedTestCount(3, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj'])
        self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail'])
        self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail', 'mainprj-failing_test'])

        self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail:fail', '--no-suite', 'subprjmix:fail'])

    def test_build_by_default(self):
        testdir = os.path.join(self.common_test_dir, '133 build by default')
        self.init(testdir)
        self.build()
        genfile1 = os.path.join(self.builddir, 'generated1.dat')
        genfile2 = os.path.join(self.builddir, 'generated2.dat')
        exe1 = os.path.join(self.builddir, 'fooprog' + exe_suffix)
        exe2 = os.path.join(self.builddir, 'barprog' + exe_suffix)
        self.assertPathExists(genfile1)
        self.assertPathExists(genfile2)
        self.assertPathDoesNotExist(exe1)
        self.assertPathDoesNotExist(exe2)
        self.build(target=('fooprog' + exe_suffix))
        self.assertPathExists(exe1)
        self.build(target=('barprog' + exe_suffix))
        self.assertPathExists(exe2)

    def test_internal_include_order(self):
        testdir = os.path.join(self.common_test_dir, '134 include order')
        self.init(testdir)
        execmd = fxecmd = None
        for cmd in self.get_compdb():
            if 'someexe' in cmd['command']:
                execmd = cmd['command']
                continue
            if 'somefxe' in cmd['command']:
                fxecmd = cmd['command']
                continue
        if not execmd or not fxecmd:
            raise Exception('Could not find someexe and somfxe commands')
        # Check include order for 'someexe'
        incs = [a for a in split_args(execmd) if a.startswith("-I")]
        self.assertEqual(len(incs), 9)
        # target private dir
        someexe_id = Target.construct_id_from_path("sub4", "someexe", "@exe")
        self.assertPathEqual(incs[0], "-I" + os.path.join("sub4", someexe_id))
        # target build subdir
        self.assertPathEqual(incs[1], "-Isub4")
        # target source subdir
        self.assertPathBasenameEqual(incs[2], 'sub4')
        # include paths added via per-target c_args: ['-I'...]
        self.assertPathBasenameEqual(incs[3], 'sub3')
        # target include_directories: build dir
        self.assertPathEqual(incs[4], "-Isub2")
        # target include_directories: source dir
        self.assertPathBasenameEqual(incs[5], 'sub2')
        # target internal dependency include_directories: build dir
        self.assertPathEqual(incs[6], "-Isub1")
        # target internal dependency include_directories: source dir
        self.assertPathBasenameEqual(incs[7], 'sub1')
        # custom target include dir
        self.assertPathEqual(incs[8], '-Ictsub')
        # Check include order for 'somefxe'
        incs = [a for a in split_args(fxecmd) if a.startswith('-I')]
        self.assertEqual(len(incs), 9)
        # target private dir
        self.assertPathEqual(incs[0], '-Isomefxe@exe')
        # target build dir
        self.assertPathEqual(incs[1], '-I.')
        # target source dir
        self.assertPathBasenameEqual(incs[2], os.path.basename(testdir))
        # target internal dependency correct include_directories: build dir
        self.assertPathEqual(incs[3], "-Isub4")
        # target internal dependency correct include_directories: source dir
        self.assertPathBasenameEqual(incs[4], 'sub4')
        # target internal dependency dep include_directories: build dir
        self.assertPathEqual(incs[5], "-Isub1")
        # target internal dependency dep include_directories: source dir
        self.assertPathBasenameEqual(incs[6], 'sub1')
        # target internal dependency wrong include_directories: build dir
        self.assertPathEqual(incs[7], "-Isub2")
        # target internal dependency wrong include_directories: source dir
        self.assertPathBasenameEqual(incs[8], 'sub2')

    def test_compiler_detection(self):
        '''
        Test that automatic compiler detection and setting from the environment
        both work just fine. This is needed because while running project tests
        and other unit tests, we always read CC/CXX/etc from the environment.
        '''
        gnu = mesonbuild.compilers.GnuCompiler
        clang = mesonbuild.compilers.ClangCompiler
        intel = mesonbuild.compilers.IntelGnuLikeCompiler
        msvc = (mesonbuild.compilers.VisualStudioCCompiler, mesonbuild.compilers.VisualStudioCPPCompiler)
        clangcl = (mesonbuild.compilers.ClangClCCompiler, mesonbuild.compilers.ClangClCPPCompiler)
        ar = mesonbuild.linkers.ArLinker
        lib = mesonbuild.linkers.VisualStudioLinker
        langs = [('c', 'CC'), ('cpp', 'CXX')]
        if not is_windows() and platform.machine().lower() != 'e2k':
            langs += [('objc', 'OBJC'), ('objcpp', 'OBJCXX')]
        testdir = os.path.join(self.unit_test_dir, '5 compiler detection')
        env = get_fake_env(testdir, self.builddir, self.prefix)
        for lang, evar in langs:
            # Detect with evar and do sanity checks on that
            if evar in os.environ:
                ecc = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
                self.assertTrue(ecc.version)
                elinker = env.detect_static_linker(ecc)
                # Pop it so we don't use it for the next detection
                evalue = os.environ.pop(evar)
                # Very rough/strict heuristics. Would never work for actual
                # compiler detection, but should be ok for the tests.
                ebase = os.path.basename(evalue)
                if ebase.startswith('g') or ebase.endswith(('-gcc', '-g++')):
                    self.assertIsInstance(ecc, gnu)
                    self.assertIsInstance(elinker, ar)
                elif 'clang-cl' in ebase:
                    self.assertIsInstance(ecc, clangcl)
                    self.assertIsInstance(elinker, lib)
                elif 'clang' in ebase:
                    self.assertIsInstance(ecc, clang)
                    self.assertIsInstance(elinker, ar)
                elif ebase.startswith('ic'):
                    self.assertIsInstance(ecc, intel)
                    self.assertIsInstance(elinker, ar)
                elif ebase.startswith('cl'):
                    self.assertIsInstance(ecc, msvc)
                    self.assertIsInstance(elinker, lib)
                else:
                    raise AssertionError('Unknown compiler {!r}'.format(evalue))
                # Check that we actually used the evalue correctly as the compiler
                self.assertEqual(ecc.get_exelist(), split_args(evalue))
            # Do auto-detection of compiler based on platform, PATH, etc.
            cc = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
            self.assertTrue(cc.version)
            linker = env.detect_static_linker(cc)
            # Check compiler type
            if isinstance(cc, gnu):
                self.assertIsInstance(linker, ar)
                if is_osx():
                    self.assertIsInstance(cc.linker, mesonbuild.linkers.AppleDynamicLinker)
                else:
                    self.assertIsInstance(cc.linker, mesonbuild.linkers.GnuLikeDynamicLinkerMixin)
            if isinstance(cc, clangcl):
                self.assertIsInstance(linker, lib)
                self.assertIsInstance(cc.linker, mesonbuild.linkers.ClangClDynamicLinker)
            if isinstance(cc, clang):
                self.assertIsInstance(linker, ar)
                if is_osx():
                    self.assertIsInstance(cc.linker, mesonbuild.linkers.AppleDynamicLinker)
                elif is_windows():
                    # This is clang, not clang-cl
                    self.assertIsInstance(cc.linker, mesonbuild.linkers.MSVCDynamicLinker)
                else:
                    self.assertIsInstance(cc.linker, mesonbuild.linkers.GnuLikeDynamicLinkerMixin)
            if isinstance(cc, intel):
                self.assertIsInstance(linker, ar)
                if is_osx():
                    self.assertIsInstance(cc.linker, mesonbuild.linkers.AppleDynamicLinker)
                elif is_windows():
                    self.assertIsInstance(cc.linker, mesonbuild.linkers.XilinkDynamicLinker)
                else:
                    self.assertIsInstance(cc.linker, mesonbuild.linkers.GnuDynamicLinker)
            if isinstance(cc, msvc):
                self.assertTrue(is_windows())
                self.assertIsInstance(linker, lib)
                self.assertEqual(cc.id, 'msvc')
                self.assertTrue(hasattr(cc, 'is_64'))
                self.assertIsInstance(cc.linker, mesonbuild.linkers.MSVCDynamicLinker)
                # If we're on Windows CI, we know what the compiler will be
                if 'arch' in os.environ:
                    if os.environ['arch'] == 'x64':
                        self.assertTrue(cc.is_64)
                    else:
                        self.assertFalse(cc.is_64)
            # Set evar ourselves to a wrapper script that just calls the same
            # exelist + some argument. This is meant to test that setting
            # something like `ccache gcc -pipe` or `distcc ccache gcc` works.
            wrapper = os.path.join(testdir, 'compiler wrapper.py')
            wrappercc = python_command + [wrapper] + cc.get_exelist() + ['-DSOME_ARG']
            wrappercc_s = ''
            for w in wrappercc:
                wrappercc_s += quote_arg(w) + ' '
            os.environ[evar] = wrappercc_s
            wcc = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
            # Check static linker too
            wrapperlinker = python_command + [wrapper] + linker.get_exelist() + linker.get_always_args()
            wrapperlinker_s = ''
            for w in wrapperlinker:
                wrapperlinker_s += quote_arg(w) + ' '
            os.environ['AR'] = wrapperlinker_s
            wlinker = env.detect_static_linker(wcc)
            # Pop it so we don't use it for the next detection
            evalue = os.environ.pop('AR')
            # Must be the same type since it's a wrapper around the same exelist
            self.assertIs(type(cc), type(wcc))
            self.assertIs(type(linker), type(wlinker))
            # Ensure that the exelist is correct
            self.assertEqual(wcc.get_exelist(), wrappercc)
            self.assertEqual(wlinker.get_exelist(), wrapperlinker)
            # Ensure that the version detection worked correctly
            self.assertEqual(cc.version, wcc.version)
            if hasattr(cc, 'is_64'):
                self.assertEqual(cc.is_64, wcc.is_64)

    def test_always_prefer_c_compiler_for_asm(self):
        testdir = os.path.join(self.common_test_dir, '137 c cpp and asm')
        # Skip if building with MSVC
        env = get_fake_env(testdir, self.builddir, self.prefix)
        if env.detect_c_compiler(MachineChoice.HOST).get_id() == 'msvc':
            raise unittest.SkipTest('MSVC can\'t compile assembly')
        self.init(testdir)
        commands = {'c-asm': {}, 'cpp-asm': {}, 'cpp-c-asm': {}, 'c-cpp-asm': {}}
        for cmd in self.get_compdb():
            # Get compiler
            split = split_args(cmd['command'])
            if split[0] == 'ccache':
                compiler = split[1]
            else:
                compiler = split[0]
            # Classify commands
            if 'Ic-asm' in cmd['command']:
                if cmd['file'].endswith('.S'):
                    commands['c-asm']['asm'] = compiler
                elif cmd['file'].endswith('.c'):
                    commands['c-asm']['c'] = compiler
                else:
                    raise AssertionError('{!r} found in cpp-asm?'.format(cmd['command']))
            elif 'Icpp-asm' in cmd['command']:
                if cmd['file'].endswith('.S'):
                    commands['cpp-asm']['asm'] = compiler
                elif cmd['file'].endswith('.cpp'):
                    commands['cpp-asm']['cpp'] = compiler
                else:
                    raise AssertionError('{!r} found in cpp-asm?'.format(cmd['command']))
            elif 'Ic-cpp-asm' in cmd['command']:
                if cmd['file'].endswith('.S'):
                    commands['c-cpp-asm']['asm'] = compiler
                elif cmd['file'].endswith('.c'):
                    commands['c-cpp-asm']['c'] = compiler
                elif cmd['file'].endswith('.cpp'):
                    commands['c-cpp-asm']['cpp'] = compiler
                else:
                    raise AssertionError('{!r} found in c-cpp-asm?'.format(cmd['command']))
            elif 'Icpp-c-asm' in cmd['command']:
                if cmd['file'].endswith('.S'):
                    commands['cpp-c-asm']['asm'] = compiler
                elif cmd['file'].endswith('.c'):
                    commands['cpp-c-asm']['c'] = compiler
                elif cmd['file'].endswith('.cpp'):
                    commands['cpp-c-asm']['cpp'] = compiler
                else:
                    raise AssertionError('{!r} found in cpp-c-asm?'.format(cmd['command']))
            else:
                raise AssertionError('Unknown command {!r} found'.format(cmd['command']))
        # Check that .S files are always built with the C compiler
        self.assertEqual(commands['c-asm']['asm'], commands['c-asm']['c'])
        self.assertEqual(commands['c-asm']['asm'], commands['cpp-asm']['asm'])
        self.assertEqual(commands['cpp-asm']['asm'], commands['c-cpp-asm']['c'])
        self.assertEqual(commands['c-cpp-asm']['asm'], commands['c-cpp-asm']['c'])
        self.assertEqual(commands['cpp-c-asm']['asm'], commands['cpp-c-asm']['c'])
        self.assertNotEqual(commands['cpp-asm']['asm'], commands['cpp-asm']['cpp'])
        self.assertNotEqual(commands['c-cpp-asm']['c'], commands['c-cpp-asm']['cpp'])
        self.assertNotEqual(commands['cpp-c-asm']['c'], commands['cpp-c-asm']['cpp'])
        # Check that the c-asm target is always linked with the C linker
        build_ninja = os.path.join(self.builddir, 'build.ninja')
        with open(build_ninja, 'r', encoding='utf-8') as f:
            contents = f.read()
            m = re.search('build c-asm.*: c_LINKER', contents)
        self.assertIsNotNone(m, msg=contents)

    def test_preprocessor_checks_CPPFLAGS(self):
        '''
        Test that preprocessor compiler checks read CPPFLAGS and also CFLAGS but
        not LDFLAGS.
        '''
        testdir = os.path.join(self.common_test_dir, '136 get define')
        define = 'MESON_TEST_DEFINE_VALUE'
        # NOTE: this list can't have \n, ' or "
        # \n is never substituted by the GNU pre-processor via a -D define
        # ' and " confuse split_args() even when they are escaped
        # % and # confuse the MSVC preprocessor
        # !, ^, *, and < confuse lcc preprocessor
        value = 'spaces and fun@$&()-=_+{}[]:;>?,./~`'
        for env_var in ['CPPFLAGS', 'CFLAGS']:
            env = {}
            env[env_var] = '-D{}="{}"'.format(define, value)
            env['LDFLAGS'] = '-DMESON_FAIL_VALUE=cflags-read'.format(define)
            self.init(testdir, extra_args=['-D{}={}'.format(define, value)], override_envvars=env)

    def test_custom_target_exe_data_deterministic(self):
        testdir = os.path.join(self.common_test_dir, '113 custom target capture')
        self.init(testdir)
        meson_exe_dat1 = glob(os.path.join(self.privatedir, 'meson_exe*.dat'))
        self.wipe()
        self.init(testdir)
        meson_exe_dat2 = glob(os.path.join(self.privatedir, 'meson_exe*.dat'))
        self.assertListEqual(meson_exe_dat1, meson_exe_dat2)

    def test_source_changes_cause_rebuild(self):
        '''
        Test that changes to sources and headers cause rebuilds, but not
        changes to unused files (as determined by the dependency file) in the
        input files list.
        '''
        testdir = os.path.join(self.common_test_dir, '20 header in file list')
        self.init(testdir)
        self.build()
        # Immediately rebuilding should not do anything
        self.assertBuildIsNoop()
        # Changing mtime of header.h should rebuild everything
        self.utime(os.path.join(testdir, 'header.h'))
        self.assertRebuiltTarget('prog')

    def test_custom_target_changes_cause_rebuild(self):
        '''
        Test that in a custom target, changes to the input files, the
        ExternalProgram, and any File objects on the command-line cause
        a rebuild.
        '''
        testdir = os.path.join(self.common_test_dir, '60 custom header generator')
        self.init(testdir)
        self.build()
        # Immediately rebuilding should not do anything
        self.assertBuildIsNoop()
        # Changing mtime of these should rebuild everything
        for f in ('input.def', 'makeheader.py', 'somefile.txt'):
            self.utime(os.path.join(testdir, f))
            self.assertRebuiltTarget('prog')

    def test_source_generator_program_cause_rebuild(self):
        '''
        Test that changes to generator programs in the source tree cause
        a rebuild.
        '''
        testdir = os.path.join(self.common_test_dir, '94 gen extra')
        self.init(testdir)
        self.build()
        # Immediately rebuilding should not do anything
        self.assertBuildIsNoop()
        # Changing mtime of generator should rebuild the executable
        self.utime(os.path.join(testdir, 'srcgen.py'))
        self.assertRebuiltTarget('basic')

    def test_static_library_lto(self):
        '''
        Test that static libraries can be built with LTO and linked to
        executables. On Linux, this requires the use of gcc-ar.
        https://github.com/mesonbuild/meson/issues/1646
        '''
        testdir = os.path.join(self.common_test_dir, '5 linkstatic')

        env = get_fake_env(testdir, self.builddir, self.prefix)
        if env.detect_c_compiler(MachineChoice.HOST).get_id() == 'clang' and is_windows():
            raise unittest.SkipTest('LTO not (yet) supported by windows clang')

        self.init(testdir, extra_args='-Db_lto=true')
        self.build()
        self.run_tests()

    def test_dist_git(self):
        if not shutil.which('git'):
            raise unittest.SkipTest('Git not found')
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('Dist is only supported with Ninja')

        try:
            self.dist_impl(_git_init)
        except PermissionError:
            # When run under Windows CI, something (virus scanner?)
            # holds on to the git files so cleaning up the dir
            # fails sometimes.
            pass

    def test_dist_hg(self):
        if not shutil.which('hg'):
            raise unittest.SkipTest('Mercurial not found')
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('Dist is only supported with Ninja')

        def hg_init(project_dir):
            subprocess.check_call(['hg', 'init'], cwd=project_dir)
            with open(os.path.join(project_dir, '.hg', 'hgrc'), 'w') as f:
                print('[ui]', file=f)
                print('username=Author Person ', file=f)
            subprocess.check_call(['hg', 'add', 'meson.build', 'distexe.c'], cwd=project_dir)
            subprocess.check_call(['hg', 'commit', '-m', 'I am a project'], cwd=project_dir)

        try:
            self.dist_impl(hg_init, include_subprojects=False)
        except PermissionError:
            # When run under Windows CI, something (virus scanner?)
            # holds on to the hg files so cleaning up the dir
            # fails sometimes.
            pass

    def test_dist_git_script(self):
        if not shutil.which('git'):
            raise unittest.SkipTest('Git not found')
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('Dist is only supported with Ninja')

        try:
            with tempfile.TemporaryDirectory() as tmpdir:
                project_dir = os.path.join(tmpdir, 'a')
                shutil.copytree(os.path.join(self.unit_test_dir, '35 dist script'),
                                project_dir)
                _git_init(project_dir)
                self.init(project_dir)
                self.build('dist')
        except PermissionError:
            # When run under Windows CI, something (virus scanner?)
            # holds on to the git files so cleaning up the dir
            # fails sometimes.
            pass

    def create_dummy_subproject(self, project_dir, name):
        path = os.path.join(project_dir, 'subprojects', name)
        os.makedirs(path)
        with open(os.path.join(path, 'meson.build'), 'w') as ofile:
            ofile.write("project('{}')".format(name))
        return path

    def dist_impl(self, vcs_init, include_subprojects=True):
        # Create this on the fly because having rogue .git directories inside
        # the source tree leads to all kinds of trouble.
        with tempfile.TemporaryDirectory() as project_dir:
            with open(os.path.join(project_dir, 'meson.build'), 'w') as ofile:
                ofile.write('''project('disttest', 'c', version : '1.4.3')
e = executable('distexe', 'distexe.c')
test('dist test', e)
subproject('vcssub', required : false)
subproject('tarballsub', required : false)
''')
            with open(os.path.join(project_dir, 'distexe.c'), 'w') as ofile:
                ofile.write('''#include

int main(int argc, char **argv) {
    printf("I am a distribution test.\\n");
    return 0;
}
''')
            xz_distfile = os.path.join(self.distdir, 'disttest-1.4.3.tar.xz')
            xz_checksumfile = xz_distfile + '.sha256sum'
            zip_distfile = os.path.join(self.distdir, 'disttest-1.4.3.zip')
            zip_checksumfile = zip_distfile + '.sha256sum'
            vcs_init(project_dir)
            if include_subprojects:
                vcs_init(self.create_dummy_subproject(project_dir, 'vcssub'))
                self.create_dummy_subproject(project_dir, 'tarballsub')
                self.create_dummy_subproject(project_dir, 'unusedsub')
            self.init(project_dir)
            self.build('dist')
            self.assertPathExists(xz_distfile)
            self.assertPathExists(xz_checksumfile)
            self.assertPathDoesNotExist(zip_distfile)
            self.assertPathDoesNotExist(zip_checksumfile)
            self._run(self.meson_command + ['dist', '--formats', 'zip'],
                      workdir=self.builddir)
            self.assertPathExists(zip_distfile)
            self.assertPathExists(zip_checksumfile)

            if include_subprojects:
                z = zipfile.ZipFile(zip_distfile)
                self.assertEqual(sorted(['disttest-1.4.3/',
                                         'disttest-1.4.3/meson.build',
                                         'disttest-1.4.3/distexe.c']),
                                 sorted(z.namelist()))

                self._run(self.meson_command + ['dist', '--formats', 'zip', '--include-subprojects'],
                          workdir=self.builddir)
                z = zipfile.ZipFile(zip_distfile)
                self.assertEqual(sorted(['disttest-1.4.3/',
                                         'disttest-1.4.3/subprojects/',
                                         'disttest-1.4.3/meson.build',
                                         'disttest-1.4.3/distexe.c',
                                         'disttest-1.4.3/subprojects/tarballsub/',
                                         'disttest-1.4.3/subprojects/vcssub/',
                                         'disttest-1.4.3/subprojects/tarballsub/meson.build',
                                         'disttest-1.4.3/subprojects/vcssub/meson.build']),
                                 sorted(z.namelist()))

    def test_rpath_uses_ORIGIN(self):
        '''
        Test that built targets use $ORIGIN in rpath, which ensures that they
        are relocatable and ensures that builds are reproducible since the
        build directory won't get embedded into the built binaries.
        '''
        if is_windows() or is_cygwin():
            raise unittest.SkipTest('Windows PE/COFF binaries do not use RPATH')
        testdir = os.path.join(self.common_test_dir, '42 library chain')
        self.init(testdir)
        self.build()
        for each in ('prog', 'subdir/liblib1.so', ):
            rpath = get_rpath(os.path.join(self.builddir, each))
            self.assertTrue(rpath, 'Rpath could not be determined for {}.'.format(each))
            if is_dragonflybsd():
                # DragonflyBSD will prepend /usr/lib/gccVERSION to the rpath,
                # so ignore that.
                self.assertTrue(rpath.startswith('/usr/lib/gcc'))
                rpaths = rpath.split(':')[1:]
            else:
                rpaths = rpath.split(':')
            for path in rpaths:
                self.assertTrue(path.startswith('$ORIGIN'), msg=(each, path))
        # These two don't link to anything else, so they do not need an rpath entry.
        for each in ('subdir/subdir2/liblib2.so', 'subdir/subdir3/liblib3.so'):
            rpath = get_rpath(os.path.join(self.builddir, each))
            if is_dragonflybsd():
                # The rpath should be equal to /usr/lib/gccVERSION
                self.assertTrue(rpath.startswith('/usr/lib/gcc'))
                self.assertEqual(len(rpath.split(':')), 1)
            else:
                self.assertTrue(rpath is None)

    def test_dash_d_dedup(self):
        testdir = os.path.join(self.unit_test_dir, '9 d dedup')
        self.init(testdir)
        cmd = self.get_compdb()[0]['command']
        self.assertTrue('-D FOO -D BAR' in cmd or
                        '"-D" "FOO" "-D" "BAR"' in cmd or
                        '/D FOO /D BAR' in cmd or
                        '"/D" "FOO" "/D" "BAR"' in cmd)

    def test_all_forbidden_targets_tested(self):
        '''
        Test that all forbidden targets are tested in the '154 reserved targets'
        test. Needs to be a unit test because it accesses Meson internals.
        '''
        testdir = os.path.join(self.common_test_dir, '154 reserved targets')
        targets = mesonbuild.coredata.forbidden_target_names
        # We don't actually define a target with this name
        targets.pop('build.ninja')
        # Remove this to avoid multiple entries with the same name
        # but different case.
        targets.pop('PHONY')
        for i in targets:
            self.assertPathExists(os.path.join(testdir, i))

    def detect_prebuild_env(self):
        env = get_fake_env()
        cc = env.detect_c_compiler(MachineChoice.HOST)
        stlinker = env.detect_static_linker(cc)
        if mesonbuild.mesonlib.is_windows():
            object_suffix = 'obj'
            shared_suffix = 'dll'
        elif mesonbuild.mesonlib.is_cygwin():
            object_suffix = 'o'
            shared_suffix = 'dll'
        elif mesonbuild.mesonlib.is_osx():
            object_suffix = 'o'
            shared_suffix = 'dylib'
        else:
            object_suffix = 'o'
            shared_suffix = 'so'
        return (cc, stlinker, object_suffix, shared_suffix)

    def pbcompile(self, compiler, source, objectfile, extra_args=None):
        cmd = compiler.get_exelist()
        extra_args = extra_args or []
        if compiler.get_argument_syntax() == 'msvc':
            cmd += ['/nologo', '/Fo' + objectfile, '/c', source] + extra_args
        else:
            cmd += ['-c', source, '-o', objectfile] + extra_args
        subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

    def test_prebuilt_object(self):
        (compiler, _, object_suffix, _) = self.detect_prebuild_env()
        tdir = os.path.join(self.unit_test_dir, '15 prebuilt object')
        source = os.path.join(tdir, 'source.c')
        objectfile = os.path.join(tdir, 'prebuilt.' + object_suffix)
        self.pbcompile(compiler, source, objectfile)
        try:
            self.init(tdir)
            self.build()
            self.run_tests()
        finally:
            os.unlink(objectfile)

    def build_static_lib(self, compiler, linker, source, objectfile, outfile, extra_args=None):
        if extra_args is None:
            extra_args = []
        if compiler.get_argument_syntax() == 'msvc':
            link_cmd = ['lib', '/NOLOGO', '/OUT:' + outfile, objectfile]
        else:
            link_cmd = ['ar', 'csr', outfile, objectfile]
        link_cmd = linker.get_exelist()
        link_cmd += linker.get_always_args()
        link_cmd += linker.get_std_link_args()
        link_cmd += linker.get_output_args(outfile)
        link_cmd += [objectfile]
        self.pbcompile(compiler, source, objectfile, extra_args=extra_args)
        try:
            subprocess.check_call(link_cmd)
        finally:
            os.unlink(objectfile)

    def test_prebuilt_static_lib(self):
        (cc, stlinker, object_suffix, _) = self.detect_prebuild_env()
        tdir = os.path.join(self.unit_test_dir, '16 prebuilt static')
        source = os.path.join(tdir, 'libdir/best.c')
        objectfile = os.path.join(tdir, 'libdir/best.' + object_suffix)
        stlibfile = os.path.join(tdir, 'libdir/libbest.a')
        self.build_static_lib(cc, stlinker, source, objectfile, stlibfile)
        # Run the test
        try:
            self.init(tdir)
            self.build()
            self.run_tests()
        finally:
            os.unlink(stlibfile)

    def build_shared_lib(self, compiler, source, objectfile, outfile, impfile, extra_args=None):
        if extra_args is None:
            extra_args = []
        if compiler.get_argument_syntax() == 'msvc':
            link_cmd = compiler.get_linker_exelist() + [
                '/NOLOGO', '/DLL', '/DEBUG', '/IMPLIB:' + impfile,
                '/OUT:' + outfile, objectfile]
        else:
            if not (compiler.info.is_windows() or compiler.info.is_cygwin() or compiler.info.is_darwin()):
                extra_args += ['-fPIC']
            link_cmd = compiler.get_exelist() + ['-shared', '-o', outfile, objectfile]
            if not mesonbuild.mesonlib.is_osx():
                link_cmd += ['-Wl,-soname=' + os.path.basename(outfile)]
        self.pbcompile(compiler, source, objectfile, extra_args=extra_args)
        try:
            subprocess.check_call(link_cmd)
        finally:
            os.unlink(objectfile)

    def test_prebuilt_shared_lib(self):
        (cc, _, object_suffix, shared_suffix) = self.detect_prebuild_env()
        tdir = os.path.join(self.unit_test_dir, '17 prebuilt shared')
        source = os.path.join(tdir, 'alexandria.c')
        objectfile = os.path.join(tdir, 'alexandria.' + object_suffix)
        impfile = os.path.join(tdir, 'alexandria.lib')
        if cc.get_argument_syntax() == 'msvc':
            shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix)
        elif is_cygwin():
            shlibfile = os.path.join(tdir, 'cygalexandria.' + shared_suffix)
        else:
            shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix)
        self.build_shared_lib(cc, source, objectfile, shlibfile, impfile)
        # Run the test
        try:
            self.init(tdir)
            self.build()
            self.run_tests()
        finally:
            os.unlink(shlibfile)
            if mesonbuild.mesonlib.is_windows():
                # Clean up all the garbage MSVC writes in the
                # source tree.
                for fname in glob(os.path.join(tdir, 'alexandria.*')):
                    if os.path.splitext(fname)[1] not in ['.c', '.h']:
                        os.unlink(fname)

    @skipIfNoPkgconfig
    def test_pkgconfig_static(self):
        '''
        Test that the we prefer static libraries when `static: true` is
        passed to dependency() with pkg-config. Can't be an ordinary test
        because we need to build libs and try to find them from meson.build

        Also test that it's not a hard error to have unsatisfiable library deps
        since system libraries -lm will never be found statically.
        https://github.com/mesonbuild/meson/issues/2785
        '''
        (cc, stlinker, objext, shext) = self.detect_prebuild_env()
        testdir = os.path.join(self.unit_test_dir, '18 pkgconfig static')
        source = os.path.join(testdir, 'foo.c')
        objectfile = os.path.join(testdir, 'foo.' + objext)
        stlibfile = os.path.join(testdir, 'libfoo.a')
        impfile = os.path.join(testdir, 'foo.lib')
        if cc.get_argument_syntax() == 'msvc':
            shlibfile = os.path.join(testdir, 'foo.' + shext)
        elif is_cygwin():
            shlibfile = os.path.join(testdir, 'cygfoo.' + shext)
        else:
            shlibfile = os.path.join(testdir, 'libfoo.' + shext)
        # Build libs
        self.build_static_lib(cc, stlinker, source, objectfile, stlibfile, extra_args=['-DFOO_STATIC'])
        self.build_shared_lib(cc, source, objectfile, shlibfile, impfile)
        # Run test
        try:
            self.init(testdir, override_envvars={'PKG_CONFIG_LIBDIR': self.builddir})
            self.build()
            self.run_tests()
        finally:
            os.unlink(stlibfile)
            os.unlink(shlibfile)
            if mesonbuild.mesonlib.is_windows():
                # Clean up all the garbage MSVC writes in the
                # source tree.
                for fname in glob(os.path.join(testdir, 'foo.*')):
                    if os.path.splitext(fname)[1] not in ['.c', '.h', '.in']:
                        os.unlink(fname)

    @skipIfNoPkgconfig
    def test_pkgconfig_gen_escaping(self):
        testdir = os.path.join(self.common_test_dir, '47 pkgconfig-gen')
        prefix = '/usr/with spaces'
        libdir = 'lib'
        self.init(testdir, extra_args=['--prefix=' + prefix,
                                       '--libdir=' + libdir])
        # Find foo dependency
        os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
        env = get_fake_env(testdir, self.builddir, self.prefix)
        kwargs = {'required': True, 'silent': True}
        foo_dep = PkgConfigDependency('libfoo', env, kwargs)
        # Ensure link_args are properly quoted
        libdir = PurePath(prefix) / PurePath(libdir)
        link_args = ['-L' + libdir.as_posix(), '-lfoo']
        self.assertEqual(foo_dep.get_link_args(), link_args)
        # Ensure include args are properly quoted
        incdir = PurePath(prefix) / PurePath('include')
        cargs = ['-I' + incdir.as_posix()]
        self.assertEqual(foo_dep.get_compile_args(), cargs)

    def test_array_option_change(self):
        def get_opt():
            opts = self.introspect('--buildoptions')
            for x in opts:
                if x.get('name') == 'list':
                    return x
            raise Exception(opts)

        expected = {
            'name': 'list',
            'description': 'list',
            'section': 'user',
            'type': 'array',
            'value': ['foo', 'bar'],
            'machine': 'any',
        }
        tdir = os.path.join(self.unit_test_dir, '19 array option')
        self.init(tdir)
        original = get_opt()
        self.assertDictEqual(original, expected)

        expected['value'] = ['oink', 'boink']
        self.setconf('-Dlist=oink,boink')
        changed = get_opt()
        self.assertEqual(changed, expected)

    def test_array_option_bad_change(self):
        def get_opt():
            opts = self.introspect('--buildoptions')
            for x in opts:
                if x.get('name') == 'list':
                    return x
            raise Exception(opts)

        expected = {
            'name': 'list',
            'description': 'list',
            'section': 'user',
            'type': 'array',
            'value': ['foo', 'bar'],
            'machine': 'any',
        }
        tdir = os.path.join(self.unit_test_dir, '19 array option')
        self.init(tdir)
        original = get_opt()
        self.assertDictEqual(original, expected)
        with self.assertRaises(subprocess.CalledProcessError):
            self.setconf('-Dlist=bad')
        changed = get_opt()
        self.assertDictEqual(changed, expected)

    def test_array_option_empty_equivalents(self):
        """Array options treat -Dopt=[] and -Dopt= as equivalent."""
        def get_opt():
            opts = self.introspect('--buildoptions')
            for x in opts:
                if x.get('name') == 'list':
                    return x
            raise Exception(opts)

        expected = {
            'name': 'list',
            'description': 'list',
            'section': 'user',
            'type': 'array',
            'value': [],
            'machine': 'any',
        }
        tdir = os.path.join(self.unit_test_dir, '19 array option')
        self.init(tdir, extra_args='-Dlist=')
        original = get_opt()
        self.assertDictEqual(original, expected)

    def opt_has(self, name, value):
        res = self.introspect('--buildoptions')
        found = False
        for i in res:
            if i['name'] == name:
                self.assertEqual(i['value'], value)
                found = True
                break
        self.assertTrue(found, "Array option not found in introspect data.")

    def test_free_stringarray_setting(self):
        testdir = os.path.join(self.common_test_dir, '43 options')
        self.init(testdir)
        self.opt_has('free_array_opt', [])
        self.setconf('-Dfree_array_opt=foo,bar', will_build=False)
        self.opt_has('free_array_opt', ['foo', 'bar'])
        self.setconf("-Dfree_array_opt=['a,b', 'c,d']", will_build=False)
        self.opt_has('free_array_opt', ['a,b', 'c,d'])

    def test_subproject_promotion(self):
        testdir = os.path.join(self.unit_test_dir, '12 promote')
        workdir = os.path.join(self.builddir, 'work')
        shutil.copytree(testdir, workdir)
        spdir = os.path.join(workdir, 'subprojects')
        s3dir = os.path.join(spdir, 's3')
        scommondir = os.path.join(spdir, 'scommon')
        self.assertFalse(os.path.isdir(s3dir))
        subprocess.check_call(self.wrap_command + ['promote', 's3'], cwd=workdir)
        self.assertTrue(os.path.isdir(s3dir))
        self.assertFalse(os.path.isdir(scommondir))
        self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'scommon'],
                                            cwd=workdir,
                                            stdout=subprocess.DEVNULL), 0)
        self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'invalid/path/to/scommon'],
                                            cwd=workdir,
                                            stderr=subprocess.DEVNULL), 0)
        self.assertFalse(os.path.isdir(scommondir))
        subprocess.check_call(self.wrap_command + ['promote', 'subprojects/s2/subprojects/scommon'], cwd=workdir)
        self.assertTrue(os.path.isdir(scommondir))
        promoted_wrap = os.path.join(spdir, 'athing.wrap')
        self.assertFalse(os.path.isfile(promoted_wrap))
        subprocess.check_call(self.wrap_command + ['promote', 'athing'], cwd=workdir)
        self.assertTrue(os.path.isfile(promoted_wrap))
        self.init(workdir)
        self.build()

    def test_subproject_promotion_wrap(self):
        testdir = os.path.join(self.unit_test_dir, '44 promote wrap')
        workdir = os.path.join(self.builddir, 'work')
        shutil.copytree(testdir, workdir)
        spdir = os.path.join(workdir, 'subprojects')

        ambiguous_wrap = os.path.join(spdir, 'ambiguous.wrap')
        self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'ambiguous'],
                                            cwd=workdir,
                                            stdout=subprocess.DEVNULL), 0)
        self.assertFalse(os.path.isfile(ambiguous_wrap))
        subprocess.check_call(self.wrap_command + ['promote', 'subprojects/s2/subprojects/ambiguous.wrap'], cwd=workdir)
        self.assertTrue(os.path.isfile(ambiguous_wrap))

    def test_warning_location(self):
        tdir = os.path.join(self.unit_test_dir, '22 warning location')
        out = self.init(tdir)
        for expected in [
            r'meson.build:4: WARNING: Keyword argument "link_with" defined multiple times.',
            r'sub' + os.path.sep + r'meson.build:3: WARNING: Keyword argument "link_with" defined multiple times.',
            r'meson.build:6: WARNING: a warning of some sort',
            r'sub' + os.path.sep + r'meson.build:4: WARNING: subdir warning',
            r'meson.build:7: WARNING: Module unstable-simd has no backwards or forwards compatibility and might not exist in future releases.',
            r"meson.build:11: WARNING: The variable(s) 'MISSING' in the input file 'conf.in' are not present in the given configuration data.",
            r'meson.build:1: WARNING: Passed invalid keyword argument "invalid".',
        ]:
            self.assertRegex(out, re.escape(expected))

    def test_permitted_method_kwargs(self):
        tdir = os.path.join(self.unit_test_dir, '25 non-permitted kwargs')
        out = self.init(tdir)
        for expected in [
            r'WARNING: Passed invalid keyword argument "prefixxx".',
            r'WARNING: Passed invalid keyword argument "argsxx".',
            r'WARNING: Passed invalid keyword argument "invalidxx".',
        ]:
            self.assertRegex(out, re.escape(expected))

    def test_templates(self):
        ninja = detect_ninja()
        if ninja is None:
            raise unittest.SkipTest('This test currently requires ninja. Fix this once "meson build" works.')
        langs = ['c']
        env = get_fake_env()
        try:
            env.detect_cpp_compiler(MachineChoice.HOST)
            langs.append('cpp')
        except EnvironmentException:
            pass
        try:
            env.detect_d_compiler(MachineChoice.HOST)
            langs.append('d')
        except EnvironmentException:
            pass
        try:
            env.detect_fortran_compiler(MachineChoice.HOST)
            if is_windows() or platform.machine().lower() != 'e2k':
                # Elbrus Fortran compiler can't generate debug information
                langs.append('fortran')
        except EnvironmentException:
            pass
        try:
            env.detect_objc_compiler(MachineChoice.HOST)
            langs.append('objc')
        except EnvironmentException:
            pass
        # FIXME: omitting rust as Windows AppVeyor CI finds Rust but doesn't link correctly

        for lang in langs:
            for target_type in ('executable', 'library'):
                # test empty directory
                with tempfile.TemporaryDirectory() as tmpdir:
                    self._run(self.meson_command + ['init', '--language', lang, '--type', target_type],
                              workdir=tmpdir)
                    self._run(self.setup_command + ['--backend=ninja', 'builddir'],
                              workdir=tmpdir)
                    self._run(ninja,
                              workdir=os.path.join(tmpdir, 'builddir'))
            # test directory with existing code file
            if lang in ('c', 'cpp'):
                with tempfile.TemporaryDirectory() as tmpdir:
                    with open(os.path.join(tmpdir, 'foo.' + lang), 'w') as f:
                        f.write('int main(void) {}')
                    self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)

    # The test uses mocking and thus requires that
    # the current process is the one to run the Meson steps.
    # If we are using an external test executable (most commonly
    # in Debian autopkgtests) then the mocking won't work.
    @unittest.skipIf('MESON_EXE' in os.environ, 'MESON_EXE is defined, can not use mocking.')
    def test_cross_file_system_paths(self):
        if is_windows():
            raise unittest.SkipTest('system crossfile paths not defined for Windows (yet)')
        if is_sunos():
            cc = 'gcc'
        else:
            cc = 'cc'

        testdir = os.path.join(self.common_test_dir, '1 trivial')
        cross_content = textwrap.dedent("""\
            [binaries]
            c = '/usr/bin/{}'
            ar = '/usr/bin/ar'
            strip = '/usr/bin/ar'

            [properties]

            [host_machine]
            system = 'linux'
            cpu_family = 'x86'
            cpu = 'i686'
            endian = 'little'
            """.format(cc))

        with tempfile.TemporaryDirectory() as d:
            dir_ = os.path.join(d, 'meson', 'cross')
            os.makedirs(dir_)
            with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f:
                f.write(cross_content)
            name = os.path.basename(f.name)

            with mock.patch.dict(os.environ, {'XDG_DATA_HOME': d}):
                self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
                self.wipe()

            with mock.patch.dict(os.environ, {'XDG_DATA_DIRS': d}):
                os.environ.pop('XDG_DATA_HOME', None)
                self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
                self.wipe()

        with tempfile.TemporaryDirectory() as d:
            dir_ = os.path.join(d, '.local', 'share', 'meson', 'cross')
            os.makedirs(dir_)
            with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f:
                f.write(cross_content)
            name = os.path.basename(f.name)

            # If XDG_DATA_HOME is set in the environment running the
            # tests this test will fail, os mock the environment, pop
            # it, then test
            with mock.patch.dict(os.environ):
                os.environ.pop('XDG_DATA_HOME', None)
                with mock.patch('mesonbuild.coredata.os.path.expanduser', lambda x: x.replace('~', d)):
                    self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
                    self.wipe()

    def test_compiler_run_command(self):
        '''
        The test checks that the compiler object can be passed to
        run_command().
        '''
        testdir = os.path.join(self.unit_test_dir, '24 compiler run_command')
        self.init(testdir)

    def test_identical_target_name_in_subproject_flat_layout(self):
        '''
        Test that identical targets in different subprojects do not collide
        if layout is flat.
        '''
        testdir = os.path.join(self.common_test_dir, '177 identical target name in subproject flat layout')
        self.init(testdir, extra_args=['--layout=flat'])
        self.build()

    def test_identical_target_name_in_subdir_flat_layout(self):
        '''
        Test that identical targets in different subdirs do not collide
        if layout is flat.
        '''
        testdir = os.path.join(self.common_test_dir, '186 same target name flat layout')
        self.init(testdir, extra_args=['--layout=flat'])
        self.build()

    def test_flock(self):
        exception_raised = False
        with tempfile.TemporaryDirectory() as tdir:
            os.mkdir(os.path.join(tdir, 'meson-private'))
            with BuildDirLock(tdir):
                try:
                    with BuildDirLock(tdir):
                        pass
                except MesonException:
                    exception_raised = True
        self.assertTrue(exception_raised, 'Double locking did not raise exception.')

    @unittest.skipIf(is_osx(), 'Test not applicable to OSX')
    def test_check_module_linking(self):
        """
        Test that link_with: a shared module issues a warning
        https://github.com/mesonbuild/meson/issues/2865
        (That an error is raised on OSX is exercised by test failing/78)
        """
        tdir = os.path.join(self.unit_test_dir, '30 shared_mod linking')
        out = self.init(tdir)
        msg = ('''WARNING: target links against shared modules. This is not
recommended as it is not supported on some platforms''')
        self.assertIn(msg, out)

    def test_ndebug_if_release_disabled(self):
        testdir = os.path.join(self.unit_test_dir, '28 ndebug if-release')
        self.init(testdir, extra_args=['--buildtype=release', '-Db_ndebug=if-release'])
        self.build()
        exe = os.path.join(self.builddir, 'main')
        self.assertEqual(b'NDEBUG=1', subprocess.check_output(exe).strip())

    def test_ndebug_if_release_enabled(self):
        testdir = os.path.join(self.unit_test_dir, '28 ndebug if-release')
        self.init(testdir, extra_args=['--buildtype=debugoptimized', '-Db_ndebug=if-release'])
        self.build()
        exe = os.path.join(self.builddir, 'main')
        self.assertEqual(b'NDEBUG=0', subprocess.check_output(exe).strip())

    def test_guessed_linker_dependencies(self):
        '''
        Test that meson adds dependencies for libraries based on the final
        linker command line.
        '''
        testdirbase = os.path.join(self.unit_test_dir, '29 guessed linker dependencies')
        testdirlib = os.path.join(testdirbase, 'lib')

        extra_args = None
        libdir_flags = ['-L']
        env = get_fake_env(testdirlib, self.builddir, self.prefix)
        if env.detect_c_compiler(MachineChoice.HOST).get_id() in {'msvc', 'clang-cl', 'intel-cl'}:
            # msvc-like compiler, also test it with msvc-specific flags
            libdir_flags += ['/LIBPATH:', '-LIBPATH:']
        else:
            # static libraries are not linkable with -l with msvc because meson installs them
            # as .a files which unix_args_to_native will not know as it expects libraries to use
            # .lib as extension. For a DLL the import library is installed as .lib. Thus for msvc
            # this tests needs to use shared libraries to test the path resolving logic in the
            # dependency generation code path.
            extra_args = ['--default-library', 'static']

        initial_builddir = self.builddir
        initial_installdir = self.installdir

        for libdir_flag in libdir_flags:
            # build library
            self.new_builddir()
            self.init(testdirlib, extra_args=extra_args)
            self.build()
            self.install()
            libbuilddir = self.builddir
            installdir = self.installdir
            libdir = os.path.join(self.installdir, self.prefix.lstrip('/').lstrip('\\'), 'lib')

            # build user of library
            self.new_builddir()
            # replace is needed because meson mangles platform paths passed via LDFLAGS
            self.init(os.path.join(testdirbase, 'exe'),
                      override_envvars={"LDFLAGS": '{}{}'.format(libdir_flag, libdir.replace('\\', '/'))})
            self.build()
            self.assertBuildIsNoop()

            # rebuild library
            exebuilddir = self.builddir
            self.installdir = installdir
            self.builddir = libbuilddir
            # Microsoft's compiler is quite smart about touching import libs on changes,
            # so ensure that there is actually a change in symbols.
            self.setconf('-Dmore_exports=true')
            self.build()
            self.install()
            # no ensure_backend_detects_changes needed because self.setconf did that already

            # assert user of library will be rebuild
            self.builddir = exebuilddir
            self.assertRebuiltTarget('app')

            # restore dirs for the next test case
            self.installdir = initial_builddir
            self.builddir = initial_installdir

    def test_conflicting_d_dash_option(self):
        testdir = os.path.join(self.unit_test_dir, '37 mixed command line args')
        with self.assertRaises(subprocess.CalledProcessError) as e:
            self.init(testdir, extra_args=['-Dbindir=foo', '--bindir=bar'])
            # Just to ensure that we caught the correct error
            self.assertIn('passed as both', e.stderr)

    def _test_same_option_twice(self, arg, args):
        testdir = os.path.join(self.unit_test_dir, '37 mixed command line args')
        self.init(testdir, extra_args=args)
        opts = self.introspect('--buildoptions')
        for item in opts:
            if item['name'] == arg:
                self.assertEqual(item['value'], 'bar')
                return
        raise Exception('Missing {} value?'.format(arg))

    def test_same_dash_option_twice(self):
        self._test_same_option_twice('bindir', ['--bindir=foo', '--bindir=bar'])

    def test_same_d_option_twice(self):
        self._test_same_option_twice('bindir', ['-Dbindir=foo', '-Dbindir=bar'])

    def test_same_project_d_option_twice(self):
        self._test_same_option_twice('one', ['-Done=foo', '-Done=bar'])

    def _test_same_option_twice_configure(self, arg, args):
        testdir = os.path.join(self.unit_test_dir, '37 mixed command line args')
        self.init(testdir)
        self.setconf(args)
        opts = self.introspect('--buildoptions')
        for item in opts:
            if item['name'] == arg:
                self.assertEqual(item['value'], 'bar')
                return
        raise Exception('Missing {} value?'.format(arg))

    def test_same_dash_option_twice_configure(self):
        self._test_same_option_twice_configure(
            'bindir', ['--bindir=foo', '--bindir=bar'])

    def test_same_d_option_twice_configure(self):
        self._test_same_option_twice_configure(
            'bindir', ['-Dbindir=foo', '-Dbindir=bar'])

    def test_same_project_d_option_twice_configure(self):
        self._test_same_option_twice_configure(
            'one', ['-Done=foo', '-Done=bar'])

    def test_command_line(self):
        testdir = os.path.join(self.unit_test_dir, '34 command line')

        # Verify default values when passing no args
        self.init(testdir)
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['default_library'].value, 'static')
        self.assertEqual(obj.builtins['warning_level'].value, '1')
        self.assertEqual(obj.user_options['set_sub_opt'].value, True)
        self.assertEqual(obj.user_options['subp:subp_opt'].value, 'default3')
        self.wipe()

        # warning_level is special, it's --warnlevel instead of --warning-level
        # for historical reasons
        self.init(testdir, extra_args=['--warnlevel=2'])
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '2')
        self.setconf('--warnlevel=3')
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '3')
        self.wipe()

        # But when using -D syntax, it should be 'warning_level'
        self.init(testdir, extra_args=['-Dwarning_level=2'])
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '2')
        self.setconf('-Dwarning_level=3')
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '3')
        self.wipe()

        # Mixing --option and -Doption is forbidden
        with self.assertRaises(subprocess.CalledProcessError) as cm:
            self.init(testdir, extra_args=['--warnlevel=1', '-Dwarning_level=3'])
        self.assertNotEqual(0, cm.exception.returncode)
        self.assertIn('as both', cm.exception.output)
        self.init(testdir)
        with self.assertRaises(subprocess.CalledProcessError) as cm:
            self.setconf(['--warnlevel=1', '-Dwarning_level=3'])
        self.assertNotEqual(0, cm.exception.returncode)
        self.assertIn('as both', cm.exception.output)
        self.wipe()

        # --default-library should override default value from project()
        self.init(testdir, extra_args=['--default-library=both'])
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['default_library'].value, 'both')
        self.setconf('--default-library=shared')
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['default_library'].value, 'shared')
        if self.backend is Backend.ninja:
            # reconfigure target works only with ninja backend
            self.build('reconfigure')
            obj = mesonbuild.coredata.load(self.builddir)
            self.assertEqual(obj.builtins['default_library'].value, 'shared')
        self.wipe()

        # Should warn on unknown options
        out = self.init(testdir, extra_args=['-Dbad=1', '-Dfoo=2', '-Dwrong_link_args=foo'])
        self.assertIn('Unknown options: "bad, foo, wrong_link_args"', out)
        self.wipe()

        # Should fail on malformed option
        with self.assertRaises(subprocess.CalledProcessError) as cm:
            self.init(testdir, extra_args=['-Dfoo'])
        self.assertNotEqual(0, cm.exception.returncode)
        self.assertIn('Option \'foo\' must have a value separated by equals sign.', cm.exception.output)
        self.init(testdir)
        with self.assertRaises(subprocess.CalledProcessError) as cm:
            self.setconf('-Dfoo')
        self.assertNotEqual(0, cm.exception.returncode)
        self.assertIn('Option \'foo\' must have a value separated by equals sign.', cm.exception.output)
        self.wipe()

        # It is not an error to set wrong option for unknown subprojects or
        # language because we don't have control on which one will be selected.
        self.init(testdir, extra_args=['-Dc_wrong=1', '-Dwrong:bad=1', '-Db_wrong=1'])
        self.wipe()

        # Test we can set subproject option
        self.init(testdir, extra_args=['-Dsubp:subp_opt=foo'])
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.user_options['subp:subp_opt'].value, 'foo')
        self.wipe()

        # c_args value should be parsed with split_args
        self.init(testdir, extra_args=['-Dc_args=-Dfoo -Dbar "-Dthird=one two"'])
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.compiler_options.host['c_args'].value, ['-Dfoo', '-Dbar', '-Dthird=one two'])

        self.setconf('-Dc_args="foo bar" one two')
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.compiler_options.host['c_args'].value, ['foo bar', 'one', 'two'])
        self.wipe()

        self.init(testdir, extra_args=['-Dset_percent_opt=myoption%'])
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.user_options['set_percent_opt'].value, 'myoption%')
        self.wipe()

        # Setting a 2nd time the same option should override the first value
        try:
            self.init(testdir, extra_args=['--bindir=foo', '--bindir=bar',
                                           '-Dbuildtype=plain', '-Dbuildtype=release',
                                           '-Db_sanitize=address', '-Db_sanitize=thread',
                                           '-Dc_args=-Dfoo', '-Dc_args=-Dbar'])
            obj = mesonbuild.coredata.load(self.builddir)
            self.assertEqual(obj.builtins['bindir'].value, 'bar')
            self.assertEqual(obj.builtins['buildtype'].value, 'release')
            self.assertEqual(obj.base_options['b_sanitize'].value, 'thread')
            self.assertEqual(obj.compiler_options.host['c_args'].value, ['-Dbar'])
            self.setconf(['--bindir=bar', '--bindir=foo',
                          '-Dbuildtype=release', '-Dbuildtype=plain',
                          '-Db_sanitize=thread', '-Db_sanitize=address',
                          '-Dc_args=-Dbar', '-Dc_args=-Dfoo'])
            obj = mesonbuild.coredata.load(self.builddir)
            self.assertEqual(obj.builtins['bindir'].value, 'foo')
            self.assertEqual(obj.builtins['buildtype'].value, 'plain')
            self.assertEqual(obj.base_options['b_sanitize'].value, 'address')
            self.assertEqual(obj.compiler_options.host['c_args'].value, ['-Dfoo'])
            self.wipe()
        except KeyError:
            # Ignore KeyError, it happens on CI for compilers that does not
            # support b_sanitize. We have to test with a base option because
            # they used to fail this test with Meson 0.46 an earlier versions.
            pass

    def test_warning_level_0(self):
        testdir = os.path.join(self.common_test_dir, '214 warning level 0')

        # Verify default values when passing no args
        self.init(testdir)
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '0')
        self.wipe()

        # verify we can override w/ --warnlevel
        self.init(testdir, extra_args=['--warnlevel=1'])
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '1')
        self.setconf('--warnlevel=0')
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '0')
        self.wipe()

        # verify we can override w/ -Dwarning_level
        self.init(testdir, extra_args=['-Dwarning_level=1'])
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '1')
        self.setconf('-Dwarning_level=0')
        obj = mesonbuild.coredata.load(self.builddir)
        self.assertEqual(obj.builtins['warning_level'].value, '0')
        self.wipe()

    def test_feature_check_usage_subprojects(self):
        testdir = os.path.join(self.unit_test_dir, '41 featurenew subprojects')
        out = self.init(testdir)
        # Parent project warns correctly
        self.assertRegex(out, "WARNING: Project targeting '>=0.45'.*'0.47.0': dict")
        # Subprojects warn correctly
        self.assertRegex(out, r"\|WARNING: Project targeting '>=0.40'.*'0.44.0': disabler")
        self.assertRegex(out, r"\|WARNING: Project targeting '!=0.40'.*'0.44.0': disabler")
        # Subproject has a new-enough meson_version, no warning
        self.assertNotRegex(out, "WARNING: Project targeting.*Python")
        # Ensure a summary is printed in the subproject and the outer project
        self.assertRegex(out, r"\|WARNING: Project specifies a minimum meson_version '>=0.40'")
        self.assertRegex(out, r"\| \* 0.44.0: {'disabler'}")
        self.assertRegex(out, "WARNING: Project specifies a minimum meson_version '>=0.45'")
        self.assertRegex(out, " * 0.47.0: {'dict'}")

    def test_configure_file_warnings(self):
        testdir = os.path.join(self.common_test_dir, "14 configure file")
        out = self.init(testdir)
        self.assertRegex(out, "WARNING:.*'empty'.*config.h.in.*not present.*")
        self.assertRegex(out, "WARNING:.*'FOO_BAR'.*nosubst-nocopy2.txt.in.*not present.*")
        self.assertRegex(out, "WARNING:.*'empty'.*config.h.in.*not present.*")
        self.assertRegex(out, "WARNING:.*empty configuration_data.*test.py.in")
        # Warnings for configuration files that are overwritten.
        self.assertRegex(out, "WARNING:.*\"double_output.txt\".*overwrites")
        self.assertRegex(out, "WARNING:.*\"subdir.double_output2.txt\".*overwrites")
        self.assertNotRegex(out, "WARNING:.*no_write_conflict.txt.*overwrites")
        self.assertNotRegex(out, "WARNING:.*@BASENAME@.*overwrites")
        self.assertRegex(out, "WARNING:.*\"sameafterbasename\".*overwrites")
        # No warnings about empty configuration data objects passed to files with substitutions
        self.assertNotRegex(out, "WARNING:.*empty configuration_data.*nosubst-nocopy1.txt.in")
        self.assertNotRegex(out, "WARNING:.*empty configuration_data.*nosubst-nocopy2.txt.in")
        with open(os.path.join(self.builddir, 'nosubst-nocopy1.txt'), 'rb') as f:
            self.assertEqual(f.read().strip(), b'/* #undef FOO_BAR */')
        with open(os.path.join(self.builddir, 'nosubst-nocopy2.txt'), 'rb') as f:
            self.assertEqual(f.read().strip(), b'')
        self.assertRegex(out, r"DEPRECATION:.*\['array'\] is invalid.*dict")

    def test_dirs(self):
        with tempfile.TemporaryDirectory() as containing:
            with tempfile.TemporaryDirectory(dir=containing) as srcdir:
                mfile = os.path.join(srcdir, 'meson.build')
                of = open(mfile, 'w')
                of.write("project('foobar', 'c')\n")
                of.close()
                pc = subprocess.run(self.setup_command,
                                    cwd=srcdir,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.DEVNULL)
                self.assertIn(b'Must specify at least one directory name', pc.stdout)
                with tempfile.TemporaryDirectory(dir=srcdir) as builddir:
                    subprocess.run(self.setup_command,
                                   check=True,
                                   cwd=builddir,
                                   stdout=subprocess.DEVNULL,
                                   stderr=subprocess.DEVNULL)

    def get_opts_as_dict(self):
        result = {}
        for i in self.introspect('--buildoptions'):
            result[i['name']] = i['value']
        return result

    def test_buildtype_setting(self):
        testdir = os.path.join(self.common_test_dir, '1 trivial')
        self.init(testdir)
        opts = self.get_opts_as_dict()
        self.assertEqual(opts['buildtype'], 'debug')
        self.assertEqual(opts['debug'], True)
        self.setconf('-Ddebug=false')
        opts = self.get_opts_as_dict()
        self.assertEqual(opts['debug'], False)
        self.assertEqual(opts['buildtype'], 'plain')
        self.assertEqual(opts['optimization'], '0')

        # Setting optimizations to 3 should cause buildtype
        # to go to release mode.
        self.setconf('-Doptimization=3')
        opts = self.get_opts_as_dict()
        self.assertEqual(opts['buildtype'], 'release')
        self.assertEqual(opts['debug'], False)
        self.assertEqual(opts['optimization'], '3')

        # Going to debug build type should reset debugging
        # and optimization
        self.setconf('-Dbuildtype=debug')
        opts = self.get_opts_as_dict()
        self.assertEqual(opts['buildtype'], 'debug')
        self.assertEqual(opts['debug'], True)
        self.assertEqual(opts['optimization'], '0')

    @skipIfNoPkgconfig
    @unittest.skipIf(is_windows(), 'Help needed with fixing this test on windows')
    def test_native_dep_pkgconfig(self):
        testdir = os.path.join(self.unit_test_dir,
                               '46 native dep pkgconfig var')
        with tempfile.NamedTemporaryFile(mode='w', delete=False) as crossfile:
            crossfile.write(textwrap.dedent(
                '''[binaries]
                pkgconfig = r'{0}'

                [properties]

                [host_machine]
                system = 'linux'
                cpu_family = 'arm'
                cpu = 'armv7'
                endian = 'little'
                '''.format(os.path.join(testdir, 'cross_pkgconfig.py'))))
            crossfile.flush()
            self.meson_cross_file = crossfile.name

        env = {'PKG_CONFIG_LIBDIR':  os.path.join(testdir,
                                                  'native_pkgconfig')}
        self.init(testdir, extra_args=['-Dstart_native=false'], override_envvars=env)
        self.wipe()
        self.init(testdir, extra_args=['-Dstart_native=true'], override_envvars=env)

    def __reconfigure(self, change_minor=False):
        # Set an older version to force a reconfigure from scratch
        filename = os.path.join(self.privatedir, 'coredata.dat')
        with open(filename, 'rb') as f:
            obj = pickle.load(f)
        if change_minor:
            v = mesonbuild.coredata.version.split('.')
            obj.version = '.'.join(v[0:2] + [str(int(v[2]) + 1)])
        else:
            obj.version = '0.47.0'
        with open(filename, 'wb') as f:
            pickle.dump(obj, f)

    def test_reconfigure(self):
        testdir = os.path.join(self.unit_test_dir, '48 reconfigure')
        self.init(testdir, extra_args=['-Dopt1=val1'])
        self.setconf('-Dopt2=val2')

        self.__reconfigure()

        out = self.init(testdir, extra_args=['--reconfigure', '-Dopt3=val3'])
        self.assertRegex(out, 'WARNING:.*Regenerating configuration from scratch')
        self.assertRegex(out, 'opt1 val1')
        self.assertRegex(out, 'opt2 val2')
        self.assertRegex(out, 'opt3 val3')
        self.assertRegex(out, 'opt4 default4')
        self.build()
        self.run_tests()

        # Create a file in builddir and verify wipe command removes it
        filename = os.path.join(self.builddir, 'something')
        open(filename, 'w').close()
        self.assertTrue(os.path.exists(filename))
        out = self.init(testdir, extra_args=['--wipe', '-Dopt4=val4'])
        self.assertFalse(os.path.exists(filename))
        self.assertRegex(out, 'opt1 val1')
        self.assertRegex(out, 'opt2 val2')
        self.assertRegex(out, 'opt3 val3')
        self.assertRegex(out, 'opt4 val4')
        self.build()
        self.run_tests()

    def test_wipe_from_builddir(self):
        testdir = os.path.join(self.common_test_dir, '161 custom target subdir depend files')
        self.init(testdir)
        self.__reconfigure()

        with Path(self.builddir):
            self.init(testdir, extra_args=['--wipe'])

    def test_minor_version_does_not_reconfigure_wipe(self):
        testdir = os.path.join(self.unit_test_dir, '48 reconfigure')
        self.init(testdir, extra_args=['-Dopt1=val1'])
        self.setconf('-Dopt2=val2')

        self.__reconfigure(change_minor=True)

        out = self.init(testdir, extra_args=['--reconfigure', '-Dopt3=val3'])
        self.assertNotRegex(out, 'WARNING:.*Regenerating configuration from scratch')
        self.assertRegex(out, 'opt1 val1')
        self.assertRegex(out, 'opt2 val2')
        self.assertRegex(out, 'opt3 val3')
        self.assertRegex(out, 'opt4 default4')
        self.build()
        self.run_tests()

    def test_target_construct_id_from_path(self):
        # This id is stable but not guessable.
        # The test is supposed to prevent unintentional
        # changes of target ID generation.
        target_id = Target.construct_id_from_path('some/obscure/subdir',
                                                  'target-id', '@suffix')
        self.assertEqual('5e002d3@@target-id@suffix', target_id)
        target_id = Target.construct_id_from_path('subproject/foo/subdir/bar',
                                                  'target2-id', '@other')
        self.assertEqual('81d46d1@@target2-id@other', target_id)

    def test_introspect_projectinfo_without_configured_build(self):
        testfile = os.path.join(self.common_test_dir, '35 run program', 'meson.build')
        res = self.introspect_directory(testfile, '--projectinfo')
        self.assertEqual(set(res['buildsystem_files']), set(['meson.build']))
        self.assertEqual(res['version'], 'undefined')
        self.assertEqual(res['descriptive_name'], 'run command')
        self.assertEqual(res['subprojects'], [])

        testfile = os.path.join(self.common_test_dir, '43 options', 'meson.build')
        res = self.introspect_directory(testfile, '--projectinfo')
        self.assertEqual(set(res['buildsystem_files']), set(['meson_options.txt', 'meson.build']))
        self.assertEqual(res['version'], 'undefined')
        self.assertEqual(res['descriptive_name'], 'options')
        self.assertEqual(res['subprojects'], [])

        testfile = os.path.join(self.common_test_dir, '46 subproject options', 'meson.build')
        res = self.introspect_directory(testfile, '--projectinfo')
        self.assertEqual(set(res['buildsystem_files']), set(['meson_options.txt', 'meson.build']))
        self.assertEqual(res['version'], 'undefined')
        self.assertEqual(res['descriptive_name'], 'suboptions')
        self.assertEqual(len(res['subprojects']), 1)
        subproject_files = set(f.replace('\\', '/') for f in res['subprojects'][0]['buildsystem_files'])
        self.assertEqual(subproject_files, set(['subprojects/subproject/meson_options.txt', 'subprojects/subproject/meson.build']))
        self.assertEqual(res['subprojects'][0]['name'], 'subproject')
        self.assertEqual(res['subprojects'][0]['version'], 'undefined')
        self.assertEqual(res['subprojects'][0]['descriptive_name'], 'subproject')

    def test_introspect_projectinfo_subprojects(self):
        testdir = os.path.join(self.common_test_dir, '102 subproject subdir')
        self.init(testdir)
        res = self.introspect('--projectinfo')
        expected = {
            'descriptive_name': 'proj',
            'version': 'undefined',
            'subproject_dir': 'subprojects',
            'subprojects': [
                {
                    'descriptive_name': 'sub',
                    'name': 'sub',
                    'version': 'undefined'
                }
            ]
        }
        self.assertDictEqual(res, expected)

    def test_introspection_target_subproject(self):
        testdir = os.path.join(self.common_test_dir, '45 subproject')
        self.init(testdir)
        res = self.introspect('--targets')

        expected = {
            'sublib': 'sublib',
            'simpletest': 'sublib',
            'user': None
        }

        for entry in res:
            name = entry['name']
            self.assertEqual(entry['subproject'], expected[name])

    def test_introspect_projectinfo_subproject_dir(self):
        testdir = os.path.join(self.common_test_dir, '78 custom subproject dir')
        self.init(testdir)
        res = self.introspect('--projectinfo')

        self.assertEqual(res['subproject_dir'], 'custom_subproject_dir')

    def test_introspect_projectinfo_subproject_dir_from_source(self):
        testfile = os.path.join(self.common_test_dir, '78 custom subproject dir', 'meson.build')
        res = self.introspect_directory(testfile, '--projectinfo')

        self.assertEqual(res['subproject_dir'], 'custom_subproject_dir')

    @skipIfNoExecutable('clang-format')
    def test_clang_format(self):
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('Clang-format is for now only supported on Ninja, not {}'.format(self.backend.name))
        testdir = os.path.join(self.unit_test_dir, '54 clang-format')
        testfile = os.path.join(testdir, 'prog.c')
        badfile = os.path.join(testdir, 'prog_orig_c')
        goodfile = os.path.join(testdir, 'prog_expected_c')
        testheader = os.path.join(testdir, 'header.h')
        badheader = os.path.join(testdir, 'header_orig_h')
        goodheader = os.path.join(testdir, 'header_expected_h')
        try:
            shutil.copyfile(badfile, testfile)
            shutil.copyfile(badheader, testheader)
            self.init(testdir)
            self.assertNotEqual(Path(testfile).read_text(),
                                Path(goodfile).read_text())
            self.assertNotEqual(Path(testheader).read_text(),
                                Path(goodheader).read_text())
            self.run_target('clang-format')
            self.assertEqual(Path(testheader).read_text(),
                             Path(goodheader).read_text())
        finally:
            if os.path.exists(testfile):
                os.unlink(testfile)
            if os.path.exists(testheader):
                os.unlink(testheader)

    @skipIfNoExecutable('clang-tidy')
    def test_clang_tidy(self):
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('Clang-tidy is for now only supported on Ninja, not {}'.format(self.backend.name))
        if shutil.which('c++') is None:
            raise unittest.SkipTest('Clang-tidy breaks when ccache is used and "c++" not in path.')
        if is_osx():
            raise unittest.SkipTest('Apple ships a broken clang-tidy that chokes on -pipe.')
        testdir = os.path.join(self.unit_test_dir, '70 clang-tidy')
        self.init(testdir, override_envvars={'CXX': 'c++'})
        out = self.run_target('clang-tidy')
        self.assertIn('cttest.cpp:4:20', out)

    def test_identity_cross(self):
        testdir = os.path.join(self.unit_test_dir, '71 cross')
        # Do a build to generate a cross file where the host is this target
        self.init(testdir, extra_args=['-Dgenerate=true'])
        self.meson_cross_file = os.path.join(self.builddir, "crossfile")
        self.assertTrue(os.path.exists(self.meson_cross_file))
        # Now verify that this is detected as cross
        self.new_builddir()
        self.init(testdir)

    def test_introspect_buildoptions_without_configured_build(self):
        testdir = os.path.join(self.unit_test_dir, '59 introspect buildoptions')
        testfile = os.path.join(testdir, 'meson.build')
        res_nb = self.introspect_directory(testfile, ['--buildoptions'] + self.meson_args)
        self.init(testdir, default_args=False)
        res_wb = self.introspect('--buildoptions')
        self.maxDiff = None
        self.assertListEqual(res_nb, res_wb)

    def test_meson_configure_from_source_does_not_crash(self):
        testdir = os.path.join(self.unit_test_dir, '59 introspect buildoptions')
        self._run(self.mconf_command + [testdir])

    def test_introspect_json_dump(self):
        testdir = os.path.join(self.unit_test_dir, '57 introspection')
        self.init(testdir)
        infodir = os.path.join(self.builddir, 'meson-info')
        self.assertPathExists(infodir)

        def assertKeyTypes(key_type_list, obj):
            for i in key_type_list:
                self.assertIn(i[0], obj)
                self.assertIsInstance(obj[i[0]], i[1])

        root_keylist = [
            ('benchmarks', list),
            ('buildoptions', list),
            ('buildsystem_files', list),
            ('dependencies', list),
            ('installed', dict),
            ('projectinfo', dict),
            ('targets', list),
            ('tests', list),
        ]

        test_keylist = [
            ('cmd', list),
            ('env', dict),
            ('name', str),
            ('timeout', int),
            ('suite', list),
            ('is_parallel', bool),
            ('protocol', str),
        ]

        buildoptions_keylist = [
            ('name', str),
            ('section', str),
            ('type', str),
            ('description', str),
            ('machine', str),
        ]

        buildoptions_typelist = [
            ('combo', str, [('choices', list)]),
            ('string', str, []),
            ('boolean', bool, []),
            ('integer', int, []),
            ('array', list, []),
        ]

        buildoptions_sections = ['core', 'backend', 'base', 'compiler', 'directory', 'user', 'test']
        buildoptions_machines = ['any', 'build', 'host']

        dependencies_typelist = [
            ('name', str),
            ('version', str),
            ('compile_args', list),
            ('link_args', list),
        ]

        targets_typelist = [
            ('name', str),
            ('id', str),
            ('type', str),
            ('defined_in', str),
            ('filename', list),
            ('build_by_default', bool),
            ('target_sources', list),
            ('installed', bool),
        ]

        targets_sources_typelist = [
            ('language', str),
            ('compiler', list),
            ('parameters', list),
            ('sources', list),
            ('generated_sources', list),
        ]

        # First load all files
        res = {}
        for i in root_keylist:
            curr = os.path.join(infodir, 'intro-{}.json'.format(i[0]))
            self.assertPathExists(curr)
            with open(curr, 'r') as fp:
                res[i[0]] = json.load(fp)

        assertKeyTypes(root_keylist, res)

        # Check Tests and benchmarks
        tests_to_find = ['test case 1', 'test case 2', 'benchmark 1']
        for i in res['benchmarks'] + res['tests']:
            assertKeyTypes(test_keylist, i)
            if i['name'] in tests_to_find:
                tests_to_find.remove(i['name'])
        self.assertListEqual(tests_to_find, [])

        # Check buildoptions
        buildopts_to_find = {'cpp_std': 'c++11'}
        for i in res['buildoptions']:
            assertKeyTypes(buildoptions_keylist, i)
            valid_type = False
            for j in buildoptions_typelist:
                if i['type'] == j[0]:
                    self.assertIsInstance(i['value'], j[1])
                    assertKeyTypes(j[2], i)
                    valid_type = True
                    break

            self.assertIn(i['section'], buildoptions_sections)
            self.assertIn(i['machine'], buildoptions_machines)
            self.assertTrue(valid_type)
            if i['name'] in buildopts_to_find:
                self.assertEqual(i['value'], buildopts_to_find[i['name']])
                buildopts_to_find.pop(i['name'], None)
        self.assertDictEqual(buildopts_to_find, {})

        # Check buildsystem_files
        bs_files = ['meson.build', 'meson_options.txt', 'sharedlib/meson.build', 'staticlib/meson.build']
        bs_files = [os.path.join(testdir, x) for x in bs_files]
        self.assertPathListEqual(list(sorted(res['buildsystem_files'])), list(sorted(bs_files)))

        # Check dependencies
        dependencies_to_find = ['threads']
        for i in res['dependencies']:
            assertKeyTypes(dependencies_typelist, i)
            if i['name'] in dependencies_to_find:
                dependencies_to_find.remove(i['name'])
        self.assertListEqual(dependencies_to_find, [])

        # Check projectinfo
        self.assertDictEqual(res['projectinfo'], {'version': '1.2.3', 'descriptive_name': 'introspection', 'subproject_dir': 'subprojects', 'subprojects': []})

        # Check targets
        targets_to_find = {
            'sharedTestLib': ('shared library', True, False, 'sharedlib/meson.build'),
            'staticTestLib': ('static library', True, False, 'staticlib/meson.build'),
            'test1': ('executable', True, True, 'meson.build'),
            'test2': ('executable', True, False, 'meson.build'),
            'test3': ('executable', True, False, 'meson.build'),
        }
        for i in res['targets']:
            assertKeyTypes(targets_typelist, i)
            if i['name'] in targets_to_find:
                tgt = targets_to_find[i['name']]
                self.assertEqual(i['type'], tgt[0])
                self.assertEqual(i['build_by_default'], tgt[1])
                self.assertEqual(i['installed'], tgt[2])
                self.assertPathEqual(i['defined_in'], os.path.join(testdir, tgt[3]))
                targets_to_find.pop(i['name'], None)
            for j in i['target_sources']:
                assertKeyTypes(targets_sources_typelist, j)
        self.assertDictEqual(targets_to_find, {})

    def test_introspect_file_dump_equals_all(self):
        testdir = os.path.join(self.unit_test_dir, '57 introspection')
        self.init(testdir)
        res_all = self.introspect('--all')
        res_file = {}

        root_keylist = [
            'benchmarks',
            'buildoptions',
            'buildsystem_files',
            'dependencies',
            'installed',
            'projectinfo',
            'targets',
            'tests',
        ]

        infodir = os.path.join(self.builddir, 'meson-info')
        self.assertPathExists(infodir)
        for i in root_keylist:
            curr = os.path.join(infodir, 'intro-{}.json'.format(i))
            self.assertPathExists(curr)
            with open(curr, 'r') as fp:
                res_file[i] = json.load(fp)

        self.assertEqual(res_all, res_file)

    def test_introspect_meson_info(self):
        testdir = os.path.join(self.unit_test_dir, '57 introspection')
        introfile = os.path.join(self.builddir, 'meson-info', 'meson-info.json')
        self.init(testdir)
        self.assertPathExists(introfile)
        with open(introfile, 'r') as fp:
            res1 = json.load(fp)

        for i in ['meson_version', 'directories', 'introspection', 'build_files_updated', 'error']:
            self.assertIn(i, res1)

        self.assertEqual(res1['error'], False)
        self.assertEqual(res1['build_files_updated'], True)

    def test_introspect_config_update(self):
        testdir = os.path.join(self.unit_test_dir, '57 introspection')
        introfile = os.path.join(self.builddir, 'meson-info', 'intro-buildoptions.json')
        self.init(testdir)
        self.assertPathExists(introfile)
        with open(introfile, 'r') as fp:
            res1 = json.load(fp)

        self.setconf('-Dcpp_std=c++14')
        self.setconf('-Dbuildtype=release')

        for idx, i in enumerate(res1):
            if i['name'] == 'cpp_std':
                res1[idx]['value'] = 'c++14'
            if i['name'] == 'build.cpp_std':
                res1[idx]['value'] = 'c++14'
            if i['name'] == 'buildtype':
                res1[idx]['value'] = 'release'
            if i['name'] == 'optimization':
                res1[idx]['value'] = '3'
            if i['name'] == 'debug':
                res1[idx]['value'] = False

        with open(introfile, 'r') as fp:
            res2 = json.load(fp)

        self.assertListEqual(res1, res2)

    def test_introspect_targets_from_source(self):
        testdir = os.path.join(self.unit_test_dir, '57 introspection')
        testfile = os.path.join(testdir, 'meson.build')
        introfile = os.path.join(self.builddir, 'meson-info', 'intro-targets.json')
        self.init(testdir)
        self.assertPathExists(introfile)
        with open(introfile, 'r') as fp:
            res_wb = json.load(fp)

        res_nb = self.introspect_directory(testfile, ['--targets'] + self.meson_args)

        # Account for differences in output
        for i in res_wb:
            i['filename'] = [os.path.relpath(x, self.builddir) for x in i['filename']]
            if 'install_filename' in i:
                del i['install_filename']

            sources = []
            for j in i['target_sources']:
                sources += j['sources']
            i['target_sources'] = [{
                'language': 'unknown',
                'compiler': [],
                'parameters': [],
                'sources': sources,
                'generated_sources': []
            }]

        self.maxDiff = None
        self.assertListEqual(res_nb, res_wb)

    def test_introspect_dependencies_from_source(self):
        testdir = os.path.join(self.unit_test_dir, '57 introspection')
        testfile = os.path.join(testdir, 'meson.build')
        res_nb = self.introspect_directory(testfile, ['--scan-dependencies'] + self.meson_args)
        expected = [
            {
                'name': 'threads',
                'required': True,
                'version': [],
                'has_fallback': False,
                'conditional': False
            },
            {
                'name': 'zlib',
                'required': False,
                'version': [],
                'has_fallback': False,
                'conditional': False
            },
            {
                'name': 'bugDep1',
                'required': True,
                'version': [],
                'has_fallback': False,
                'conditional': False
            },
            {
                'name': 'somethingthatdoesnotexist',
                'required': True,
                'version': ['>=1.2.3'],
                'has_fallback': False,
                'conditional': True
            },
            {
                'name': 'look_i_have_a_fallback',
                'required': True,
                'version': ['>=1.0.0', '<=99.9.9'],
                'has_fallback': True,
                'conditional': True
            }
        ]
        self.maxDiff = None
        self.assertListEqual(res_nb, expected)

    def test_unstable_coredata(self):
        testdir = os.path.join(self.common_test_dir, '1 trivial')
        self.init(testdir)
        # just test that the command does not fail (e.g. because it throws an exception)
        self._run([*self.meson_command, 'unstable-coredata', self.builddir])

    @skip_if_no_cmake
    def test_cmake_prefix_path(self):
        testdir = os.path.join(self.unit_test_dir, '64 cmake_prefix_path')
        self.init(testdir, extra_args=['-Dcmake_prefix_path=' + os.path.join(testdir, 'prefix')])

    @skip_if_no_cmake
    def test_cmake_parser(self):
        testdir = os.path.join(self.unit_test_dir, '65 cmake parser')
        self.init(testdir, extra_args=['-Dcmake_prefix_path=' + os.path.join(testdir, 'prefix')])

    def test_alias_target(self):
        if self.backend is Backend.vs:
            # FIXME: This unit test is broken with vs backend, needs investigation
            raise unittest.SkipTest('Skipping alias_target test with {} backend'.format(self.backend.name))
        testdir = os.path.join(self.unit_test_dir, '66 alias target')
        self.init(testdir)
        self.build()
        self.assertPathDoesNotExist(os.path.join(self.builddir, 'prog' + exe_suffix))
        self.assertPathDoesNotExist(os.path.join(self.builddir, 'hello.txt'))
        self.run_target('build-all')
        self.assertPathExists(os.path.join(self.builddir, 'prog' + exe_suffix))
        self.assertPathExists(os.path.join(self.builddir, 'hello.txt'))

    def test_configure(self):
        testdir = os.path.join(self.common_test_dir, '2 cpp')
        self.init(testdir)
        self._run(self.mconf_command + [self.builddir])

    def test_summary(self):
        testdir = os.path.join(self.unit_test_dir, '74 summary')
        out = self.init(testdir)
        expected = textwrap.dedent(r'''
            Some Subproject 2.0

                 string: bar
                integer: 1
                boolean: True

            My Project 1.0

              Configuration
                   Some boolean: False
                Another boolean: True
                    Some string: Hello World
                         A list: string
                                 1
                                 True
                     empty list: 
                       A number: 1
                            yes: YES
                             no: NO

              Subprojects
                            sub: YES
                           sub2: NO
            ''')
        expected_lines = expected.split('\n')[1:]
        out_start = out.find(expected_lines[0])
        out_lines = out[out_start:].split('\n')[:len(expected_lines)]
        if sys.version_info < (3, 7, 0):
            # Dictionary order is not stable in Python <3.7, so sort the lines
            # while comparing
            self.assertEqual(sorted(expected_lines), sorted(out_lines))
        else:
            self.assertEqual(expected_lines, out_lines)


class FailureTests(BasePlatformTests):
    '''
    Tests that test failure conditions. Build files here should be dynamically
    generated and static tests should go into `test cases/failing*`.
    This is useful because there can be many ways in which a particular
    function can fail, and creating failing tests for all of them is tedious
    and slows down testing.
    '''
    dnf = "[Dd]ependency.*not found(:.*)?"
    nopkg = '[Pp]kg-config.*not found'

    def setUp(self):
        super().setUp()
        self.srcdir = os.path.realpath(tempfile.mkdtemp())
        self.mbuild = os.path.join(self.srcdir, 'meson.build')
        self.moptions = os.path.join(self.srcdir, 'meson_options.txt')

    def tearDown(self):
        super().tearDown()
        windows_proof_rmtree(self.srcdir)

    def assertMesonRaises(self, contents, match, *,
                          extra_args=None,
                          langs=None,
                          meson_version=None,
                          options=None,
                          override_envvars=None):
        '''
        Assert that running meson configure on the specified @contents raises
        a error message matching regex @match.
        '''
        if langs is None:
            langs = []
        with open(self.mbuild, 'w') as f:
            f.write("project('failure test', 'c', 'cpp'")
            if meson_version:
                f.write(", meson_version: '{}'".format(meson_version))
            f.write(")\n")
            for lang in langs:
                f.write("add_languages('{}', required : false)\n".format(lang))
            f.write(contents)
        if options is not None:
            with open(self.moptions, 'w') as f:
                f.write(options)
        o = {'MESON_FORCE_BACKTRACE': '1'}
        if override_envvars is None:
            override_envvars = o
        else:
            override_envvars.update(o)
        # Force tracebacks so we can detect them properly
        with self.assertRaisesRegex(MesonException, match, msg=contents):
            # Must run in-process or we'll get a generic CalledProcessError
            self.init(self.srcdir, extra_args=extra_args,
                      inprocess=True,
                      override_envvars = override_envvars)

    def obtainMesonOutput(self, contents, match, extra_args, langs, meson_version=None):
        if langs is None:
            langs = []
        with open(self.mbuild, 'w') as f:
            f.write("project('output test', 'c', 'cpp'")
            if meson_version:
                f.write(", meson_version: '{}'".format(meson_version))
            f.write(")\n")
            for lang in langs:
                f.write("add_languages('{}', required : false)\n".format(lang))
            f.write(contents)
        # Run in-process for speed and consistency with assertMesonRaises
        return self.init(self.srcdir, extra_args=extra_args, inprocess=True)

    def assertMesonOutputs(self, contents, match, extra_args=None, langs=None, meson_version=None):
        '''
        Assert that running meson configure on the specified @contents outputs
        something that matches regex @match.
        '''
        out = self.obtainMesonOutput(contents, match, extra_args, langs, meson_version)
        self.assertRegex(out, match)

    def assertMesonDoesNotOutput(self, contents, match, extra_args=None, langs=None, meson_version=None):
        '''
        Assert that running meson configure on the specified @contents does not output
        something that matches regex @match.
        '''
        out = self.obtainMesonOutput(contents, match, extra_args, langs, meson_version)
        self.assertNotRegex(out, match)

    @skipIfNoPkgconfig
    def test_dependency(self):
        if subprocess.call(['pkg-config', '--exists', 'zlib']) != 0:
            raise unittest.SkipTest('zlib not found with pkg-config')
        a = (("dependency('zlib', method : 'fail')", "'fail' is invalid"),
             ("dependency('zlib', static : '1')", "[Ss]tatic.*boolean"),
             ("dependency('zlib', version : 1)", "[Vv]ersion.*string or list"),
             ("dependency('zlib', required : 1)", "[Rr]equired.*boolean"),
             ("dependency('zlib', method : 1)", "[Mm]ethod.*string"),
             ("dependency('zlibfail')", self.dnf),)
        for contents, match in a:
            self.assertMesonRaises(contents, match)

    def test_apple_frameworks_dependency(self):
        if not is_osx():
            raise unittest.SkipTest('only run on macOS')
        self.assertMesonRaises("dependency('appleframeworks')",
                               "requires at least one module")

    def test_extraframework_dependency_method(self):
        code = "dependency('python', method : 'extraframework')"
        if not is_osx():
            self.assertMesonRaises(code, self.dnf)
        else:
            # Python2 framework is always available on macOS
            self.assertMesonOutputs(code, '[Dd]ependency.*python.*found.*YES')

    def test_sdl2_notfound_dependency(self):
        # Want to test failure, so skip if available
        if shutil.which('sdl2-config'):
            raise unittest.SkipTest('sdl2-config found')
        self.assertMesonRaises("dependency('sdl2', method : 'sdlconfig')", self.dnf)
        if shutil.which('pkg-config'):
            self.assertMesonRaises("dependency('sdl2', method : 'pkg-config')", self.dnf)
        with no_pkgconfig():
            # Look for pkg-config, cache it, then
            # Use cached pkg-config without erroring out, then
            # Use cached pkg-config to error out
            code = "dependency('foobarrr', method : 'pkg-config', required : false)\n" \
                "dependency('foobarrr2', method : 'pkg-config', required : false)\n" \
                "dependency('sdl2', method : 'pkg-config')"
            self.assertMesonRaises(code, self.nopkg)

    def test_gnustep_notfound_dependency(self):
        # Want to test failure, so skip if available
        if shutil.which('gnustep-config'):
            raise unittest.SkipTest('gnustep-config found')
        self.assertMesonRaises("dependency('gnustep')",
                               "(requires a Objc compiler|{})".format(self.dnf),
                               langs = ['objc'])

    def test_wx_notfound_dependency(self):
        # Want to test failure, so skip if available
        if shutil.which('wx-config-3.0') or shutil.which('wx-config') or shutil.which('wx-config-gtk3'):
            raise unittest.SkipTest('wx-config, wx-config-3.0 or wx-config-gtk3 found')
        self.assertMesonRaises("dependency('wxwidgets')", self.dnf)
        self.assertMesonOutputs("dependency('wxwidgets', required : false)",
                                "Run-time dependency .*WxWidgets.* found: .*NO.*")

    def test_wx_dependency(self):
        if not shutil.which('wx-config-3.0') and not shutil.which('wx-config') and not shutil.which('wx-config-gtk3'):
            raise unittest.SkipTest('Neither wx-config, wx-config-3.0 nor wx-config-gtk3 found')
        self.assertMesonRaises("dependency('wxwidgets', modules : 1)",
                               "module argument is not a string")

    def test_llvm_dependency(self):
        self.assertMesonRaises("dependency('llvm', modules : 'fail')",
                               "(required.*fail|{})".format(self.dnf))

    def test_boost_notfound_dependency(self):
        # Can be run even if Boost is found or not
        self.assertMesonRaises("dependency('boost', modules : 1)",
                               "module.*not a string")
        self.assertMesonRaises("dependency('boost', modules : 'fail')",
                               "(fail.*not found|{})".format(self.dnf))

    def test_boost_BOOST_ROOT_dependency(self):
        # Test BOOST_ROOT; can be run even if Boost is found or not
        self.assertMesonRaises("dependency('boost')",
                               "(BOOST_ROOT.*absolute|{})".format(self.dnf),
                               override_envvars = {'BOOST_ROOT': 'relative/path'})

    def test_dependency_invalid_method(self):
        code = '''zlib_dep = dependency('zlib', required : false)
        zlib_dep.get_configtool_variable('foo')
        '''
        self.assertMesonRaises(code, ".* is not a config-tool dependency")
        code = '''zlib_dep = dependency('zlib', required : false)
        dep = declare_dependency(dependencies : zlib_dep)
        dep.get_pkgconfig_variable('foo')
        '''
        self.assertMesonRaises(code, "Method.*pkgconfig.*is invalid.*internal")
        code = '''zlib_dep = dependency('zlib', required : false)
        dep = declare_dependency(dependencies : zlib_dep)
        dep.get_configtool_variable('foo')
        '''
        self.assertMesonRaises(code, "Method.*configtool.*is invalid.*internal")

    def test_objc_cpp_detection(self):
        '''
        Test that when we can't detect objc or objcpp, we fail gracefully.
        '''
        env = get_fake_env()
        try:
            env.detect_objc_compiler(MachineChoice.HOST)
            env.detect_objcpp_compiler(MachineChoice.HOST)
        except EnvironmentException:
            code = "add_languages('objc')\nadd_languages('objcpp')"
            self.assertMesonRaises(code, "Unknown compiler")
            return
        raise unittest.SkipTest("objc and objcpp found, can't test detection failure")

    def test_subproject_variables(self):
        '''
        Test that:
        1. The correct message is outputted when a not-required dep is not
           found and the fallback subproject is also not found.
        2. A not-required fallback dependency is not found because the
           subproject failed to parse.
        3. A not-found not-required dep with a fallback subproject outputs the
           correct message when the fallback subproject is found but the
           variable inside it is not.
        4. A fallback dependency is found from the subproject parsed in (3)
        5. The correct message is outputted when the .wrap file is missing for
           a sub-subproject.
        '''
        tdir = os.path.join(self.unit_test_dir, '20 subproj dep variables')
        out = self.init(tdir, inprocess=True)
        self.assertRegex(out, r"Subproject directory not found and .*nosubproj.wrap.* file not found")
        self.assertRegex(out, r'Function does not take positional arguments.')
        self.assertRegex(out, r'WARNING:.* Dependency .*subsubproject.* not found but it is available in a sub-subproject.')
        self.assertRegex(out, r'Subproject directory not found and .*subsubproject.wrap.* file not found')
        self.assertRegex(out, r'Dependency .*zlibproxy.* from subproject .*subprojects.*somesubproj.* found: .*YES.*')

    def test_exception_exit_status(self):
        '''
        Test exit status on python exception
        '''
        tdir = os.path.join(self.unit_test_dir, '21 exit status')
        with self.assertRaises(subprocess.CalledProcessError) as cm:
            self.init(tdir, inprocess=False, override_envvars = {'MESON_UNIT_TEST': '1'})
        self.assertEqual(cm.exception.returncode, 2)
        self.wipe()

    def test_dict_requires_key_value_pairs(self):
        self.assertMesonRaises("dict = {3, 'foo': 'bar'}",
                               'Only key:value pairs are valid in dict construction.')
        self.assertMesonRaises("{'foo': 'bar', 3}",
                               'Only key:value pairs are valid in dict construction.')

    def test_dict_forbids_duplicate_keys(self):
        self.assertMesonRaises("dict = {'a': 41, 'a': 42}",
                               'Duplicate dictionary key: a.*')

    def test_dict_forbids_integer_key(self):
        self.assertMesonRaises("dict = {3: 'foo'}",
                               'Key must be a string.*')

    def test_using_too_recent_feature(self):
        # Here we use a dict, which was introduced in 0.47.0
        self.assertMesonOutputs("dict = {}",
                                ".*WARNING.*Project targeting.*but.*",
                                meson_version='>= 0.46.0')

    def test_using_recent_feature(self):
        # Same as above, except the meson version is now appropriate
        self.assertMesonDoesNotOutput("dict = {}",
                                      ".*WARNING.*Project targeting.*but.*",
                                      meson_version='>= 0.47')

    def test_using_too_recent_feature_dependency(self):
        self.assertMesonOutputs("dependency('pcap', required: false)",
                                ".*WARNING.*Project targeting.*but.*",
                                meson_version='>= 0.41.0')

    def test_vcs_tag_featurenew_build_always_stale(self):
        'https://github.com/mesonbuild/meson/issues/3904'
        vcs_tag = '''version_data = configuration_data()
        version_data.set('PROJVER', '@VCS_TAG@')
        vf = configure_file(output : 'version.h.in', configuration: version_data)
        f = vcs_tag(input : vf, output : 'version.h')
        '''
        msg = '.*WARNING:.*feature.*build_always_stale.*custom_target.*'
        self.assertMesonDoesNotOutput(vcs_tag, msg, meson_version='>=0.43')

    def test_missing_subproject_not_required_and_required(self):
        self.assertMesonRaises("sub1 = subproject('not-found-subproject', required: false)\n" +
                               "sub2 = subproject('not-found-subproject', required: true)",
                               """.*Subproject "subprojects/not-found-subproject" required but not found.*""")

    def test_get_variable_on_not_found_project(self):
        self.assertMesonRaises("sub1 = subproject('not-found-subproject', required: false)\n" +
                               "sub1.get_variable('naaa')",
                               """Subproject "subprojects/not-found-subproject" disabled can't get_variable on it.""")

    def test_version_checked_before_parsing_options(self):
        '''
        https://github.com/mesonbuild/meson/issues/5281
        '''
        options = "option('some-option', type: 'foo', value: '')"
        match = 'Meson version is.*but project requires >=2000'
        self.assertMesonRaises("", match, meson_version='>=2000', options=options)

    def test_assert_default_message(self):
        self.assertMesonRaises("k1 = 'a'\n" +
                               "assert({\n" +
                               "  k1: 1,\n" +
                               "}['a'] == 2)\n",
                               r"Assert failed: {k1 : 1}\['a'\] == 2")

@unittest.skipUnless(is_windows() or is_cygwin(), "requires Windows (or Windows via Cygwin)")
class WindowsTests(BasePlatformTests):
    '''
    Tests that should run on Cygwin, MinGW, and MSVC
    '''

    def setUp(self):
        super().setUp()
        self.platform_test_dir = os.path.join(self.src_root, 'test cases/windows')

    @unittest.skipIf(is_cygwin(), 'Test only applicable to Windows')
    def test_find_program(self):
        '''
        Test that Windows-specific edge-cases in find_program are functioning
        correctly. Cannot be an ordinary test because it involves manipulating
        PATH to point to a directory with Python scripts.
        '''
        testdir = os.path.join(self.platform_test_dir, '8 find program')
        # Find `cmd` and `cmd.exe`
        prog1 = ExternalProgram('cmd')
        self.assertTrue(prog1.found(), msg='cmd not found')
        prog2 = ExternalProgram('cmd.exe')
        self.assertTrue(prog2.found(), msg='cmd.exe not found')
        self.assertPathEqual(prog1.get_path(), prog2.get_path())
        # Find cmd with an absolute path that's missing the extension
        cmd_path = prog2.get_path()[:-4]
        prog = ExternalProgram(cmd_path)
        self.assertTrue(prog.found(), msg='{!r} not found'.format(cmd_path))
        # Finding a script with no extension inside a directory works
        prog = ExternalProgram(os.path.join(testdir, 'test-script'))
        self.assertTrue(prog.found(), msg='test-script not found')
        # Finding a script with an extension inside a directory works
        prog = ExternalProgram(os.path.join(testdir, 'test-script-ext.py'))
        self.assertTrue(prog.found(), msg='test-script-ext.py not found')
        # Finding a script in PATH
        os.environ['PATH'] += os.pathsep + testdir
        # Finding a script in PATH w/o extension works and adds the interpreter
        # (check only if `.PY` is in PATHEXT)
        if '.PY' in [ext.upper() for ext in os.environ['PATHEXT'].split(';')]:
            prog = ExternalProgram('test-script-ext')
            self.assertTrue(prog.found(), msg='test-script-ext not found in PATH')
            self.assertPathEqual(prog.get_command()[0], python_command[0])
            self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
        # Finding a script in PATH with extension works and adds the interpreter
        prog = ExternalProgram('test-script-ext.py')
        self.assertTrue(prog.found(), msg='test-script-ext.py not found in PATH')
        self.assertPathEqual(prog.get_command()[0], python_command[0])
        self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
        # Ensure that WindowsApps gets removed from PATH
        path = os.environ['PATH']
        if 'WindowsApps' not in path:
            username = os.environ['USERNAME']
            appstore_dir = r'C:\Users\{}\AppData\Local\Microsoft\WindowsApps'.format(username)
            path = os.pathsep + appstore_dir
        path = ExternalProgram._windows_sanitize_path(path)
        self.assertNotIn('WindowsApps', path)

    def test_ignore_libs(self):
        '''
        Test that find_library on libs that are to be ignored returns an empty
        array of arguments. Must be a unit test because we cannot inspect
        ExternalLibraryHolder from build files.
        '''
        testdir = os.path.join(self.platform_test_dir, '1 basic')
        env = get_fake_env(testdir, self.builddir, self.prefix)
        cc = env.detect_c_compiler(MachineChoice.HOST)
        if cc.get_argument_syntax() != 'msvc':
            raise unittest.SkipTest('Not using MSVC')
        # To force people to update this test, and also test
        self.assertEqual(set(cc.ignore_libs), {'c', 'm', 'pthread', 'dl', 'rt', 'execinfo'})
        for l in cc.ignore_libs:
            self.assertEqual(cc.find_library(l, env, []), [])

    def test_rc_depends_files(self):
        testdir = os.path.join(self.platform_test_dir, '5 resources')

        # resource compiler depfile generation is not yet implemented for msvc
        env = get_fake_env(testdir, self.builddir, self.prefix)
        depfile_works = env.detect_c_compiler(MachineChoice.HOST).get_id() not in {'msvc', 'clang-cl', 'intel-cl'}

        self.init(testdir)
        self.build()
        # Immediately rebuilding should not do anything
        self.assertBuildIsNoop()
        # Test compile_resources(depend_file:)
        # Changing mtime of sample.ico should rebuild prog
        self.utime(os.path.join(testdir, 'res', 'sample.ico'))
        self.assertRebuiltTarget('prog')
        # Test depfile generation by compile_resources
        # Changing mtime of resource.h should rebuild myres.rc and then prog
        if depfile_works:
            self.utime(os.path.join(testdir, 'inc', 'resource', 'resource.h'))
            self.assertRebuiltTarget('prog')
        self.wipe()

        if depfile_works:
            testdir = os.path.join(self.platform_test_dir, '12 resources with custom targets')
            self.init(testdir)
            self.build()
            # Immediately rebuilding should not do anything
            self.assertBuildIsNoop()
            # Changing mtime of resource.h should rebuild myres_1.rc and then prog_1
            self.utime(os.path.join(testdir, 'res', 'resource.h'))
            self.assertRebuiltTarget('prog_1')

    def test_msvc_cpp17(self):
        testdir = os.path.join(self.unit_test_dir, '45 vscpp17')

        env = get_fake_env(testdir, self.builddir, self.prefix)
        cc = env.detect_c_compiler(MachineChoice.HOST)
        if cc.get_argument_syntax() != 'msvc':
            raise unittest.SkipTest('Test only applies to MSVC-like compilers')

        try:
            self.init(testdir)
        except subprocess.CalledProcessError:
            # According to Python docs, output is only stored when
            # using check_output. We don't use it, so we can't check
            # that the output is correct (i.e. that it failed due
            # to the right reason).
            return
        self.build()

    def test_install_pdb_introspection(self):
        testdir = os.path.join(self.platform_test_dir, '1 basic')

        env = get_fake_env(testdir, self.builddir, self.prefix)
        cc = env.detect_c_compiler(MachineChoice.HOST)
        if cc.get_argument_syntax() != 'msvc':
            raise unittest.SkipTest('Test only applies to MSVC-like compilers')

        self.init(testdir)
        installed = self.introspect('--installed')
        files = [os.path.basename(path) for path in installed.values()]

        self.assertTrue('prog.pdb' in files)

    def _check_ld(self, name: str, lang: str, expected: str) -> None:
        if not shutil.which(name):
            raise unittest.SkipTest('Could not find {}.'.format(name))
        envvar = mesonbuild.envconfig.BinaryTable.evarMap['{}_ld'.format(lang)]
        with mock.patch.dict(os.environ, {envvar: name}):
            env = get_fake_env()
            try:
                comp = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
            except EnvironmentException:
                raise unittest.SkipTest('Could not find a compiler for {}'.format(lang))
            self.assertEqual(comp.linker.id, expected)

    def test_link_environment_variable_lld_link(self):
        self._check_ld('lld-link', 'c', 'lld-link')

    def test_link_environment_variable_link(self):
        self._check_ld('link', 'c', 'link')

    def test_link_environment_variable_optlink(self):
        self._check_ld('optlink', 'c', 'optlink')

    def test_link_environment_variable_rust(self):
        self._check_ld('link', 'rust', 'link')

    def test_pefile_checksum(self):
        try:
            import pefile
        except ImportError:
            if is_ci():
                raise
            raise unittest.SkipTest('pefile module not found')
        testdir = os.path.join(self.common_test_dir, '6 linkshared')
        self.init(testdir)
        self.build()
        # Test that binaries have a non-zero checksum
        env = get_fake_env()
        cc = env.detect_c_compiler(MachineChoice.HOST)
        cc_id = cc.get_id()
        ld_id = cc.get_linker_id()
        dll = glob(os.path.join(self.builddir, '*mycpplib.dll'))[0]
        exe = os.path.join(self.builddir, 'cppprog.exe')
        for f in (dll, exe):
            pe = pefile.PE(f)
            msg = 'PE file: {!r}, compiler: {!r}, linker: {!r}'.format(f, cc_id, ld_id)
            if cc_id == 'clang-cl':
                # Latest clang-cl tested (7.0) does not write checksums out
                self.assertFalse(pe.verify_checksum(), msg=msg)
            else:
                # Verify that a valid checksum was written by all other compilers
                self.assertTrue(pe.verify_checksum(), msg=msg)


@unittest.skipUnless(is_osx(), "requires Darwin")
class DarwinTests(BasePlatformTests):
    '''
    Tests that should run on macOS
    '''

    def setUp(self):
        super().setUp()
        self.platform_test_dir = os.path.join(self.src_root, 'test cases/osx')

    def test_apple_bitcode(self):
        '''
        Test that -fembed-bitcode is correctly added while compiling and
        -bitcode_bundle is added while linking when b_bitcode is true and not
        when it is false.  This can't be an ordinary test case because we need
        to inspect the compiler database.
        '''
        testdir = os.path.join(self.platform_test_dir, '7 bitcode')
        env = get_fake_env(testdir, self.builddir, self.prefix)
        cc = env.detect_c_compiler(MachineChoice.HOST)
        if cc.id != 'clang':
            raise unittest.SkipTest('Not using Clang on OSX')
        # Try with bitcode enabled
        out = self.init(testdir, extra_args='-Db_bitcode=true')
        # Warning was printed
        self.assertRegex(out, 'WARNING:.*b_bitcode')
        # Compiler options were added
        for compdb in self.get_compdb():
            if 'module' in compdb['file']:
                self.assertNotIn('-fembed-bitcode', compdb['command'])
            else:
                self.assertIn('-fembed-bitcode', compdb['command'])
        build_ninja = os.path.join(self.builddir, 'build.ninja')
        # Linker options were added
        with open(build_ninja, 'r', encoding='utf-8') as f:
            contents = f.read()
            m = re.search('LINK_ARGS =.*-bitcode_bundle', contents)
        self.assertIsNotNone(m, msg=contents)
        # Try with bitcode disabled
        self.setconf('-Db_bitcode=false')
        # Regenerate build
        self.build()
        for compdb in self.get_compdb():
            self.assertNotIn('-fembed-bitcode', compdb['command'])
        build_ninja = os.path.join(self.builddir, 'build.ninja')
        with open(build_ninja, 'r', encoding='utf-8') as f:
            contents = f.read()
            m = re.search('LINK_ARGS =.*-bitcode_bundle', contents)
        self.assertIsNone(m, msg=contents)

    def test_apple_bitcode_modules(self):
        '''
        Same as above, just for shared_module()
        '''
        testdir = os.path.join(self.common_test_dir, '152 shared module resolving symbol in executable')
        # Ensure that it builds even with bitcode enabled
        self.init(testdir, extra_args='-Db_bitcode=true')
        self.build()
        self.run_tests()

    def _get_darwin_versions(self, fname):
        fname = os.path.join(self.builddir, fname)
        out = subprocess.check_output(['otool', '-L', fname], universal_newlines=True)
        m = re.match(r'.*version (.*), current version (.*)\)', out.split('\n')[1])
        self.assertIsNotNone(m, msg=out)
        return m.groups()

    @skipIfNoPkgconfig
    def test_library_versioning(self):
        '''
        Ensure that compatibility_version and current_version are set correctly
        '''
        testdir = os.path.join(self.platform_test_dir, '2 library versions')
        self.init(testdir)
        self.build()
        targets = {}
        for t in self.introspect('--targets'):
            targets[t['name']] = t['filename'][0] if isinstance(t['filename'], list) else t['filename']
        self.assertEqual(self._get_darwin_versions(targets['some']), ('7.0.0', '7.0.0'))
        self.assertEqual(self._get_darwin_versions(targets['noversion']), ('0.0.0', '0.0.0'))
        self.assertEqual(self._get_darwin_versions(targets['onlyversion']), ('1.0.0', '1.0.0'))
        self.assertEqual(self._get_darwin_versions(targets['onlysoversion']), ('5.0.0', '5.0.0'))
        self.assertEqual(self._get_darwin_versions(targets['intver']), ('2.0.0', '2.0.0'))
        self.assertEqual(self._get_darwin_versions(targets['stringver']), ('2.3.0', '2.3.0'))
        self.assertEqual(self._get_darwin_versions(targets['stringlistver']), ('2.4.0', '2.4.0'))
        self.assertEqual(self._get_darwin_versions(targets['intstringver']), ('1111.0.0', '2.5.0'))
        self.assertEqual(self._get_darwin_versions(targets['stringlistvers']), ('2.6.0', '2.6.1'))

    def test_duplicate_rpath(self):
        testdir = os.path.join(self.unit_test_dir, '10 build_rpath')
        # We purposely pass a duplicate rpath to Meson, in order
        # to ascertain that Meson does not call install_name_tool
        # with duplicate -delete_rpath arguments, which would
        # lead to erroring out on installation
        env = {"LDFLAGS": "-Wl,-rpath,/foo/bar"}
        self.init(testdir, override_envvars=env)
        self.build()
        self.install()

    def test_removing_unused_linker_args(self):
        testdir = os.path.join(self.common_test_dir, '108 has arg')
        env = {'CFLAGS': '-L/tmp -L /var/tmp -headerpad_max_install_names -Wl,-export_dynamic'}
        self.init(testdir, override_envvars=env)


@unittest.skipUnless(not is_windows(), "requires something Unix-like")
class LinuxlikeTests(BasePlatformTests):
    '''
    Tests that should run on Linux, macOS, and *BSD
    '''

    def test_basic_soname(self):
        '''
        Test that the soname is set correctly for shared libraries. This can't
        be an ordinary test case because we need to run `readelf` and actually
        check the soname.
        https://github.com/mesonbuild/meson/issues/785
        '''
        testdir = os.path.join(self.common_test_dir, '4 shared')
        self.init(testdir)
        self.build()
        lib1 = os.path.join(self.builddir, 'libmylib.so')
        soname = get_soname(lib1)
        self.assertEqual(soname, 'libmylib.so')

    def test_custom_soname(self):
        '''
        Test that the soname is set correctly for shared libraries when
        a custom prefix and/or suffix is used. This can't be an ordinary test
        case because we need to run `readelf` and actually check the soname.
        https://github.com/mesonbuild/meson/issues/785
        '''
        testdir = os.path.join(self.common_test_dir, '25 library versions')
        self.init(testdir)
        self.build()
        lib1 = os.path.join(self.builddir, 'prefixsomelib.suffix')
        soname = get_soname(lib1)
        self.assertEqual(soname, 'prefixsomelib.suffix')

    def test_pic(self):
        '''
        Test that -fPIC is correctly added to static libraries when b_staticpic
        is true and not when it is false. This can't be an ordinary test case
        because we need to inspect the compiler database.
        '''
        if is_windows() or is_cygwin() or is_osx():
            raise unittest.SkipTest('PIC not relevant')

        testdir = os.path.join(self.common_test_dir, '3 static')
        self.init(testdir)
        compdb = self.get_compdb()
        self.assertIn('-fPIC', compdb[0]['command'])
        self.setconf('-Db_staticpic=false')
        # Regenerate build
        self.build()
        compdb = self.get_compdb()
        self.assertNotIn('-fPIC', compdb[0]['command'])

    def test_pkgconfig_gen(self):
        '''
        Test that generated pkg-config files can be found and have the correct
        version and link args. This can't be an ordinary test case because we
        need to run pkg-config outside of a Meson build file.
        https://github.com/mesonbuild/meson/issues/889
        '''
        testdir = os.path.join(self.common_test_dir, '47 pkgconfig-gen')
        self.init(testdir)
        env = get_fake_env(testdir, self.builddir, self.prefix)
        kwargs = {'required': True, 'silent': True}
        os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
        foo_dep = PkgConfigDependency('libfoo', env, kwargs)
        self.assertTrue(foo_dep.found())
        self.assertEqual(foo_dep.get_version(), '1.0')
        self.assertIn('-lfoo', foo_dep.get_link_args())
        self.assertEqual(foo_dep.get_pkgconfig_variable('foo', {}), 'bar')
        self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir', {}), '/usr/data')

    def test_pkgconfig_gen_deps(self):
        '''
        Test that generated pkg-config files correctly handle dependencies
        '''
        testdir = os.path.join(self.common_test_dir, '47 pkgconfig-gen')
        self.init(testdir)
        privatedir1 = self.privatedir

        self.new_builddir()
        testdir = os.path.join(self.common_test_dir, '47 pkgconfig-gen', 'dependencies')
        self.init(testdir, override_envvars={'PKG_CONFIG_LIBDIR': privatedir1})
        privatedir2 = self.privatedir

        os.environ
        env = {
            'PKG_CONFIG_LIBDIR': os.pathsep.join([privatedir1, privatedir2]),
            'PKG_CONFIG_SYSTEM_LIBRARY_PATH': '/usr/lib',
        }
        self._run(['pkg-config', 'dependency-test', '--validate'], override_envvars=env)

        # pkg-config strips some duplicated flags so we have to parse the
        # generated file ourself.
        expected = {
            'Requires': 'libexposed',
            'Requires.private': 'libfoo >= 1.0',
            'Libs': '-L${libdir} -llibmain -pthread -lcustom',
            'Libs.private': '-lcustom2 -L${libdir} -llibinternal',
            'Cflags': '-I${includedir} -pthread -DCUSTOM',
        }
        if is_osx() or is_haiku():
            expected['Cflags'] = expected['Cflags'].replace('-pthread ', '')
        with open(os.path.join(privatedir2, 'dependency-test.pc')) as f:
            matched_lines = 0
            for line in f:
                parts = line.split(':', 1)
                if parts[0] in expected:
                    key = parts[0]
                    val = parts[1].strip()
                    expected_val = expected[key]
                    self.assertEqual(expected_val, val)
                    matched_lines += 1
            self.assertEqual(len(expected), matched_lines)

        cmd = ['pkg-config', 'requires-test']
        out = self._run(cmd + ['--print-requires'], override_envvars=env).strip().split('\n')
        if not is_openbsd():
            self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo >= 1.0', 'libhello']))
        else:
            self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo>=1.0', 'libhello']))

        cmd = ['pkg-config', 'requires-private-test']
        out = self._run(cmd + ['--print-requires-private'], override_envvars=env).strip().split('\n')
        if not is_openbsd():
            self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo >= 1.0', 'libhello']))
        else:
            self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo>=1.0', 'libhello']))

        cmd = ['pkg-config', 'pub-lib-order']
        out = self._run(cmd + ['--libs'], override_envvars=env).strip().split()
        self.assertEqual(out, ['-llibmain2', '-llibinternal'])

    def test_pkg_unfound(self):
        testdir = os.path.join(self.unit_test_dir, '23 unfound pkgconfig')
        self.init(testdir)
        with open(os.path.join(self.privatedir, 'somename.pc')) as f:
            pcfile = f.read()
        self.assertFalse('blub_blob_blib' in pcfile)

    def test_vala_c_warnings(self):
        '''
        Test that no warnings are emitted for C code generated by Vala. This
        can't be an ordinary test case because we need to inspect the compiler
        database.
        https://github.com/mesonbuild/meson/issues/864
        '''
        if not shutil.which('valac'):
            raise unittest.SkipTest('valac not installed.')
        testdir = os.path.join(self.vala_test_dir, '5 target glib')
        self.init(testdir)
        compdb = self.get_compdb()
        vala_command = None
        c_command = None
        for each in compdb:
            if each['file'].endswith('GLib.Thread.c'):
                vala_command = each['command']
            elif each['file'].endswith('GLib.Thread.vala'):
                continue
            elif each['file'].endswith('retcode.c'):
                c_command = each['command']
            else:
                m = 'Unknown file {!r} in vala_c_warnings test'.format(each['file'])
                raise AssertionError(m)
        self.assertIsNotNone(vala_command)
        self.assertIsNotNone(c_command)
        # -w suppresses all warnings, should be there in Vala but not in C
        self.assertIn(" -w ", vala_command)
        self.assertNotIn(" -w ", c_command)
        # -Wall enables all warnings, should be there in C but not in Vala
        self.assertNotIn(" -Wall ", vala_command)
        self.assertIn(" -Wall ", c_command)
        # -Werror converts warnings to errors, should always be there since it's
        # injected by an unrelated piece of code and the project has werror=true
        self.assertIn(" -Werror ", vala_command)
        self.assertIn(" -Werror ", c_command)

    @skipIfNoPkgconfig
    def test_qtdependency_pkgconfig_detection(self):
        '''
        Test that qt4 and qt5 detection with pkgconfig works.
        '''
        # Verify Qt4 or Qt5 can be found with pkg-config
        qt4 = subprocess.call(['pkg-config', '--exists', 'QtCore'])
        qt5 = subprocess.call(['pkg-config', '--exists', 'Qt5Core'])
        testdir = os.path.join(self.framework_test_dir, '4 qt')
        self.init(testdir, extra_args=['-Dmethod=pkg-config'])
        # Confirm that the dependency was found with pkg-config
        mesonlog = self.get_meson_log()
        if qt4 == 0:
            self.assertRegex('\n'.join(mesonlog),
                             r'Run-time dependency qt4 \(modules: Core\) found: YES 4.* \(pkg-config\)\n')
        if qt5 == 0:
            self.assertRegex('\n'.join(mesonlog),
                             r'Run-time dependency qt5 \(modules: Core\) found: YES 5.* \(pkg-config\)\n')

    @skip_if_not_base_option('b_sanitize')
    def test_generate_gir_with_address_sanitizer(self):
        if is_cygwin():
            raise unittest.SkipTest('asan not available on Cygwin')
        if is_openbsd():
            raise unittest.SkipTest('-fsanitize=address is not supported on OpenBSD')

        testdir = os.path.join(self.framework_test_dir, '7 gnome')
        self.init(testdir, extra_args=['-Db_sanitize=address', '-Db_lundef=false'])
        self.build()

    def test_qt5dependency_qmake_detection(self):
        '''
        Test that qt5 detection with qmake works. This can't be an ordinary
        test case because it involves setting the environment.
        '''
        # Verify that qmake is for Qt5
        if not shutil.which('qmake-qt5'):
            if not shutil.which('qmake'):
                raise unittest.SkipTest('QMake not found')
            output = subprocess.getoutput('qmake --version')
            if 'Qt version 5' not in output:
                raise unittest.SkipTest('Qmake found, but it is not for Qt 5.')
        # Disable pkg-config codepath and force searching with qmake/qmake-qt5
        testdir = os.path.join(self.framework_test_dir, '4 qt')
        self.init(testdir, extra_args=['-Dmethod=qmake'])
        # Confirm that the dependency was found with qmake
        mesonlog = self.get_meson_log()
        self.assertRegex('\n'.join(mesonlog),
                         r'Run-time dependency qt5 \(modules: Core\) found: YES .* \((qmake|qmake-qt5)\)\n')

    def _test_soname_impl(self, libpath, install):
        if is_cygwin() or is_osx():
            raise unittest.SkipTest('Test only applicable to ELF and linuxlike sonames')

        testdir = os.path.join(self.unit_test_dir, '1 soname')
        self.init(testdir)
        self.build()
        if install:
            self.install()

        # File without aliases set.
        nover = os.path.join(libpath, 'libnover.so')
        self.assertPathExists(nover)
        self.assertFalse(os.path.islink(nover))
        self.assertEqual(get_soname(nover), 'libnover.so')
        self.assertEqual(len(glob(nover[:-3] + '*')), 1)

        # File with version set
        verset = os.path.join(libpath, 'libverset.so')
        self.assertPathExists(verset + '.4.5.6')
        self.assertEqual(os.readlink(verset), 'libverset.so.4')
        self.assertEqual(get_soname(verset), 'libverset.so.4')
        self.assertEqual(len(glob(verset[:-3] + '*')), 3)

        # File with soversion set
        soverset = os.path.join(libpath, 'libsoverset.so')
        self.assertPathExists(soverset + '.1.2.3')
        self.assertEqual(os.readlink(soverset), 'libsoverset.so.1.2.3')
        self.assertEqual(get_soname(soverset), 'libsoverset.so.1.2.3')
        self.assertEqual(len(glob(soverset[:-3] + '*')), 2)

        # File with version and soversion set to same values
        settosame = os.path.join(libpath, 'libsettosame.so')
        self.assertPathExists(settosame + '.7.8.9')
        self.assertEqual(os.readlink(settosame), 'libsettosame.so.7.8.9')
        self.assertEqual(get_soname(settosame), 'libsettosame.so.7.8.9')
        self.assertEqual(len(glob(settosame[:-3] + '*')), 2)

        # File with version and soversion set to different values
        bothset = os.path.join(libpath, 'libbothset.so')
        self.assertPathExists(bothset + '.1.2.3')
        self.assertEqual(os.readlink(bothset), 'libbothset.so.1.2.3')
        self.assertEqual(os.readlink(bothset + '.1.2.3'), 'libbothset.so.4.5.6')
        self.assertEqual(get_soname(bothset), 'libbothset.so.1.2.3')
        self.assertEqual(len(glob(bothset[:-3] + '*')), 3)

    def test_soname(self):
        self._test_soname_impl(self.builddir, False)

    def test_installed_soname(self):
        libdir = self.installdir + os.path.join(self.prefix, self.libdir)
        self._test_soname_impl(libdir, True)

    def test_compiler_check_flags_order(self):
        '''
        Test that compiler check flags override all other flags. This can't be
        an ordinary test case because it needs the environment to be set.
        '''
        testdir = os.path.join(self.common_test_dir, '39 has function')
        env = get_fake_env(testdir, self.builddir, self.prefix)
        cpp = env.detect_cpp_compiler(MachineChoice.HOST)
        Oflag = '-O3'
        OflagCPP = Oflag
        if cpp.get_id() in ('clang', 'gcc'):
            # prevent developers from adding "int main(int argc, char **argv)"
            # to small Meson checks unless these parameters are actually used
            OflagCPP += ' -Werror=unused-parameter'
        env = {'CFLAGS': Oflag,
               'CXXFLAGS': OflagCPP}
        self.init(testdir, override_envvars=env)
        cmds = self.get_meson_log_compiler_checks()
        for cmd in cmds:
            if cmd[0] == 'ccache':
                cmd = cmd[1:]
            # Verify that -I flags from the `args` kwarg are first
            # This is set in the '39 has function' test case
            self.assertEqual(cmd[1], '-I/tmp')
            # Verify that -O3 set via the environment is overridden by -O0
            Oargs = [arg for arg in cmd if arg.startswith('-O')]
            self.assertEqual(Oargs, [Oflag, '-O0'])

    def _test_stds_impl(self, testdir, compiler, p: str):
        lang_std = p + '_std'

        has_cpp17 = (compiler.get_id() not in {'clang', 'gcc'} or
                     compiler.get_id() == 'clang' and _clang_at_least(compiler, '>=5.0.0', '>=9.1') or
                     compiler.get_id() == 'gcc' and version_compare(compiler.version, '>=5.0.0'))
        has_cpp2a_c17 = (compiler.get_id() not in {'clang', 'gcc'} or
                         compiler.get_id() == 'clang' and _clang_at_least(compiler, '>=6.0.0', '>=10.0') or
                         compiler.get_id() == 'gcc' and version_compare(compiler.version, '>=8.0.0'))
        has_c18 = (compiler.get_id() not in {'clang', 'gcc'} or
                   compiler.get_id() == 'clang' and _clang_at_least(compiler, '>=8.0.0', '>=11.0') or
                   compiler.get_id() == 'gcc' and version_compare(compiler.version, '>=8.0.0'))
        # Check that all the listed -std=xxx options for this compiler work just fine when used
        # https://en.wikipedia.org/wiki/Xcode#Latest_versions
        # https://www.gnu.org/software/gcc/projects/cxx-status.html
        for v in compiler.get_options()[lang_std].choices:
            # we do it like this to handle gnu++17,c++17 and gnu17,c17 cleanly
            # thus, C++ first
            if '++17' in v and not has_cpp17:
                continue
            elif '++2a' in v and not has_cpp2a_c17:  # https://en.cppreference.com/w/cpp/compiler_support
                continue
            # now C
            elif '17' in v and not has_cpp2a_c17:
                continue
            elif '18' in v and not has_c18:
                continue
            std_opt = '{}={}'.format(lang_std, v)
            self.init(testdir, extra_args=['-D' + std_opt])
            cmd = self.get_compdb()[0]['command']
            # c++03 and gnu++03 are not understood by ICC, don't try to look for them
            skiplist = frozenset([
                ('intel', 'c++03'),
                ('intel', 'gnu++03')])
            if v != 'none' and not (compiler.get_id(), v) in skiplist:
                cmd_std = " -std={} ".format(v)
                self.assertIn(cmd_std, cmd)
            try:
                self.build()
            except Exception:
                print('{} was {!r}'.format(lang_std, v))
                raise
            self.wipe()
        # Check that an invalid std option in CFLAGS/CPPFLAGS fails
        # Needed because by default ICC ignores invalid options
        cmd_std = '-std=FAIL'
        if p == 'c':
            env_flag_name = 'CFLAGS'
        elif p == 'cpp':
            env_flag_name = 'CXXFLAGS'
        else:
            raise NotImplementedError('Language {} not defined.'.format(p))
        env = {}
        env[env_flag_name] = cmd_std
        with self.assertRaises((subprocess.CalledProcessError, mesonbuild.mesonlib.EnvironmentException),
                               msg='C compiler should have failed with -std=FAIL'):
            self.init(testdir, override_envvars = env)
            # ICC won't fail in the above because additional flags are needed to
            # make unknown -std=... options errors.
            self.build()

    def test_compiler_c_stds(self):
        '''
        Test that C stds specified for this compiler can all be used. Can't be
        an ordinary test because it requires passing options to meson.
        '''
        testdir = os.path.join(self.common_test_dir, '1 trivial')
        env = get_fake_env(testdir, self.builddir, self.prefix)
        cc = env.detect_c_compiler(MachineChoice.HOST)
        self._test_stds_impl(testdir, cc, 'c')

    def test_compiler_cpp_stds(self):
        '''
        Test that C++ stds specified for this compiler can all be used. Can't
        be an ordinary test because it requires passing options to meson.
        '''
        testdir = os.path.join(self.common_test_dir, '2 cpp')
        env = get_fake_env(testdir, self.builddir, self.prefix)
        cpp = env.detect_cpp_compiler(MachineChoice.HOST)
        self._test_stds_impl(testdir, cpp, 'cpp')

    def test_unity_subproj(self):
        testdir = os.path.join(self.common_test_dir, '45 subproject')
        self.init(testdir, extra_args='--unity=subprojects')
        simpletest_id = Target.construct_id_from_path('subprojects/sublib', 'simpletest', '@exe')
        self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib', simpletest_id, 'simpletest-unity.c'))
        sublib_id = Target.construct_id_from_path('subprojects/sublib', 'sublib', '@sha')
        self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib', sublib_id, 'sublib-unity.c'))
        self.assertPathDoesNotExist(os.path.join(self.builddir, 'user@exe/user-unity.c'))
        self.build()

    def test_installed_modes(self):
        '''
        Test that files installed by these tests have the correct permissions.
        Can't be an ordinary test because our installed_files.txt is very basic.
        '''
        # Test file modes
        testdir = os.path.join(self.common_test_dir, '12 data')
        self.init(testdir)
        self.install()

        f = os.path.join(self.installdir, 'etc', 'etcfile.dat')
        found_mode = stat.filemode(os.stat(f).st_mode)
        want_mode = 'rw------T'
        self.assertEqual(want_mode, found_mode[1:])

        f = os.path.join(self.installdir, 'usr', 'bin', 'runscript.sh')
        statf = os.stat(f)
        found_mode = stat.filemode(statf.st_mode)
        want_mode = 'rwxr-sr-x'
        self.assertEqual(want_mode, found_mode[1:])
        if os.getuid() == 0:
            # The chown failed nonfatally if we're not root
            self.assertEqual(0, statf.st_uid)
            self.assertEqual(0, statf.st_gid)

        f = os.path.join(self.installdir, 'usr', 'share', 'progname',
                         'fileobject_datafile.dat')
        orig = os.path.join(testdir, 'fileobject_datafile.dat')
        statf = os.stat(f)
        statorig = os.stat(orig)
        found_mode = stat.filemode(statf.st_mode)
        orig_mode = stat.filemode(statorig.st_mode)
        self.assertEqual(orig_mode[1:], found_mode[1:])
        self.assertEqual(os.getuid(), statf.st_uid)
        if os.getuid() == 0:
            # The chown failed nonfatally if we're not root
            self.assertEqual(0, statf.st_gid)

        self.wipe()
        # Test directory modes
        testdir = os.path.join(self.common_test_dir, '62 install subdir')
        self.init(testdir)
        self.install()

        f = os.path.join(self.installdir, 'usr', 'share', 'sub1', 'second.dat')
        statf = os.stat(f)
        found_mode = stat.filemode(statf.st_mode)
        want_mode = 'rwxr-x--t'
        self.assertEqual(want_mode, found_mode[1:])
        if os.getuid() == 0:
            # The chown failed nonfatally if we're not root
            self.assertEqual(0, statf.st_uid)

    def test_installed_modes_extended(self):
        '''
        Test that files are installed with correct permissions using install_mode.
        '''
        testdir = os.path.join(self.common_test_dir, '195 install_mode')
        self.init(testdir)
        self.build()
        self.install()

        for fsobj, want_mode in [
                ('bin', 'drwxr-x---'),
                ('bin/runscript.sh', '-rwxr-sr-x'),
                ('bin/trivialprog', '-rwxr-sr-x'),
                ('include', 'drwxr-x---'),
                ('include/config.h', '-rw-rwSr--'),
                ('include/rootdir.h', '-r--r--r-T'),
                ('lib', 'drwxr-x---'),
                ('lib/libstat.a', '-rw---Sr--'),
                ('share', 'drwxr-x---'),
                ('share/man', 'drwxr-x---'),
                ('share/man/man1', 'drwxr-x---'),
                ('share/man/man1/foo.1', '-r--r--r-T'),
                ('share/sub1', 'drwxr-x---'),
                ('share/sub1/second.dat', '-rwxr-x--t'),
                ('subdir', 'drwxr-x---'),
                ('subdir/data.dat', '-rw-rwSr--'),
        ]:
            f = os.path.join(self.installdir, 'usr', *fsobj.split('/'))
            found_mode = stat.filemode(os.stat(f).st_mode)
            self.assertEqual(want_mode, found_mode,
                             msg=('Expected file %s to have mode %s but found %s instead.' %
                                  (fsobj, want_mode, found_mode)))
        # Ensure that introspect --installed works on all types of files
        # FIXME: also verify the files list
        self.introspect('--installed')

    def test_install_umask(self):
        '''
        Test that files are installed with correct permissions using default
        install umask of 022, regardless of the umask at time the worktree
        was checked out or the build was executed.
        '''
        # Copy source tree to a temporary directory and change permissions
        # there to simulate a checkout with umask 002.
        orig_testdir = os.path.join(self.unit_test_dir, '26 install umask')
        # Create a new testdir under tmpdir.
        tmpdir = os.path.realpath(tempfile.mkdtemp())
        self.addCleanup(windows_proof_rmtree, tmpdir)
        testdir = os.path.join(tmpdir, '26 install umask')
        # Copy the tree using shutil.copyfile, which will use the current umask
        # instead of preserving permissions of the old tree.
        save_umask = os.umask(0o002)
        self.addCleanup(os.umask, save_umask)
        shutil.copytree(orig_testdir, testdir, copy_function=shutil.copyfile)
        # Preserve the executable status of subdir/sayhello though.
        os.chmod(os.path.join(testdir, 'subdir', 'sayhello'), 0o775)
        self.init(testdir)
        # Run the build under a 027 umask now.
        os.umask(0o027)
        self.build()
        # And keep umask 027 for the install step too.
        self.install()

        for executable in [
                'bin/prog',
                'share/subdir/sayhello',
        ]:
            f = os.path.join(self.installdir, 'usr', *executable.split('/'))
            found_mode = stat.filemode(os.stat(f).st_mode)
            want_mode = '-rwxr-xr-x'
            self.assertEqual(want_mode, found_mode,
                             msg=('Expected file %s to have mode %s but found %s instead.' %
                                  (executable, want_mode, found_mode)))

        for directory in [
                'usr',
                'usr/bin',
                'usr/include',
                'usr/share',
                'usr/share/man',
                'usr/share/man/man1',
                'usr/share/subdir',
        ]:
            f = os.path.join(self.installdir, *directory.split('/'))
            found_mode = stat.filemode(os.stat(f).st_mode)
            want_mode = 'drwxr-xr-x'
            self.assertEqual(want_mode, found_mode,
                             msg=('Expected directory %s to have mode %s but found %s instead.' %
                                  (directory, want_mode, found_mode)))

        for datafile in [
                'include/sample.h',
                'share/datafile.cat',
                'share/file.dat',
                'share/man/man1/prog.1',
                'share/subdir/datafile.dog',
        ]:
            f = os.path.join(self.installdir, 'usr', *datafile.split('/'))
            found_mode = stat.filemode(os.stat(f).st_mode)
            want_mode = '-rw-r--r--'
            self.assertEqual(want_mode, found_mode,
                             msg=('Expected file %s to have mode %s but found %s instead.' %
                                  (datafile, want_mode, found_mode)))

    def test_cpp_std_override(self):
        testdir = os.path.join(self.unit_test_dir, '6 std override')
        self.init(testdir)
        compdb = self.get_compdb()
        # Don't try to use -std=c++03 as a check for the
        # presence of a compiler flag, as ICC does not
        # support it.
        for i in compdb:
            if 'prog98' in i['file']:
                c98_comp = i['command']
            if 'prog11' in i['file']:
                c11_comp = i['command']
            if 'progp' in i['file']:
                plain_comp = i['command']
        self.assertNotEqual(len(plain_comp), 0)
        self.assertIn('-std=c++98', c98_comp)
        self.assertNotIn('-std=c++11', c98_comp)
        self.assertIn('-std=c++11', c11_comp)
        self.assertNotIn('-std=c++98', c11_comp)
        self.assertNotIn('-std=c++98', plain_comp)
        self.assertNotIn('-std=c++11', plain_comp)
        # Now werror
        self.assertIn('-Werror', plain_comp)
        self.assertNotIn('-Werror', c98_comp)

    def test_run_installed(self):
        if is_cygwin() or is_osx():
            raise unittest.SkipTest('LD_LIBRARY_PATH and RPATH not applicable')

        testdir = os.path.join(self.unit_test_dir, '7 run installed')
        self.init(testdir)
        self.build()
        self.install()
        installed_exe = os.path.join(self.installdir, 'usr/bin/prog')
        installed_libdir = os.path.join(self.installdir, 'usr/foo')
        installed_lib = os.path.join(installed_libdir, 'libfoo.so')
        self.assertTrue(os.path.isfile(installed_exe))
        self.assertTrue(os.path.isdir(installed_libdir))
        self.assertTrue(os.path.isfile(installed_lib))
        # Must fail when run without LD_LIBRARY_PATH to ensure that
        # rpath has been properly stripped rather than pointing to the builddir.
        self.assertNotEqual(subprocess.call(installed_exe, stderr=subprocess.DEVNULL), 0)
        # When LD_LIBRARY_PATH is set it should start working.
        # For some reason setting LD_LIBRARY_PATH in os.environ fails
        # when all tests are run (but works when only this test is run),
        # but doing this explicitly works.
        env = os.environ.copy()
        env['LD_LIBRARY_PATH'] = ':'.join([installed_libdir, env.get('LD_LIBRARY_PATH', '')])
        self.assertEqual(subprocess.call(installed_exe, env=env), 0)
        # Ensure that introspect --installed works
        installed = self.introspect('--installed')
        for v in installed.values():
            self.assertTrue('prog' in v or 'foo' in v)

    @skipIfNoPkgconfig
    def test_order_of_l_arguments(self):
        testdir = os.path.join(self.unit_test_dir, '8 -L -l order')
        self.init(testdir, override_envvars={'PKG_CONFIG_PATH': testdir})
        # NOTE: .pc file has -Lfoo -lfoo -Lbar -lbar but pkg-config reorders
        # the flags before returning them to -Lfoo -Lbar -lfoo -lbar
        # but pkgconf seems to not do that. Sigh. Support both.
        expected_order = [('-L/me/first', '-lfoo1'),
                          ('-L/me/second', '-lfoo2'),
                          ('-L/me/first', '-L/me/second'),
                          ('-lfoo1', '-lfoo2'),
                          ('-L/me/second', '-L/me/third'),
                          ('-L/me/third', '-L/me/fourth',),
                          ('-L/me/third', '-lfoo3'),
                          ('-L/me/fourth', '-lfoo4'),
                          ('-lfoo3', '-lfoo4'),
                          ]
        with open(os.path.join(self.builddir, 'build.ninja')) as ifile:
            for line in ifile:
                if expected_order[0][0] in line:
                    for first, second in expected_order:
                        self.assertLess(line.index(first), line.index(second))
                    return
        raise RuntimeError('Linker entries not found in the Ninja file.')

    def test_introspect_dependencies(self):
        '''
        Tests that mesonintrospect --dependencies returns expected output.
        '''
        testdir = os.path.join(self.framework_test_dir, '7 gnome')
        self.init(testdir)
        glib_found = False
        gobject_found = False
        deps = self.introspect('--dependencies')
        self.assertIsInstance(deps, list)
        for dep in deps:
            self.assertIsInstance(dep, dict)
            self.assertIn('name', dep)
            self.assertIn('compile_args', dep)
            self.assertIn('link_args', dep)
            if dep['name'] == 'glib-2.0':
                glib_found = True
            elif dep['name'] == 'gobject-2.0':
                gobject_found = True
        self.assertTrue(glib_found)
        self.assertTrue(gobject_found)
        if subprocess.call(['pkg-config', '--exists', 'glib-2.0 >= 2.56.2']) != 0:
            raise unittest.SkipTest('glib >= 2.56.2 needed for the rest')
        targets = self.introspect('--targets')
        docbook_target = None
        for t in targets:
            if t['name'] == 'generated-gdbus-docbook':
                docbook_target = t
                break
        self.assertIsInstance(docbook_target, dict)
        self.assertEqual(os.path.basename(t['filename'][0]), 'generated-gdbus-doc-' + os.path.basename(t['target_sources'][0]['sources'][0]))

    def test_build_rpath(self):
        if is_cygwin():
            raise unittest.SkipTest('Windows PE/COFF binaries do not use RPATH')
        testdir = os.path.join(self.unit_test_dir, '10 build_rpath')
        self.init(testdir)
        self.build()
        # C program RPATH
        build_rpath = get_rpath(os.path.join(self.builddir, 'prog'))
        self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar')
        self.install()
        install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/prog'))
        self.assertEqual(install_rpath, '/baz')
        # C++ program RPATH
        build_rpath = get_rpath(os.path.join(self.builddir, 'progcxx'))
        self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar')
        self.install()
        install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/progcxx'))
        self.assertEqual(install_rpath, 'baz')

    @skip_if_not_base_option('b_sanitize')
    def test_pch_with_address_sanitizer(self):
        if is_cygwin():
            raise unittest.SkipTest('asan not available on Cygwin')
        if is_openbsd():
            raise unittest.SkipTest('-fsanitize=address is not supported on OpenBSD')

        testdir = os.path.join(self.common_test_dir, '13 pch')
        self.init(testdir, extra_args=['-Db_sanitize=address', '-Db_lundef=false'])
        self.build()
        compdb = self.get_compdb()
        for i in compdb:
            self.assertIn("-fsanitize=address", i["command"])

    def test_coverage(self):
        gcovr_exe, gcovr_new_rootdir = mesonbuild.environment.detect_gcovr()
        if not gcovr_exe:
            raise unittest.SkipTest('gcovr not found')
        if not shutil.which('genhtml') and not gcovr_new_rootdir:
            raise unittest.SkipTest('genhtml not found and gcovr is too old')
        if 'clang' in os.environ.get('CC', ''):
            # We need to use llvm-cov instead of gcovr with clang
            raise unittest.SkipTest('Coverage does not work with clang right now, help wanted!')
        testdir = os.path.join(self.common_test_dir, '1 trivial')
        self.init(testdir, extra_args=['-Db_coverage=true'])
        self.build()
        self.run_tests()
        self.run_target('coverage-html')

    def test_cross_find_program(self):
        testdir = os.path.join(self.unit_test_dir, '11 cross prog')
        crossfile = tempfile.NamedTemporaryFile(mode='w')
        print(os.path.join(testdir, 'some_cross_tool.py'))
        crossfile.write(textwrap.dedent('''\
            [binaries]
            c = '/usr/bin/{1}'
            ar = '/usr/bin/ar'
            strip = '/usr/bin/ar'
            sometool.py = ['{0}']
            someothertool.py = '{0}'

            [properties]

            [host_machine]
            system = 'linux'
            cpu_family = 'arm'
            cpu = 'armv7' # Not sure if correct.
            endian = 'little'
            ''').format(os.path.join(testdir, 'some_cross_tool.py'),
                        'gcc' if is_sunos() else 'cc'))
        crossfile.flush()
        self.meson_cross_file = crossfile.name
        self.init(testdir)

    def test_reconfigure(self):
        testdir = os.path.join(self.unit_test_dir, '13 reconfigure')
        self.init(testdir, extra_args=['-Db_coverage=true'], default_args=False)
        self.build('reconfigure')

    def test_vala_generated_source_buildir_inside_source_tree(self):
        '''
        Test that valac outputs generated C files in the expected location when
        the builddir is a subdir of the source tree.
        '''
        if not shutil.which('valac'):
            raise unittest.SkipTest('valac not installed.')

        testdir = os.path.join(self.vala_test_dir, '8 generated sources')
        newdir = os.path.join(self.builddir, 'srctree')
        shutil.copytree(testdir, newdir)
        testdir = newdir
        # New builddir
        builddir = os.path.join(testdir, 'subdir/_build')
        os.makedirs(builddir, exist_ok=True)
        self.change_builddir(builddir)
        self.init(testdir)
        self.build()

    def test_old_gnome_module_codepaths(self):
        '''
        A lot of code in the GNOME module is conditional on the version of the
        glib tools that are installed, and breakages in the old code can slip
        by once the CI has a newer glib version. So we force the GNOME module
        to pretend that it's running on an ancient glib so the fallback code is
        also tested.
        '''
        testdir = os.path.join(self.framework_test_dir, '7 gnome')
        mesonbuild.modules.gnome.native_glib_version = '2.20'
        env = {'MESON_UNIT_TEST_PRETEND_GLIB_OLD': "1"}
        try:
            self.init(testdir,
                      inprocess=True,
                      override_envvars=env)
            self.build(override_envvars=env)
        finally:
            mesonbuild.modules.gnome.native_glib_version = None

    @skipIfNoPkgconfig
    def test_pkgconfig_usage(self):
        testdir1 = os.path.join(self.unit_test_dir, '27 pkgconfig usage/dependency')
        testdir2 = os.path.join(self.unit_test_dir, '27 pkgconfig usage/dependee')
        if subprocess.call(['pkg-config', '--cflags', 'glib-2.0'],
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL) != 0:
            raise unittest.SkipTest('Glib 2.0 dependency not available.')
        with tempfile.TemporaryDirectory() as tempdirname:
            self.init(testdir1, extra_args=['--prefix=' + tempdirname, '--libdir=lib'], default_args=False)
            self.install(use_destdir=False)
            shutil.rmtree(self.builddir)
            os.mkdir(self.builddir)
            pkg_dir = os.path.join(tempdirname, 'lib/pkgconfig')
            self.assertTrue(os.path.exists(os.path.join(pkg_dir, 'libpkgdep.pc')))
            lib_dir = os.path.join(tempdirname, 'lib')
            myenv = os.environ.copy()
            myenv['PKG_CONFIG_PATH'] = pkg_dir
            # Private internal libraries must not leak out.
            pkg_out = subprocess.check_output(['pkg-config', '--static', '--libs', 'libpkgdep'], env=myenv)
            self.assertFalse(b'libpkgdep-int' in pkg_out, 'Internal library leaked out.')
            # Dependencies must not leak to cflags when building only a shared library.
            pkg_out = subprocess.check_output(['pkg-config', '--cflags', 'libpkgdep'], env=myenv)
            self.assertFalse(b'glib' in pkg_out, 'Internal dependency leaked to headers.')
            # Test that the result is usable.
            self.init(testdir2, override_envvars=myenv)
            self.build(override_envvars=myenv)
            myenv = os.environ.copy()
            myenv['LD_LIBRARY_PATH'] = ':'.join([lib_dir, myenv.get('LD_LIBRARY_PATH', '')])
            if is_cygwin():
                bin_dir = os.path.join(tempdirname, 'bin')
                myenv['PATH'] = bin_dir + os.pathsep + myenv['PATH']
            self.assertTrue(os.path.isdir(lib_dir))
            test_exe = os.path.join(self.builddir, 'pkguser')
            self.assertTrue(os.path.isfile(test_exe))
            subprocess.check_call(test_exe, env=myenv)

    @skipIfNoPkgconfig
    def test_pkgconfig_relative_paths(self):
        testdir = os.path.join(self.unit_test_dir, '62 pkgconfig relative paths')
        pkg_dir = os.path.join(testdir, 'pkgconfig')
        self.assertTrue(os.path.exists(os.path.join(pkg_dir, 'librelativepath.pc')))

        env = get_fake_env(testdir, self.builddir, self.prefix)
        env.coredata.set_options({'pkg_config_path': pkg_dir}, subproject='')
        kwargs = {'required': True, 'silent': True}
        relative_path_dep = PkgConfigDependency('librelativepath', env, kwargs)
        self.assertTrue(relative_path_dep.found())

        # Ensure link_args are properly quoted
        libpath = Path(self.builddir) / '../relativepath/lib'
        link_args = ['-L' + libpath.as_posix(), '-lrelativepath']
        self.assertEqual(relative_path_dep.get_link_args(), link_args)

    @skipIfNoPkgconfig
    def test_pkgconfig_internal_libraries(self):
        '''
        '''
        with tempfile.TemporaryDirectory() as tempdirname:
            # build library
            testdirbase = os.path.join(self.unit_test_dir, '32 pkgconfig use libraries')
            testdirlib = os.path.join(testdirbase, 'lib')
            self.init(testdirlib, extra_args=['--prefix=' + tempdirname,
                                              '--libdir=lib',
                                              '--default-library=static'], default_args=False)
            self.build()
            self.install(use_destdir=False)

            # build user of library
            pkg_dir = os.path.join(tempdirname, 'lib/pkgconfig')
            self.new_builddir()
            self.init(os.path.join(testdirbase, 'app'),
                      override_envvars={'PKG_CONFIG_PATH': pkg_dir})
            self.build()

    @skipIfNoPkgconfig
    def test_static_archive_stripping(self):
        '''
        Check that Meson produces valid static archives with --strip enabled
        '''
        with tempfile.TemporaryDirectory() as tempdirname:
            testdirbase = os.path.join(self.unit_test_dir, '68 static archive stripping')

            # build lib
            self.new_builddir()
            testdirlib = os.path.join(testdirbase, 'lib')
            testlibprefix = os.path.join(tempdirname, 'libprefix')
            self.init(testdirlib, extra_args=['--prefix=' + testlibprefix,
                                              '--libdir=lib',
                                              '--default-library=static',
                                              '--buildtype=debug',
                                              '--strip'], default_args=False)
            self.build()
            self.install(use_destdir=False)

            # build executable (uses lib, fails if static archive has been stripped incorrectly)
            pkg_dir = os.path.join(testlibprefix, 'lib/pkgconfig')
            self.new_builddir()
            self.init(os.path.join(testdirbase, 'app'),
                      override_envvars={'PKG_CONFIG_PATH': pkg_dir})
            self.build()

    @skipIfNoPkgconfig
    def test_pkgconfig_formatting(self):
        testdir = os.path.join(self.unit_test_dir, '38 pkgconfig format')
        self.init(testdir)
        myenv = os.environ.copy()
        myenv['PKG_CONFIG_PATH'] = self.privatedir
        stdo = subprocess.check_output(['pkg-config', '--libs-only-l', 'libsomething'], env=myenv)
        deps = [b'-lgobject-2.0', b'-lgio-2.0', b'-lglib-2.0', b'-lsomething']
        if is_windows() or is_cygwin() or is_osx() or is_openbsd():
            # On Windows, libintl is a separate library
            deps.append(b'-lintl')
        self.assertEqual(set(deps), set(stdo.split()))

    @skipIfNoPkgconfig
    @skip_if_not_language('cs')
    def test_pkgconfig_csharp_library(self):
        testdir = os.path.join(self.unit_test_dir, '50 pkgconfig csharp library')
        self.init(testdir)
        myenv = os.environ.copy()
        myenv['PKG_CONFIG_PATH'] = self.privatedir
        stdo = subprocess.check_output(['pkg-config', '--libs', 'libsomething'], env=myenv)

        self.assertEqual("-r/usr/lib/libsomething.dll", str(stdo.decode('ascii')).strip())

    @skipIfNoPkgconfig
    def test_pkgconfig_link_order(self):
        '''
        Test that libraries are listed before their dependencies.
        '''
        testdir = os.path.join(self.unit_test_dir, '53 pkgconfig static link order')
        self.init(testdir)
        myenv = os.environ.copy()
        myenv['PKG_CONFIG_PATH'] = self.privatedir
        stdo = subprocess.check_output(['pkg-config', '--libs', 'libsomething'], env=myenv)
        deps = stdo.split()
        self.assertTrue(deps.index(b'-lsomething') < deps.index(b'-ldependency'))

    def test_deterministic_dep_order(self):
        '''
        Test that the dependencies are always listed in a deterministic order.
        '''
        testdir = os.path.join(self.unit_test_dir, '43 dep order')
        self.init(testdir)
        with open(os.path.join(self.builddir, 'build.ninja')) as bfile:
            for line in bfile:
                if 'build myexe:' in line or 'build myexe.exe:' in line:
                    self.assertIn('liblib1.a liblib2.a', line)
                    return
        raise RuntimeError('Could not find the build rule')

    def test_deterministic_rpath_order(self):
        '''
        Test that the rpaths are always listed in a deterministic order.
        '''
        if is_cygwin():
            raise unittest.SkipTest('rpath are not used on Cygwin')
        testdir = os.path.join(self.unit_test_dir, '42 rpath order')
        self.init(testdir)
        if is_osx():
            rpathre = re.compile(r'-rpath,.*/subprojects/sub1.*-rpath,.*/subprojects/sub2')
        else:
            rpathre = re.compile(r'-rpath,\$\$ORIGIN/subprojects/sub1:\$\$ORIGIN/subprojects/sub2')
        with open(os.path.join(self.builddir, 'build.ninja')) as bfile:
            for line in bfile:
                if '-rpath' in line:
                    self.assertRegex(line, rpathre)
                    return
        raise RuntimeError('Could not find the rpath')

    def test_override_with_exe_dep(self):
        '''
        Test that we produce the correct dependencies when a program is overridden with an executable.
        '''
        testdir = os.path.join(self.common_test_dir, '201 override with exe')
        self.init(testdir)
        with open(os.path.join(self.builddir, 'build.ninja')) as bfile:
            for line in bfile:
                if 'main1.c:' in line or 'main2.c:' in line:
                    self.assertIn('| subprojects/sub/foobar', line)

    @skipIfNoPkgconfig
    def test_usage_external_library(self):
        '''
        Test that uninstalled usage of an external library (from the system or
        PkgConfigDependency) works. On macOS, this workflow works out of the
        box. On Linux, BSDs, Windows, etc, you need to set extra arguments such
        as LD_LIBRARY_PATH, etc, so this test is skipped.

        The system library is found with cc.find_library() and pkg-config deps.
        '''
        oldprefix = self.prefix
        # Install external library so we can find it
        testdir = os.path.join(self.unit_test_dir, '40 external, internal library rpath', 'external library')
        # install into installdir without using DESTDIR
        installdir = self.installdir
        self.prefix = installdir
        self.init(testdir)
        self.prefix = oldprefix
        self.build()
        self.install(use_destdir=False)
        ## New builddir for the consumer
        self.new_builddir()
        env = {'LIBRARY_PATH': os.path.join(installdir, self.libdir),
               'PKG_CONFIG_PATH': os.path.join(installdir, self.libdir, 'pkgconfig')}
        testdir = os.path.join(self.unit_test_dir, '40 external, internal library rpath', 'built library')
        # install into installdir without using DESTDIR
        self.prefix = self.installdir
        self.init(testdir, override_envvars=env)
        self.prefix = oldprefix
        self.build(override_envvars=env)
        # test uninstalled
        self.run_tests(override_envvars=env)
        if not is_osx():
            # Rest of the workflow only works on macOS
            return
        # test running after installation
        self.install(use_destdir=False)
        prog = os.path.join(self.installdir, 'bin', 'prog')
        self._run([prog])
        out = self._run(['otool', '-L', prog])
        self.assertNotIn('@rpath', out)
        ## New builddir for testing that DESTDIR is not added to install_name
        self.new_builddir()
        # install into installdir with DESTDIR
        self.init(testdir, override_envvars=env)
        self.build(override_envvars=env)
        # test running after installation
        self.install(override_envvars=env)
        prog = self.installdir + os.path.join(self.prefix, 'bin', 'prog')
        lib = self.installdir + os.path.join(self.prefix, 'lib', 'libbar_built.dylib')
        for f in prog, lib:
            out = self._run(['otool', '-L', f])
            # Ensure that the otool output does not contain self.installdir
            self.assertNotRegex(out, self.installdir + '.*dylib ')

    def install_subdir_invalid_symlinks(self, testdir, subdir_path):
        '''
        Test that installation of broken symlinks works fine.
        https://github.com/mesonbuild/meson/issues/3914
        '''
        testdir = os.path.join(self.common_test_dir, testdir)
        subdir = os.path.join(testdir, subdir_path)
        curdir = os.getcwd()
        os.chdir(subdir)
        # Can't distribute broken symlinks in the source tree because it breaks
        # the creation of zipapps. Create it dynamically and run the test by
        # hand.
        src = '../../nonexistent.txt'
        os.symlink(src, 'invalid-symlink.txt')
        try:
            self.init(testdir)
            self.build()
            self.install()
            install_path = subdir_path.split(os.path.sep)[-1]
            link = os.path.join(self.installdir, 'usr', 'share', install_path, 'invalid-symlink.txt')
            self.assertTrue(os.path.islink(link), msg=link)
            self.assertEqual(src, os.readlink(link))
            self.assertFalse(os.path.isfile(link), msg=link)
        finally:
            os.remove(os.path.join(subdir, 'invalid-symlink.txt'))
            os.chdir(curdir)

    def test_install_subdir_symlinks(self):
        self.install_subdir_invalid_symlinks('62 install subdir', os.path.join('sub', 'sub1'))

    def test_install_subdir_symlinks_with_default_umask(self):
        self.install_subdir_invalid_symlinks('195 install_mode', 'sub2')

    def test_install_subdir_symlinks_with_default_umask_and_mode(self):
        self.install_subdir_invalid_symlinks('195 install_mode', 'sub1')

    @skipIfNoPkgconfigDep('gmodule-2.0')
    def test_ldflag_dedup(self):
        testdir = os.path.join(self.unit_test_dir, '52 ldflagdedup')
        if is_cygwin() or is_osx():
            raise unittest.SkipTest('Not applicable on Cygwin or OSX.')
        self.init(testdir)
        build_ninja = os.path.join(self.builddir, 'build.ninja')
        max_count = 0
        search_term = '-Wl,--export-dynamic'
        with open(build_ninja, 'r', encoding='utf-8') as f:
            for line in f:
                max_count = max(max_count, line.count(search_term))
        self.assertEqual(max_count, 1, 'Export dynamic incorrectly deduplicated.')

    def test_compiler_libs_static_dedup(self):
        testdir = os.path.join(self.unit_test_dir, '56 dedup compiler libs')
        self.init(testdir)
        build_ninja = os.path.join(self.builddir, 'build.ninja')
        with open(build_ninja, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        for lib in ('-ldl', '-lm', '-lc', '-lrt'):
            for line in lines:
                if lib not in line:
                    continue
                # Assert that
                self.assertEqual(len(line.split(lib)), 2, msg=(lib, line))

    @skipIfNoPkgconfig
    def test_noncross_options(self):
        # C_std defined in project options must be in effect also when native compiling.
        testdir = os.path.join(self.unit_test_dir, '51 noncross options')
        self.init(testdir, extra_args=['-Dpkg_config_path=' + testdir])
        compdb = self.get_compdb()
        self.assertEqual(len(compdb), 2)
        self.assertRegex(compdb[0]['command'], '-std=c99')
        self.assertRegex(compdb[1]['command'], '-std=c99')
        self.build()

    def test_identity_cross(self):
        testdir = os.path.join(self.unit_test_dir, '61 identity cross')
        crossfile = tempfile.NamedTemporaryFile(mode='w')
        env = {'CC': '"' + os.path.join(testdir, 'build_wrapper.py') + '"'}
        crossfile.write('''[binaries]
c = ['{0}']
'''.format(os.path.join(testdir, 'host_wrapper.py')))
        crossfile.flush()
        self.meson_cross_file = crossfile.name
        # TODO should someday be explicit about build platform only here
        self.init(testdir, override_envvars=env)

    @skipIfNoPkgconfig
    def test_static_link(self):
        if is_cygwin():
            raise unittest.SkipTest("Cygwin doesn't support LD_LIBRARY_PATH.")

        # Build some libraries and install them
        testdir = os.path.join(self.unit_test_dir, '69 static link/lib')
        libdir = os.path.join(self.installdir, self.libdir)
        oldprefix = self.prefix
        self.prefix = self.installdir
        self.init(testdir)
        self.install(use_destdir=False)

        # Test that installed libraries works
        self.new_builddir()
        self.prefix = oldprefix
        meson_args = ['-Dc_link_args=-L{}'.format(libdir),
                      '--fatal-meson-warnings']
        testdir = os.path.join(self.unit_test_dir, '69 static link')
        env = {'PKG_CONFIG_LIBDIR': os.path.join(libdir, 'pkgconfig')}
        self.init(testdir, extra_args=meson_args, override_envvars=env)
        self.build()
        self.run_tests()

    def _check_ld(self, check: str, name: str, lang: str, expected: str) -> None:
        if is_sunos():
            raise unittest.SkipTest('Solaris currently cannot override the linker.')
        if not shutil.which(check):
            raise unittest.SkipTest('Could not find {}.'.format(check))
        envvar = mesonbuild.envconfig.BinaryTable.evarMap['{}_ld'.format(lang)]
        with mock.patch.dict(os.environ, {envvar: name}):
            env = get_fake_env()
            comp = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
            if lang != 'rust' and comp.use_linker_args('foo') == []:
                raise unittest.SkipTest(
                    'Compiler {} does not support using alternative linkers'.format(comp.id))
            self.assertEqual(comp.linker.id, expected)

    def test_ld_environment_variable_bfd(self):
        self._check_ld('ld.bfd', 'bfd', 'c', 'ld.bfd')

    def test_ld_environment_variable_gold(self):
        self._check_ld('ld.gold', 'gold', 'c', 'ld.gold')

    def test_ld_environment_variable_lld(self):
        self._check_ld('ld.lld', 'lld', 'c', 'ld.lld')

    @skipIfNoExecutable('rustc')
    def test_ld_environment_variable_rust(self):
        self._check_ld('ld.gold', 'gold', 'rust', 'ld.gold')

    def test_ld_environment_variable_cpp(self):
        self._check_ld('ld.gold', 'gold', 'cpp', 'ld.gold')

    def test_ld_environment_variable_objc(self):
        self._check_ld('ld.gold', 'gold', 'objc', 'ld.gold')

    def test_ld_environment_variable_objcpp(self):
        self._check_ld('ld.gold', 'gold', 'objcpp', 'ld.gold')

    @skipIfNoExecutable('gfortran')
    def test_ld_environment_variable_fortran(self):
        self._check_ld('ld.gold', 'gold', 'fortran', 'ld.gold')

    def compute_sha256(self, filename):
        with open(filename, 'rb') as f:
            return hashlib.sha256(f.read()).hexdigest()

    def test_wrap_with_file_url(self):
        testdir = os.path.join(self.unit_test_dir, '73 wrap file url')
        source_filename = os.path.join(testdir, 'subprojects', 'foo.tar.xz')
        patch_filename = os.path.join(testdir, 'subprojects', 'foo-patch.tar.xz')
        wrap_filename = os.path.join(testdir, 'subprojects', 'foo.wrap')
        source_hash = self.compute_sha256(source_filename)
        patch_hash = self.compute_sha256(patch_filename)
        wrap = textwrap.dedent("""\
            [wrap-file]
            directory = foo

            source_url = file://{}
            source_filename = foo.tar.xz
            source_hash = {}

            patch_url = file://{}
            patch_filename = foo-patch.tar.xz
            patch_hash = {}
            """.format(source_filename, source_hash, patch_filename, patch_hash))
        with open(wrap_filename, 'w') as f:
            f.write(wrap)
        self.init(testdir)
        self.build()
        self.run_tests()

        windows_proof_rmtree(os.path.join(testdir, 'subprojects', 'packagecache'))
        windows_proof_rmtree(os.path.join(testdir, 'subprojects', 'foo'))
        os.unlink(wrap_filename)


def should_run_cross_arm_tests():
    return shutil.which('arm-linux-gnueabihf-gcc') and not platform.machine().lower().startswith('arm')

@unittest.skipUnless(not is_windows() and should_run_cross_arm_tests(), "requires ability to cross compile to ARM")
class LinuxCrossArmTests(BasePlatformTests):
    '''
    Tests that cross-compilation to Linux/ARM works
    '''

    def setUp(self):
        super().setUp()
        src_root = os.path.dirname(__file__)
        self.meson_cross_file = os.path.join(src_root, 'cross', 'ubuntu-armhf.txt')

    def test_cflags_cross_environment_pollution(self):
        '''
        Test that the CFLAGS environment variable does not pollute the cross
        environment. This can't be an ordinary test case because we need to
        inspect the compiler database.
        '''
        testdir = os.path.join(self.common_test_dir, '3 static')
        self.init(testdir, override_envvars={'CFLAGS': '-DBUILD_ENVIRONMENT_ONLY'})
        compdb = self.get_compdb()
        self.assertNotIn('-DBUILD_ENVIRONMENT_ONLY', compdb[0]['command'])

    def test_cross_file_overrides_always_args(self):
        '''
        Test that $lang_args in cross files always override get_always_args().
        Needed for overriding the default -D_FILE_OFFSET_BITS=64 on some
        architectures such as some Android versions and Raspbian.
        https://github.com/mesonbuild/meson/issues/3049
        https://github.com/mesonbuild/meson/issues/3089
        '''
        testdir = os.path.join(self.unit_test_dir, '33 cross file overrides always args')
        self.meson_cross_file = os.path.join(testdir, 'ubuntu-armhf-overrides.txt')
        self.init(testdir)
        compdb = self.get_compdb()
        self.assertRegex(compdb[0]['command'], '-D_FILE_OFFSET_BITS=64.*-U_FILE_OFFSET_BITS')
        self.build()

    def test_cross_libdir(self):
        # When cross compiling "libdir" should default to "lib"
        # rather than "lib/x86_64-linux-gnu" or something like that.
        testdir = os.path.join(self.common_test_dir, '1 trivial')
        self.init(testdir)
        for i in self.introspect('--buildoptions'):
            if i['name'] == 'libdir':
                self.assertEqual(i['value'], 'lib')
                return
        self.assertTrue(False, 'Option libdir not in introspect data.')

    def test_std_remains(self):
        # C_std defined in project options must be in effect also when cross compiling.
        testdir = os.path.join(self.unit_test_dir, '51 noncross options')
        self.init(testdir)
        compdb = self.get_compdb()
        self.assertRegex(compdb[0]['command'], '-std=c99')
        self.build()

    @skipIfNoPkgconfig
    def test_pkg_config_option(self):
        if not shutil.which('arm-linux-gnueabihf-pkg-config'):
            raise unittest.SkipTest('Cross-pkgconfig not found.')
        testdir = os.path.join(self.unit_test_dir, '58 pkg_config_path option')
        self.init(testdir, extra_args=[
            '-Dbuild.pkg_config_path=' + os.path.join(testdir, 'build_extra_path'),
            '-Dpkg_config_path=' + os.path.join(testdir, 'host_extra_path'),
        ])


def should_run_cross_mingw_tests():
    return shutil.which('x86_64-w64-mingw32-gcc') and not (is_windows() or is_cygwin())

@unittest.skipUnless(not is_windows() and should_run_cross_mingw_tests(), "requires ability to cross compile with MinGW")
class LinuxCrossMingwTests(BasePlatformTests):
    '''
    Tests that cross-compilation to Windows/MinGW works
    '''

    def setUp(self):
        super().setUp()
        src_root = os.path.dirname(__file__)
        self.meson_cross_file = os.path.join(src_root, 'cross', 'linux-mingw-w64-64bit.txt')

    def test_exe_wrapper_behaviour(self):
        '''
        Test that an exe wrapper that isn't found doesn't cause compiler sanity
        checks and compiler checks to fail, but causes configure to fail if it
        requires running a cross-built executable (custom_target or run_target)
        and causes the tests to be skipped if they are run.
        '''
        testdir = os.path.join(self.unit_test_dir, '36 exe_wrapper behaviour')
        # Configures, builds, and tests fine by default
        self.init(testdir)
        self.build()
        self.run_tests()
        self.wipe()
        os.mkdir(self.builddir)
        # Change cross file to use a non-existing exe_wrapper and it should fail
        self.meson_cross_file = os.path.join(testdir, 'broken-cross.txt')
        # Force tracebacks so we can detect them properly
        env = {'MESON_FORCE_BACKTRACE': '1'}
        with self.assertRaisesRegex(MesonException, 'exe_wrapper.*target.*use-exe-wrapper'):
            # Must run in-process or we'll get a generic CalledProcessError
            self.init(testdir, extra_args='-Drun-target=false',
                      inprocess=True,
                      override_envvars=env)
        with self.assertRaisesRegex(MesonException, 'exe_wrapper.*run target.*run-prog'):
            # Must run in-process or we'll get a generic CalledProcessError
            self.init(testdir, extra_args='-Dcustom-target=false',
                      inprocess=True,
                      override_envvars=env)
        self.init(testdir, extra_args=['-Dcustom-target=false', '-Drun-target=false'],
                  override_envvars=env)
        self.build()
        with self.assertRaisesRegex(MesonException, 'exe_wrapper.*PATH'):
            # Must run in-process or we'll get a generic CalledProcessError
            self.run_tests(inprocess=True, override_envvars=env)

    @skipIfNoPkgconfig
    def test_cross_pkg_config_option(self):
        testdir = os.path.join(self.unit_test_dir, '58 pkg_config_path option')
        self.init(testdir, extra_args=[
            '-Dbuild.pkg_config_path=' + os.path.join(testdir, 'build_extra_path'),
            '-Dpkg_config_path=' + os.path.join(testdir, 'host_extra_path'),
        ])


class PythonTests(BasePlatformTests):
    '''
    Tests that verify compilation of python extension modules
    '''

    def test_versions(self):
        if self.backend is not Backend.ninja:
            raise unittest.SkipTest('Skipping python tests with {} backend'.format(self.backend.name))

        testdir = os.path.join(self.src_root, 'test cases', 'unit', '39 python extmodule')

        # No python version specified, this will use meson's python
        self.init(testdir)
        self.build()
        self.run_tests()
        self.wipe()

        # When specifying a known name, (python2 / python3) the module
        # will also try 'python' as a fallback and use it if the major
        # version matches
        try:
            self.init(testdir, extra_args=['-Dpython=python2'])
            self.build()
            self.run_tests()
        except unittest.SkipTest:
            # python2 is not necessarily installed on the test machine,
            # if it is not, or the python headers can't be found, the test
            # will raise MESON_SKIP_TEST, we could check beforehand what version
            # of python is available, but it's a bit of a chicken and egg situation,
            # as that is the job of the module, so we just ask for forgiveness rather
            # than permission.
            pass

        self.wipe()

        for py in ('pypy', 'pypy3'):
            try:
                self.init(testdir, extra_args=['-Dpython=%s' % py])
            except unittest.SkipTest:
                # Same as above, pypy2 and pypy3 are not expected to be present
                # on the test system, the test project only raises in these cases
                continue

            # We have a pypy, this is expected to work
            self.build()
            self.run_tests()
            self.wipe()

        # The test is configured to error out with MESON_SKIP_TEST
        # in case it could not find python
        with self.assertRaises(unittest.SkipTest):
            self.init(testdir, extra_args=['-Dpython=not-python'])
        self.wipe()

        # While dir is an external command on both Windows and Linux,
        # it certainly isn't python
        with self.assertRaises(unittest.SkipTest):
            self.init(testdir, extra_args=['-Dpython=dir'])
        self.wipe()


class RewriterTests(BasePlatformTests):
    def setUp(self):
        super().setUp()
        self.maxDiff = None

    def prime(self, dirname):
        copy_tree(os.path.join(self.rewrite_test_dir, dirname), self.builddir)

    def rewrite_raw(self, directory, args):
        if isinstance(args, str):
            args = [args]
        command = self.rewrite_command + ['--verbose', '--skip', '--sourcedir', directory] + args
        p = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                           universal_newlines=True, timeout=60)
        print('STDOUT:')
        print(p.stdout)
        print('STDERR:')
        print(p.stderr)
        if p.returncode != 0:
            if 'MESON_SKIP_TEST' in p.stdout:
                raise unittest.SkipTest('Project requested skipping.')
            raise subprocess.CalledProcessError(p.returncode, command, output=p.stdout)
        if not p.stderr:
            return {}
        return json.loads(p.stderr)

    def rewrite(self, directory, args):
        if isinstance(args, str):
            args = [args]
        return self.rewrite_raw(directory, ['command'] + args)

    def test_target_source_list(self):
        self.prime('1 basic')
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'target': {
                'trivialprog0@exe': {'name': 'trivialprog0', 'sources': ['main.cpp', 'fileA.cpp', 'fileB.cpp', 'fileC.cpp']},
                'trivialprog1@exe': {'name': 'trivialprog1', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog2@exe': {'name': 'trivialprog2', 'sources': ['fileB.cpp', 'fileC.cpp']},
                'trivialprog3@exe': {'name': 'trivialprog3', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog4@exe': {'name': 'trivialprog4', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog5@exe': {'name': 'trivialprog5', 'sources': ['main.cpp', 'fileB.cpp', 'fileC.cpp']},
                'trivialprog6@exe': {'name': 'trivialprog6', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog7@exe': {'name': 'trivialprog7', 'sources': ['fileB.cpp', 'fileC.cpp', 'main.cpp', 'fileA.cpp']},
                'trivialprog8@exe': {'name': 'trivialprog8', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog9@exe': {'name': 'trivialprog9', 'sources': ['main.cpp', 'fileA.cpp']},
            }
        }
        self.assertDictEqual(out, expected)

    def test_target_add_sources(self):
        self.prime('1 basic')
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'addSrc.json'))
        expected = {
            'target': {
                'trivialprog0@exe': {'name': 'trivialprog0', 'sources': ['a1.cpp', 'a2.cpp', 'a6.cpp', 'fileA.cpp', 'main.cpp', 'a7.cpp', 'fileB.cpp', 'fileC.cpp']},
                'trivialprog1@exe': {'name': 'trivialprog1', 'sources': ['a1.cpp', 'a2.cpp', 'a6.cpp', 'fileA.cpp', 'main.cpp']},
                'trivialprog2@exe': {'name': 'trivialprog2', 'sources': ['a7.cpp', 'fileB.cpp', 'fileC.cpp']},
                'trivialprog3@exe': {'name': 'trivialprog3', 'sources': ['a5.cpp', 'fileA.cpp', 'main.cpp']},
                'trivialprog4@exe': {'name': 'trivialprog4', 'sources': ['a5.cpp', 'main.cpp', 'fileA.cpp']},
                'trivialprog5@exe': {'name': 'trivialprog5', 'sources': ['a3.cpp', 'main.cpp', 'a7.cpp', 'fileB.cpp', 'fileC.cpp']},
                'trivialprog6@exe': {'name': 'trivialprog6', 'sources': ['main.cpp', 'fileA.cpp', 'a4.cpp']},
                'trivialprog7@exe': {'name': 'trivialprog7', 'sources': ['fileB.cpp', 'fileC.cpp', 'a1.cpp', 'a2.cpp', 'a6.cpp', 'fileA.cpp', 'main.cpp']},
                'trivialprog8@exe': {'name': 'trivialprog8', 'sources': ['a1.cpp', 'a2.cpp', 'a6.cpp', 'fileA.cpp', 'main.cpp']},
                'trivialprog9@exe': {'name': 'trivialprog9', 'sources': ['a1.cpp', 'a2.cpp', 'a6.cpp', 'fileA.cpp', 'main.cpp']},
            }
        }
        self.assertDictEqual(out, expected)

        # Check the written file
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        self.assertDictEqual(out, expected)

    def test_target_add_sources_abs(self):
        self.prime('1 basic')
        abs_src = [os.path.join(self.builddir, x) for x in ['a1.cpp', 'a2.cpp', 'a6.cpp']]
        add = json.dumps([{"type": "target", "target": "trivialprog1", "operation": "src_add", "sources": abs_src}])
        inf = json.dumps([{"type": "target", "target": "trivialprog1", "operation": "info"}])
        self.rewrite(self.builddir, add)
        out = self.rewrite(self.builddir, inf)
        expected = {'target': {'trivialprog1@exe': {'name': 'trivialprog1', 'sources': ['a1.cpp', 'a2.cpp', 'a6.cpp', 'fileA.cpp', 'main.cpp']}}}
        self.assertDictEqual(out, expected)

    def test_target_remove_sources(self):
        self.prime('1 basic')
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'rmSrc.json'))
        expected = {
            'target': {
                'trivialprog0@exe': {'name': 'trivialprog0', 'sources': ['main.cpp', 'fileC.cpp']},
                'trivialprog1@exe': {'name': 'trivialprog1', 'sources': ['main.cpp']},
                'trivialprog2@exe': {'name': 'trivialprog2', 'sources': ['fileC.cpp']},
                'trivialprog3@exe': {'name': 'trivialprog3', 'sources': ['main.cpp']},
                'trivialprog4@exe': {'name': 'trivialprog4', 'sources': ['main.cpp']},
                'trivialprog5@exe': {'name': 'trivialprog5', 'sources': ['main.cpp', 'fileC.cpp']},
                'trivialprog6@exe': {'name': 'trivialprog6', 'sources': ['main.cpp']},
                'trivialprog7@exe': {'name': 'trivialprog7', 'sources': ['fileC.cpp', 'main.cpp']},
                'trivialprog8@exe': {'name': 'trivialprog8', 'sources': ['main.cpp']},
                'trivialprog9@exe': {'name': 'trivialprog9', 'sources': ['main.cpp']},
            }
        }
        self.assertDictEqual(out, expected)

        # Check the written file
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        self.assertDictEqual(out, expected)

    def test_target_subdir(self):
        self.prime('2 subdirs')
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'addSrc.json'))
        expected = {'name': 'something', 'sources': ['first.c', 'second.c', 'third.c']}
        self.assertDictEqual(list(out['target'].values())[0], expected)

        # Check the written file
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        self.assertDictEqual(list(out['target'].values())[0], expected)

    def test_target_remove(self):
        self.prime('1 basic')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'rmTgt.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))

        expected = {
            'target': {
                'trivialprog2@exe': {'name': 'trivialprog2', 'sources': ['fileB.cpp', 'fileC.cpp']},
                'trivialprog3@exe': {'name': 'trivialprog3', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog4@exe': {'name': 'trivialprog4', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog5@exe': {'name': 'trivialprog5', 'sources': ['main.cpp', 'fileB.cpp', 'fileC.cpp']},
                'trivialprog6@exe': {'name': 'trivialprog6', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog7@exe': {'name': 'trivialprog7', 'sources': ['fileB.cpp', 'fileC.cpp', 'main.cpp', 'fileA.cpp']},
                'trivialprog8@exe': {'name': 'trivialprog8', 'sources': ['main.cpp', 'fileA.cpp']},
            }
        }
        self.assertDictEqual(out, expected)

    def test_tatrget_add(self):
        self.prime('1 basic')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'addTgt.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))

        expected = {
            'target': {
                'trivialprog0@exe': {'name': 'trivialprog0', 'sources': ['main.cpp', 'fileA.cpp', 'fileB.cpp', 'fileC.cpp']},
                'trivialprog1@exe': {'name': 'trivialprog1', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog2@exe': {'name': 'trivialprog2', 'sources': ['fileB.cpp', 'fileC.cpp']},
                'trivialprog3@exe': {'name': 'trivialprog3', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog4@exe': {'name': 'trivialprog4', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog5@exe': {'name': 'trivialprog5', 'sources': ['main.cpp', 'fileB.cpp', 'fileC.cpp']},
                'trivialprog6@exe': {'name': 'trivialprog6', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog7@exe': {'name': 'trivialprog7', 'sources': ['fileB.cpp', 'fileC.cpp', 'main.cpp', 'fileA.cpp']},
                'trivialprog8@exe': {'name': 'trivialprog8', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog9@exe': {'name': 'trivialprog9', 'sources': ['main.cpp', 'fileA.cpp']},
                'trivialprog10@sha': {'name': 'trivialprog10', 'sources': ['new1.cpp', 'new2.cpp']},
            }
        }
        self.assertDictEqual(out, expected)

    def test_target_remove_subdir(self):
        self.prime('2 subdirs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'rmTgt.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        self.assertDictEqual(out, {})

    def test_target_add_subdir(self):
        self.prime('2 subdirs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'addTgt.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {'name': 'something', 'sources': ['first.c', 'second.c']}
        self.assertDictEqual(out['target']['94b671c@@something@exe'], expected)

    def test_target_source_sorting(self):
        self.prime('5 sorting')
        add_json = json.dumps([{'type': 'target', 'target': 'exe1', 'operation': 'src_add', 'sources': ['a666.c']}])
        inf_json = json.dumps([{'type': 'target', 'target': 'exe1', 'operation': 'info'}])
        out = self.rewrite(self.builddir, add_json)
        out = self.rewrite(self.builddir, inf_json)
        expected = {
            'target': {
                'exe1@exe': {
                    'name': 'exe1',
                    'sources': [
                        'aaa/a/a1.c',
                        'aaa/b/b1.c',
                        'aaa/b/b2.c',
                        'aaa/f1.c',
                        'aaa/f2.c',
                        'aaa/f3.c',
                        'bbb/a/b1.c',
                        'bbb/b/b2.c',
                        'bbb/c1/b5.c',
                        'bbb/c2/b7.c',
                        'bbb/c10/b6.c',
                        'bbb/a4.c',
                        'bbb/b3.c',
                        'bbb/b4.c',
                        'bbb/b5.c',
                        'a1.c',
                        'a2.c',
                        'a3.c',
                        'a10.c',
                        'a20.c',
                        'a30.c',
                        'a100.c',
                        'a101.c',
                        'a110.c',
                        'a210.c',
                        'a666.c',
                        'b1.c',
                        'c2.c'
                    ]
                }
            }
        }
        self.assertDictEqual(out, expected)

    def test_target_same_name_skip(self):
        self.prime('4 same name targets')
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'addSrc.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {'name': 'myExe', 'sources': ['main.cpp']}
        self.assertEqual(len(out['target']), 2)
        for val in out['target'].values():
            self.assertDictEqual(expected, val)

    def test_kwargs_info(self):
        self.prime('3 kwargs')
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'kwargs': {
                'project#/': {'version': '0.0.1'},
                'target#tgt1': {'build_by_default': True},
                'dependency#dep1': {'required': False}
            }
        }
        self.assertDictEqual(out, expected)

    def test_kwargs_set(self):
        self.prime('3 kwargs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'set.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'kwargs': {
                'project#/': {'version': '0.0.2', 'meson_version': '0.50.0', 'license': ['GPL', 'MIT']},
                'target#tgt1': {'build_by_default': False, 'build_rpath': '/usr/local', 'dependencies': 'dep1'},
                'dependency#dep1': {'required': True, 'method': 'cmake'}
            }
        }
        self.assertDictEqual(out, expected)

    def test_kwargs_add(self):
        self.prime('3 kwargs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'add.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'kwargs': {
                'project#/': {'version': '0.0.1', 'license': ['GPL', 'MIT', 'BSD']},
                'target#tgt1': {'build_by_default': True},
                'dependency#dep1': {'required': False}
            }
        }
        self.assertDictEqual(out, expected)

    def test_kwargs_remove(self):
        self.prime('3 kwargs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'remove.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'kwargs': {
                'project#/': {'version': '0.0.1', 'license': 'GPL'},
                'target#tgt1': {'build_by_default': True},
                'dependency#dep1': {'required': False}
            }
        }
        self.assertDictEqual(out, expected)

    def test_kwargs_remove_regex(self):
        self.prime('3 kwargs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'remove_regex.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'kwargs': {
                'project#/': {'version': '0.0.1', 'default_options': ['buildtype=release', 'debug=true']},
                'target#tgt1': {'build_by_default': True},
                'dependency#dep1': {'required': False}
            }
        }
        self.assertDictEqual(out, expected)

    def test_kwargs_delete(self):
        self.prime('3 kwargs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'delete.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'kwargs': {
                'project#/': {},
                'target#tgt1': {},
                'dependency#dep1': {'required': False}
            }
        }
        self.assertDictEqual(out, expected)

    def test_default_options_set(self):
        self.prime('3 kwargs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'defopts_set.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'kwargs': {
                'project#/': {'version': '0.0.1', 'default_options': ['buildtype=release', 'debug=True', 'cpp_std=c++11']},
                'target#tgt1': {'build_by_default': True},
                'dependency#dep1': {'required': False}
            }
        }
        self.assertDictEqual(out, expected)

    def test_default_options_delete(self):
        self.prime('3 kwargs')
        self.rewrite(self.builddir, os.path.join(self.builddir, 'defopts_delete.json'))
        out = self.rewrite(self.builddir, os.path.join(self.builddir, 'info.json'))
        expected = {
            'kwargs': {
                'project#/': {'version': '0.0.1', 'default_options': ['cpp_std=c++14', 'debug=true']},
                'target#tgt1': {'build_by_default': True},
                'dependency#dep1': {'required': False}
            }
        }
        self.assertDictEqual(out, expected)

class NativeFileTests(BasePlatformTests):

    def setUp(self):
        super().setUp()
        self.testcase = os.path.join(self.unit_test_dir, '47 native file binary')
        self.current_config = 0
        self.current_wrapper = 0

    def helper_create_native_file(self, values):
        """Create a config file as a temporary file.

        values should be a nested dictionary structure of {section: {key:
        value}}
        """
        filename = os.path.join(self.builddir, 'generated{}.config'.format(self.current_config))
        self.current_config += 1
        with open(filename, 'wt') as f:
            for section, entries in values.items():
                f.write('[{}]\n'.format(section))
                for k, v in entries.items():
                    f.write("{}='{}'\n".format(k, v))
        return filename

    def helper_create_binary_wrapper(self, binary, dir_=None, extra_args=None, **kwargs):
        """Creates a wrapper around a binary that overrides specific values."""
        filename = os.path.join(dir_ or self.builddir, 'binary_wrapper{}.py'.format(self.current_wrapper))
        extra_args = extra_args or {}
        self.current_wrapper += 1
        if is_haiku():
            chbang = '#!/bin/env python3'
        else:
            chbang = '#!/usr/bin/env python3'

        with open(filename, 'wt') as f:
            f.write(textwrap.dedent('''\
                {}
                import argparse
                import subprocess
                import sys

                def main():
                    parser = argparse.ArgumentParser()
                '''.format(chbang)))
            for name in chain(extra_args, kwargs):
                f.write('    parser.add_argument("-{0}", "--{0}", action="store_true")\n'.format(name))
            f.write('    args, extra_args = parser.parse_known_args()\n')
            for name, value in chain(extra_args.items(), kwargs.items()):
                f.write('    if args.{}:\n'.format(name))
                f.write('        print("{}", file=sys.{})\n'.format(value, kwargs.get('outfile', 'stdout')))
                f.write('        sys.exit(0)\n')
            f.write(textwrap.dedent('''
                    ret = subprocess.run(
                        ["{}"] + extra_args,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)
                    print(ret.stdout.decode('utf-8'))
                    print(ret.stderr.decode('utf-8'), file=sys.stderr)
                    sys.exit(ret.returncode)

                if __name__ == '__main__':
                    main()
                '''.format(binary)))

        if not is_windows():
            os.chmod(filename, 0o755)
            return filename

        # On windows we need yet another level of indirection, as cmd cannot
        # invoke python files itself, so instead we generate a .bat file, which
        # invokes our python wrapper
        batfile = os.path.join(self.builddir, 'binary_wrapper{}.bat'.format(self.current_wrapper))
        with open(batfile, 'wt') as f:
            f.write(r'@{} {} %*'.format(sys.executable, filename))
        return batfile

    def helper_for_compiler(self, lang, cb, for_machine = MachineChoice.HOST):
        """Helper for generating tests for overriding compilers for langaugages
        with more than one implementation, such as C, C++, ObjC, ObjC++, and D.
        """
        env = get_fake_env()
        getter = getattr(env, 'detect_{}_compiler'.format(lang))
        getter = functools.partial(getter, for_machine)
        cc = getter()
        binary, newid = cb(cc)
        env.binaries[for_machine].binaries[lang] = binary
        compiler = getter()
        self.assertEqual(compiler.id, newid)

    def test_multiple_native_files_override(self):
        wrapper = self.helper_create_binary_wrapper('bash', version='foo')
        config = self.helper_create_native_file({'binaries': {'bash': wrapper}})
        wrapper = self.helper_create_binary_wrapper('bash', version='12345')
        config2 = self.helper_create_native_file({'binaries': {'bash': wrapper}})
        self.init(self.testcase, extra_args=[
            '--native-file', config, '--native-file', config2,
            '-Dcase=find_program'])

    # This test hangs on cygwin.
    @unittest.skipIf(os.name != 'posix' or is_cygwin(), 'Uses fifos, which are not available on non Unix OSes.')
    def test_native_file_is_pipe(self):
        fifo = os.path.join(self.builddir, 'native.file')
        os.mkfifo(fifo)
        with tempfile.TemporaryDirectory() as d:
            wrapper = self.helper_create_binary_wrapper('bash', d, version='12345')

            def filler():
                with open(fifo, 'w') as f:
                    f.write('[binaries]\n')
                    f.write("bash = '{}'\n".format(wrapper))

            thread = threading.Thread(target=filler)
            thread.start()

            self.init(self.testcase, extra_args=['--native-file', fifo, '-Dcase=find_program'])

            thread.join()
            os.unlink(fifo)

            self.init(self.testcase, extra_args=['--wipe'])

    def test_multiple_native_files(self):
        wrapper = self.helper_create_binary_wrapper('bash', version='12345')
        config = self.helper_create_native_file({'binaries': {'bash': wrapper}})
        wrapper = self.helper_create_binary_wrapper('python')
        config2 = self.helper_create_native_file({'binaries': {'python': wrapper}})
        self.init(self.testcase, extra_args=[
            '--native-file', config, '--native-file', config2,
            '-Dcase=find_program'])

    def _simple_test(self, case, binary):
        wrapper = self.helper_create_binary_wrapper(binary, version='12345')
        config = self.helper_create_native_file({'binaries': {binary: wrapper}})
        self.init(self.testcase, extra_args=['--native-file', config, '-Dcase={}'.format(case)])

    def test_find_program(self):
        self._simple_test('find_program', 'bash')

    def test_config_tool_dep(self):
        # Do the skip at this level to avoid screwing up the cache
        if mesonbuild.environment.detect_msys2_arch():
            raise unittest.SkipTest('Skipped due to problems with LLVM on MSYS2')
        if not shutil.which('llvm-config'):
            raise unittest.SkipTest('No llvm-installed, cannot test')
        self._simple_test('config_dep', 'llvm-config')

    def test_python3_module(self):
        self._simple_test('python3', 'python3')

    def test_python_module(self):
        if is_windows():
            # Bat adds extra crap to stdout, so the version check logic in the
            # python module breaks. This is fine on other OSes because they
            # don't need the extra indirection.
            raise unittest.SkipTest('bat indirection breaks internal sanity checks.')
        if os.path.exists('/etc/debian_version'):
            rc = subprocess.call(['pkg-config', '--cflags', 'python2'],
                                 stdout=subprocess.DEVNULL,
                                 stderr=subprocess.DEVNULL)
            if rc != 0:
                # Python 2 will be removed in Debian Bullseye, thus we must
                # remove the build dependency on python2-dev. Keep the tests
                # but only run them if dev packages are available.
                raise unittest.SkipTest('Not running Python 2 tests because dev packages not installed.')
        self._simple_test('python', 'python')

    @unittest.skipIf(is_windows(), 'Setting up multiple compilers on windows is hard')
    @skip_if_env_set('CC')
    def test_c_compiler(self):
        def cb(comp):
            if comp.id == 'gcc':
                if not shutil.which('clang'):
                    raise unittest.SkipTest('Only one compiler found, cannot test.')
                return 'clang', 'clang'
            if not is_real_gnu_compiler(shutil.which('gcc')):
                raise unittest.SkipTest('Only one compiler found, cannot test.')
            return 'gcc', 'gcc'
        self.helper_for_compiler('c', cb)

    @unittest.skipIf(is_windows(), 'Setting up multiple compilers on windows is hard')
    @skip_if_env_set('CXX')
    def test_cpp_compiler(self):
        def cb(comp):
            if comp.id == 'gcc':
                if not shutil.which('clang++'):
                    raise unittest.SkipTest('Only one compiler found, cannot test.')
                return 'clang++', 'clang'
            if not is_real_gnu_compiler(shutil.which('g++')):
                raise unittest.SkipTest('Only one compiler found, cannot test.')
            return 'g++', 'gcc'
        self.helper_for_compiler('cpp', cb)

    @skip_if_not_language('objc')
    @skip_if_env_set('OBJC')
    def test_objc_compiler(self):
        def cb(comp):
            if comp.id == 'gcc':
                if not shutil.which('clang'):
                    raise unittest.SkipTest('Only one compiler found, cannot test.')
                return 'clang', 'clang'
            if not is_real_gnu_compiler(shutil.which('gcc')):
                raise unittest.SkipTest('Only one compiler found, cannot test.')
            return 'gcc', 'gcc'
        self.helper_for_compiler('objc', cb)

    @skip_if_not_language('objcpp')
    @skip_if_env_set('OBJCXX')
    def test_objcpp_compiler(self):
        def cb(comp):
            if comp.id == 'gcc':
                if not shutil.which('clang++'):
                    raise unittest.SkipTest('Only one compiler found, cannot test.')
                return 'clang++', 'clang'
            if not is_real_gnu_compiler(shutil.which('g++')):
                raise unittest.SkipTest('Only one compiler found, cannot test.')
            return 'g++', 'gcc'
        self.helper_for_compiler('objcpp', cb)

    @skip_if_not_language('d')
    @skip_if_env_set('DC')
    def test_d_compiler(self):
        def cb(comp):
            if comp.id == 'dmd':
                if shutil.which('ldc'):
                    return 'ldc', 'ldc'
                elif shutil.which('gdc'):
                    return 'gdc', 'gdc'
                else:
                    raise unittest.SkipTest('No alternative dlang compiler found.')
            if shutil.which('dmd'):
                return 'dmd', 'dmd'
            raise unittest.SkipTest('No alternative dlang compiler found.')
        self.helper_for_compiler('d', cb)

    @skip_if_not_language('cs')
    @skip_if_env_set('CSC')
    def test_cs_compiler(self):
        def cb(comp):
            if comp.id == 'csc':
                if not shutil.which('mcs'):
                    raise unittest.SkipTest('No alternate C# implementation.')
                return 'mcs', 'mcs'
            if not shutil.which('csc'):
                raise unittest.SkipTest('No alternate C# implementation.')
            return 'csc', 'csc'
        self.helper_for_compiler('cs', cb)

    @skip_if_not_language('fortran')
    @skip_if_env_set('FC')
    def test_fortran_compiler(self):
        def cb(comp):
            if comp.id == 'lcc':
                if shutil.which('lfortran'):
                    return 'lfortran', 'lcc'
                raise unittest.SkipTest('No alternate Fortran implementation.')
            elif comp.id == 'gcc':
                if shutil.which('ifort'):
                    # There is an ICC for windows (windows build, linux host),
                    # but we don't support that ATM so lets not worry about it.
                    if is_windows():
                        return 'ifort', 'intel-cl'
                    return 'ifort', 'intel'
                elif shutil.which('flang'):
                    return 'flang', 'flang'
                elif shutil.which('pgfortran'):
                    return 'pgfortran', 'pgi'
                # XXX: there are several other fortran compilers meson
                # supports, but I don't have any of them to test with
                raise unittest.SkipTest('No alternate Fortran implementation.')
            if not shutil.which('gfortran'):
                raise unittest.SkipTest('No alternate Fortran implementation.')
            return 'gfortran', 'gcc'
        self.helper_for_compiler('fortran', cb)

    def _single_implementation_compiler(self, lang, binary, version_str, version):
        """Helper for languages with a single (supported) implementation.

        Builds a wrapper around the compiler to override the version.
        """
        wrapper = self.helper_create_binary_wrapper(binary, version=version_str)
        env = get_fake_env()
        getter = getattr(env, 'detect_{}_compiler'.format(lang))
        getter = functools.partial(getter, MachineChoice.HOST)
        env.binaries.host.binaries[lang] = wrapper
        compiler = getter()
        self.assertEqual(compiler.version, version)

    @skip_if_not_language('vala')
    @skip_if_env_set('VALAC')
    def test_vala_compiler(self):
        self._single_implementation_compiler(
            'vala', 'valac', 'Vala 1.2345', '1.2345')

    @skip_if_not_language('rust')
    @skip_if_env_set('RUSTC')
    def test_rust_compiler(self):
        self._single_implementation_compiler(
            'rust', 'rustc', 'rustc 1.2345', '1.2345')

    @skip_if_not_language('java')
    def test_java_compiler(self):
        self._single_implementation_compiler(
            'java', 'javac', 'javac 9.99.77', '9.99.77')

    @skip_if_not_language('swift')
    def test_swift_compiler(self):
        wrapper = self.helper_create_binary_wrapper(
            'swiftc', version='Swift 1.2345', outfile='stderr',
            extra_args={'Xlinker': 'macosx_version. PROJECT:ld - 1.2.3'})
        env = get_fake_env()
        env.binaries.host.binaries['swift'] = wrapper
        compiler = env.detect_swift_compiler(MachineChoice.HOST)
        self.assertEqual(compiler.version, '1.2345')

    def test_native_file_dirs(self):
        testcase = os.path.join(self.unit_test_dir, '60 native file override')
        self.init(testcase, default_args=False,
                  extra_args=['--native-file', os.path.join(testcase, 'nativefile')])

    def test_native_file_dirs_overriden(self):
        testcase = os.path.join(self.unit_test_dir, '60 native file override')
        self.init(testcase, default_args=False,
                  extra_args=['--native-file', os.path.join(testcase, 'nativefile'),
                              '-Ddef_libdir=liblib', '-Dlibdir=liblib'])

    def test_compile_sys_path(self):
        """Compiling with a native file stored in a system path works.

        There was a bug which caused the paths to be stored incorrectly and
        would result in ninja invoking meson in an infinite loop. This tests
        for that by actually invoking ninja.
        """
        testcase = os.path.join(self.common_test_dir, '1 trivial')

        # It really doesn't matter what's in the native file, just that it exists
        config = self.helper_create_native_file({'binaries': {'bash': 'false'}})

        self.init(testcase, extra_args=['--native-file', config])
        self.build()


class CrossFileTests(BasePlatformTests):

    """Tests for cross file functioality not directly related to
    cross compiling.

    This is mainly aimed to testing overrides from cross files.
    """

    def test_cross_file_dirs(self):
        testcase = os.path.join(self.unit_test_dir, '60 native file override')
        self.init(testcase, default_args=False,
                  extra_args=['--native-file', os.path.join(testcase, 'nativefile'),
                              '--cross-file', os.path.join(testcase, 'crossfile'),
                              '-Ddef_bindir=binbar',
                              '-Ddef_datadir=databar',
                              '-Ddef_includedir=includebar',
                              '-Ddef_infodir=infobar',
                              '-Ddef_libdir=libbar',
                              '-Ddef_libexecdir=libexecbar',
                              '-Ddef_localedir=localebar',
                              '-Ddef_localstatedir=localstatebar',
                              '-Ddef_mandir=manbar',
                              '-Ddef_sbindir=sbinbar',
                              '-Ddef_sharedstatedir=sharedstatebar',
                              '-Ddef_sysconfdir=sysconfbar'])

    def test_cross_file_dirs_overriden(self):
        testcase = os.path.join(self.unit_test_dir, '60 native file override')
        self.init(testcase, default_args=False,
                  extra_args=['--native-file', os.path.join(testcase, 'nativefile'),
                              '--cross-file', os.path.join(testcase, 'crossfile'),
                              '-Ddef_libdir=liblib', '-Dlibdir=liblib',
                              '-Ddef_bindir=binbar',
                              '-Ddef_datadir=databar',
                              '-Ddef_includedir=includebar',
                              '-Ddef_infodir=infobar',
                              '-Ddef_libexecdir=libexecbar',
                              '-Ddef_localedir=localebar',
                              '-Ddef_localstatedir=localstatebar',
                              '-Ddef_mandir=manbar',
                              '-Ddef_sbindir=sbinbar',
                              '-Ddef_sharedstatedir=sharedstatebar',
                              '-Ddef_sysconfdir=sysconfbar'])

    def test_cross_file_dirs_chain(self):
        # crossfile2 overrides crossfile overrides nativefile
        testcase = os.path.join(self.unit_test_dir, '60 native file override')
        self.init(testcase, default_args=False,
                  extra_args=['--native-file', os.path.join(testcase, 'nativefile'),
                              '--cross-file', os.path.join(testcase, 'crossfile'),
                              '--cross-file', os.path.join(testcase, 'crossfile2'),
                              '-Ddef_bindir=binbar2',
                              '-Ddef_datadir=databar',
                              '-Ddef_includedir=includebar',
                              '-Ddef_infodir=infobar',
                              '-Ddef_libdir=libbar',
                              '-Ddef_libexecdir=libexecbar',
                              '-Ddef_localedir=localebar',
                              '-Ddef_localstatedir=localstatebar',
                              '-Ddef_mandir=manbar',
                              '-Ddef_sbindir=sbinbar',
                              '-Ddef_sharedstatedir=sharedstatebar',
                              '-Ddef_sysconfdir=sysconfbar'])

class TAPParserTests(unittest.TestCase):
    def assert_test(self, events, **kwargs):
        if 'explanation' not in kwargs:
            kwargs['explanation'] = None
        self.assertEqual(next(events), TAPParser.Test(**kwargs))

    def assert_plan(self, events, **kwargs):
        if 'skipped' not in kwargs:
            kwargs['skipped'] = False
        if 'explanation' not in kwargs:
            kwargs['explanation'] = None
        self.assertEqual(next(events), TAPParser.Plan(**kwargs))

    def assert_version(self, events, **kwargs):
        self.assertEqual(next(events), TAPParser.Version(**kwargs))

    def assert_error(self, events):
        self.assertEqual(type(next(events)), TAPParser.Error)

    def assert_bailout(self, events, **kwargs):
        self.assertEqual(next(events), TAPParser.Bailout(**kwargs))

    def assert_last(self, events):
        with self.assertRaises(StopIteration):
            next(events)

    def parse_tap(self, s):
        parser = TAPParser(io.StringIO(s))
        return iter(parser.parse())

    def parse_tap_v13(self, s):
        events = self.parse_tap('TAP version 13\n' + s)
        self.assert_version(events, version=13)
        return events

    def test_empty(self):
        events = self.parse_tap('')
        self.assert_last(events)

    def test_empty_plan(self):
        events = self.parse_tap('1..0')
        self.assert_plan(events, count=0, late=False, skipped=True)
        self.assert_last(events)

    def test_plan_directive(self):
        events = self.parse_tap('1..0 # skipped for some reason')
        self.assert_plan(events, count=0, late=False, skipped=True,
                         explanation='for some reason')
        self.assert_last(events)

        events = self.parse_tap('1..1 # skipped for some reason\nok 1')
        self.assert_error(events)
        self.assert_plan(events, count=1, late=False, skipped=True,
                         explanation='for some reason')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

        events = self.parse_tap('1..1 # todo not supported here\nok 1')
        self.assert_error(events)
        self.assert_plan(events, count=1, late=False, skipped=False,
                         explanation='not supported here')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_one_test_ok(self):
        events = self.parse_tap('ok')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_one_test_with_number(self):
        events = self.parse_tap('ok 1')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_one_test_with_name(self):
        events = self.parse_tap('ok 1 abc')
        self.assert_test(events, number=1, name='abc', result=TestResult.OK)
        self.assert_last(events)

    def test_one_test_not_ok(self):
        events = self.parse_tap('not ok')
        self.assert_test(events, number=1, name='', result=TestResult.FAIL)
        self.assert_last(events)

    def test_one_test_todo(self):
        events = self.parse_tap('not ok 1 abc # TODO')
        self.assert_test(events, number=1, name='abc', result=TestResult.EXPECTEDFAIL)
        self.assert_last(events)

        events = self.parse_tap('ok 1 abc # TODO')
        self.assert_test(events, number=1, name='abc', result=TestResult.UNEXPECTEDPASS)
        self.assert_last(events)

    def test_one_test_skip(self):
        events = self.parse_tap('ok 1 abc # SKIP')
        self.assert_test(events, number=1, name='abc', result=TestResult.SKIP)
        self.assert_last(events)

    def test_one_test_skip_failure(self):
        events = self.parse_tap('not ok 1 abc # SKIP')
        self.assert_test(events, number=1, name='abc', result=TestResult.FAIL)
        self.assert_last(events)

    def test_many_early_plan(self):
        events = self.parse_tap('1..4\nok 1\nnot ok 2\nok 3\nnot ok 4')
        self.assert_plan(events, count=4, late=False)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_test(events, number=2, name='', result=TestResult.FAIL)
        self.assert_test(events, number=3, name='', result=TestResult.OK)
        self.assert_test(events, number=4, name='', result=TestResult.FAIL)
        self.assert_last(events)

    def test_many_late_plan(self):
        events = self.parse_tap('ok 1\nnot ok 2\nok 3\nnot ok 4\n1..4')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_test(events, number=2, name='', result=TestResult.FAIL)
        self.assert_test(events, number=3, name='', result=TestResult.OK)
        self.assert_test(events, number=4, name='', result=TestResult.FAIL)
        self.assert_plan(events, count=4, late=True)
        self.assert_last(events)

    def test_directive_case(self):
        events = self.parse_tap('ok 1 abc # skip')
        self.assert_test(events, number=1, name='abc', result=TestResult.SKIP)
        self.assert_last(events)

        events = self.parse_tap('ok 1 abc # ToDo')
        self.assert_test(events, number=1, name='abc', result=TestResult.UNEXPECTEDPASS)
        self.assert_last(events)

    def test_directive_explanation(self):
        events = self.parse_tap('ok 1 abc # skip why')
        self.assert_test(events, number=1, name='abc', result=TestResult.SKIP,
                         explanation='why')
        self.assert_last(events)

        events = self.parse_tap('ok 1 abc # ToDo Because')
        self.assert_test(events, number=1, name='abc', result=TestResult.UNEXPECTEDPASS,
                         explanation='Because')
        self.assert_last(events)

    def test_one_test_early_plan(self):
        events = self.parse_tap('1..1\nok')
        self.assert_plan(events, count=1, late=False)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_one_test_late_plan(self):
        events = self.parse_tap('ok\n1..1')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_plan(events, count=1, late=True)
        self.assert_last(events)

    def test_out_of_order(self):
        events = self.parse_tap('ok 2')
        self.assert_error(events)
        self.assert_test(events, number=2, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_middle_plan(self):
        events = self.parse_tap('ok 1\n1..2\nok 2')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_plan(events, count=2, late=True)
        self.assert_error(events)
        self.assert_test(events, number=2, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_too_many_plans(self):
        events = self.parse_tap('1..1\n1..2\nok 1')
        self.assert_plan(events, count=1, late=False)
        self.assert_error(events)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_too_many(self):
        events = self.parse_tap('ok 1\nnot ok 2\n1..1')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_test(events, number=2, name='', result=TestResult.FAIL)
        self.assert_plan(events, count=1, late=True)
        self.assert_error(events)
        self.assert_last(events)

        events = self.parse_tap('1..1\nok 1\nnot ok 2')
        self.assert_plan(events, count=1, late=False)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_test(events, number=2, name='', result=TestResult.FAIL)
        self.assert_error(events)
        self.assert_last(events)

    def test_too_few(self):
        events = self.parse_tap('ok 1\nnot ok 2\n1..3')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_test(events, number=2, name='', result=TestResult.FAIL)
        self.assert_plan(events, count=3, late=True)
        self.assert_error(events)
        self.assert_last(events)

        events = self.parse_tap('1..3\nok 1\nnot ok 2')
        self.assert_plan(events, count=3, late=False)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_test(events, number=2, name='', result=TestResult.FAIL)
        self.assert_error(events)
        self.assert_last(events)

    def test_too_few_bailout(self):
        events = self.parse_tap('1..3\nok 1\nnot ok 2\nBail out! no third test')
        self.assert_plan(events, count=3, late=False)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_test(events, number=2, name='', result=TestResult.FAIL)
        self.assert_bailout(events, message='no third test')
        self.assert_last(events)

    def test_diagnostics(self):
        events = self.parse_tap('1..1\n# ignored\nok 1')
        self.assert_plan(events, count=1, late=False)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

        events = self.parse_tap('# ignored\n1..1\nok 1\n# ignored too')
        self.assert_plan(events, count=1, late=False)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

        events = self.parse_tap('# ignored\nok 1\n1..1\n# ignored too')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_plan(events, count=1, late=True)
        self.assert_last(events)

    def test_empty_line(self):
        events = self.parse_tap('1..1\n\nok 1')
        self.assert_plan(events, count=1, late=False)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_unexpected(self):
        events = self.parse_tap('1..1\ninvalid\nok 1')
        self.assert_plan(events, count=1, late=False)
        self.assert_error(events)
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_last(events)

    def test_version(self):
        events = self.parse_tap('TAP version 13\n')
        self.assert_version(events, version=13)
        self.assert_last(events)

        events = self.parse_tap('TAP version 12\n')
        self.assert_error(events)
        self.assert_last(events)

        events = self.parse_tap('1..0\nTAP version 13\n')
        self.assert_plan(events, count=0, late=False, skipped=True)
        self.assert_error(events)
        self.assert_last(events)

    def test_yaml(self):
        events = self.parse_tap_v13('ok\n ---\n foo: abc\n  bar: def\n ...\nok 2')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_test(events, number=2, name='', result=TestResult.OK)
        self.assert_last(events)

        events = self.parse_tap_v13('ok\n ---\n foo: abc\n  bar: def')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_error(events)
        self.assert_last(events)

        events = self.parse_tap_v13('ok 1\n ---\n foo: abc\n  bar: def\nnot ok 2')
        self.assert_test(events, number=1, name='', result=TestResult.OK)
        self.assert_error(events)
        self.assert_test(events, number=2, name='', result=TestResult.FAIL)
        self.assert_last(events)


def _clang_at_least(compiler, minver: str, apple_minver: str) -> bool:
    """
    check that Clang compiler is at least a specified version, whether AppleClang or regular Clang

    Parameters
    ----------
    compiler:
        Meson compiler object
    minver: str
        Clang minimum version
    apple_minver: str
        AppleCLang minimum version

    Returns
    -------
    at_least: bool
        Clang is at least the specified version
    """
    if isinstance(compiler, (mesonbuild.compilers.AppleClangCCompiler,
                             mesonbuild.compilers.AppleClangCPPCompiler)):
        return version_compare(compiler.version, apple_minver)
    return version_compare(compiler.version, minver)


def unset_envs():
    # For unit tests we must fully control all command lines
    # so that there are no unexpected changes coming from the
    # environment, for example when doing a package build.
    varnames = ['CPPFLAGS', 'LDFLAGS'] + list(mesonbuild.compilers.compilers.cflags_mapping.values())
    for v in varnames:
        if v in os.environ:
            del os.environ[v]

def convert_args(argv):
    # If we got passed a list of tests, pass it on
    pytest_args = ['-v'] if '-v' in argv else []
    test_list = []
    for arg in argv:
        if arg.startswith('-'):
            continue
        # ClassName.test_name => 'ClassName and test_name'
        if '.' in arg:
            arg = ' and '.join(arg.split('.'))
        test_list.append(arg)
    if test_list:
        pytest_args += ['-k', ' or '.join(test_list)]
    return pytest_args

def main():
    unset_envs()
    try:
        import pytest # noqa: F401
        # Need pytest-xdist for `-n` arg
        import xdist # noqa: F401
        if sys.version_info.major <= 3 and sys.version_info.minor <= 5:
            raise ImportError('pytest with python <= 3.5 is causing issues on the CI')
        pytest_args = ['-n', 'auto', './run_unittests.py']
        pytest_args += convert_args(sys.argv[1:])
        return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode
    except ImportError:
        print('pytest-xdist not found, using unittest instead')
        pass
    # All attempts at locating pytest failed, fall back to plain unittest.
    cases = ['InternalTests', 'DataTests', 'AllPlatformTests', 'FailureTests',
             'PythonTests', 'NativeFileTests', 'RewriterTests', 'CrossFileTests',
             'TAPParserTests',

             'LinuxlikeTests', 'LinuxCrossArmTests', 'LinuxCrossMingwTests',
             'WindowsTests', 'DarwinTests']

    return unittest.main(defaultTest=cases, buffer=True)

if __name__ == '__main__':
    raise SystemExit(main())
meson-0.53.2/setup.cfg0000644000175000017500000000241413625242402016136 0ustar  jpakkanejpakkane00000000000000[metadata]
description = A high performance build system
author = Jussi Pakkanen
author_email = jpakkane@gmail.com
url = https://mesonbuild.com
keywords = 
	meson
	mesonbuild
	build system
	cmake
license = Apache License, Version 2.0
license_file = COPYING
classifiers = 
	Development Status :: 5 - Production/Stable
	Environment :: Console
	Intended Audience :: Developers
	License :: OSI Approved :: Apache Software License
	Natural Language :: English
	Operating System :: MacOS :: MacOS X
	Operating System :: Microsoft :: Windows
	Operating System :: POSIX :: BSD
	Operating System :: POSIX :: Linux
	Programming Language :: Python :: 3 :: Only
	Programming Language :: Python :: 3.5
	Programming Language :: Python :: 3.6
	Programming Language :: Python :: 3.7
	Programming Language :: Python :: 3.8
	Topic :: Software Development :: Build Tools
long_description = Meson is a cross-platform build system designed to be both as fast and as user friendly as possible. It supports many languages and compilers, including GCC, Clang, PGI, Intel, and Visual Studio. Its build definitions are written in a simple non-Turing complete DSL.

[options]
python_requires = >= 3.5.2

[options.extras_require]
progress = 
	tqdm

[tool:pytest]
python_classes = 

[egg_info]
tag_build = 
tag_date = 0

meson-0.53.2/setup.py0000644000175000017500000000405413625260317016036 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys

if sys.version_info < (3, 5, 2):
    raise SystemExit('ERROR: Tried to install Meson with an unsupported Python version: \n{}'
                     '\nMeson requires Python 3.5.2 or greater'.format(sys.version))

from mesonbuild.coredata import version
from setuptools import setup

# On windows, will create Scripts/meson.exe and Scripts/meson-script.py
# Other platforms will create bin/meson
entries = {'console_scripts': ['meson=mesonbuild.mesonmain:main']}
packages = ['mesonbuild',
            'mesonbuild.ast',
            'mesonbuild.backend',
            'mesonbuild.cmake',
            'mesonbuild.compilers',
            'mesonbuild.compilers.mixins',
            'mesonbuild.dependencies',
            'mesonbuild.modules',
            'mesonbuild.scripts',
            'mesonbuild.templates',
            'mesonbuild.wrap']
package_data = {
    'mesonbuild.dependencies': ['data/CMakeLists.txt', 'data/CMakeListsLLVM.txt', 'data/CMakePathInfo.txt'],
    'mesonbuild.cmake': ['data/run_ctgt.py', 'data/preload.cmake'],
}
data_files = []
if sys.platform != 'win32':
    # Only useful on UNIX-like systems
    data_files = [('share/man/man1', ['man/meson.1']),
                  ('share/polkit-1/actions', ['data/com.mesonbuild.install.policy'])]

if __name__ == '__main__':
    setup(name='meson',
          version=version,
          packages=packages,
          package_data=package_data,
          entry_points=entries,
          data_files=data_files,)
meson-0.53.2/test cases/0000755000175000017500000000000013625242353016357 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/0000755000175000017500000000000013625242350017434 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/1 basic/0000755000175000017500000000000013625242354020642 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/1 basic/main.cpp0000644000175000017500000000023213571777336022304 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(void) {
  cmModClass obj("Hello");
  cout << obj.getStr() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/1 basic/meson.build0000644000175000017500000000075513625260317023012 0ustar  jpakkanejpakkane00000000000000project('cmakeSubTest', ['c', 'cpp'])

cm = import('cmake')

sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib++')

assert(sub_pro.found(), 'found() method reports not found, but should be found')
assert(sub_pro.target_list() == ['cmModLib++'], 'There should be exactly one target')
assert(sub_pro.target_type('cmModLib++') == 'shared_library', 'Target type should be shared_library')

exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep])
test('test1', exe1)
meson-0.53.2/test cases/cmake/1 basic/subprojects/0000755000175000017500000000000013625242350023201 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/1 basic/subprojects/cmMod/0000755000175000017500000000000013625242354024244 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/1 basic/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000043413625260317027004 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod)
set (CMAKE_CXX_STANDARD 14)

include_directories(${CMAKE_CURRENT_BINARY_DIR})

add_definitions("-DDO_NOTHING_JUST_A_FLAG=1")

add_library(cmModLib++ SHARED cmMod.cpp)
include(GenerateExportHeader)
generate_export_header(cmModLib++)
meson-0.53.2/test cases/cmake/1 basic/subprojects/cmMod/cmMod.cpp0000644000175000017500000000024013501510132025764 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"

using namespace std;

cmModClass::cmModClass(string foo) {
  str = foo + " World";
}

string cmModClass::getStr() const {
  return str;
}
meson-0.53.2/test cases/cmake/1 basic/subprojects/cmMod/cmMod.hpp0000644000175000017500000000031313625260317026010 0ustar  jpakkanejpakkane00000000000000#pragma once

#include "cmmodlib++_export.h"
#include 

class CMMODLIB___EXPORT cmModClass {
private:
  std::string str;

public:
  cmModClass(std::string foo);

  std::string getStr() const;
};
meson-0.53.2/test cases/cmake/10 header only/0000755000175000017500000000000013625242354022033 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/10 header only/main.cpp0000644000175000017500000000023213571777336023475 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(void) {
  cmModClass obj("Hello");
  cout << obj.getStr() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/10 header only/meson.build0000644000175000017500000000062013605171262024170 0ustar  jpakkanejpakkane00000000000000project('cmakeSubTest', ['c', 'cpp'])

cm = import('cmake')

sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib')

assert(sub_pro.target_list() == ['cmModLib'], 'There should be exactly one target')
assert(sub_pro.target_type('cmModLib') == 'header_only', 'Target type should be header_only')

exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep])
test('test1', exe1)
meson-0.53.2/test cases/cmake/10 header only/subprojects/0000755000175000017500000000000013625242350024372 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/10 header only/subprojects/cmMod/0000755000175000017500000000000013625242354025435 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/10 header only/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000071413531533273030176 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod)
set (CMAKE_CXX_STANDARD 14)

add_definitions("-DDO_NOTHING_JUST_A_FLAG=1")

add_library(cmModLib INTERFACE)
set_target_properties(cmModLib PROPERTIES INTERFACE_COMPILE_OPTIONS "-DCMAKE_FLAG_MUST_BE_PRESENT")
target_include_directories(cmModLib INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_compile_definitions(cmModLib INTERFACE -DCMAKE_COMPILER_DEFINE_STR="compDef")
meson-0.53.2/test cases/cmake/10 header only/subprojects/cmMod/include/0000755000175000017500000000000013625242354027060 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/10 header only/subprojects/cmMod/include/cmMod.hpp0000644000175000017500000000055113531533273030630 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

#ifndef CMAKE_FLAG_MUST_BE_PRESENT
#error "The flag CMAKE_FLAG_MUST_BE_PRESENT was not set"
#endif

class cmModClass {
  private:
    std::string str;
  public:
    cmModClass(std::string foo) {
      str = foo + " World ";
      str += CMAKE_COMPILER_DEFINE_STR;
    }

    inline std::string getStr() const { return str; }
};
meson-0.53.2/test cases/cmake/11 cmake_module_path/0000755000175000017500000000000013625242354023303 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/11 cmake_module_path/cmake/0000755000175000017500000000000013625242354024363 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/11 cmake_module_path/cmake/FindSomethingLikePython.cmake0000644000175000017500000000131613531533273032132 0ustar  jpakkanejpakkane00000000000000cmake_policy(VERSION 3.7)

if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
  find_package(Python COMPONENTS Interpreter)
else()
  find_package(PythonInterp)
endif()

if(Python_FOUND OR PYTHONINTERP_FOUND)
  set(SomethingLikePython_FOUND      ON)
  set(SomethingLikePython_EXECUTABLE ${Python_EXECUTABLE})

  if(NOT DEFINED Python_VERSION)
    set(Python_VERSION ${Python_VERSION_STRING})
  endif()
  if(NOT TARGET Python::Interpreter)
    add_executable(Python::Interpreter IMPORTED)
    set_target_properties(Python::Interpreter PROPERTIES
                          IMPORTED_LOCATION ${Python_EXECUTABLE}
                          VERSION ${Python_VERSION})
  endif()
else()
  set(SomethingLikePython_FOUND OFF)
endif()
meson-0.53.2/test cases/cmake/11 cmake_module_path/meson.build0000644000175000017500000000143613605171243025445 0ustar  jpakkanejpakkane00000000000000# We use Python3 as it's the only thing guaranteed to be available on any platform Meson can run on (unlike Zlib in linuxlike/13 cmake dependency).

project('user CMake find_package module using cmake_module_path',
  meson_version: '>= 0.50.0')

if not find_program('cmake', required: false).found()
  error('MESON_SKIP_TEST cmake binary not available.')
endif

# NOTE: can't request Python3 via dependency('Python3', method: 'cmake')
#  Meson intercepts and wants "method: auto"

# Try to find a dependency with a custom CMake module

dependency('SomethingLikePython', required : true, method : 'cmake', cmake_module_path : 'cmake', modules: 'Python::Interpreter')

dependency('SomethingLikePython', method : 'cmake', cmake_module_path : ['doesNotExist', 'cmake'], modules: 'Python::Interpreter')
meson-0.53.2/test cases/cmake/12 generator expressions/0000755000175000017500000000000013625242354024174 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/12 generator expressions/main.cpp0000644000175000017500000000023213571777336025636 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(void) {
  cmModClass obj("Hello");
  cout << obj.getStr() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/12 generator expressions/meson.build0000644000175000017500000000062013605171270026330 0ustar  jpakkanejpakkane00000000000000project('cmakeSubTest', ['c', 'cpp'])

cm = import('cmake')

sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib')

assert(sub_pro.target_list() == ['cmModLib'], 'There should be exactly one target')
assert(sub_pro.target_type('cmModLib') == 'header_only', 'Target type should be header_only')

exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep])
test('test1', exe1)
meson-0.53.2/test cases/cmake/12 generator expressions/subprojects/0000755000175000017500000000000013625242350026533 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/12 generator expressions/subprojects/cmMod/0000755000175000017500000000000013625242354027576 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/12 generator expressions/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000132413531533273032335 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod)
set (CMAKE_CXX_STANDARD 14)

include(GNUInstallDirs)

add_library(cmModLib INTERFACE)

target_compile_options(cmModLib
  INTERFACE $<$,$>:-DCMAKE_FLAG_ERROR_A> # Check discard = false
  INTERFACE "-DCMAKE_FLAG_REQUIRED_A"
  INTERFACE $<$>,$>>:-DCMAKE_FLAG_REQUIRED_B>
  INTERFACE $<$:-DCMAKE_FLAG_REQUIRED_C>
)

target_include_directories(cmModLib INTERFACE
  $
  $
)

target_compile_definitions(cmModLib INTERFACE -DCMAKE_COMPILER_DEFINE_STR="compDef")
meson-0.53.2/test cases/cmake/12 generator expressions/subprojects/cmMod/include/0000755000175000017500000000000013625242354031221 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/12 generator expressions/subprojects/cmMod/include/cmMod.hpp0000644000175000017500000000114213531533273032766 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

#ifndef CMAKE_FLAG_REQUIRED_A
#error "The flag CMAKE_FLAG_REQUIRED_A was not set"
#endif

#ifndef CMAKE_FLAG_REQUIRED_B
#error "The flag CMAKE_FLAG_REQUIRED_B was not set"
#endif

#ifndef CMAKE_FLAG_REQUIRED_C
#error "The flag CMAKE_FLAG_REQUIRED_C was not set"
#endif

#ifdef CMAKE_FLAG_ERROR_A
#error "The flag CMAKE_FLAG_ERROR_A was set"
#endif

class cmModClass {
  private:
    std::string str;
  public:
    cmModClass(std::string foo) {
      str = foo + " World ";
      str += CMAKE_COMPILER_DEFINE_STR;
    }

    inline std::string getStr() const { return str; }
};
meson-0.53.2/test cases/cmake/13 system includes/0000755000175000017500000000000013625242354022757 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/13 system includes/main.cpp0000644000175000017500000000023213571777336024421 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(void) {
  cmModClass obj("Hello");
  cout << obj.getStr() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/13 system includes/meson.build0000644000175000017500000000070713605171274025125 0ustar  jpakkanejpakkane00000000000000project(
  'meson_cmake_system_include_bug', ['c', 'cpp'],
  default_options: [
    'warning_level=3',
    'werror=true',
  ],
)

if meson.get_compiler('cpp').get_argument_syntax() == 'msvc'
  error('MESON_SKIP_TEST: Skipp with msvc due to missing -system support')
endif

cm = import('cmake')
sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib')

exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep])
test('test1', exe1)
meson-0.53.2/test cases/cmake/13 system includes/subprojects/0000755000175000017500000000000013625242350025316 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/13 system includes/subprojects/cmMod/0000755000175000017500000000000013625242354026361 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/13 system includes/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000062113554403650031117 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod)
set (CMAKE_CXX_STANDARD 14)

include_directories(${CMAKE_CURRENT_BINARY_DIR})

add_definitions("-DDO_NOTHING_JUST_A_FLAG=1")

add_library(cmModLib SHARED cmMod.cpp)
include(GenerateExportHeader)
generate_export_header(cmModLib)

target_compile_options(cmModLib PRIVATE "-Wall" "-Werror")
target_include_directories(cmModLib SYSTEM PRIVATE "sysInc")
meson-0.53.2/test cases/cmake/13 system includes/subprojects/cmMod/cmMod.cpp0000644000175000017500000000032413554403650030122 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"
#include "triggerWarn.hpp"

using namespace std;

cmModClass::cmModClass(string foo) {
  str = foo + " World " + to_string(bar(World));
}

string cmModClass::getStr() const {
  return str;
}
meson-0.53.2/test cases/cmake/13 system includes/subprojects/cmMod/cmMod.hpp0000644000175000017500000000032013554403650030123 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 
#include "cmmodlib_export.h"

class CMMODLIB_EXPORT cmModClass {
  private:
    std::string str;
  public:
    cmModClass(std::string foo);

    std::string getStr() const;
};
meson-0.53.2/test cases/cmake/13 system includes/subprojects/cmMod/sysInc/0000755000175000017500000000000013625242354027631 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/13 system includes/subprojects/cmMod/sysInc/triggerWarn.hpp0000644000175000017500000000027013554403650032633 0ustar  jpakkanejpakkane00000000000000#pragma once

enum Foo {
    Hello,
    World
};

inline int bar( Foo foo ) {
  switch(foo) {
    case Hello: return 0;
    // Warn because of missung case for World
  }
  return 1;
}
meson-0.53.2/test cases/cmake/14 fortran threads/0000755000175000017500000000000013625242354022733 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/14 fortran threads/meson.build0000644000175000017500000000070213605171271025071 0ustar  jpakkanejpakkane00000000000000project('FortranThreads')

if not add_languages('fortran', required: false)
  error('MESON_SKIP_TEST: Fortran language not available.')
endif

# want to be sure that CMake can find dependencies where even if the
# project isn't C, the C language is required to find the library.
threads = dependency('threads', method: 'cmake', required: false)
if not threads.found()
  error('MESON_SKIP_TEST: CMake backend not working for Fortran / threads')
endif
meson-0.53.2/test cases/cmake/15 object library advanced/0000755000175000017500000000000013625242354024267 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/15 object library advanced/main.cpp0000644000175000017500000000027513602226377025725 0ustar  jpakkanejpakkane00000000000000#include 
#include "libA.hpp"
#include "libB.hpp"

using namespace std;

int main(void) {
  cout << getLibStr() << endl;
  cout << getZlibVers() << endl;
  return EXIT_SUCCESS;
}
meson-0.53.2/test cases/cmake/15 object library advanced/meson.build0000644000175000017500000000062313605171300026420 0ustar  jpakkanejpakkane00000000000000project('cmake_object_lib_test', 'cpp', default_options: ['cpp_std=c++11'])

cm = import('cmake')

sub_pro = cm.subproject('cmObjLib')
sub_sha = sub_pro.dependency('lib_sha')
sub_sta = sub_pro.dependency('lib_sta')

exe_sha = executable('shared', ['main.cpp'], dependencies: [sub_sha])
exe_sta = executable('static', ['main.cpp'], dependencies: [sub_sta])

test('test1', exe_sha)
test('test1', exe_sta)
meson-0.53.2/test cases/cmake/15 object library advanced/subprojects/0000755000175000017500000000000013625242350026626 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/0000755000175000017500000000000013625242354030313 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/CMakeLists.txt0000644000175000017500000000114613602226377033057 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.7)
project(cmObject CXX)

add_executable(genC genC.cpp)

add_custom_command(
  OUTPUT  "${CMAKE_CURRENT_BINARY_DIR}/libC.cpp" "${CMAKE_CURRENT_BINARY_DIR}/libC.hpp"
  COMMAND genC
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)

include_directories("${CMAKE_CURRENT_BINARY_DIR}")

add_library(lib_obj OBJECT libA.cpp libB.cpp "${CMAKE_CURRENT_BINARY_DIR}/libC.cpp" "${CMAKE_CURRENT_BINARY_DIR}/libC.hpp")
add_library(lib_sha SHARED $)
add_library(lib_sta STATIC $)

target_compile_definitions(lib_obj PRIVATE "-DBUILD_AS_OBJ=1")
meson-0.53.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/genC.cpp0000644000175000017500000000071313602226377031676 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main() {
  ofstream hpp("libC.hpp");
  ofstream cpp("libC.cpp");
  if (!hpp.is_open() || !cpp.is_open()) {
    cerr << "Failed to open 'libC.hpp' or 'libC.cpp' for writing" << endl;
    return 1;
  }

  hpp << R"cpp(
#pragma once

#include 

std::string getGenStr();
)cpp";

  cpp << R"cpp(
#include "libC.hpp"

std::string getGenStr(void) {
  return "GEN STR";
}
)cpp";

  return 0;
}meson-0.53.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/libA.cpp0000644000175000017500000000022013602226377031662 0ustar  jpakkanejpakkane00000000000000#include "libA.hpp"

#if not BUILD_AS_OBJ
#error "BUILD_AS_OBJ was not defined"
#endif

std::string getLibStr(void) {
  return "Hello World";
}
meson-0.53.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/libA.hpp0000644000175000017500000000055213602226377031677 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

std::string DLL_PUBLIC getLibStr();
meson-0.53.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/libB.cpp0000644000175000017500000000014113602226377031665 0ustar  jpakkanejpakkane00000000000000#include "libB.hpp"
#include "libC.hpp"

std::string getZlibVers(void) {
  return getGenStr();
}
meson-0.53.2/test cases/cmake/15 object library advanced/subprojects/cmObjLib/libB.hpp0000644000175000017500000000055413602226377031702 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

std::string DLL_PUBLIC getZlibVers();
meson-0.53.2/test cases/cmake/16 threads/0000755000175000017500000000000013625242354021301 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/16 threads/main.cpp0000644000175000017500000000022513602226377022732 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"

#include 

int main() {
  CmMod cc;
  cc.asyncIncrement();
  return cc.getNum() == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
}
meson-0.53.2/test cases/cmake/16 threads/meson.build0000644000175000017500000000070613625260317023445 0ustar  jpakkanejpakkane00000000000000project('cmMod', ['c', 'cpp'])

cm        = import('cmake')
cmOpts    = ['-DUSE_PTHREAD=@0@'.format(get_option('use_pthread'))]
cmMod     = cm.subproject('cmMod', cmake_options: cmOpts)
cmModDep1 = cmMod.dependency('cmModLib')
cmModDep2 = cmMod.dependency('cmModLib_shared')

exe1 = executable('exe1', ['main.cpp'], dependencies: [cmModDep1])
exe2 = executable('exe2', ['main.cpp'], dependencies: [cmModDep2])
test('exe1_OK', exe1)
test('exe2_OK', exe2)
meson-0.53.2/test cases/cmake/16 threads/meson_options.txt0000644000175000017500000000012513625260317024733 0ustar  jpakkanejpakkane00000000000000option('use_pthread', type: 'combo', choices: ['ON', 'OFF', 'NOT_SET'], value: 'ON')
meson-0.53.2/test cases/cmake/16 threads/subprojects/0000755000175000017500000000000013625242350023640 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/16 threads/subprojects/cmMod/0000755000175000017500000000000013625242354024703 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000063113625260317027442 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod CXX)
set (CMAKE_CXX_STANDARD 14)

if(NOT USE_PTHREAD STREQUAL NOT_SET)
  set(THREADS_PREFER_PTHREAD_FLAG ${USE_PTHREAD})
endif()
find_package(Threads)

add_library(cmModLib STATIC cmMod.cpp)
target_link_libraries(cmModLib PRIVATE Threads::Threads)

add_library(cmModLib_shared SHARED cmMod.cpp)
target_link_libraries(cmModLib_shared PUBLIC Threads::Threads)
meson-0.53.2/test cases/cmake/16 threads/subprojects/cmMod/cmMod.cpp0000644000175000017500000000035113602226377026447 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"

#include 
#include 

using namespace std::chrono_literals;

void CmMod::asyncIncrement() {
  std::thread t1([this]() {
    std::this_thread::sleep_for(100ms);
    num += 1;
  });

  t1.join();
}
meson-0.53.2/test cases/cmake/16 threads/subprojects/cmMod/cmMod.hpp0000644000175000017500000000063713625260317026460 0ustar  jpakkanejpakkane00000000000000#pragma once

#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
#if defined __GNUC__
#define DLL_PUBLIC __attribute__((visibility("default")))
#else
#pragma message("Compiler does not support symbol visibility.")
#define DLL_PUBLIC
#endif
#endif

class DLL_PUBLIC CmMod {
private:
  int num = 0;

public:
  inline int getNum() const { return num; }
  void asyncIncrement();
};
meson-0.53.2/test cases/cmake/16 threads/subprojects/cmMod/main.cpp0000644000175000017500000000022513602226377026334 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"

#include 

int main() {
  CmMod cc;
  cc.asyncIncrement();
  return cc.getNum() == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
}
meson-0.53.2/test cases/cmake/16 threads/test_matrix.json0000644000175000017500000000020513625260317024533 0ustar  jpakkanejpakkane00000000000000{
  "options": {
    "use_pthread": [
      { "val": "ON"      },
      { "val": "OFF"     },
      { "val": "NOT_SET" }
    ]
  }
}
meson-0.53.2/test cases/cmake/2 advanced/0000755000175000017500000000000013625242354021327 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/2 advanced/installed_files.txt0000644000175000017500000000017713571777336025253 0ustar  jpakkanejpakkane00000000000000usr/?lib/libcm_cmModLib?so
?cygwin:usr/lib/libcm_cmModLib?implib
?!cygwin:usr/bin/libcm_cmModLib?implib
usr/bin/cm_testEXE?exe
meson-0.53.2/test cases/cmake/2 advanced/main.cpp0000644000175000017500000000036013571777336022773 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "config.h"

#if CONFIG_OPT != 42
#error "Invalid value of CONFIG_OPT"
#endif

using namespace std;

int main(void) {
  cmModClass obj("Hello");
  cout << obj.getStr() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/2 advanced/meson.build0000644000175000017500000000136213605171221023463 0ustar  jpakkanejpakkane00000000000000project('cmakeSubTest_advanced', ['c', 'cpp'])

dep_test = dependency('ZLIB', method: 'cmake', required: false)
if not dep_test.found()
  error('MESON_SKIP_TEST: zlib is not installed')
endif

cm = import('cmake')

# Test the "normal" subproject call
sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib')
sub_sta = sub_pro.dependency('cmModLibStatic')

# Build some files
exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep])
exe2 = executable('main2', ['main.cpp'], dependencies: [sub_sta])
test('test1', exe1)
test('test2', exe2)

# Test if we can also extract executables
assert(sub_pro.target_type('testEXE') == 'executable', 'The type must be executable for obvious reasons')
test('test3', sub_pro.target('testEXE'))
meson-0.53.2/test cases/cmake/2 advanced/subprojects/0000755000175000017500000000000013625242350023666 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/2 advanced/subprojects/cmMod/0000755000175000017500000000000013625242355024732 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000153713602226377027501 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod)
set(CMAKE_CXX_STANDARD 14)

find_package(ZLIB REQUIRED)

include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib)

set(CONFIG_OPT 42)
configure_file("config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)

add_library(cmModLib       SHARED lib/cmMod.cpp)
add_library(cmModLibStatic STATIC lib/cmMod.cpp)
include(GenerateExportHeader)
generate_export_header(cmModLib)

set_target_properties(cmModLib PROPERTIES VERSION 1.0.1)

add_executable(testEXE main.cpp)

target_link_libraries(cmModLib       ZLIB::ZLIB)
target_link_libraries(cmModLibStatic ZLIB::ZLIB)
target_link_libraries(testEXE cmModLib)

target_compile_definitions(cmModLibStatic PUBLIC CMMODLIB_STATIC_DEFINE)

install(TARGETS cmModLib testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin)
meson-0.53.2/test cases/cmake/2 advanced/subprojects/cmMod/config.h.in0000644000175000017500000000005613501510132026736 0ustar  jpakkanejpakkane00000000000000#pragma once

#define CONFIG_OPT @CONFIG_OPT@
meson-0.53.2/test cases/cmake/2 advanced/subprojects/cmMod/lib/0000755000175000017500000000000013625242355025500 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/2 advanced/subprojects/cmMod/lib/cmMod.cpp0000644000175000017500000000043113501510132027221 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"
#include 
#include "config.h"

#if CONFIG_OPT != 42
#error "Invalid value of CONFIG_OPT"
#endif

using namespace std;

cmModClass::cmModClass(string foo) {
  str = foo + " World " + zlibVersion();
}

string cmModClass::getStr() const {
  return str;
}
meson-0.53.2/test cases/cmake/2 advanced/subprojects/cmMod/lib/cmMod.hpp0000644000175000017500000000032013501510132027223 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 
#include "cmmodlib_export.h"

class CMMODLIB_EXPORT cmModClass {
  private:
    std::string str;
  public:
    cmModClass(std::string foo);

    std::string getStr() const;
};
meson-0.53.2/test cases/cmake/2 advanced/subprojects/cmMod/main.cpp0000644000175000017500000000033113571777336026373 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "lib/cmMod.hpp"

using namespace std;

int main(void) {
  cmModClass obj("Hello (LIB TEST)");
  cout << obj.getStr() << " ZLIB: " << zlibVersion() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/3 advanced no dep/0000755000175000017500000000000013625242355022457 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/3 advanced no dep/installed_files.txt0000644000175000017500000000027113571777336026375 0ustar  jpakkanejpakkane00000000000000usr/?lib/libcm_cmModLib?so
?cygwin:usr/lib/libcm_cmModLib?implib
?!cygwin:usr/bin/libcm_cmModLib?implib
?msvc:usr/bin/cm_cmModLib.pdb
?msvc:usr/bin/cm_testEXE.pdb
usr/bin/cm_testEXE?exemeson-0.53.2/test cases/cmake/3 advanced no dep/main.cpp0000644000175000017500000000036013571777336024122 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "config.h"

#if CONFIG_OPT != 42
#error "Invalid value of CONFIG_OPT"
#endif

using namespace std;

int main(void) {
  cmModClass obj("Hello");
  cout << obj.getStr() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/3 advanced no dep/meson.build0000644000175000017500000000114113605171220024604 0ustar  jpakkanejpakkane00000000000000project('cmakeSubTest_advanced', ['c', 'cpp'])

cm = import('cmake')

# Test the "normal" subproject call
sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib')
sub_sta = sub_pro.dependency('cmModLibStatic')

# Build some files
exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep])
exe2 = executable('main2', ['main.cpp'], dependencies: [sub_sta])
test('test1', exe1)
test('test2', exe2)

# Test if we can also extract executables
assert(sub_pro.target_type('testEXE') == 'executable', 'The type must be executable for obvious reasons')
test('test3', sub_pro.target('testEXE'))
meson-0.53.2/test cases/cmake/3 advanced no dep/subprojects/0000755000175000017500000000000013625242350025015 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/0000755000175000017500000000000013625242355026061 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000134013602226377030620 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod)
set(CMAKE_CXX_STANDARD 14)

include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib)

set(CONFIG_OPT 42)
configure_file("config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)

add_library(cmModLib       SHARED lib/cmMod.cpp)
add_library(cmModLibStatic STATIC lib/cmMod.cpp)
include(GenerateExportHeader)
generate_export_header(cmModLib)

set_target_properties(cmModLib PROPERTIES VERSION 1.0.1)

add_executable(testEXE main.cpp)

target_link_libraries(testEXE cmModLib)

target_compile_definitions(cmModLibStatic PUBLIC CMMODLIB_STATIC_DEFINE)

install(TARGETS cmModLib testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin)
meson-0.53.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/config.h.in0000644000175000017500000000005613501510132030065 0ustar  jpakkanejpakkane00000000000000#pragma once

#define CONFIG_OPT @CONFIG_OPT@
meson-0.53.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/lib/0000755000175000017500000000000013625242355026627 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/lib/cmMod.cpp0000644000175000017500000000036613501510132030357 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"
#include "config.h"

#if CONFIG_OPT != 42
#error "Invalid value of CONFIG_OPT"
#endif

using namespace std;

cmModClass::cmModClass(string foo) {
  str = foo + " World";
}

string cmModClass::getStr() const {
  return str;
}
meson-0.53.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/lib/cmMod.hpp0000644000175000017500000000032013501510132030352 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 
#include "cmmodlib_export.h"

class CMMODLIB_EXPORT cmModClass {
  private:
    std::string str;
  public:
    cmModClass(std::string foo);

    std::string getStr() const;
};
meson-0.53.2/test cases/cmake/3 advanced no dep/subprojects/cmMod/main.cpp0000644000175000017500000000025113571777336027523 0ustar  jpakkanejpakkane00000000000000#include 
#include "lib/cmMod.hpp"

using namespace std;

int main(void) {
  cmModClass obj("Hello (LIB TEST)");
  cout << obj.getStr() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/4 code gen/0000755000175000017500000000000013625242355021231 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/4 code gen/main.cpp0000644000175000017500000000015613571777336022677 0ustar  jpakkanejpakkane00000000000000#include 
#include "test.hpp"

using namespace std;

int main(void) {
  cout << getStr() << endl;
}
meson-0.53.2/test cases/cmake/4 code gen/meson.build0000644000175000017500000000062513605171215023370 0ustar  jpakkanejpakkane00000000000000project('cmake_code_gen', ['c', 'cpp'])

cm = import('cmake')

# Subproject with the "code generator"
sub_pro = cm.subproject('cmCodeGen')
sub_exe = sub_pro.target('genA')

# Generate the source
generated = custom_target(
  'cmake-generated',
  input: [],
  output: ['test.cpp'],
  command: [sub_exe, '@OUTPUT@']
)

# Build the exe
exe1 = executable('main1', ['main.cpp', generated])

test('test1', exe1)
meson-0.53.2/test cases/cmake/4 code gen/subprojects/0000755000175000017500000000000013625242350023567 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/4 code gen/subprojects/cmCodeGen/0000755000175000017500000000000013625242355025420 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/4 code gen/subprojects/cmCodeGen/CMakeLists.txt0000644000175000017500000000013713501510132030141 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.7)

set(CMAKE_CXX_STANDARD 14)

add_executable(genA main.cpp)
meson-0.53.2/test cases/cmake/4 code gen/subprojects/cmCodeGen/main.cpp0000644000175000017500000000050513501510132027030 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(int argc, const char *argv[]) {
  if(argc < 2) {
    cerr << argv[0] << " requires an output file!" << endl;
    return 1;
  }
  ofstream out(argv[1]);
  out << R"(
#include "test.hpp"

std::string getStr() {
  return "Hello World";
}
)";

  return 0;
}
meson-0.53.2/test cases/cmake/4 code gen/test.hpp0000644000175000017500000000006713501510132022704 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

std::string getStr();
meson-0.53.2/test cases/cmake/5 object library/0000755000175000017500000000000013625242355022461 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/5 object library/main.cpp0000644000175000017500000000031313612411367024103 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "libA.hpp"
#include "libB.hpp"

using namespace std;

int main(void) {
  cout << getLibStr() << " -- " << getZlibVers() << endl;
  return EXIT_SUCCESS;
}
meson-0.53.2/test cases/cmake/5 object library/meson.build0000644000175000017500000000112213605171232024610 0ustar  jpakkanejpakkane00000000000000project('cmake_object_lib_test', ['c', 'cpp'])

dep_test = dependency('ZLIB', method: 'cmake', required: false)
if not dep_test.found()
  error('MESON_SKIP_TEST: zlib is not installed')
endif

cm = import('cmake')

sub_pro = cm.subproject('cmObjLib')
sub_sha = sub_pro.dependency('lib_sha')
sub_sta = sub_pro.dependency('lib_sta')

# Required for the static library
zlib_dep = dependency('zlib')

exe_sha = executable('shared', ['main.cpp'], dependencies: [sub_sha])
exe_sta = executable('static', ['main.cpp'], dependencies: [sub_sta, zlib_dep])

test('test1', exe_sha)
test('test1', exe_sta)
meson-0.53.2/test cases/cmake/5 object library/subprojects/0000755000175000017500000000000013625242350025017 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/5 object library/subprojects/cmObjLib/0000755000175000017500000000000013625242355026505 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/5 object library/subprojects/cmObjLib/CMakeLists.txt0000644000175000017500000000050713602226377031250 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.7)
project(cmObject CXX)

find_package(ZLIB REQUIRED)

add_library(lib_obj OBJECT libA.cpp libB.cpp)
add_library(lib_sha SHARED $)
add_library(lib_sta STATIC $)

target_link_libraries(lib_sha ZLIB::ZLIB)
target_link_libraries(lib_sta ZLIB::ZLIB)
meson-0.53.2/test cases/cmake/5 object library/subprojects/cmObjLib/libA.cpp0000644000175000017500000000011513602226377030056 0ustar  jpakkanejpakkane00000000000000#include "libA.hpp"

std::string getLibStr(void) {
  return "Hello World";
}
meson-0.53.2/test cases/cmake/5 object library/subprojects/cmObjLib/libA.hpp0000644000175000017500000000055213602226377030070 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

std::string DLL_PUBLIC getLibStr();
meson-0.53.2/test cases/cmake/5 object library/subprojects/cmObjLib/libB.cpp0000644000175000017500000000014113602226377030056 0ustar  jpakkanejpakkane00000000000000#include "libB.hpp"
#include 

std::string getZlibVers(void) {
  return zlibVersion();
}
meson-0.53.2/test cases/cmake/5 object library/subprojects/cmObjLib/libB.hpp0000644000175000017500000000055413602226377030073 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

std::string DLL_PUBLIC getZlibVers();
meson-0.53.2/test cases/cmake/6 object library no dep/0000755000175000017500000000000013625242355023610 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/6 object library no dep/main.cpp0000644000175000017500000000031313612411367025232 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "libA.hpp"
#include "libB.hpp"

using namespace std;

int main(void) {
  cout << getLibStr() << " -- " << getZlibVers() << endl;
  return EXIT_SUCCESS;
}
meson-0.53.2/test cases/cmake/6 object library no dep/meson.build0000644000175000017500000000055713605171233025753 0ustar  jpakkanejpakkane00000000000000project('cmake_object_lib_test', 'cpp')

cm = import('cmake')

sub_pro = cm.subproject('cmObjLib')
sub_sha = sub_pro.dependency('lib_sha')
sub_sta = sub_pro.dependency('lib_sta')

exe_sha = executable('shared', ['main.cpp'], dependencies: [sub_sha])
exe_sta = executable('static', ['main.cpp'], dependencies: [sub_sta])

test('test1', exe_sha)
test('test1', exe_sta)
meson-0.53.2/test cases/cmake/6 object library no dep/subprojects/0000755000175000017500000000000013625242350026146 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/0000755000175000017500000000000013625242355027634 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/CMakeLists.txt0000644000175000017500000000032513602226377032375 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.7)
project(cmObject CXX)

add_library(lib_obj OBJECT libA.cpp libB.cpp)
add_library(lib_sha SHARED $)
add_library(lib_sta STATIC $)
meson-0.53.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/libA.cpp0000644000175000017500000000011513602226377031205 0ustar  jpakkanejpakkane00000000000000#include "libA.hpp"

std::string getLibStr(void) {
  return "Hello World";
}
meson-0.53.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/libA.hpp0000644000175000017500000000055213602226377031217 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

std::string DLL_PUBLIC getLibStr();
meson-0.53.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/libB.cpp0000644000175000017500000000011013602226377031201 0ustar  jpakkanejpakkane00000000000000#include "libB.hpp"

std::string getZlibVers(void) {
  return "STUB";
}
meson-0.53.2/test cases/cmake/6 object library no dep/subprojects/cmObjLib/libB.hpp0000644000175000017500000000055413602226377031222 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

std::string DLL_PUBLIC getZlibVers();
meson-0.53.2/test cases/cmake/7 cmake options/0000755000175000017500000000000013625242355022324 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/7 cmake options/meson.build0000644000175000017500000000017213605171246024464 0ustar  jpakkanejpakkane00000000000000project('cmake_set_opt', ['c', 'cpp'])

import('cmake').subproject('cmOpts', cmake_options: '-DSOME_CMAKE_VAR=something')
meson-0.53.2/test cases/cmake/7 cmake options/subprojects/0000755000175000017500000000000013625242350024662 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/7 cmake options/subprojects/cmOpts/0000755000175000017500000000000013625242355026134 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/7 cmake options/subprojects/cmOpts/CMakeLists.txt0000644000175000017500000000022413501510132030652 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.7)

if(NOT "${SOME_CMAKE_VAR}" STREQUAL "something")
  message(FATAL_ERROR "Setting the CMake var failed")
endif()
meson-0.53.2/test cases/cmake/8 custom command/0000755000175000017500000000000013625242355022502 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/8 custom command/main.cpp0000644000175000017500000000027413571777336024151 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(void) {
  cmModClass obj("Hello");
  cout << obj.getStr() << endl;
  cout << obj.getOther() << endl;
  return 0;
}
meson-0.53.2/test cases/cmake/8 custom command/meson.build0000644000175000017500000000063113605171262024640 0ustar  jpakkanejpakkane00000000000000project('cmakeSubTest', ['c', 'cpp'])

cm = import('cmake')

sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib')

assert(sub_pro.target_type('cmModLib') == 'shared_library', 'Target type should be shared_library')
assert(sub_pro.target_type('gen') == 'executable', 'Target type should be executable')

exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep])
test('test1', exe1)
meson-0.53.2/test cases/cmake/8 custom command/subprojects/0000755000175000017500000000000013625242350025040 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/0000755000175000017500000000000013625242355026104 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/CMakeLists.txt0000644000175000017500000001063713625260317030651 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod)
set (CMAKE_CXX_STANDARD 14)
set (CMAKE_CXX_STANDARD_REQUIRED ON)

include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_definitions("-DDO_NOTHING_JUST_A_FLAG=1")

add_executable(gen main.cpp)
add_executable(mycpy cp.cpp)

# cpyBase
add_custom_command(
  OUTPUT  "${CMAKE_CURRENT_BINARY_DIR}/genTest.cpp" "${CMAKE_CURRENT_BINARY_DIR}/genTest.hpp"
  COMMAND gen ARGS genTest
)

add_custom_command(
  OUTPUT cpyBase.cpp
  COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyBase.cpp.am" cpyBase.cpp.in
  COMMAND mycpy cpyBase.cpp.in                               cpyBase.cpp.something
  COMMAND mycpy cpyBase.cpp.something                        cpyBase.cpp.IAmRunningOutOfIdeas
  COMMAND mycpy cpyBase.cpp.IAmRunningOutOfIdeas             cpyBase.cpp
  DEPENDS cpyBase.cpp.am;gen
)

add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyBase.hpp.in"
  COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyBase.hpp.am" cpyBase.hpp.in
  DEPENDS cpyBase.hpp.am
)

add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyBase.hpp.something"
  COMMAND mycpy cpyBase.hpp.in                               cpyBase.hpp.something
  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/cpyBase.hpp.in"
)

add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyBase.hpp"
  COMMAND mycpy cpyBase.hpp.something                        cpyBase.hpp
  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/cpyBase.hpp.something"
)

# cpyNext (out of order is on purpose)
# -- first copy round
add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/s1_a_hpp/file.txt"
  COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyNext.hpp.am" file.txt
  DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/cpyNext.hpp.am"
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/s1_a_hpp"
)

add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/s1_b_cpp/file.txt"
  COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyNext.cpp.am" file.txt
  DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/cpyNext.cpp.am"
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/s1_b_cpp"
)

# -- final cpy round
add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyNext.hpp"
  COMMAND mycpy "${CMAKE_CURRENT_BINARY_DIR}/s2_b_hpp/file.txt" cpyNext.hpp
  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/s2_b_hpp/file.txt"
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)

add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyNext.cpp"
  COMMAND mycpy "${CMAKE_CURRENT_BINARY_DIR}/s2_a_cpp/file.txt" cpyNext.cpp
  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/s2_a_cpp/file.txt"
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)

# -- second copy round
add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/s2_b_hpp/file.txt"
  COMMAND mycpy "${CMAKE_CURRENT_BINARY_DIR}/s1_a_hpp/file.txt" file.txt
  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/s1_a_hpp/file.txt"
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/s2_b_hpp"
)

add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/s2_a_cpp/file.txt"
  COMMAND mycpy "${CMAKE_CURRENT_BINARY_DIR}/s1_b_cpp/file.txt" file.txt
  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/s1_b_cpp/file.txt"
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/s2_a_cpp"
)

# cpyTest (copy file without renaming)
add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyTest.hpp"
  COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyTest/cpyTest.hpp" "${CMAKE_CURRENT_BINARY_DIR}/cpyTest.hpp"
  DEPENDS "cpyTest/cpyTest.hpp"
)

add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyTest2.hpp"
  COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyTest/cpyTest2.hpp" "${CMAKE_CURRENT_BINARY_DIR}/cpyTest2.hpp"
  DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/cpyTest/cpyTest2.hpp"
)

add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cpyTest3.hpp"
  COMMAND mycpy cpyTest3.hpp "${CMAKE_CURRENT_BINARY_DIR}/cpyTest3.hpp"
  DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/cpyTest/cpyTest3.hpp"
  WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cpyTest"
)

add_subdirectory(cpyTest ccppyyTTeesstt)

add_library(cmModLib SHARED cmMod.cpp genTest.cpp cpyBase.cpp cpyBase.hpp cpyNext.cpp cpyNext.hpp cpyTest.cpp cpyTest.hpp cpyTest2.hpp cpyTest3.hpp)
include(GenerateExportHeader)
generate_export_header(cmModLib)

set(ARGS_TEST arg1)
set(ARGS_TEST ${ARGS_TEST} arg2)

add_executable(macro_name macro_name.cpp)
add_executable(args_test args_test.cpp)
add_custom_target(args_test_cmd
  COMMAND args_test ${ARGS_TEST}
)
add_custom_target(macro_name_cmd COMMAND macro_name)

add_dependencies(cmModLib args_test_cmd tgtCpyTest4)
add_dependencies(args_test_cmd macro_name_cmd;gen;mycpy)
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/args_test.cpp0000644000175000017500000000060213571777336030615 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(int argc, const char *argv[]) {
  if(argc != 3 || string(argv[1]) != "arg1" || string(argv[2]) != "arg2") {
    cerr << argv[0] << " requires 2 args" << endl;
    return 1;
  }

  ifstream in1("macro_name.txt");
  ofstream out1("cmModLib.hpp");
  out1 << "#define " << in1.rdbuf() << " = \"plop\"";


  return 0;
}
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cmMod.cpp0000644000175000017500000000070513625260317027647 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"
#include "genTest.hpp"
#include "cpyBase.hpp"
#include "cpyNext.hpp"
#include "cpyTest.hpp"
#include "cmModLib.hpp"

#ifndef FOO
#error FOO not declared
#endif

using namespace std;

cmModClass::cmModClass(string foo) {
  str = foo + " World";
}

string cmModClass::getStr() const {
  return str;
}

string cmModClass::getOther() const {
  return "Srings:\n - " + getStrCpy() + "\n - " + getStrNext() + "\n - " + getStrCpyTest();
}
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cmMod.hpp0000644000175000017500000000036213531533273027653 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 
#include "cmmodlib_export.h"

class CMMODLIB_EXPORT cmModClass {
  private:
    std::string str;
  public:
    cmModClass(std::string foo);

    std::string getStr() const;
    std::string getOther() const;
};
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cp.cpp0000644000175000017500000000060113571777347027225 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(int argc, char *argv[]) {
  if(argc < 3) {
    cerr << argv[0] << " requires an input and an output file!" << endl;
    return 1;
  }

  ifstream src(argv[1]);
  ofstream dst(argv[2]);

  if(!src.is_open()) {
    cerr << "Failed to open " << argv[1] << endl;
    return 2;
  }

  dst << src.rdbuf();
  return 0;
}
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyBase.cpp.am0000644000175000017500000000012213531533273030563 0ustar  jpakkanejpakkane00000000000000#include "cpyBase.hpp"

std::string getStrCpy() {
  return "Hello Copied File";
}
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyBase.hpp.am0000644000175000017500000000007213531533273030574 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

std::string getStrCpy();
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyNext.cpp.am0000644000175000017500000000016013571777347030651 0ustar  jpakkanejpakkane00000000000000#include "cpyNext.hpp"

std::string getStrNext() {
  return "Hello Copied File -- now even more convoluted!";
}
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyNext.hpp.am0000644000175000017500000000007313571777347030661 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

std::string getStrNext();
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/0000755000175000017500000000000013625242355027537 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/CMakeLists.txt0000644000175000017500000000033613625260317032277 0ustar  jpakkanejpakkane00000000000000add_custom_command(
  OUTPUT cpyTest4.hpp
  COMMAND mycpy "${CMAKE_CURRENT_SOURCE_DIR}/cpyTest4.hpp" cpyTest4.hpp
  DEPENDS cpyTest4.hpp
)

add_custom_target(tgtCpyTest4 DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/cpyTest4.hpp")
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest.hpp0000644000175000017500000000007613625260317031704 0ustar  jpakkanejpakkane00000000000000#pragma once

#include 

std::string getStrCpyTest();
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest2.hpp0000644000175000017500000000005613625260317031764 0ustar  jpakkanejpakkane00000000000000#pragma once

#define CPY_TEST_STR_2 "Hello "
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest3.hpp0000644000175000017500000000006013625260317031760 0ustar  jpakkanejpakkane00000000000000#pragma once

#define CPY_TEST_STR_3 "CopyFile"
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest/cpyTest4.hpp0000644000175000017500000000005513625260317031765 0ustar  jpakkanejpakkane00000000000000#pragma once

#define CPY_TEST_STR_4 " test"
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/cpyTest.cpp0000644000175000017500000000030613625260317030240 0ustar  jpakkanejpakkane00000000000000#include "cpyTest.hpp"
#include "cpyTest2.hpp"
#include "cpyTest3.hpp"
#include "ccppyyTTeesstt/cpyTest4.hpp"

std::string getStrCpyTest() {
  return CPY_TEST_STR_2 CPY_TEST_STR_3 CPY_TEST_STR_4;
}
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/macro_name.cpp0000644000175000017500000000034013571777336030722 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include 
#include 

using namespace std;

int main() {
  this_thread::sleep_for(chrono::seconds(1));
  ofstream out1("macro_name.txt");
  out1 << "FOO";

  return 0;
}
meson-0.53.2/test cases/cmake/8 custom command/subprojects/cmMod/main.cpp0000644000175000017500000000073513531533273027537 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(int argc, const char *argv[]) {
  if(argc < 2) {
    cerr << argv[0] << " requires an output file!" << endl;
    return 1;
  }
  ofstream out1(string(argv[1]) + ".hpp");
  ofstream out2(string(argv[1]) + ".cpp");
  out1 << R"(
#pragma once

#include 

std::string getStr();
)";

  out2 << R"(
#include ")" << argv[1] << R"(.hpp"

std::string getStr() {
  return "Hello World";
}
)";

  return 0;
}
meson-0.53.2/test cases/cmake/9 disabled subproject/0000755000175000017500000000000013625242355023502 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cmake/9 disabled subproject/meson.build0000644000175000017500000000027013625260317025641 0ustar  jpakkanejpakkane00000000000000project('cmakeSubTest', ['c', 'cpp'])

cm = import('cmake')

sub_pro = cm.subproject('nothinig', required: false)
assert(not sub_pro.found(), 'subproject found() reports wrong value')
meson-0.53.2/test cases/common/0000755000175000017500000000000013625242351017645 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/1 trivial/0000755000175000017500000000000013625242355021444 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/1 trivial/meson.build0000644000175000017500000000165313605171303023603 0ustar  jpakkanejpakkane00000000000000# Comment on the first line
project('trivial test',
  # Comment inside a function call + array for language list
  ['c'],
  meson_version : '>=0.52.0')
#this is a comment
sources = 'trivial.c'

cc = meson.get_compiler('c')
if cc.get_id() == 'intel'
  # Error out if the -std=xxx option is incorrect
  add_project_arguments('-diag-error', '10159', language : 'c')
elif cc.get_id() == 'intel-cl'
  add_project_arguments('/Qdiag-error:10159', language : 'c')
endif

if meson.is_cross_build()
  native_exe = executable('native-trivialprog', sources : sources, native : true)
  test('native exe in cross build', native_exe)
endif

exe = executable('trivialprog', sources : sources)

test('runtest', exe) # This is a comment

has_not_changed = false
if is_disabler(exe)
    has_not_changed = true
else
    has_not_changed = true
endif
assert(has_not_changed, 'Executable has changed.')

assert(not is_disabler(exe), 'Executable is a disabler.')
meson-0.53.2/test cases/common/1 trivial/trivial.c0000644000175000017500000000013613571777336023276 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("Trivial test is working.\n");
    return 0;
}
meson-0.53.2/test cases/common/10 man install/0000755000175000017500000000000013625242355022254 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/10 man install/bar.20000644000175000017500000000007012650745767023114 0ustar  jpakkanejpakkane00000000000000this is a man page of bar.2, its contents are irrelevantmeson-0.53.2/test cases/common/10 man install/baz.1.in0000644000175000017500000000041413140423077023510 0ustar  jpakkanejpakkane00000000000000This is a man page of baz.1 it was generated @TODAY@.

You should not put generation timestamps in real world projects
because they break reproducible builds. This manpage is written
by professionals or under the supervision of professionals. Do
not try this at home.
meson-0.53.2/test cases/common/10 man install/foo.10000644000175000017500000000007012650745767023132 0ustar  jpakkanejpakkane00000000000000this is a man page of foo.1 its contents are irrelevant
meson-0.53.2/test cases/common/10 man install/installed_files.txt0000644000175000017500000000021113403223104026131 0ustar  jpakkanejpakkane00000000000000usr/share/man/man1/foo.1
usr/share/man/man2/bar.2
usr/share/man/man1/vanishing.1
usr/share/man/man2/vanishing.2
usr/share/man/man1/baz.1
meson-0.53.2/test cases/common/10 man install/meson.build0000644000175000017500000000045513605171312024412 0ustar  jpakkanejpakkane00000000000000project('man install', 'c')
m1 = install_man('foo.1')
m2 = install_man('bar.2')
install_man('vanishing/vanishing.2')
subdir('vanishing')

cdata = configuration_data()
cdata.set('TODAY', '$this_day')
b1 = configure_file(input : 'baz.1.in',
  output : 'baz.1',
  configuration : cdata)

install_man(b1)
meson-0.53.2/test cases/common/10 man install/vanishing/0000755000175000017500000000000013625242355024242 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/10 man install/vanishing/meson.build0000644000175000017500000000003312650745767026414 0ustar  jpakkanejpakkane00000000000000install_man('vanishing.1')
meson-0.53.2/test cases/common/10 man install/vanishing/vanishing.10000644000175000017500000000006212650745767026324 0ustar  jpakkanejpakkane00000000000000This is a man page of the vanishing subdirectory.
meson-0.53.2/test cases/common/10 man install/vanishing/vanishing.20000644000175000017500000000007112723634706026314 0ustar  jpakkanejpakkane00000000000000This is a second man page of the vanishing subdirectory.
meson-0.53.2/test cases/common/100 stringdef/0000755000175000017500000000000013625242355022117 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/100 stringdef/meson.build0000644000175000017500000000015513605171443024257 0ustar  jpakkanejpakkane00000000000000project('stringdef', 'c')

test('stringdef', executable('stringdef', 'stringdef.c', c_args : '-DFOO="bar"'))
meson-0.53.2/test cases/common/100 stringdef/stringdef.c0000644000175000017500000000025313571777336024264 0ustar  jpakkanejpakkane00000000000000#include
#include

int main(void) {
    if(strcmp(FOO, "bar")) {
        printf("FOO is misquoted: %s\n", FOO);
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/101 find program path/0000755000175000017500000000000013625242355023420 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/101 find program path/meson.build0000644000175000017500000000146213605171445025564 0ustar  jpakkanejpakkane00000000000000project('find program', 'c')

python = import('python3').find_python()

# Source file via string
prog = find_program('program.py')
# Source file via files()
progf = files('program.py')
# Built file
py = configure_file(input : 'program.py',
                    output : 'builtprogram.py',
                    configuration : configuration_data())

foreach f : [prog, progf, py, find_program(py), find_program(progf)]
  ret = run_command(python, f)
  assert(ret.returncode() == 0, 'can\'t manually run @0@'.format(prog.path()))
  assert(ret.stdout().strip() == 'Found', 'wrong output from manually-run @0@'.format(prog.path()))

  ret = run_command(f)
  assert(ret.returncode() == 0, 'can\'t run @0@'.format(prog.path()))
  assert(ret.stdout().strip() == 'Found', 'wrong output from @0@'.format(prog.path()))
endforeach
meson-0.53.2/test cases/common/101 find program path/program.py0000755000175000017500000000004713531533273025443 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

print("Found")
meson-0.53.2/test cases/common/102 subproject subdir/0000755000175000017500000000000013625242355023565 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/102 subproject subdir/meson.build0000644000175000017500000000027013605171446025726 0ustar  jpakkanejpakkane00000000000000project('proj', 'c')
subproject('sub')
libSub = dependency('sub', fallback: ['sub', 'libSub'])

exe = executable('prog', 'prog.c', dependencies: libSub)
test('subproject subdir', exe)
meson-0.53.2/test cases/common/102 subproject subdir/prog.c0000644000175000017500000000006713571777336024717 0ustar  jpakkanejpakkane00000000000000#include 

int main(void) {
    return sub();
}
meson-0.53.2/test cases/common/102 subproject subdir/subprojects/0000755000175000017500000000000013625242350026123 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/102 subproject subdir/subprojects/sub/0000755000175000017500000000000013625242355026721 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/102 subproject subdir/subprojects/sub/lib/0000755000175000017500000000000013625242355027467 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/102 subproject subdir/subprojects/sub/lib/meson.build0000644000175000017500000000020013531533273031617 0ustar  jpakkanejpakkane00000000000000lib = static_library('sub', 'sub.c')
libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)
meson-0.53.2/test cases/common/102 subproject subdir/subprojects/sub/lib/sub.c0000644000175000017500000000006213571777336030436 0ustar  jpakkanejpakkane00000000000000#include "sub.h"

int sub(void) {
    return 0;
}
meson-0.53.2/test cases/common/102 subproject subdir/subprojects/sub/lib/sub.h0000644000175000017500000000006413571777336030445 0ustar  jpakkanejpakkane00000000000000#ifndef SUB_H
#define SUB_H

int sub(void);

#endif
meson-0.53.2/test cases/common/102 subproject subdir/subprojects/sub/meson.build0000644000175000017500000000004213531533273031055 0ustar  jpakkanejpakkane00000000000000project('sub', 'c')
subdir('lib')
meson-0.53.2/test cases/common/103 postconf/0000755000175000017500000000000013625242355021770 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/103 postconf/meson.build0000644000175000017500000000016613605171446024135 0ustar  jpakkanejpakkane00000000000000project('postconf script', 'c')

meson.add_postconf_script('postconf.py')

test('post', executable('prog', 'prog.c'))
meson-0.53.2/test cases/common/103 postconf/postconf.py0000644000175000017500000000055413531533273024177 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os

template = '''#pragma once

#define THE_NUMBER {}
'''

input_file = os.path.join(os.environ['MESON_SOURCE_ROOT'], 'raw.dat')
output_file = os.path.join(os.environ['MESON_BUILD_ROOT'], 'generated.h')

with open(input_file) as f:
    data = f.readline().strip()
with open(output_file, 'w') as f:
    f.write(template.format(data))
meson-0.53.2/test cases/common/103 postconf/prog.c0000644000175000017500000000010613571777336023114 0ustar  jpakkanejpakkane00000000000000#include"generated.h"

int main(void) {
    return THE_NUMBER != 9;
}
meson-0.53.2/test cases/common/103 postconf/raw.dat0000644000175000017500000000000213531533273023241 0ustar  jpakkanejpakkane000000000000009
meson-0.53.2/test cases/common/104 postconf with args/0000755000175000017500000000000013625242355023642 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/104 postconf with args/meson.build0000644000175000017500000000020113605171447025776 0ustar  jpakkanejpakkane00000000000000project('postconf script', 'c')

meson.add_postconf_script('postconf.py', '5', '33')

test('post', executable('prog', 'prog.c'))
meson-0.53.2/test cases/common/104 postconf with args/postconf.py0000644000175000017500000000066313531533273026052 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os

template = '''#pragma once

#define THE_NUMBER {}
#define THE_ARG1 {}
#define THE_ARG2 {}
'''

input_file = os.path.join(os.environ['MESON_SOURCE_ROOT'], 'raw.dat')
output_file = os.path.join(os.environ['MESON_BUILD_ROOT'], 'generated.h')

with open(input_file) as f:
    data = f.readline().strip()
with open(output_file, 'w') as f:
    f.write(template.format(data, sys.argv[1], sys.argv[2]))
meson-0.53.2/test cases/common/104 postconf with args/prog.c0000644000175000017500000000015113571777336024766 0ustar  jpakkanejpakkane00000000000000#include"generated.h"

int main(void) {
    return THE_NUMBER != 9 || THE_ARG1 != 5 || THE_ARG2 != 33;
}
meson-0.53.2/test cases/common/104 postconf with args/raw.dat0000644000175000017500000000000213531533273025113 0ustar  jpakkanejpakkane000000000000009
meson-0.53.2/test cases/common/105 testframework options/0000755000175000017500000000000013625242355024510 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/105 testframework options/meson.build0000644000175000017500000000044113605171451026645 0ustar  jpakkanejpakkane00000000000000project('options', 'c')

assert(get_option('testoption') == 'A string with spaces', 'Incorrect value for testoption option.')
assert(get_option('other_one') == true, 'Incorrect value for other_one option.')
assert(get_option('combo_opt') == 'one', 'Incorrect value for combo_opt option.')
meson-0.53.2/test cases/common/105 testframework options/meson_options.txt0000644000175000017500000000036013531533273030142 0ustar  jpakkanejpakkane00000000000000option('testoption', type : 'string', value : 'optval', description : 'An option to do something')
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'combo'], value : 'combo')
meson-0.53.2/test cases/common/105 testframework options/test_args.txt0000644000175000017500000000035113531533273027241 0ustar  jpakkanejpakkane00000000000000# This file is not read by meson itself, but by the test framework.
# It is not possible to pass arguments to meson from a file.
['--werror', '-D', 'testoption=A string with spaces', '-D', 'other_one=true', \
 '-D', 'combo_opt=one']
meson-0.53.2/test cases/common/106 extract same name/0000755000175000017500000000000013625242355023421 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/106 extract same name/lib.c0000644000175000017500000000004313571777336024344 0ustar  jpakkanejpakkane00000000000000int func1(void) {
    return 23;
}
meson-0.53.2/test cases/common/106 extract same name/main.c0000644000175000017500000000014413571777336024524 0ustar  jpakkanejpakkane00000000000000int func1(void);
int func2(void);

int main(void) {
    return !(func1() == 23 && func2() == 42);
}
meson-0.53.2/test cases/common/106 extract same name/meson.build0000644000175000017500000000042013605171452025554 0ustar  jpakkanejpakkane00000000000000project('object extraction', 'c')

lib = shared_library('somelib', ['lib.c', 'src/lib.c'])
# Also tests that the object list is flattened properly
obj = lib.extract_objects(['lib.c', ['src/lib.c']])
exe = executable('main', 'main.c', objects: obj)
test('extraction', exe)
meson-0.53.2/test cases/common/106 extract same name/src/0000755000175000017500000000000013625242356024211 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/106 extract same name/src/lib.c0000644000175000017500000000004313571777336025133 0ustar  jpakkanejpakkane00000000000000int func2(void) {
    return 42;
}
meson-0.53.2/test cases/common/107 has header symbol/0000755000175000017500000000000013625242356023414 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/107 has header symbol/meson.build0000644000175000017500000000375713605171464025571 0ustar  jpakkanejpakkane00000000000000project('has header symbol', 'c', 'cpp')

cc = meson.get_compiler('c')
cpp = meson.get_compiler('cpp')

foreach comp : [cc, cpp]
  assert (comp.has_header_symbol('stdio.h', 'int'), 'base types should always be available')
  assert (comp.has_header_symbol('stdio.h', 'printf'), 'printf function not found')
  assert (comp.has_header_symbol('stdio.h', 'FILE'), 'FILE structure not found')
  assert (comp.has_header_symbol('limits.h', 'INT_MAX'), 'INT_MAX define not found')
  assert (not comp.has_header_symbol('limits.h', 'guint64'), 'guint64 is not defined in limits.h')
  assert (not comp.has_header_symbol('stdlib.h', 'FILE'), 'FILE structure is defined in stdio.h, not stdlib.h')
  assert (not comp.has_header_symbol('stdlol.h', 'printf'), 'stdlol.h shouldn\'t exist')
  assert (not comp.has_header_symbol('stdlol.h', 'int'), 'shouldn\'t be able to find "int" with invalid header')
endforeach

# This is available on Glibc, Solaris & the BSD's, so just test for _GNU_SOURCE
# on Linux
if cc.has_function('ppoll') and host_machine.system() == 'linux'
  assert (not cc.has_header_symbol('poll.h', 'ppoll'), 'ppoll should not be accessible without _GNU_SOURCE')
  assert (cc.has_header_symbol('poll.h', 'ppoll', prefix : '#define _GNU_SOURCE'), 'ppoll should be accessible with _GNU_SOURCE')
endif

assert (cpp.has_header_symbol('iostream', 'std::iostream'), 'iostream not found in iostream.h')
assert (cpp.has_header_symbol('vector', 'std::vector'), 'vector not found in vector.h')
assert (not cpp.has_header_symbol('limits.h', 'std::iostream'), 'iostream should not be defined in limits.h')

# Cross compilation and boost do not mix.
if not meson.is_cross_build()
  boost = dependency('boost', required : false)
  if boost.found()
    assert (cpp.has_header_symbol('boost/math/quaternion.hpp', 'boost::math::quaternion', dependencies : boost), 'quaternion not found')
  else
    assert (not cpp.has_header_symbol('boost/math/quaternion.hpp', 'boost::math::quaternion',  dependencies : boost), 'quaternion found?!')
  endif
endif
meson-0.53.2/test cases/common/108 has arg/0000755000175000017500000000000013625242356021450 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/108 has arg/meson.build0000644000175000017500000000542013605171455023612 0ustar  jpakkanejpakkane00000000000000project('has arg', 'c', 'cpp')

cc = meson.get_compiler('c')
cpp = meson.get_compiler('cpp')

if cc.get_id() == 'msvc'
  is_arg = '/O2'
  useless = '/DFOO'
else
  is_arg = '-O2'
  useless = '-DFOO'
endif

isnt_arg = '-fiambroken'

assert(cc.has_argument(is_arg), 'Arg that should have worked does not work.')
assert(not cc.has_argument(isnt_arg), 'Arg that should be broken is not.')

assert(cpp.has_argument(is_arg), 'Arg that should have worked does not work.')
assert(not cpp.has_argument(isnt_arg), 'Arg that should be broken is not.')

assert(cc.get_supported_arguments([is_arg, isnt_arg, useless]) == [is_arg, useless], 'Arg filtering returned different result.')
assert(cpp.get_supported_arguments([is_arg, isnt_arg, useless]) == [is_arg, useless], 'Arg filtering returned different result.')

# Have useless at the end to ensure that the search goes from front to back.
l1 = cc.first_supported_argument([isnt_arg, is_arg, isnt_arg, useless])
l2 = cc.first_supported_argument(isnt_arg, isnt_arg, isnt_arg)

assert(l1.length() == 1, 'First supported returned wrong result.')
assert(l1.get(0) == is_arg, 'First supported returned wrong argument.')
assert(l2.length() == 0, 'First supported did not return empty array.')

l1 = cpp.first_supported_argument([isnt_arg, is_arg, isnt_arg, useless])
l2 = cpp.first_supported_argument(isnt_arg, isnt_arg, isnt_arg)

assert(l1.length() == 1, 'First supported returned wrong result.')
assert(l1.get(0) == is_arg, 'First supported returned wrong argument.')
assert(l2.length() == 0, 'First supported did not return empty array.')

if cc.get_id() == 'gcc'
  pre_arg = '-Wformat'
  # NOTE: We have special handling for -Wno-foo args because gcc silently
  # ignores unknown -Wno-foo args unless you pass -Werror, so for this test, we
  # pass it as two separate arguments.
  anti_pre_arg = ['-W', 'no-format']
  arg = '-Werror=format-security'
  assert(not cc.has_multi_arguments([anti_pre_arg, arg]), 'Arg that should be broken is not.')
  assert(cc.has_multi_arguments(pre_arg), 'Arg that should have worked does not work.')
  assert(cc.has_multi_arguments([pre_arg, arg]), 'Arg that should have worked does not work.')
  # Test that gcc correctly errors out on unknown -Wno flags
  assert(not cc.has_argument('-Wno-lol-meson-test-flags'), 'should error out on unknown -Wno args')
  assert(not cc.has_multi_arguments(['-Wno-pragmas', '-Wno-lol-meson-test-flags']), 'should error out even if some -Wno args are valid')
endif

if cc.get_id() == 'clang' and cc.version().version_compare('<=4.0.0')
  # 4.0.0 does not support -fpeel-loops. Newer versions may.
  # Please adjust above version number as new versions of clang are released.
  notyet_arg = '-fpeel-loops'
  assert(not cc.has_argument(notyet_arg), 'Arg that should be broken (unless clang added support recently) is not.')
endif
meson-0.53.2/test cases/common/109 generatorcustom/0000755000175000017500000000000013625242356023365 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/109 generatorcustom/catter.py0000755000175000017500000000045113531533273025221 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

output = sys.argv[-1]
inputs = sys.argv[1:-1]

with open(output, 'w') as ofile:
    ofile.write('#pragma once\n')
    for i in inputs:
        with open(i, 'r') as ifile:
            content = ifile.read()
        ofile.write(content)
        ofile.write('\n')
meson-0.53.2/test cases/common/109 generatorcustom/gen.py0000755000175000017500000000036513531533273024514 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

ifile = sys.argv[1]
ofile = sys.argv[2]

with open(ifile, 'r') as f:
    resname = f.readline().strip()

templ = 'const char %s[] = "%s";\n'
with open(ofile, 'w') as f:
    f.write(templ % (resname, resname))
meson-0.53.2/test cases/common/109 generatorcustom/main.c0000644000175000017500000000011513571777336024465 0ustar  jpakkanejpakkane00000000000000#include

#include"alltogether.h"

int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/109 generatorcustom/meson.build0000644000175000017500000000063413605171454025530 0ustar  jpakkanejpakkane00000000000000project('generatorcustom', 'c')

creator = find_program('gen.py')
catter = find_program('catter.py')

gen = generator(creator,
  output: '@BASENAME@.h',
  arguments : ['@INPUT@', '@OUTPUT@'])

hs = gen.process('res1.txt', 'res2.txt')

allinone = custom_target('alltogether',
    input : hs,
    output : 'alltogether.h',
    command : [catter, '@INPUT@', '@OUTPUT@'])

executable('proggie', 'main.c', allinone)

meson-0.53.2/test cases/common/109 generatorcustom/res1.txt0000644000175000017500000000000513531533273024770 0ustar  jpakkanejpakkane00000000000000res1
meson-0.53.2/test cases/common/109 generatorcustom/res2.txt0000644000175000017500000000000513531533273024771 0ustar  jpakkanejpakkane00000000000000res2
meson-0.53.2/test cases/common/11 subdir/0000755000175000017500000000000013625242356021344 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/11 subdir/meson.build0000644000175000017500000000005513605171312023475 0ustar  jpakkanejpakkane00000000000000project('subdir test', 'c')
subdir('subdir')
meson-0.53.2/test cases/common/11 subdir/subdir/0000755000175000017500000000000013625242356022634 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/11 subdir/subdir/meson.build0000644000175000017500000000003512650745767025007 0ustar  jpakkanejpakkane00000000000000executable('prog', 'prog.c')
meson-0.53.2/test cases/common/11 subdir/subdir/prog.c0000644000175000017500000000003513571777336023760 0ustar  jpakkanejpakkane00000000000000int main(void) { return 0; }
meson-0.53.2/test cases/common/110 multiple dir configure file/0000755000175000017500000000000013625242356025370 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/110 multiple dir configure file/meson.build0000644000175000017500000000036513605171455027535 0ustar  jpakkanejpakkane00000000000000project('multiple dir configure file', 'c')

subdir('subdir')

configure_file(input : 'subdir/someinput.in',
  output : 'outputhere',
  copy: true)

configure_file(input : cfile1,
               output : '@BASENAME@',
               copy: true)
meson-0.53.2/test cases/common/110 multiple dir configure file/subdir/0000755000175000017500000000000013625242356026660 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/110 multiple dir configure file/subdir/foo.txt0000644000175000017500000000000013531533273030167 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/110 multiple dir configure file/subdir/meson.build0000644000175000017500000000053313531533273031020 0ustar  jpakkanejpakkane00000000000000configure_file(input : 'someinput.in',
  output : 'outputsubdir',
  install : false,
  copy: true)

py3 = import('python3').find_python()

cfile1 = configure_file(input : 'foo.txt',
                        output : 'foo.h.in',
                        capture : true,
                        command : [py3, '-c', 'print("#mesondefine FOO_BAR")'])
meson-0.53.2/test cases/common/110 multiple dir configure file/subdir/someinput.in0000644000175000017500000000000013531533273031216 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/111 spaces backslash/0000755000175000017500000000000013625242356023327 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/111 spaces backslash/asm output/0000755000175000017500000000000013625242356025430 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/111 spaces backslash/asm output/meson.build0000644000175000017500000000011413531533273027563 0ustar  jpakkanejpakkane00000000000000configure_file(output : 'blank.txt', configuration : configuration_data())

meson-0.53.2/test cases/common/111 spaces backslash/comparer-end-notstring.c0000644000175000017500000000100013571777336030076 0ustar  jpakkanejpakkane00000000000000#include "comparer.h"

#ifndef COMPARER_INCLUDED
#error "comparer.h not included"
#endif

/* This converts foo\\\\bar\\\\ to "foo\\bar\\" (string literal) */
#define Q(x) #x
#define QUOTE(x) Q(x)

#define COMPARE_WITH "foo\\bar\\" /* This is the literal `foo\bar\` */

int main(void) {
    if(strcmp(QUOTE(DEF_WITH_BACKSLASH), COMPARE_WITH)) {
        printf("Arg string is quoted incorrectly: %s instead of %s\n",
               QUOTE(DEF_WITH_BACKSLASH), COMPARE_WITH);
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/111 spaces backslash/comparer-end.c0000644000175000017500000000056713571777336026072 0ustar  jpakkanejpakkane00000000000000#include "comparer.h"

#ifndef COMPARER_INCLUDED
#error "comparer.h not included"
#endif

#define COMPARE_WITH "foo\\bar\\" /* This is `foo\bar\` */

int main(void) {
    if (strcmp (DEF_WITH_BACKSLASH, COMPARE_WITH)) {
        printf ("Arg string is quoted incorrectly: %s vs %s\n",
                DEF_WITH_BACKSLASH, COMPARE_WITH);
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/111 spaces backslash/comparer.c0000644000175000017500000000061013571777336025313 0ustar  jpakkanejpakkane00000000000000#include "comparer.h"

#ifndef COMPARER_INCLUDED
#error "comparer.h not included"
#endif

#define COMPARE_WITH "foo\\bar" /* This is the literal `foo\bar` */

int main(void) {
    if (strcmp (DEF_WITH_BACKSLASH, COMPARE_WITH)) {
        printf ("Arg string is quoted incorrectly: %s instead of %s\n",
                DEF_WITH_BACKSLASH, COMPARE_WITH);
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/111 spaces backslash/include/0000755000175000017500000000000013625242356024752 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/111 spaces backslash/include/comparer.h0000644000175000017500000000010213531533273026721 0ustar  jpakkanejpakkane00000000000000#include 
#include 

#define COMPARER_INCLUDED
meson-0.53.2/test cases/common/111 spaces backslash/meson.build0000644000175000017500000000250213605171457025471 0ustar  jpakkanejpakkane00000000000000project('comparer', 'c')

# Added manually as a c_arg to test handling of include paths with backslashes
# and spaces. This is especially useful on Windows in vcxproj files since it
# stores include directories in a separate element that has its own
# context-specific escaping/quoting.
include_dir = meson.current_source_dir() + '/include'
default_c_args = ['-I' + include_dir]

if meson.get_compiler('c').get_argument_syntax() == 'msvc'
  default_c_args += ['/Faasm output\\']
  # Hack to create the 'asm output' directory in the builddir
  subdir('asm output')
endif

# Path can contain \. Here we're sending `"foo\bar"`.
test('backslash quoting',
     executable('comparer', 'comparer.c',
                c_args : default_c_args + ['-DDEF_WITH_BACKSLASH="foo\\bar"']))
# Path can end in \ without any special quoting. Here we send `"foo\bar\"`.
test('backslash end quoting',
     executable('comparer-end', 'comparer-end.c',
                c_args : default_c_args + ['-DDEF_WITH_BACKSLASH="foo\\bar\\"']))
# Path can (really) end in \ if we're not passing a string literal without any
# special quoting. Here we're sending `foo\bar\`.
test('backslash end quoting when not a string literal',
     executable('comparer-end-notstring', 'comparer-end-notstring.c',
                c_args : default_c_args + ['-DDEF_WITH_BACKSLASH=foo\\bar\\']))
meson-0.53.2/test cases/common/112 ternary/0000755000175000017500000000000013625242356021622 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/112 ternary/meson.build0000644000175000017500000000077713605171457024000 0ustar  jpakkanejpakkane00000000000000project('ternary operator', 'c')

x = true
one = true ? 1 : error('False branch should not be evaluated')
two = false ? error('True branch should not be evaluated.') : 2
three = '@0@'.format(x ? 'yes' : 'no')
four = [x ? '0' : '1']

assert(one == 1, 'Return value from ternary true is wrong.')
assert(two == 2, 'Return value from ternary false is wrong.')
assert(three == 'yes', 'Return value for ternary inside method call is wrong.')
assert(four == ['0'], 'Return value for ternary inside of list is wrong.')
meson-0.53.2/test cases/common/113 custom target capture/0000755000175000017500000000000013625242356024344 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/113 custom target capture/data_source.txt0000644000175000017500000000004013531533273027365 0ustar  jpakkanejpakkane00000000000000This is a text only input file.
meson-0.53.2/test cases/common/113 custom target capture/installed_files.txt0000644000175000017500000000002413531533273030237 0ustar  jpakkanejpakkane00000000000000usr/subdir/data.dat
meson-0.53.2/test cases/common/113 custom target capture/meson.build0000644000175000017500000000125713605171462026510 0ustar  jpakkanejpakkane00000000000000project('custom target', 'c')

python3 = import('python3').find_python()

# Note that this will not add a dependency to the compiler executable.
# Code will not be rebuilt if it changes.
comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py')

mytarget = custom_target('bindat',
  output : 'data.dat',
  input : 'data_source.txt',
  capture : true,
  command : [python3, comp, '@INPUT@'],
  install : true,
  install_dir : 'subdir'
)

ct_output_exists = '''import os, sys
if not os.path.exists(sys.argv[1]):
  print("could not find {!r} in {!r}".format(sys.argv[1], os.getcwd()))
  sys.exit(1)
'''

test('capture-wrote', python3, args : ['-c', ct_output_exists, mytarget])
meson-0.53.2/test cases/common/113 custom target capture/my_compiler.py0000755000175000017500000000054613531533273027242 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print(sys.argv[0], 'input_file')
        sys.exit(1)
    with open(sys.argv[1]) as f:
        ifile = f.read()
    if ifile != 'This is a text only input file.\n':
        print('Malformed input')
        sys.exit(1)
    print('This is a binary output file.')
meson-0.53.2/test cases/common/114 allgenerate/0000755000175000017500000000000013625242356022423 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/114 allgenerate/converter.py0000755000175000017500000000017013531533273025002 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

ifile = sys.argv[1]
ofile = sys.argv[2]

open(ofile, 'w').write(open(ifile).read())
meson-0.53.2/test cases/common/114 allgenerate/foobar.cpp.in0000644000175000017500000000012113571777336025011 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
  printf("I am a program.\n");
  return 0;
}
meson-0.53.2/test cases/common/114 allgenerate/meson.build0000644000175000017500000000072113605171463024563 0ustar  jpakkanejpakkane00000000000000# Must have two languages here to exercise linker language
# selection bug
project('all sources generated', 'c', 'cpp')

comp = find_program('converter.py')

g = generator(comp,
  output : '@BASENAME@',
  arguments : ['@INPUT@', '@OUTPUT@'])

c = g.process('foobar.cpp.in')

prog = executable('genexe', c)

c2 = custom_target('c2gen',
  output : '@BASENAME@',
  input : 'foobar.cpp.in',
  command : [comp, '@INPUT@', '@OUTPUT@'])

prog2 = executable('genexe2', c2)
meson-0.53.2/test cases/common/115 pathjoin/0000755000175000017500000000000013625242356021755 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/115 pathjoin/meson.build0000644000175000017500000000303713605171463024120 0ustar  jpakkanejpakkane00000000000000project('pathjoin', 'c')

# Test string-args form since that is the canonical way
assert(join_paths('foo')               == 'foo', 'Single argument join is broken')
assert(join_paths('foo', 'bar')        == 'foo/bar', 'Path joining is broken')
assert(join_paths('foo', 'bar', 'baz') == 'foo/bar/baz', 'Path joining is broken')
assert(join_paths('/foo', 'bar')       == '/foo/bar', 'Path joining is broken')
assert(join_paths('foo', '/bar')       == '/bar', 'Absolute path joining is broken')
assert(join_paths('/foo', '/bar')      == '/bar', 'Absolute path joining is broken')

# Test array form since people are using that too
assert(join_paths(['foo'])               == 'foo', 'Single argument join is broken')
assert(join_paths(['foo', 'bar'])        == 'foo/bar', 'Path joining is broken')
assert(join_paths(['foo', 'bar', 'baz']) == 'foo/bar/baz', 'Path joining is broken')
assert(join_paths(['/foo', 'bar'])       == '/foo/bar', 'Path joining is broken')
assert(join_paths(['foo', '/bar'])       == '/bar', 'Absolute path joining is broken')
assert(join_paths(['/foo', '/bar'])      == '/bar', 'Absolute path joining is broken')

# Division operator should do the same as join_paths
assert('foo' / 'bar'       == 'foo/bar',     'Path division is broken')
assert('foo' /'bar' /'baz' == 'foo/bar/baz', 'Path division is broken')
assert('/foo' / 'bar'      == '/foo/bar',    'Path division is broken')
assert('foo' / '/bar'      == '/bar',        'Absolute path division is broken')
assert('/foo' / '/bar'     == '/bar',        'Absolute path division is broken')
meson-0.53.2/test cases/common/116 subdir subproject/0000755000175000017500000000000013625242356023573 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/116 subdir subproject/meson.build0000644000175000017500000000004413605171466025734 0ustar  jpakkanejpakkane00000000000000project('proj', 'c')
subdir('prog')
meson-0.53.2/test cases/common/116 subdir subproject/prog/0000755000175000017500000000000013625242356024542 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/116 subdir subproject/prog/meson.build0000644000175000017500000000024313531533273026700 0ustar  jpakkanejpakkane00000000000000subproject('sub')
libSub = dependency('sub', fallback: ['sub', 'libSub'])

exe = executable('prog', 'prog.c', dependencies: libSub)
test('subdir subproject', exe)
meson-0.53.2/test cases/common/116 subdir subproject/prog/prog.c0000644000175000017500000000006713571777336025673 0ustar  jpakkanejpakkane00000000000000#include 

int main(void) {
    return sub();
}
meson-0.53.2/test cases/common/116 subdir subproject/subprojects/0000755000175000017500000000000013625242350026130 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/116 subdir subproject/subprojects/sub/0000755000175000017500000000000013625242356026727 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/116 subdir subproject/subprojects/sub/meson.build0000644000175000017500000000022413531533273031064 0ustar  jpakkanejpakkane00000000000000project('sub', 'c')
lib = static_library('sub', 'sub.c')
libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)
meson-0.53.2/test cases/common/116 subdir subproject/subprojects/sub/sub.c0000644000175000017500000000006213571777336027675 0ustar  jpakkanejpakkane00000000000000#include "sub.h"

int sub(void) {
    return 0;
}
meson-0.53.2/test cases/common/116 subdir subproject/subprojects/sub/sub.h0000644000175000017500000000006413571777336027704 0ustar  jpakkanejpakkane00000000000000#ifndef SUB_H
#define SUB_H

int sub(void);

#endif
meson-0.53.2/test cases/common/117 interpreter copy mutable var on assignment/0000755000175000017500000000000013625242356030352 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/117 interpreter copy mutable var on assignment/meson.build0000644000175000017500000000105213605171466032513 0ustar  jpakkanejpakkane00000000000000project('foo', 'c')

a = configuration_data()
a.set('HELLO', 1)

b = a

assert(a.has('HELLO'), 'Original config data should be set on a')
assert(b.has('HELLO'), 'Original config data should be set on copy')

configure_file(output : 'b.h', configuration : b)

# This should still work, as we didn't use the original above but a copy!
a.set('WORLD', 1)

assert(a.has('WORLD'), 'New config data should have been set')
assert(not b.has('WORLD'), 'New config data set should not affect var copied earlier')

configure_file(output : 'a.h', configuration : a)

meson-0.53.2/test cases/common/118 skip/0000755000175000017500000000000013625242356021112 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/118 skip/meson.build0000644000175000017500000000011513531533273023246 0ustar  jpakkanejpakkane00000000000000project('skip', 'c')

error('MESON_SKIP_TEST this test is always skipped.')

meson-0.53.2/test cases/common/119 subproject project arguments/0000755000175000017500000000000013625242356025742 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/119 subproject project arguments/exe.c0000644000175000017500000000041313571777336026700 0ustar  jpakkanejpakkane00000000000000#ifndef PROJECT_OPTION
#error
#endif

#ifndef PROJECT_OPTION_1
#error
#endif

#ifndef GLOBAL_ARGUMENT
#error
#endif

#ifdef SUBPROJECT_OPTION
#error
#endif

#ifdef OPTION_CPP
#error
#endif

#ifndef PROJECT_OPTION_C_CPP
#error
#endif

int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/119 subproject project arguments/exe.cpp0000644000175000017500000000042213571777336027240 0ustar  jpakkanejpakkane00000000000000#ifdef PROJECT_OPTION
#error
#endif

#ifdef PROJECT_OPTION_1
#error
#endif

#ifdef GLOBAL_ARGUMENT
#error
#endif

#ifdef SUBPROJECT_OPTION
#error
#endif

#ifndef PROJECT_OPTION_CPP
#error
#endif

#ifndef PROJECT_OPTION_C_CPP
#error
#endif

int main(void) {
    return 0;
}

meson-0.53.2/test cases/common/119 subproject project arguments/meson.build0000644000175000017500000000105613605171470030102 0ustar  jpakkanejpakkane00000000000000project('project options tester', 'c', 'cpp',
  version : '2.3.4',
  license : 'mylicense')

add_global_arguments('-DGLOBAL_ARGUMENT', language: 'c')
add_project_arguments('-DPROJECT_OPTION', language: 'c')
add_project_arguments('-DPROJECT_OPTION_CPP', language: 'cpp')
add_project_arguments('-DPROJECT_OPTION_C_CPP', language: ['c', 'cpp'])

sub = subproject('subexe', version : '1.0.0')

add_project_arguments('-DPROJECT_OPTION_1', language: 'c')

e = executable('exe', 'exe.c')
e = executable('execpp', 'exe.cpp')
test('exetest', e)
test('execpptest', e)
meson-0.53.2/test cases/common/119 subproject project arguments/subprojects/0000755000175000017500000000000013625242350030277 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/119 subproject project arguments/subprojects/subexe/0000755000175000017500000000000013625242356031600 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/119 subproject project arguments/subprojects/subexe/meson.build0000644000175000017500000000061413531533273033740 0ustar  jpakkanejpakkane00000000000000project('subproject', 'c',
  version : '1.0.0',
  license : ['sublicense1', 'sublicense2'])

if not meson.is_subproject()
  error('Claimed to be master project even though we are a subproject.')
endif

assert(meson.project_name() == 'subproject', 'Incorrect subproject name')

add_project_arguments('-DSUBPROJECT_OPTION', language: 'c')
e = executable('subexe', 'subexe.c')
test('subexetest', e)
meson-0.53.2/test cases/common/119 subproject project arguments/subprojects/subexe/subexe.c0000644000175000017500000000041113571777336033246 0ustar  jpakkanejpakkane00000000000000#ifdef PROJECT_OPTION
#error
#endif

#ifdef PROJECT_OPTION_1
#error
#endif

#ifdef PROJECT_OPTION_C_CPP
#error
#endif

#ifndef GLOBAL_ARGUMENT
#error
#endif

#ifndef SUBPROJECT_OPTION
#error
#endif

#ifdef OPTION_CPP
#error
#endif

int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/12 data/0000755000175000017500000000000013625242356020766 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/12 data/datafile.dat0000644000175000017500000000002412650745767023240 0ustar  jpakkanejpakkane00000000000000this is a data file
meson-0.53.2/test cases/common/12 data/etcfile.dat0000644000175000017500000000004012650745767023100 0ustar  jpakkanejpakkane00000000000000This goes into /etc/etcfile.dat
meson-0.53.2/test cases/common/12 data/fileobject_datafile.dat0000644000175000017500000000007113016624375025414 0ustar  jpakkanejpakkane00000000000000This is a data file that is installed via a File object.
meson-0.53.2/test cases/common/12 data/installed_files.txt0000644000175000017500000000057213340206727024670 0ustar  jpakkanejpakkane00000000000000usr/share/progname/datafile.dat
usr/share/progname/fileobject_datafile.dat
usr/share/progname/vanishing.dat
usr/share/progname/vanishing2.dat
usr/share/data install test/renamed file.txt
usr/share/data install test/somefile.txt
usr/share/data install test/some/nested/path.txt
usr/share/renamed/renamed 2.txt
usr/share/renamed/renamed 3.txt
etc/etcfile.dat
usr/bin/runscript.sh
meson-0.53.2/test cases/common/12 data/meson.build0000644000175000017500000000207513605171312023123 0ustar  jpakkanejpakkane00000000000000project('data install test', 'c',
  default_options : ['install_umask=preserve'])
install_data(sources : 'datafile.dat', install_dir : 'share/progname')
# Some file in /etc that is only read-write by root; add a sticky bit for testing
install_data(sources : 'etcfile.dat', install_dir : '/etc', install_mode : 'rw------T')
# Some script that needs to be executable by the group
install_data('runscript.sh',
  install_dir : get_option('bindir'),
  install_mode : ['rwxr-sr-x', 'root', 0])
install_data(files('fileobject_datafile.dat'),
  install_dir : 'share/progname',
  install_mode : [false, false, 0])

install_data(files('somefile.txt'))

subdir('vanishing')

install_data(sources : 'vanishing/vanishing2.dat', install_dir : 'share/progname')

install_data(sources : 'to_be_renamed_1.txt', rename : 'renamed file.txt')
install_data(sources : ['vanishing/to_be_renamed_2.txt', 'to_be_renamed_3.txt'],
             install_dir : 'share/renamed',
             rename : ['renamed 2.txt', 'renamed 3.txt'])
install_data(sources : 'to_be_renamed_4.txt', rename : 'some/nested/path.txt')
meson-0.53.2/test cases/common/12 data/runscript.sh0000644000175000017500000000003413043224360023335 0ustar  jpakkanejpakkane00000000000000#!/bin/sh

echo "Runscript"
meson-0.53.2/test cases/common/12 data/somefile.txt0000644000175000017500000000000013340206727023314 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/12 data/to_be_renamed_1.txt0000644000175000017500000000000013340206727024514 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/12 data/to_be_renamed_3.txt0000644000175000017500000000000013340206727024516 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/12 data/to_be_renamed_4.txt0000644000175000017500000000000013340206727024517 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/12 data/vanishing/0000755000175000017500000000000013625242356022754 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/12 data/vanishing/meson.build0000644000175000017500000000011012650745767025121 0ustar  jpakkanejpakkane00000000000000install_data(sources : 'vanishing.dat', install_dir : 'share/progname')
meson-0.53.2/test cases/common/12 data/vanishing/to_be_renamed_2.txt0000644000175000017500000000000013340206727026503 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/12 data/vanishing/vanishing.dat0000644000175000017500000000006712650745767025452 0ustar  jpakkanejpakkane00000000000000This is a data file to be installed in a subdirectory.
meson-0.53.2/test cases/common/12 data/vanishing/vanishing2.dat0000644000175000017500000000023612703007422025504 0ustar  jpakkanejpakkane00000000000000This is a data file to be installed in a subdirectory.

It is installed from a different subdir to test that the
installer strips the source tree dir prefix.
meson-0.53.2/test cases/common/120 test skip/0000755000175000017500000000000013625242356022043 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/120 test skip/meson.build0000644000175000017500000000016313605171467024207 0ustar  jpakkanejpakkane00000000000000project('test skip', 'c')

exe_test_skip = executable('test_skip', 'test_skip.c')
test('test_skip', exe_test_skip)
meson-0.53.2/test cases/common/120 test skip/test_skip.c0000644000175000017500000000004213571777336024223 0ustar  jpakkanejpakkane00000000000000int main(void) {
    return 77;
}
meson-0.53.2/test cases/common/121 shared module/0000755000175000017500000000000013625242356022652 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/121 shared module/installed_files.txt0000644000175000017500000000014413531533273026550 0ustar  jpakkanejpakkane00000000000000usr/lib/modules/libnosyms?so
usr/lib/modules/libnosyms?implibempty
?msvc:usr/lib/modules/nosyms.pdb
meson-0.53.2/test cases/common/121 shared module/meson.build0000644000175000017500000000160413605171472025013 0ustar  jpakkanejpakkane00000000000000project('shared module', 'c')

dl = meson.get_compiler('c').find_library('dl', required : false)
l = shared_library('runtime', 'runtime.c')
# Do NOT link the module with the runtime library. This
# is a common approach for plugins that are only used
# with dlopen. Any symbols are resolved dynamically
# at runtime.  This requires extra help on Windows, so
# should be avoided unless really necessary.
m = shared_module('mymodule', 'module.c')
e = executable('prog', 'prog.c',
  link_with : l, export_dynamic : true, dependencies : dl)
test('import test', e, args : m)

# Same as above, but module created with build_target()
m2 = build_target('mymodule2', 'module.c', target_type: 'shared_module')
test('import test 2', e, args : m2)

# Shared module that does not export any symbols
shared_module('nosyms', 'nosyms.c',
  install : true,
  install_dir : join_paths(get_option('libdir'), 'modules'))
meson-0.53.2/test cases/common/121 shared module/module.c0000644000175000017500000000454413571777336024325 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

#if defined(_WIN32) || defined(__CYGWIN__)

#include 

typedef int (*fptr) (void);

#ifdef __CYGWIN__

#include 

fptr find_any_f (const char *name) {
    return (fptr) dlsym(RTLD_DEFAULT, name);
}
#else /* _WIN32 */

#include 
#include 

static wchar_t*
win32_get_last_error (void)
{
    wchar_t *msg = NULL;

    FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER
                    | FORMAT_MESSAGE_IGNORE_INSERTS
                    | FORMAT_MESSAGE_FROM_SYSTEM,
                    NULL, GetLastError (), 0,
                    (LPWSTR) &msg, 0, NULL);
    return msg;
}

/* Unlike Linux and OS X, when a library is loaded, all the symbols aren't
 * loaded into a single namespace. You must fetch the symbol by iterating over
 * all loaded modules. Code for finding the function from any of the loaded
 * modules is taken from gmodule.c in glib */
fptr find_any_f (const char *name) {
    fptr f;
    HANDLE snapshot;
    MODULEENTRY32 me32;

    snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
    if (snapshot == (HANDLE) -1) {
        wchar_t *msg = win32_get_last_error();
        printf("Could not get snapshot: %S\n", msg);
        return 0;
    }

    me32.dwSize = sizeof (me32);

    f = NULL;
    if (Module32First (snapshot, &me32)) {
        do {
            if ((f = (fptr) GetProcAddress (me32.hModule, name)) != NULL)
                break;
        } while (Module32Next (snapshot, &me32));
    }

    CloseHandle (snapshot);
    return f;
}
#endif

int DLL_PUBLIC func(void) {
    fptr f;

    f = find_any_f ("func_from_language_runtime");
    if (f != NULL)
        return f();
    printf ("Could not find function\n");
    return 1;
}

#else
/*
 * Shared modules often have references to symbols that are not defined
 * at link time, but which will be provided from deps of the executable that
 * dlopens it. We need to make sure that this works, i.e. that we do
 * not pass -Wl,--no-undefined when linking modules.
 */
int func_from_language_runtime(void);

int DLL_PUBLIC func(void) {
    return func_from_language_runtime();
}
#endif
meson-0.53.2/test cases/common/121 shared module/nosyms.c0000644000175000017500000000006713531533273024346 0ustar  jpakkanejpakkane00000000000000static int
func_not_exported (void) {
    return 99;
}
meson-0.53.2/test cases/common/121 shared module/prog.c0000644000175000017500000000410213571777336023775 0ustar  jpakkanejpakkane00000000000000
#include 

int func_from_language_runtime(void);
typedef int (*fptr) (void);

#ifdef _WIN32

#include 

static wchar_t*
win32_get_last_error (void)
{
    wchar_t *msg = NULL;

    FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER
                    | FORMAT_MESSAGE_IGNORE_INSERTS
                    | FORMAT_MESSAGE_FROM_SYSTEM,
                    NULL, GetLastError (), 0,
                    (LPWSTR) &msg, 0, NULL);
    return msg;
}

int main(int argc, char **argv)
{
    HINSTANCE handle;
    fptr importedfunc;
    int expected, actual;
    int ret = 1;
    if(argc==0) {};

    handle = LoadLibraryA (argv[1]);
    if (!handle) {
        wchar_t *msg = win32_get_last_error ();
        printf ("Could not open %s: %S\n", argv[1], msg);
        goto nohandle;
    }

    importedfunc = (fptr) GetProcAddress (handle, "func");
    if (importedfunc == NULL) {
        wchar_t *msg = win32_get_last_error ();
        printf ("Could not find 'func': %S\n", msg);
        goto out;
    }

    actual = importedfunc ();
    expected = func_from_language_runtime ();
    if (actual != expected) {
        printf ("Got %i instead of %i\n", actual, expected);
        goto out;
    }

    ret = 0;
out:
    FreeLibrary (handle);
nohandle:
    return ret;
}

#else

#include
#include

int main(int argc, char **argv) {
    void *dl;
    fptr importedfunc;
    int expected, actual;
    char *error;
    int ret = 1;
    if(argc==0) {};

    dlerror();
    dl = dlopen(argv[1], RTLD_LAZY);
    error = dlerror();
    if(error) {
        printf("Could not open %s: %s\n", argv[1], error);
        goto nodl;
    }

    importedfunc = (fptr) dlsym(dl, "func");
    if (importedfunc == NULL) {
        printf ("Could not find 'func'\n");
        goto out;
    }

    assert(importedfunc != func_from_language_runtime);

    actual = (*importedfunc)();
    expected = func_from_language_runtime ();
    if (actual != expected) {
        printf ("Got %i instead of %i\n", actual, expected);
        goto out;
    }

    ret = 0;
out:
    dlclose(dl);
nodl:
    return ret;
}

#endif
meson-0.53.2/test cases/common/121 shared module/runtime.c0000644000175000017500000000070313531533273024476 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

/*
 * This file pretends to be a language runtime that supports extension
 * modules.
 */

int DLL_PUBLIC func_from_language_runtime(void) {
    return 86;
}
meson-0.53.2/test cases/common/122 llvm ir and assembly/0000755000175000017500000000000013625242356024027 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/122 llvm ir and assembly/main.c0000644000175000017500000000032313571777336025130 0ustar  jpakkanejpakkane00000000000000#include 

unsigned square_unsigned (unsigned a);

int main(void)
{
  unsigned int ret = square_unsigned (2);
  if (ret != 4) {
    printf("Got %u instead of 4\n", ret);
    return 1;
  }
  return 0;
}
meson-0.53.2/test cases/common/122 llvm ir and assembly/main.cpp0000644000175000017500000000034513571777336025474 0ustar  jpakkanejpakkane00000000000000#include 

extern "C" {
  unsigned square_unsigned (unsigned a);
}

int main (void)
{
  unsigned int ret = square_unsigned (2);
  if (ret != 4) {
    printf("Got %u instead of 4\n", ret);
    return 1;
  }
  return 0;
}
meson-0.53.2/test cases/common/122 llvm ir and assembly/meson.build0000644000175000017500000000505313605171472026172 0ustar  jpakkanejpakkane00000000000000project('llvm-ir', 'c', 'cpp')

cpu = host_machine.cpu_family()
supported_cpus = ['arm', 'x86', 'x86_64']

foreach lang : ['c', 'cpp']
  cc = meson.get_compiler(lang)
  cc_id = cc.get_id()
  ## Build a trivial executable with mixed LLVM IR source
  if cc_id == 'clang'
    e = executable('square_ir_' + lang, 'square.ll', 'main.' + lang)
    test('test IR square' + lang, e)
  endif
  ## Build a trivial executable with mixed assembly source
  # This also helps test whether cc.symbols_have_underscore_prefix() is working
  # properly. This is done by assembling some assembly into an object that will
  # provide the unsigned_squared() symbol to main.c/cpp. This requires the
  # C symbol mangling to be known in advance.
  if cc.symbols_have_underscore_prefix()
    uscore_args = ['-DMESON_TEST__UNDERSCORE_SYMBOL']
    message('underscore is prefixed')
  else
    uscore_args = []
    message('underscore is NOT prefixed')
  endif
  square_base = 'square-' + cpu
  square_impl = square_base + '.S'
  # MSVC cannot directly compile assembly files, so we pass it through the
  # cl.exe pre-processor first and then assemble it with the ml.exe assembler.
  # Then we can link it into the executable.
  if cc.get_argument_syntax() == 'msvc'
    cl = cc.cmd_array()
    if cpu == 'x86'
      ml = find_program('ml', required: false)
    elif cpu == 'x86_64'
      ml = find_program('ml64', required: false)
    else
      error('Unsupported cpu family: "' + cpu + '"')
    endif
    if not ml.found()
      error('MESON_SKIP_TEST: ML (masm) not found')
    endif
    # Preprocess file (ml doesn't support pre-processing)
    # Force the intput to be C (/Tc) because ICL otherwise assumes it's an object (.obj) file
    preproc_name = lang + square_base + '.i'
    square_preproc = custom_target(lang + square_impl + 'preproc',
        input : square_impl,
        output : preproc_name,
        command : [cl, '/nologo', '/EP', '/P', '/Fi' + preproc_name, '/Tc', '@INPUT@'] + uscore_args)
    # Use assembled object file instead of the original .S assembly source
    square_impl = custom_target(lang + square_impl,
        input : square_preproc,
        output : lang + square_base + '.obj',
        command : [ml, '/nologo', '/safeseh', '/Fo', '@OUTPUT@', '/c', '@INPUT@'])
  endif
  if supported_cpus.contains(cpu)
    e = executable('square_asm_' + lang, square_impl, 'main.' + lang,
        c_args : uscore_args, cpp_args : uscore_args)
    test('test ASM square' + lang, e)
  elif cc_id != 'clang'
    error('MESON_SKIP_TEST: Unsupported cpu: "' + cpu + '", and LLVM not found')
  endif
endforeach
meson-0.53.2/test cases/common/122 llvm ir and assembly/square-arm.S0000644000175000017500000000032413531533273026224 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

.text
.globl SYMBOL_NAME(square_unsigned)
# ifdef __linux__
.type square_unsigned, %function
#endif

SYMBOL_NAME(square_unsigned):
    mul r1, r0, r0
    mov r0, r1
    mov pc, lr
meson-0.53.2/test cases/common/122 llvm ir and assembly/square-x86.S0000644000175000017500000000111113531533273026065 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

/* This sadly doesn't test the symbol underscore stuff. I can't figure out how
 * to not use an automatic stdcall mechanism and do everything manually. */
#ifdef _MSC_VER

.386
.MODEL FLAT, C

PUBLIC square_unsigned
_TEXT   SEGMENT

square_unsigned PROC var1:DWORD
    mov     eax, var1
    imul eax, eax
    ret

square_unsigned ENDP

_TEXT   ENDS
END

#else

.text
.globl SYMBOL_NAME(square_unsigned)
# ifdef __linux__
.type square_unsigned, %function
#endif

SYMBOL_NAME(square_unsigned):
    movl 4(%esp), %eax
    imull %eax, %eax
    retl

#endif
meson-0.53.2/test cases/common/122 llvm ir and assembly/square-x86_64.S0000644000175000017500000000115713531533273026410 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

#ifdef _MSC_VER /* MSVC on Windows */

PUBLIC SYMBOL_NAME(square_unsigned)
_TEXT   SEGMENT

SYMBOL_NAME(square_unsigned) PROC
        mov     eax, ecx
    imul eax, eax
    ret
SYMBOL_NAME(square_unsigned) ENDP

_TEXT   ENDS
END

#else

.text
.globl SYMBOL_NAME(square_unsigned)
# ifdef __linux__
.type square_unsigned, %function
#endif

# if defined(_WIN32) || defined(__CYGWIN__) /* msabi */
SYMBOL_NAME(square_unsigned):
    imull %ecx, %ecx
    movl %ecx, %eax
    retq
# else /* sysvabi */
SYMBOL_NAME(square_unsigned):
    imull %edi, %edi
    movl %edi, %eax
    retq
# endif

#endif
meson-0.53.2/test cases/common/122 llvm ir and assembly/square.ll0000644000175000017500000000011313531533273025650 0ustar  jpakkanejpakkane00000000000000define i32 @square_unsigned(i32 %a) {
  %1 = mul i32 %a, %a
  ret i32 %1
}
meson-0.53.2/test cases/common/122 llvm ir and assembly/symbol-underscore.h0000644000175000017500000000017313531533273027652 0ustar  jpakkanejpakkane00000000000000#if defined(MESON_TEST__UNDERSCORE_SYMBOL)
# define SYMBOL_NAME(name) _##name
#else
# define SYMBOL_NAME(name) name
#endif
meson-0.53.2/test cases/common/123 cpp and asm/0000755000175000017500000000000013625242356022206 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/123 cpp and asm/meson.build0000644000175000017500000000135313605171474024352 0ustar  jpakkanejpakkane00000000000000project('c++ and assembly test', 'cpp')

cpp = meson.get_compiler('cpp')
cpu = host_machine.cpu_family()

supported_cpus = ['arm', 'x86', 'x86_64']

if not supported_cpus.contains(cpu)
  error('MESON_SKIP_TEST unsupported cpu:' + cpu)
endif

if cpp.symbols_have_underscore_prefix()
  add_project_arguments('-DMESON_TEST__UNDERSCORE_SYMBOL', language : 'cpp')
endif

sources = ['trivial.cc']
# If the compiler cannot compile assembly, don't use it
if not ['msvc', 'clang-cl', 'intel-cl'].contains(meson.get_compiler('cpp').get_id())
  sources += ['retval-' + cpu + '.S']
  cpp_args = ['-DUSE_ASM']
  message('Using ASM')
else
  cpp_args = ['-DNO_USE_ASM']
endif

exe = executable('trivialprog', sources,
  cpp_args : cpp_args)
test('runtest', exe)
meson-0.53.2/test cases/common/123 cpp and asm/retval-arm.S0000644000175000017500000000026213531533273024401 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

.text
.globl SYMBOL_NAME(get_retval)
# ifdef __linux__
.type get_retval, %function
#endif

SYMBOL_NAME(get_retval):
    mov	r0, #0
    mov	pc, lr
meson-0.53.2/test cases/common/123 cpp and asm/retval-x86.S0000644000175000017500000000026113531533273024246 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

.text
.globl SYMBOL_NAME(get_retval)
# ifdef __linux__
.type get_retval, %function
#endif

SYMBOL_NAME(get_retval):
    xorl	%eax, %eax
    retl
meson-0.53.2/test cases/common/123 cpp and asm/retval-x86_64.S0000644000175000017500000000026113531533273024557 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

.text
.globl SYMBOL_NAME(get_retval)
# ifdef __linux__
.type get_retval, %function
#endif

SYMBOL_NAME(get_retval):
    xorl	%eax, %eax
    retq
meson-0.53.2/test cases/common/123 cpp and asm/symbol-underscore.h0000644000175000017500000000017313531533273026031 0ustar  jpakkanejpakkane00000000000000#if defined(MESON_TEST__UNDERSCORE_SYMBOL)
# define SYMBOL_NAME(name) _##name
#else
# define SYMBOL_NAME(name) name
#endif
meson-0.53.2/test cases/common/123 cpp and asm/trivial.cc0000644000175000017500000000041313571777336024200 0ustar  jpakkanejpakkane00000000000000#include

extern "C" {
  int get_retval(void);
}

int main(void) {
  std::cout << "C++ seems to be working." << std::endl;
#if defined(USE_ASM)
  return get_retval();
#elif defined(NO_USE_ASM)
  return 0;
#else
  #error "Forgot to pass asm define"
#endif
}
meson-0.53.2/test cases/common/124 extract all shared library/0000755000175000017500000000000013625242356025220 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/124 extract all shared library/extractor.h0000644000175000017500000000012213571777336027412 0ustar  jpakkanejpakkane00000000000000#pragma once

int func1(void);
int func2(void);
int func3(void);
int func4(void);
meson-0.53.2/test cases/common/124 extract all shared library/four.c0000644000175000017500000000007113571777336026350 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"

int func4(void) {
    return 4;
}
meson-0.53.2/test cases/common/124 extract all shared library/func1234.def0000644000175000017500000000004413531533273027140 0ustar  jpakkanejpakkane00000000000000EXPORTS
	func1
	func2
	func3
	func4
meson-0.53.2/test cases/common/124 extract all shared library/meson.build0000644000175000017500000000047413605171474027367 0ustar  jpakkanejpakkane00000000000000project('extract all', 'c', 'cpp')

a = static_library('a', 'one.c', 'two.c')
b = static_library('b', 'three.c', 'four.c')
c = shared_library('c',
  objects : [a.extract_all_objects(), b.extract_all_objects()],
  vs_module_defs : 'func1234.def')

e = executable('proggie', 'prog.c', link_with : c)
test('extall', e)
meson-0.53.2/test cases/common/124 extract all shared library/one.c0000644000175000017500000000007113571777336026156 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"

int func1(void) {
    return 1;
}
meson-0.53.2/test cases/common/124 extract all shared library/prog.c0000644000175000017500000000031213571777336026342 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"
#include

int main(void) {
    if((1+2+3+4) != (func1() + func2() + func3() + func4())) {
        printf("Arithmetic is fail.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/124 extract all shared library/three.c0000644000175000017500000000007113571777336026504 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"

int func3(void) {
    return 3;
}
meson-0.53.2/test cases/common/124 extract all shared library/two.c0000644000175000017500000000007113571777336026206 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"

int func2(void) {
    return 2;
}
meson-0.53.2/test cases/common/125 object only target/0000755000175000017500000000000013625242357023622 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/125 object only target/installed_files.txt0000644000175000017500000000005013531533273027513 0ustar  jpakkanejpakkane00000000000000usr/bin/prog?exe
?msvc:usr/bin/prog.pdb
meson-0.53.2/test cases/common/125 object only target/meson.build0000644000175000017500000000232713605171477025772 0ustar  jpakkanejpakkane00000000000000project('object generator', 'c')

# FIXME: Note that this will not add a dependency to the compiler executable.
# Code will not be rebuilt if it changes.
comp = find_program('obj_generator.py')

if host_machine.system() == 'windows'
  ext = '.obj'
else
  ext = '.o'
endif

cc = meson.get_compiler('c').cmd_array().get(-1)

# Generate an object file with configure_file to mimic prebuilt objects
# provided by the source tree
source1 = configure_file(input : 'source.c',
  output : 'source' + ext,
  command : [comp, cc, files('source.c'),
             join_paths(meson.current_build_dir(), 'source' + ext)])

obj = static_library('obj', objects : source1)

# Generate an object file manually.
gen = generator(comp,
 output : '@BASENAME@' + ext,
 arguments : [cc, '@INPUT@', '@OUTPUT@'])

generated = gen.process(['source2.c'])

shr = shared_library('shr', generated,
  vs_module_defs : 'source2.def')

# Generate an object file with indexed OUTPUT replacement.
gen2 = generator(comp,
 output : '@BASENAME@' + ext,
 arguments : [cc, '@INPUT@', '@OUTPUT0@'])
generated2 = gen2.process(['source3.c'])

stc = static_library('stc', generated2)

e = executable('prog', 'prog.c', link_with : [obj, shr, stc],
  install : true)

test('objgen', e)
meson-0.53.2/test cases/common/125 object only target/obj_generator.py0000755000175000017500000000101313531533273027006 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# Mimic a binary that generates an object file (e.g. windres).

import sys, subprocess

if __name__ == '__main__':
    if len(sys.argv) != 4:
        print(sys.argv[0], 'compiler input_file output_file')
        sys.exit(1)
    compiler = sys.argv[1]
    ifile = sys.argv[2]
    ofile = sys.argv[3]
    if compiler.endswith('cl'):
        cmd = [compiler, '/nologo', '/MDd', '/Fo' + ofile, '/c', ifile]
    else:
        cmd = [compiler, '-c', ifile, '-o', ofile]
    sys.exit(subprocess.call(cmd))
meson-0.53.2/test cases/common/125 object only target/prog.c0000644000175000017500000000023113571777336024743 0ustar  jpakkanejpakkane00000000000000int func1_in_obj(void);
int func2_in_obj(void);
int func3_in_obj(void);

int main(void) {
    return func1_in_obj() + func2_in_obj() + func3_in_obj();
}
meson-0.53.2/test cases/common/125 object only target/source.c0000644000175000017500000000005113571777336025274 0ustar  jpakkanejpakkane00000000000000int func1_in_obj(void) {
    return 0;
}
meson-0.53.2/test cases/common/125 object only target/source2.c0000644000175000017500000000005113571777336025356 0ustar  jpakkanejpakkane00000000000000int func2_in_obj(void) {
    return 0;
}
meson-0.53.2/test cases/common/125 object only target/source2.def0000644000175000017500000000003513531533273025656 0ustar  jpakkanejpakkane00000000000000EXPORTS
        func2_in_obj
meson-0.53.2/test cases/common/125 object only target/source3.c0000644000175000017500000000005113571777336025357 0ustar  jpakkanejpakkane00000000000000int func3_in_obj(void) {
    return 0;
}
meson-0.53.2/test cases/common/126 no buildincdir/0000755000175000017500000000000013625242357023031 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/126 no buildincdir/include/0000755000175000017500000000000013625242357024454 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/126 no buildincdir/include/header.h0000644000175000017500000000004013571777336026061 0ustar  jpakkanejpakkane00000000000000#pragma once

int foobar(void);
meson-0.53.2/test cases/common/126 no buildincdir/meson.build0000644000175000017500000000056713605171476025204 0ustar  jpakkanejpakkane00000000000000project('nobuilddir', 'c',
  default_options : ['werror=true', 'buildtype=plain'])

cc = meson.get_compiler('c')

incwarg = '-Wmissing-include-dirs'

if cc.has_argument(incwarg)
  executable('prog', 'prog.c',
    c_args : incwarg,
    include_directories : include_directories('include'))
else
  error('MESON_SKIP_TEST compiler does not support bad inc dir argument.')
endif
meson-0.53.2/test cases/common/126 no buildincdir/prog.c0000644000175000017500000000006513571777336024157 0ustar  jpakkanejpakkane00000000000000#include"header.h"

int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/127 custom target directory install/0000755000175000017500000000000013625242357026342 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/127 custom target directory install/docgen.py0000644000175000017500000000027713531533273030155 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys

out = sys.argv[1]

os.mkdir(out)

for name in ('a', 'b', 'c'):
    with open(os.path.join(out, name + '.html'), 'w') as f:
        f.write(name)
meson-0.53.2/test cases/common/127 custom target directory install/installed_files.txt0000644000175000017500000000016213531533273032237 0ustar  jpakkanejpakkane00000000000000usr/share/doc/testpkgname/html/a.html
usr/share/doc/testpkgname/html/b.html
usr/share/doc/testpkgname/html/c.html
meson-0.53.2/test cases/common/127 custom target directory install/meson.build0000644000175000017500000000036413605171476030510 0ustar  jpakkanejpakkane00000000000000project('custom-target-dir-install', 'c')

docgen = find_program('docgen.py')

custom_target('docgen',
  output : 'html',
  command : [docgen, '@OUTPUT@'],
  install : true,
  install_dir : join_paths(get_option('datadir'), 'doc/testpkgname'))
meson-0.53.2/test cases/common/128 dependency file generation/0000755000175000017500000000000013625242357025300 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/128 dependency file generation/main .c0000644000175000017500000000003713571777336026442 0ustar  jpakkanejpakkane00000000000000int main(void) {
  return 0;
}
meson-0.53.2/test cases/common/128 dependency file generation/meson.build0000644000175000017500000000107613605171500027433 0ustar  jpakkanejpakkane00000000000000project('dep file gen', 'c')

cc_id  = meson.get_compiler('c').get_id()
cc_ver = meson.get_compiler('c').version()

if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08'))
  # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
  # (correctly) thinks that the rule has multiple outputs and errors out:
  # 'depfile has multiple output paths'
  error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
endif

e = executable('main file', 'main .c')
test('test it', e)
meson-0.53.2/test cases/common/129 configure file in generator/0000755000175000017500000000000013625242357025366 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/129 configure file in generator/inc/0000755000175000017500000000000013625242357026137 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/129 configure file in generator/inc/confdata.in0000644000175000017500000000001013531533273030231 0ustar  jpakkanejpakkane00000000000000@VALUE@
meson-0.53.2/test cases/common/129 configure file in generator/inc/meson.build0000644000175000017500000000022113531533273030270 0ustar  jpakkanejpakkane00000000000000cdata = configuration_data()
cdata.set('VALUE', '42')

cfile = configure_file(input : 'confdata.in',
output : 'confdata',
configuration : cdata)
meson-0.53.2/test cases/common/129 configure file in generator/meson.build0000644000175000017500000000010413605171501027511 0ustar  jpakkanejpakkane00000000000000project('conf file in generator', 'c')

subdir('inc')
subdir('src')
meson-0.53.2/test cases/common/129 configure file in generator/src/0000755000175000017500000000000013625242357026155 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/129 configure file in generator/src/gen.py0000755000175000017500000000035013531533273027275 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

ifile = sys.argv[1]
ofile = sys.argv[2]

with open(ifile, 'r') as f:
    resval = f.readline().strip()

templ = '#define RESULT (%s)\n'
with open(ofile, 'w') as f:
    f.write(templ % (resval, ))
meson-0.53.2/test cases/common/129 configure file in generator/src/main.c0000644000175000017500000000040013571777336027251 0ustar  jpakkanejpakkane00000000000000#include

#include"confdata.h"
#if RESULT != 42
#error Configuration RESULT is not defined correctly
#endif

#undef RESULT

#include"source.h"
#if RESULT != 23
#error Source RESULT is not defined correctly
#endif

int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/129 configure file in generator/src/meson.build0000644000175000017500000000031313531533273030310 0ustar  jpakkanejpakkane00000000000000compiler = find_program('gen.py')
gen = generator(compiler,
  output: '@BASENAME@.h',
  arguments : ['@INPUT@', '@OUTPUT@'])
hs = gen.process(cfile, files('source'))

executable('proggie', 'main.c', hs)
meson-0.53.2/test cases/common/129 configure file in generator/src/source0000644000175000017500000000000313531533273027365 0ustar  jpakkanejpakkane0000000000000023
meson-0.53.2/test cases/common/13 pch/0000755000175000017500000000000013625242357020631 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/c/0000755000175000017500000000000013625242357021053 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/c/meson.build0000644000175000017500000000043013531533273023206 0ustar  jpakkanejpakkane00000000000000cc = meson.get_compiler('c')
cc_id = cc.get_id()

if cc_id == 'lcc'
  error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.')
endif

# PGI compiler only supports PCH for C++
if cc_id == 'pgi'
  subdir_done()
endif

exe = executable('prog', 'prog.c',
c_pch : 'pch/prog.h')
meson-0.53.2/test cases/common/13 pch/c/pch/0000755000175000017500000000000013625242357021625 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/c/pch/prog.h0000644000175000017500000000025113426772653022751 0ustar  jpakkanejpakkane00000000000000#ifndef PROG_H
// Header guards for PCH confuse msvc in some situations.
// Using them here makes sure we handle this correctly.
#define PROG_H
#include
#endif
meson-0.53.2/test cases/common/13 pch/c/prog.c0000644000175000017500000000027713571777336022206 0ustar  jpakkanejpakkane00000000000000// No includes here, they need to come from the PCH

void func(void) {
    fprintf(stdout, "This is a function that fails if stdio is not #included.\n");
}

int main(void) {
    return 0;
}

meson-0.53.2/test cases/common/13 pch/cpp/0000755000175000017500000000000013625242357021413 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/cpp/meson.build0000644000175000017500000000007513440031012023532 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.cc', cpp_pch : 'pch/prog.hh')
meson-0.53.2/test cases/common/13 pch/cpp/pch/0000755000175000017500000000000013625242357022165 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/cpp/pch/prog.hh0000644000175000017500000000002313366273150023445 0ustar  jpakkanejpakkane00000000000000#include
meson-0.53.2/test cases/common/13 pch/cpp/prog.cc0000644000175000017500000000046113571777336022704 0ustar  jpakkanejpakkane00000000000000// Note: if using PGI compilers, you will need to add #include "prog.hh"
// even though you're using precompiled headers.
void func(void) {
    std::cout << "This is a function that fails to compile if iostream is not included."
              << std::endl;
}

int main(void) {
    func();
    return 0;
}
meson-0.53.2/test cases/common/13 pch/generated/0000755000175000017500000000000013625242357022567 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/generated/gen_custom.py0000644000175000017500000000014213431063044025266 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3
import sys

with open(sys.argv[1], 'w') as f:
    f.write("#define FOO 0")
meson-0.53.2/test cases/common/13 pch/generated/gen_generator.py0000644000175000017500000000021613431063044025744 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as f:
    content = f.read()
with open(sys.argv[2], 'w') as f:
    f.write(content)
meson-0.53.2/test cases/common/13 pch/generated/generated_generator.in0000644000175000017500000000001613431063044027105 0ustar  jpakkanejpakkane00000000000000#define BAR 0
meson-0.53.2/test cases/common/13 pch/generated/meson.build0000644000175000017500000000120113531533273024717 0ustar  jpakkanejpakkane00000000000000cc = meson.get_compiler('c')
cc_id = cc.get_id()

if cc_id == 'lcc'
  error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.')
endif

# PGI compiler only supports PCH for C++
if cc_id == 'pgi'
  subdir_done()
endif

generated_customTarget = custom_target('makeheader',
  output: 'generated_customTarget.h',
  command : [find_program('gen_custom.py'), '@OUTPUT0@'])

generated_generator = generator(find_program('gen_generator.py'),
  output: '@BASENAME@.h',
  arguments: ['@INPUT@', '@OUTPUT@'])

exe = executable('prog', 'prog.c', generated_customTarget, generated_generator.process('generated_generator.in'),
  c_pch: 'pch/prog.h')
meson-0.53.2/test cases/common/13 pch/generated/pch/0000755000175000017500000000000013625242357023341 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/generated/pch/prog.h0000644000175000017500000000010513431063044024442 0ustar  jpakkanejpakkane00000000000000#include "generated_customTarget.h"
#include "generated_generator.h"
meson-0.53.2/test cases/common/13 pch/generated/prog.c0000644000175000017500000000013713571777336023715 0ustar  jpakkanejpakkane00000000000000// No includes here, they need to come from the PCH

int main(void) {
    return FOO + BAR;
}

meson-0.53.2/test cases/common/13 pch/meson.build0000644000175000017500000000127313605171317022771 0ustar  jpakkanejpakkane00000000000000project('pch test', 'c', 'cpp',
  meson_version: '>= 0.46.0')

cc = meson.get_compiler('c')
cc_id = cc.get_id()

if cc_id == 'pgi'
  error('MESON_SKIP_TEST: PGI compiler does support PCH, however, PGI cannot tolerate spaces in the --pch_dir path and Meson run_project_tests.py uses spaces in temporary build path names. If this test is run individually with no spaces in build path, it will pass.')
endif

subdir('c')
subdir('cpp')
subdir('generated')
subdir('userDefined')
subdir('withIncludeDirectories')

if meson.backend() == 'xcode'
  warning('Xcode backend only supports one precompiled header per target. Skipping "mixed" which has various precompiled headers.')
else
  subdir('mixed')
endif
meson-0.53.2/test cases/common/13 pch/mixed/0000755000175000017500000000000013625242357021737 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/mixed/func.c0000644000175000017500000000021613571777336023047 0ustar  jpakkanejpakkane00000000000000void tmp_func(void) {
    fprintf(stdout, "This is a function that fails if stdio is not #included.\n");
}

int cfunc(void) {
    return 0;
}
meson-0.53.2/test cases/common/13 pch/mixed/main.cc0000644000175000017500000000031213571777336023200 0ustar  jpakkanejpakkane00000000000000extern "C" int cfunc();

void func(void) {
    std::cout << "This is a function that fails to compile if iostream is not included."
              << std::endl;
}

int main(void) {
    return cfunc();
}
meson-0.53.2/test cases/common/13 pch/mixed/meson.build0000644000175000017500000000036613531533273024102 0ustar  jpakkanejpakkane00000000000000cc = meson.get_compiler('c')
cc_id = cc.get_id()

# PGI compiler only supports PCH for C++
if cc_id == 'pgi'
  subdir_done()
endif

exe = executable(
  'prog',
  files('main.cc', 'func.c'),
  c_pch : ['pch/func.h'],
  cpp_pch : ['pch/main.h'],
)
meson-0.53.2/test cases/common/13 pch/mixed/pch/0000755000175000017500000000000013625242357022511 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/mixed/pch/func.h0000644000175000017500000000002213366273150023604 0ustar  jpakkanejpakkane00000000000000#include
meson-0.53.2/test cases/common/13 pch/mixed/pch/main.h0000644000175000017500000000002313366273150023576 0ustar  jpakkanejpakkane00000000000000#include
meson-0.53.2/test cases/common/13 pch/userDefined/0000755000175000017500000000000013625242357023066 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/userDefined/meson.build0000644000175000017500000000057113440031012025206 0ustar  jpakkanejpakkane00000000000000cc = meson.get_compiler('c')
cc_id = cc.get_id()

# User supplied PCH implementation should override the auto
# generated one. PCH implementations are only supported for
# msvc and generally should not be used at all. Support for
# them is only kept for backwards compatibility.
if cc_id == 'msvc'
  exe = executable('prog', 'prog.c', c_pch : ['pch/pch.h', 'pch/pch.c'])
endif
meson-0.53.2/test cases/common/13 pch/userDefined/pch/0000755000175000017500000000000013625242357023640 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/userDefined/pch/pch.c0000644000175000017500000000006213571777336024566 0ustar  jpakkanejpakkane00000000000000#include "pch.h"

int foo(void) {
    return 0;
}
meson-0.53.2/test cases/common/13 pch/userDefined/pch/pch.h0000644000175000017500000000001313440031012024530 0ustar  jpakkanejpakkane00000000000000int foo();
meson-0.53.2/test cases/common/13 pch/userDefined/prog.c0000644000175000017500000000040313571777336024210 0ustar  jpakkanejpakkane00000000000000// No includes here, they need to come from the PCH

int main(void) {
    // Method is implemented in pch.c.
    // This makes sure that we can properly handle user defined
    // pch implementation files and not only auto-generated ones.
    return foo();
}
meson-0.53.2/test cases/common/13 pch/withIncludeDirectories/0000755000175000017500000000000013625242357025305 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/withIncludeDirectories/include/0000755000175000017500000000000013625242350026721 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/withIncludeDirectories/include/lib/0000755000175000017500000000000013625242357027476 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/withIncludeDirectories/include/lib/lib.h0000644000175000017500000000002313431063044030375 0ustar  jpakkanejpakkane00000000000000#include 
meson-0.53.2/test cases/common/13 pch/withIncludeDirectories/meson.build0000644000175000017500000000047413531533273027450 0ustar  jpakkanejpakkane00000000000000cc = meson.get_compiler('c')
cc_id = cc.get_id()

if cc_id == 'lcc'
  error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.')
endif

# PGI compiler only supports PCH for C++
if cc_id == 'pgi'
  subdir_done()
endif

exe = executable('prog', 'prog.c',
  include_directories: 'include',
  c_pch : 'pch/prog.h')
meson-0.53.2/test cases/common/13 pch/withIncludeDirectories/pch/0000755000175000017500000000000013625242357026057 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/13 pch/withIncludeDirectories/pch/prog.h0000644000175000017500000000002413431063044027160 0ustar  jpakkanejpakkane00000000000000#include
meson-0.53.2/test cases/common/13 pch/withIncludeDirectories/prog.c0000644000175000017500000000027713571777336026440 0ustar  jpakkanejpakkane00000000000000// No includes here, they need to come from the PCH

void func(void) {
    fprintf(stdout, "This is a function that fails if stdio is not #included.\n");
}

int main(void) {
    return 0;
}

meson-0.53.2/test cases/common/130 generated llvm ir/0000755000175000017500000000000013625242357023423 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/130 generated llvm ir/copyfile.py0000644000175000017500000000013413531533273025601 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import shutil

shutil.copyfile(sys.argv[1], sys.argv[2])
meson-0.53.2/test cases/common/130 generated llvm ir/main.c0000644000175000017500000000032313571777336024523 0ustar  jpakkanejpakkane00000000000000#include 

unsigned square_unsigned (unsigned a);

int main(void)
{
  unsigned int ret = square_unsigned (2);
  if (ret != 4) {
    printf("Got %u instead of 4\n", ret);
    return 1;
  }
  return 0;
}
meson-0.53.2/test cases/common/130 generated llvm ir/meson.build0000644000175000017500000000125113531533273025560 0ustar  jpakkanejpakkane00000000000000project('generated llvm ir', 'c')

if meson.get_compiler('c').get_id() != 'clang'
  error('MESON_SKIP_TEST: LLVM IR files can only be built with clang')
endif

copy = find_program('copyfile.py')

copygen = generator(copy,
  arguments : ['@INPUT@', '@OUTPUT@'],
  output : '@BASENAME@')

l = shared_library('square-gen', copygen.process('square.ll.in'))

test('square-gen-test', executable('square-gen-test', 'main.c', link_with : l))

copyct = custom_target('square',
  input : 'square.ll.in',
  output : 'square.ll',
  command : [copy, '@INPUT@', '@OUTPUT@'])

l = shared_library('square-ct', copyct)

test('square-ct-test', executable('square-ct-test', 'main.c', link_with : l))
meson-0.53.2/test cases/common/130 generated llvm ir/square.ll.in0000644000175000017500000000011313531533273025650 0ustar  jpakkanejpakkane00000000000000define i32 @square_unsigned(i32 %a) {
  %1 = mul i32 %a, %a
  ret i32 %1
}
meson-0.53.2/test cases/common/131 generated assembly/0000755000175000017500000000000013625242357023676 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/131 generated assembly/copyfile.py0000644000175000017500000000013413531533273026054 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import shutil

shutil.copyfile(sys.argv[1], sys.argv[2])
meson-0.53.2/test cases/common/131 generated assembly/main.c0000644000175000017500000000043413571777336025001 0ustar  jpakkanejpakkane00000000000000#include 

#if defined(_WIN32) || defined(__CYGWIN__)
 __declspec(dllimport)
#endif
unsigned square_unsigned (unsigned a);

int main(void)
{
  unsigned int ret = square_unsigned (2);
  if (ret != 4) {
    printf("Got %u instead of 4\n", ret);
    return 1;
  }
  return 0;
}
meson-0.53.2/test cases/common/131 generated assembly/meson.build0000644000175000017500000000206113605171503026027 0ustar  jpakkanejpakkane00000000000000project('generated assembly', 'c')

cc = meson.get_compiler('c')

if ['msvc', 'clang-cl', 'intel-cl'].contains(cc.get_id())
  error('MESON_SKIP_TEST: assembly files cannot be compiled directly by the compiler')
endif

cpu = host_machine.cpu_family()
supported_cpus = ['arm', 'x86', 'x86_64']

if not supported_cpus.contains(cpu)
  error('MESON_SKIP_TEST: unsupported cpu family: ' + cpu)
endif

if cc.symbols_have_underscore_prefix()
  add_project_arguments('-DMESON_TEST__UNDERSCORE_SYMBOL', language : 'c')
endif

copy = find_program('copyfile.py')
output = 'square-@0@.S'.format(cpu)
input = output + '.in'

copygen = generator(copy,
  arguments : ['@INPUT@', '@OUTPUT@'],
  output : '@BASENAME@')

l = shared_library('square-gen', copygen.process(input))

test('square-gen-test', executable('square-gen-test', 'main.c', link_with : l))

copyct = custom_target('square',
  input : input,
  output : output,
  command : [copy, '@INPUT@', '@OUTPUT@'])

l = shared_library('square-ct', copyct)

test('square-ct-test', executable('square-ct-test', 'main.c', link_with : l))
meson-0.53.2/test cases/common/131 generated assembly/square-arm.S.in0000644000175000017500000000046713531533273026507 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

.text
.globl SYMBOL_NAME(square_unsigned)
/* Only supported with GAS */
# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
.type	square_unsigned,%function
#endif

SYMBOL_NAME(square_unsigned):
	mul	r1, r0, r0
	mov	r0, r1
	mov	pc, lr
meson-0.53.2/test cases/common/131 generated assembly/square-x86.S.in0000644000175000017500000000102013531533273026337 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

#ifdef _MSC_VER

.386
.MODEL FLAT, C

PUBLIC square_unsigned
_TEXT   SEGMENT

square_unsigned PROC var1:DWORD
        mov     eax, var1
	imul	eax, eax
	ret
square_unsigned ENDP

_TEXT   ENDS
END

#else

.text
.globl SYMBOL_NAME(square_unsigned)
/* Only supported with GAS */
# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
.type  square_unsigned,@function
# endif

SYMBOL_NAME(square_unsigned):
	movl	4(%esp), %eax
	imull	%eax, %eax
	retl

#endif
meson-0.53.2/test cases/common/131 generated assembly/square-x86_64.S.in0000644000175000017500000000132713537776255026701 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

#ifdef _MSC_VER /* MSVC on Windows */

PUBLIC SYMBOL_NAME(square_unsigned)
_TEXT   SEGMENT

SYMBOL_NAME(square_unsigned) PROC
        mov     eax, ecx
	imul	eax, eax
	ret
SYMBOL_NAME(square_unsigned) ENDP

_TEXT   ENDS
END

#else

.text
.globl SYMBOL_NAME(square_unsigned)
/* Only supported with GAS */
# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun)
.type  square_unsigned,@function
# endif

# if defined(_WIN32) || defined(__CYGWIN__) /* msabi */
SYMBOL_NAME(square_unsigned):
	imull	%ecx, %ecx
	movl	%ecx, %eax
	retq
# else /* sysvabi */
SYMBOL_NAME(square_unsigned):
	imull	%edi, %edi
	movl	%edi, %eax
	retq
# endif

#endif
meson-0.53.2/test cases/common/131 generated assembly/symbol-underscore.h0000644000175000017500000000017313531533273027520 0ustar  jpakkanejpakkane00000000000000#if defined(MESON_TEST__UNDERSCORE_SYMBOL)
# define SYMBOL_NAME(name) _##name
#else
# define SYMBOL_NAME(name) name
#endif
meson-0.53.2/test cases/common/132 build by default targets in tests/0000755000175000017500000000000013625242357026404 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/132 build by default targets in tests/main.c0000644000175000017500000000003713571777336027506 0ustar  jpakkanejpakkane00000000000000int main(void) {
  return 0;
}
meson-0.53.2/test cases/common/132 build by default targets in tests/meson.build0000644000175000017500000000164413605171503030543 0ustar  jpakkanejpakkane00000000000000project('unit-test', 'c', version : '1.0')

write_file = find_program('write_file.py')

# A test that consumes and verifies the output generated by a custom target.
# Should work even if target is not built by default. Makes sure that foo.out
# is actually created before the test command that uses foo_out is run.
foo_out = custom_target('foo.out',
  output : 'foo.out',
  command : [write_file, '@OUTPUT@'])

# Also verify that a build_by_default : false BuildTarget added to a test is
# built before the test is run.
exe_out = executable('out', 'main.c', build_by_default : false)

py_file_exists = '''import os, sys
if not os.path.exists(sys.argv[1]) or not os.path.exists(sys.argv[2]):
  print("could not find {!r} or {!r} in {!r}"
        "".format(sys.argv[1], sys.argv[2], os.getcwd()))
  sys.exit(1)'''

python = import('python3').find_python()
test('output-check', python, args : ['-c', py_file_exists, foo_out, exe_out])
meson-0.53.2/test cases/common/132 build by default targets in tests/write_file.py0000644000175000017500000000013213531533273031077 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

with open(sys.argv[1], 'w') as f:
    f.write('Test')
meson-0.53.2/test cases/common/133 build by default/0000755000175000017500000000000013625242357023241 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/133 build by default/checkexists.py0000644000175000017500000000030413531533273026121 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os.path, sys

invert = False
for path in sys.argv[1:]:
    if path == '--not':
        invert = True
    elif not os.path.exists(path) ^ invert:
        sys.exit(1)
meson-0.53.2/test cases/common/133 build by default/foo.c0000644000175000017500000000012513571777336024200 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("Existentialism.\n");
    return 0;
}
meson-0.53.2/test cases/common/133 build by default/meson.build0000644000175000017500000000215213605171503025373 0ustar  jpakkanejpakkane00000000000000project('build on all', 'c')

py3_mod = import('python3')
py3 = py3_mod.find_python()

executable('fooprog', 'foo.c',
    build_by_default : false,
)

executable('barprog', 'foo.c',
    build_by_default : false,
    build_always : true,
)

comp = files('mygen.py')
checkexists = files('checkexists.py')

mytarget = custom_target('gendat1',
  output : 'generated1.dat',
  input : 'source.txt',
  command : [py3] + comp + ['@INPUT@', '@OUTPUT@'],
  build_by_default : true,
)

mytarget = custom_target('gendat2',
  output : 'generated2.dat',
  input : 'source.txt',
  command : [py3] + comp + ['@INPUT@', '@OUTPUT@'],
  build_by_default : true,
  build_always : false,
)

ct1_output = join_paths(meson.build_root(), 'generated1.dat')
ct2_output = join_paths(meson.build_root(), 'generated2.dat')
exe1_output = join_paths(meson.build_root(), 'fooprog')
exe2_output = join_paths(meson.build_root(), 'barprog')

if host_machine.system() == 'windows'
  exe1_output += '.exe'
  exe2_output += '.exe'
endif

test('check-build-by-default', py3,
     args : [checkexists,
        ct1_output, ct2_output, '--not', exe1_output, exe2_output])
meson-0.53.2/test cases/common/133 build by default/mygen.py0000644000175000017500000000017013531533273024724 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

ifile = open(sys.argv[1])
ofile = open(sys.argv[2], 'w')

ofile.write(ifile.read())
meson-0.53.2/test cases/common/133 build by default/source.txt0000644000175000017500000000002613531533273025274 0ustar  jpakkanejpakkane00000000000000I am a bunch of text.
meson-0.53.2/test cases/common/134 include order/0000755000175000017500000000000013625242357022662 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/ctsub/0000755000175000017500000000000013625242357024002 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/ctsub/copyfile.py0000644000175000017500000000013413531533273026160 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import shutil

shutil.copyfile(sys.argv[1], sys.argv[2])
meson-0.53.2/test cases/common/134 include order/ctsub/emptyfile.c0000644000175000017500000000000013531533273026126 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/ctsub/main.h0000644000175000017500000000003713531533273025073 0ustar  jpakkanejpakkane00000000000000#error "ctsub/main.h included"
meson-0.53.2/test cases/common/134 include order/ctsub/meson.build0000644000175000017500000000061713531533273026144 0ustar  jpakkanejpakkane00000000000000# https://github.com/mesonbuild/meson/pull/2291
copy = find_program('copyfile.py')
configure_file(input : 'main.h',
               output : 'main.h',
               command : [copy, '@INPUT@', '@OUTPUT@'])
ctfile = custom_target('emptyfile',
                       input : 'emptyfile.c',
                       output : 'emptyfile.c',
                       command : [copy, '@INPUT@', '@OUTPUT@'])
meson-0.53.2/test cases/common/134 include order/inc1/0000755000175000017500000000000013625242357023514 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/inc1/hdr.h0000644000175000017500000000002713531533273024435 0ustar  jpakkanejpakkane00000000000000#define SOME_DEFINE 42
meson-0.53.2/test cases/common/134 include order/inc2/0000755000175000017500000000000013625242357023515 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/inc2/hdr.h0000644000175000017500000000002313531533273024432 0ustar  jpakkanejpakkane00000000000000#undef SOME_DEFINE
meson-0.53.2/test cases/common/134 include order/meson.build0000644000175000017500000000251213605171506025017 0ustar  jpakkanejpakkane00000000000000project('include order', 'c')

# Test that the order of priority of include paths (from first to last) is:
#
# 1. Target's current build directory
# 2. Target's current source directory
# 3. Include paths added with the `c_args:` kwarg
# 4. Include paths added with the `include_directories`: kwarg
#    Within this, the build dir takes precedence over the source dir
# 5. Include paths added via `include_directories:` of internal deps
#    Within this, the build dir takes precedence over the source dir

# Custom target dir with a built header
subdir('ctsub')
# Defines an internal dep
subdir('sub1')
# Defines a per-target include path
subdir('sub2')
# Directory for `c_args:` include path
subdir('sub3')
# The directory where the target resides
subdir('sub4')

# Test that the order in which internal dependencies are specified is
# preserved. This is needed especially when subprojects get involved and
# multiple build-root config.h files exist, and we must be sure that the
# correct one is found: https://github.com/mesonbuild/meson/issues/1495
f = executable('somefxe', 'sub4/main.c',
               dependencies : [correctinc, dep, wronginc])

test('eh', e)
test('oh', f)

# Test that the order in include_directories() is maintained
incs = include_directories('inc1', 'inc2')
executable('ordertest', 'ordertest.c', include_directories: incs)
meson-0.53.2/test cases/common/134 include order/ordertest.c0000644000175000017500000000023513571777336025053 0ustar  jpakkanejpakkane00000000000000#include "hdr.h"

#if !defined(SOME_DEFINE) || SOME_DEFINE != 42
#error "Should have picked up hdr.h from inc1/hdr.h"
#endif

int main(void)
{
  return 0;
}
meson-0.53.2/test cases/common/134 include order/sub1/0000755000175000017500000000000013625242357023534 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/sub1/main.h0000644000175000017500000000003613531533273024624 0ustar  jpakkanejpakkane00000000000000#error "sub1/main.h included"
meson-0.53.2/test cases/common/134 include order/sub1/meson.build0000644000175000017500000000023713531533273025674 0ustar  jpakkanejpakkane00000000000000i = include_directories('.')
l = shared_library('somelib', 'some.c')
dep = declare_dependency(link_with : l,
                         include_directories : i)
meson-0.53.2/test cases/common/134 include order/sub1/some.c0000644000175000017500000000015613531533273024641 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  __declspec(dllexport)
#endif
int somefunc(void) {
  return 1984;
}
meson-0.53.2/test cases/common/134 include order/sub1/some.h0000644000175000017500000000024413531533273024644 0ustar  jpakkanejpakkane00000000000000#pragma once

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllimport)
#else
  #define DLL_PUBLIC
#endif

DLL_PUBLIC
int somefunc(void);
meson-0.53.2/test cases/common/134 include order/sub2/0000755000175000017500000000000013625242357023535 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/sub2/main.h0000644000175000017500000000003613531533273024625 0ustar  jpakkanejpakkane00000000000000#error "sub2/main.h included"
meson-0.53.2/test cases/common/134 include order/sub2/meson.build0000644000175000017500000000012413531533273025670 0ustar  jpakkanejpakkane00000000000000j = include_directories('.')
wronginc = declare_dependency(include_directories : j)
meson-0.53.2/test cases/common/134 include order/sub3/0000755000175000017500000000000013625242360023530 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/sub3/main.h0000644000175000017500000000003613531533273024626 0ustar  jpakkanejpakkane00000000000000#error "sub3/main.h included"
meson-0.53.2/test cases/common/134 include order/sub3/meson.build0000644000175000017500000000004213531533273025670 0ustar  jpakkanejpakkane00000000000000sub3 = meson.current_source_dir()
meson-0.53.2/test cases/common/134 include order/sub4/0000755000175000017500000000000013625242360023531 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/134 include order/sub4/main.c0000644000175000017500000000024613571777336024643 0ustar  jpakkanejpakkane00000000000000/* Use the <> include notation to force searching in include directories */
#include 

int main(void) {
  if (somefunc() == 1984)
    return 0;
  return 1;
}
meson-0.53.2/test cases/common/134 include order/sub4/main.h0000644000175000017500000000004013531533273024622 0ustar  jpakkanejpakkane00000000000000#pragma once

#include "some.h"
meson-0.53.2/test cases/common/134 include order/sub4/meson.build0000644000175000017500000000035713531533273025702 0ustar  jpakkanejpakkane00000000000000e = executable('someexe', 'main.c', ctfile,
               c_args : ['-I' + sub3],
               include_directories : j,
               dependencies : dep)

correctinc = declare_dependency(include_directories : include_directories('.'))
meson-0.53.2/test cases/common/135 override options/0000755000175000017500000000000013625242360023431 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/135 override options/four.c0000644000175000017500000000017613571777336024574 0ustar  jpakkanejpakkane00000000000000int func(void);

static int duplicate_func(void) {
    return -4;
}

int main(void) {
    return duplicate_func() + func();
}
meson-0.53.2/test cases/common/135 override options/meson.build0000644000175000017500000000027313605171507025577 0ustar  jpakkanejpakkane00000000000000project('option override', 'c',
  default_options : 'unity=on')

executable('mustunity', 'one.c', 'two.c')
executable('notunity', 'three.c', 'four.c',
  override_options : ['unity=off'])
meson-0.53.2/test cases/common/135 override options/one.c0000644000175000017500000000005713571777336024400 0ustar  jpakkanejpakkane00000000000000static int hidden_func(void) {
    return 0;
}
meson-0.53.2/test cases/common/135 override options/three.c0000644000175000017500000000014313571777336024722 0ustar  jpakkanejpakkane00000000000000static int duplicate_func(void) {
    return 4;
}

int func(void) {
    return duplicate_func();
}
meson-0.53.2/test cases/common/135 override options/two.c0000644000175000017500000000016713571777336024432 0ustar  jpakkanejpakkane00000000000000/*
 * Requires a Unity build. Otherwise hidden_func is not specified.
 */
int main(void) {
    return hidden_func();
}
meson-0.53.2/test cases/common/136 get define/0000755000175000017500000000000013625242360022131 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/136 get define/concat.h0000644000175000017500000000122613531533273023554 0ustar  jpakkanejpakkane00000000000000#define __STRINGIFY(x) #x
#define TEST_STRINGIFY(x) __STRINGIFY(x)

#define TEST_VERSION_MAJOR 6
#define TEST_VERSION_MINOR 0
#define TEST_VERSION_BUGFIX 0

#define TEST_VERSION_STR                                       \
    TEST_STRINGIFY(TEST_VERSION_MAJOR)                         \
    "." TEST_STRINGIFY(TEST_VERSION_MINOR) "." TEST_STRINGIFY( \
        TEST_VERSION_BUGFIX)

#define TEST_CONCAT_1 \
    "ab"              \
    "cd"              \
    "ef"              \
    ""
#define TEST_CONCAT_2 1
#define TEST_CONCAT_3 1 2 3
#define TEST_CONCAT_4 "ab" 1 "cd"
#define TEST_CONCAT_5 \
    "ab\""            \
    "cd"
#define TEST_CONCAT_6 "ab\" \"cd"
meson-0.53.2/test cases/common/136 get define/meson.build0000644000175000017500000001052413605171511024272 0ustar  jpakkanejpakkane00000000000000project('get define', 'c', 'cpp')

host_system = host_machine.system()

foreach lang : ['c', 'cpp']
  cc = meson.get_compiler(lang)
  if host_system == 'linux'
    d = cc.get_define('__linux__')
    assert(d == '1', '__linux__ value is @0@ instead of 1'.format(d))
  elif host_system == 'darwin'
    d = cc.get_define('__APPLE__')
    assert(d == '1', '__APPLE__ value is @0@ instead of 1'.format(d))
  elif host_system == 'windows'
    d = cc.get_define('_WIN32')
    assert(d == '1', '_WIN32 value is @0@ instead of 1'.format(d))
  elif host_system == 'cygwin'
    d = cc.get_define('__CYGWIN__')
    assert(d == '1', '__CYGWIN__ value is @0@ instead of 1'.format(d))
  elif host_system == 'haiku'
    d = cc.get_define('__HAIKU__')
    assert(d == '1', '__HAIKU__ value is @0@ instead of 1'.format(d))
  elif host_system == 'freebsd'
    # the __FreeBSD__ define will be equal to the major version of the release
    # (ex, in FreeBSD 11.x, __FreeBSD__ == 11). To make the test robust when
    # being run on various versions of FreeBSD, just test that the define is
    # set.
    d = cc.get_define('__FreeBSD__')
    assert(d != '', '__FreeBSD__ value is unset')
  elif host_system == 'dragonfly'
    d = cc.get_define('__DragonFly__')
    assert(d == '1', '__DragonFly__ value is @0@ instead of 1'.format(d))
  elif host_system == 'netbsd'
    d = cc.get_define('__NetBSD__')
    assert(d == '1', '__NetBSD__ value is @0@ instead of 1'.format(d))
  elif host_system == 'openbsd'
    d = cc.get_define('__OpenBSD__')
    assert(d == '1', '__OpenBSD__ value is @0@ instead of 1'.format(d))
  elif host_system == 'gnu'
    d = cc.get_define('__GNU__')
    assert(d == '1', '__GNU__ value is @0@ instead of 1'.format(d))
  elif host_system == 'sunos'
    d = cc.get_define('__sun__')
    assert(d == '1', '__sun__ value is @0@ instead of 1'.format(d))
  else
    error('Please report a bug and help us improve support for this platform')
  endif

  if cc.find_library('z', required : false).found()
    # When a C file containing #include  is pre-processed and foo.h is
    # found in the compiler's default search path, GCC inserts an extra comment
    # between the delimiter and the define which causes a parsing error.
    # https://github.com/mesonbuild/meson/issues/1726
    if host_machine.system() == 'netbsd' or host_machine.system() == 'openbsd'
      # NetBSD and OpenBSD's zlib don't have a ZLIB_VER_MAJOR, but they do have
      # a ZLIB_VERSION (which is a string), so check the first non-quote
      # character of that.
      ver = cc.get_define('ZLIB_VERSION', prefix : '#include ')[1]
      assert(ver == '1', 'ZLIB_VERSION (major) value is "@0@" instead of "1"'.format(ver))
    else
      ver = cc.get_define('ZLIB_VER_MAJOR', prefix : '#include ')
      assert(ver == '1', 'ZLIB_VER_MAJOR value is "@0@" instead of "1"'.format(ver))
    endif
  endif

  # Check that an undefined value is empty.
  have = cc.get_define('MESON_FAIL_VALUE')
  assert(have == '', 'MESON_FAIL_VALUE value is "@0@" instead of ""'.format(have))

  # This is used in the test_preprocessor_checks_CPPFLAGS() unit test.
  have = cc.get_define('MESON_TEST_DEFINE_VALUE')
  expect = get_option('MESON_TEST_DEFINE_VALUE')
  assert(have == expect, 'MESON_TEST_DEFINE_VALUE value is "@0@" instead of "@1@"'.format(have, expect))

  run_1665_test = false
  if meson.is_cross_build()
    lang_arg = meson.get_cross_property(lang + '_args', '')
    if lang_arg == '-DMESON_TEST_ISSUE_1665=1'
      run_1665_test = true
    endif
  endif

  if run_1665_test
    have = cc.get_define('MESON_TEST_ISSUE_1665')
    assert(have == '1', 'MESON_TEST_ISSUE_1665 value is "@0@" instead of "1"'.format(have))
  endif

  have = cc.get_define('TEST_VERSION_STR',
        prefix : '#include ', include_directories: include_directories('.'))
  assert(have == '"6.0.0"', 'TEST_VERSION_STR value is "@0@" instead of ""6.0.0""'.format(have))

  concat_examples = {
  'TEST_CONCAT_1': '"abcdef"',
  'TEST_CONCAT_2': '1',
  'TEST_CONCAT_3': '1 2 3',
  'TEST_CONCAT_4': '"ab" 1 "cd"',
  'TEST_CONCAT_5': '"ab\"cd"',
  'TEST_CONCAT_6': '"ab\" \"cd"',
  }
  foreach def,expected : concat_examples
    have = cc.get_define(def,
          prefix : '#include ', include_directories: include_directories('.'))
    assert(have == expected, '@0@ value is "@1@" instead of "@2@"'.format(def, have, expected))
  endforeach
endforeach
meson-0.53.2/test cases/common/136 get define/meson_options.txt0000644000175000017500000000007713531533273025574 0ustar  jpakkanejpakkane00000000000000option('MESON_TEST_DEFINE_VALUE', type : 'string', value : '')
meson-0.53.2/test cases/common/137 c cpp and asm/0000755000175000017500000000000013625242360022411 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/137 c cpp and asm/main.c0000644000175000017500000000017313571777336023522 0ustar  jpakkanejpakkane00000000000000#include 

int get_retval(void);

int main(void) {
  printf("C seems to be working.\n");
  return get_retval();
}
meson-0.53.2/test cases/common/137 c cpp and asm/main.cpp0000644000175000017500000000026513571777336024064 0ustar  jpakkanejpakkane00000000000000#include 

extern "C" {
  int get_retval(void);
  int get_cval(void);
}

int main(void) {
  std::cout << "C++ seems to be working." << std::endl;
  return get_retval();
}
meson-0.53.2/test cases/common/137 c cpp and asm/meson.build0000644000175000017500000000150213605171512024547 0ustar  jpakkanejpakkane00000000000000project('c cpp and asm', 'c', 'cpp')

cpu = host_machine.cpu_family()
cc = meson.get_compiler('c')

supported_cpus = ['arm', 'x86', 'x86_64']

if not supported_cpus.contains(cpu)
  error('MESON_SKIP_TEST unsupported cpu:' + cpu)
endif

if meson.get_compiler('c').get_argument_syntax() == 'msvc'
  error('MESON_SKIP_TEST MSVC can\'t compile assembly')
endif

if cc.symbols_have_underscore_prefix()
  add_project_arguments('-DMESON_TEST__UNDERSCORE_SYMBOL', language: 'c')
endif

test('test-c-asm', executable('c-asm', ['main.c', 'retval-' + cpu + '.S']))
test('test-cpp-asm', executable('cpp-asm', ['main.cpp', 'retval-' + cpu + '.S']))
test('test-c-cpp-asm', executable('c-cpp-asm', ['somelib.c', 'main.cpp', 'retval-' + cpu + '.S']))
test('test-cpp-c-asm', executable('cpp-c-asm', ['main.cpp', 'somelib.c', 'retval-' + cpu + '.S']))
meson-0.53.2/test cases/common/137 c cpp and asm/retval-arm.S0000644000175000017500000000026213531533273024611 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

.text
.globl SYMBOL_NAME(get_retval)
# ifdef __linux__
.type get_retval, %function
#endif

SYMBOL_NAME(get_retval):
    mov	r0, #0
    mov	pc, lr
meson-0.53.2/test cases/common/137 c cpp and asm/retval-x86.S0000644000175000017500000000033013531533273024453 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

.text
.globl SYMBOL_NAME(get_retval)
/* Only supported on Linux with GAS */
# ifdef __linux__
.type get_retval, %function
#endif

SYMBOL_NAME(get_retval):
    xorl	%eax, %eax
    retl
meson-0.53.2/test cases/common/137 c cpp and asm/retval-x86_64.S0000644000175000017500000000026113531533273024767 0ustar  jpakkanejpakkane00000000000000#include "symbol-underscore.h"

.text
.globl SYMBOL_NAME(get_retval)
# ifdef __linux__
.type get_retval, %function
#endif

SYMBOL_NAME(get_retval):
    xorl	%eax, %eax
    retq
meson-0.53.2/test cases/common/137 c cpp and asm/somelib.c0000644000175000017500000000004413531533273024207 0ustar  jpakkanejpakkane00000000000000int get_cval (void) {
  return 0;
}
meson-0.53.2/test cases/common/137 c cpp and asm/symbol-underscore.h0000644000175000017500000000017313531533273026241 0ustar  jpakkanejpakkane00000000000000#if defined(MESON_TEST__UNDERSCORE_SYMBOL)
# define SYMBOL_NAME(name) _##name
#else
# define SYMBOL_NAME(name) name
#endif
meson-0.53.2/test cases/common/138 compute int/0000755000175000017500000000000013625242360022370 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/138 compute int/config.h.in0000644000175000017500000000015613531533273024417 0ustar  jpakkanejpakkane00000000000000#define INTSIZE @INTSIZE@
#define FOOBAR_IN_CONFIG_H @FOOBAR@
#define MAXINT @MAXINT@
#define MININT @MININT@
meson-0.53.2/test cases/common/138 compute int/foobar.h0000644000175000017500000000014513531533273024013 0ustar  jpakkanejpakkane00000000000000#ifndef __FOOBAR_H__
#define __FOOBAR_H__

#define FOOBAR_IN_FOOBAR_H    10

#endif /*__FOOBAR_H__*/
meson-0.53.2/test cases/common/138 compute int/meson.build0000644000175000017500000000320713605171516024536 0ustar  jpakkanejpakkane00000000000000project('compute int', 'c', 'cpp')

inc = include_directories('.')

# Test with C
cc = meson.get_compiler('c')

intsize = cc.compute_int('sizeof(int)', low : 1, high : 16, guess : 4)
foobar = cc.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc)
maxint = cc.compute_int('INT_MAX', prefix: '#include ')
minint = cc.compute_int('INT_MIN', prefix: '#include ')

# Regression test for the special case -1 that used to fail when cross compiling
assert(cc.compute_int('-1') == -1, 'compute_int(-1) failed')

cd = configuration_data()
cd.set('INTSIZE', intsize)
cd.set('FOOBAR', foobar)
cd.set('CONFIG', 'config.h')
cd.set('MAXINT', maxint)
cd.set('MININT', minint)
configure_file(input : 'config.h.in', output : 'config.h', configuration : cd)
s = configure_file(input : 'prog.c.in', output : 'prog.c', configuration : cd)

e = executable('prog', s)
test('compute int test', e)

# Test with C++
cpp = meson.get_compiler('cpp')

intsize = cpp.compute_int('sizeof(int)')
foobar = cpp.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc)
maxint = cpp.compute_int('INT_MAX', prefix: '#include ')
minint = cpp.compute_int('INT_MIN', prefix: '#include ')

cdpp = configuration_data()
cdpp.set('INTSIZE', intsize)
cdpp.set('FOOBAR', foobar)
cdpp.set('CONFIG', 'config.hpp')
cdpp.set('MAXINT', maxint)
cdpp.set('MININT', minint)
configure_file(input : 'config.h.in', output : 'config.hpp', configuration : cdpp)
spp = configure_file(input : 'prog.c.in', output : 'prog.cc', configuration : cdpp)

epp = executable('progpp', spp)
test('compute int test c++', epp)
meson-0.53.2/test cases/common/138 compute int/prog.c.in0000644000175000017500000000140013571777336024123 0ustar  jpakkanejpakkane00000000000000#include "@CONFIG@"
#include 
#include 
#include 
#include "foobar.h"

int main(void) {
    if(INTSIZE != sizeof(int)) {
        fprintf(stderr, "Mismatch: computed int size %d, actual size %d.\n", INTSIZE, (int)sizeof(int));
        return 1;
    }
    if(FOOBAR_IN_CONFIG_H != FOOBAR_IN_FOOBAR_H) {
        fprintf(stderr, "Mismatch: computed int %d, should be %d.\n", FOOBAR_IN_CONFIG_H, FOOBAR_IN_FOOBAR_H);
        return 1;
    }
    if(MAXINT != INT_MAX) {
        fprintf(stderr, "Mismatch: computed max int %d, should be %d.\n", MAXINT, INT_MAX);
        return 1;
    }
    if(MININT != INT_MIN) {
        fprintf(stderr, "Mismatch: computed min int %d, should be %d.\n", MININT, INT_MIN);
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/139 custom target object output/0000755000175000017500000000000013625242360025473 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/139 custom target object output/meson.build0000644000175000017500000000045613605171512027640 0ustar  jpakkanejpakkane00000000000000project('custom target object output', 'c')

comp = find_program('obj_generator.py')

if host_machine.system() == 'windows'
  outputname = '@BASENAME@.obj'
else
  outputname = '@BASENAME@.o'
endif

cc = meson.get_compiler('c').cmd_array().get(-1)

subdir('objdir')
subdir('progdir')

test('objgen', e)
meson-0.53.2/test cases/common/139 custom target object output/obj_generator.py0000644000175000017500000000101313531533273030662 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# Mimic a binary that generates an object file (e.g. windres).

import sys, subprocess

if __name__ == '__main__':
    if len(sys.argv) != 4:
        print(sys.argv[0], 'compiler input_file output_file')
        sys.exit(1)
    compiler = sys.argv[1]
    ifile = sys.argv[2]
    ofile = sys.argv[3]
    if compiler.endswith('cl'):
        cmd = [compiler, '/nologo', '/MDd', '/Fo' + ofile, '/c', ifile]
    else:
        cmd = [compiler, '-c', ifile, '-o', ofile]
    sys.exit(subprocess.call(cmd))
meson-0.53.2/test cases/common/139 custom target object output/objdir/0000755000175000017500000000000013625242360026744 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/139 custom target object output/objdir/meson.build0000644000175000017500000000024113531533273031105 0ustar  jpakkanejpakkane00000000000000# Generate an object file manually.
object = custom_target('object',
  input : 'source.c',
  output : outputname,
  command : [comp, cc, '@INPUT@', '@OUTPUT@'])
meson-0.53.2/test cases/common/139 custom target object output/objdir/source.c0000644000175000017500000000005113571777336030424 0ustar  jpakkanejpakkane00000000000000int func1_in_obj(void) {
    return 0;
}
meson-0.53.2/test cases/common/139 custom target object output/progdir/0000755000175000017500000000000013625242360027141 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/139 custom target object output/progdir/meson.build0000644000175000017500000000005113531533273031301 0ustar  jpakkanejpakkane00000000000000e = executable('prog', 'prog.c', object)
meson-0.53.2/test cases/common/139 custom target object output/progdir/prog.c0000644000175000017500000000010713571777336030272 0ustar  jpakkanejpakkane00000000000000int func1_in_obj(void);

int main(void) {
    return func1_in_obj();
}
meson-0.53.2/test cases/common/14 configure file/0000755000175000017500000000000013625242361022734 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/14 configure file/basename.py0000644000175000017500000000101613366273150025061 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import argparse
import os

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('text', nargs='*', type=str)
    args = parser.parse_args()

    text = args.text if isinstance(args.text, list) else [args.text]

    output = ''
    for t in text:
        t = os.path.basename(t)

        if not output:
            output += t
        else:
            output += ' ' + t

    output += '\n'

    sys.stdout.write(output)

if __name__ == '__main__':
    sys.exit(main())
meson-0.53.2/test cases/common/14 configure file/check_file.py0000644000175000017500000000100613625260317025360 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys

if len(sys.argv) == 2:
    assert(os.path.exists(sys.argv[1]))
elif len(sys.argv) == 3:
    f1 = sys.argv[1]
    f2 = sys.argv[2]
    m1 = os.stat(f1).st_mtime_ns
    m2 = os.stat(f2).st_mtime_ns
    # Compare only os.stat()
    if m1 != m2:
        raise RuntimeError('mtime of {!r} () != mtime of {!r} ()'.format(f1, m1, f2, m2))
    import filecmp
    if not filecmp.cmp(f1, f2):
        raise RuntimeError('{!r} != {!r}'.format(f1, f2))
else:
    raise AssertionError
meson-0.53.2/test cases/common/14 configure file/check_inputs.py0000644000175000017500000000053013543771101025761 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
from pathlib import Path

files = [Path(f) for f in sys.argv[1:]]
names = [f.name for f in files]

assert names == ['check_inputs.txt', 'prog.c', 'prog.c', 'prog2.c', 'prog4.c', 'prog5.c']
for f in files[1:]:
    assert f.exists()

with files[0].open('w') as ofile:
    ofile.write("#define ZERO_RESULT 0\n")
meson-0.53.2/test cases/common/14 configure file/config.h0000644000175000017500000000014313366273150024352 0ustar  jpakkanejpakkane00000000000000#error "This file should not be included. Build dir must become before source dir in search order"
meson-0.53.2/test cases/common/14 configure file/config.h.in0000644000175000017500000000017013366273150024757 0ustar  jpakkanejpakkane00000000000000#define MESSAGE "@var@"
#define OTHER "@other@" "@second@" "@empty@"

#mesondefine BE_TRUE
#mesondefine SHOULD_BE_UNDEF
meson-0.53.2/test cases/common/14 configure file/config4a.h.in0000644000175000017500000000005013366273150025201 0ustar  jpakkanejpakkane00000000000000/* Dummy file */
#define RESULTA @ZERO@
meson-0.53.2/test cases/common/14 configure file/config4b.h.in0000644000175000017500000000005013366273150025202 0ustar  jpakkanejpakkane00000000000000/* Dummy file */
#define RESULTB @ZERO@
meson-0.53.2/test cases/common/14 configure file/config5.h.in0000644000175000017500000000003013366273150025037 0ustar  jpakkanejpakkane00000000000000#define MESSAGE "@var@"
meson-0.53.2/test cases/common/14 configure file/config6.h.in0000644000175000017500000000106213366273150025046 0ustar  jpakkanejpakkane00000000000000/* No escape */
#define MESSAGE1 "@var1@"

/* Single escape means no replace */
#define MESSAGE2 "\@var1@"

/* Replace pairs of escapes before '@' or '\@' with escape characters
 * (note we have to double number of pairs due to C string escaping)
 */
#define MESSAGE3 "\\\\@var1@"

/* Pairs of escapes and then single escape to avoid replace */
#define MESSAGE4 "\\\\\@var1@"

/* Check escaped variable does not overlap following variable */
#define MESSAGE5 "\@var1@var2@"

/* Check escape character outside variables */
#define MESSAGE6 "\\ @ \@ \\\\@ \\\\\@"
meson-0.53.2/test cases/common/14 configure file/config7.h.in0000644000175000017500000000073013366273150025050 0ustar  jpakkanejpakkane00000000000000/* No escape */
#define MESSAGE1 "${var1}"

/* Single escape means no replace */
#define MESSAGE2 "\${var1}"

/* Replace pairs of escapes before '@' or '\@' with escape characters
 * (note we have to double number of pairs due to C string escaping)
 */
#define MESSAGE3 "\\\\${var1}"

/* Pairs of escapes and then single escape to avoid replace */
#define MESSAGE4 "\\\\\${var1}"

/* Check escape character outside variables */
#define MESSAGE5 "\\ ${ \${ \\\\${ \\\\\${"
meson-0.53.2/test cases/common/14 configure file/config8.h.in0000644000175000017500000000012013366273150025042 0ustar  jpakkanejpakkane00000000000000#define MESSAGE "@var@"

#define "non isolatin1 char Ä fails decode with utf-8"
meson-0.53.2/test cases/common/14 configure file/depfile0000644000175000017500000000000013546416757024273 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/14 configure file/differentafterbasename1.in0000644000175000017500000000000013403223104030003 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/14 configure file/differentafterbasename2.in0000644000175000017500000000000013403223104030004 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/14 configure file/dummy.dat0000644000175000017500000000000013366273150024551 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/14 configure file/dumpprog.c0000644000175000017500000000240013571777347024752 0ustar  jpakkanejpakkane00000000000000#define SHOULD_BE_UNDEFINED 1

#include"config3.h"
#include
#include

#ifdef SHOULD_BE_UNDEFINED
#error Token did not get undefined.
#endif

#ifndef SHOULD_BE_DEFINED
#error Token did not get defined
#endif

#define stringify(s) str(s)
#define str(s) #s

int main(void) {
#if !(SHOULD_BE_UNQUOTED_STRING == string)
        printf("String token (unquoted) defined wrong.\n");
        return 1;
#endif
    if(strcmp(SHOULD_BE_STRING, "string") != 0) {
        printf("String token defined wrong.\n");
        return 1;
    }
    if(strcmp(SHOULD_BE_STRING2, "A \"B\" C") != 0) {
        printf("String token 2 defined wrong.\n");
        return 1;
    }
    if(strcmp(SHOULD_BE_STRING3, "A \"\" C") != 0) {
        printf("String token 3 defined wrong.\n");
        return 1;
    }
    if(strcmp(SHOULD_BE_STRING4, "A \" C") != 0) {
        printf("String token 4 defined wrong.\n");
        return 1;
    }
    if(SHOULD_BE_ONE != 1) {
        printf("One defined incorrectly.\n");
        return 1;
    }
    if(SHOULD_BE_ZERO != 0) {
        printf("Zero defined incorrectly.\n");
        return 1;
    }
    if(strcmp(SHOULD_BE_QUOTED_ONE, "1") != 0) {
        printf("Quoted number defined incorrectly.\n");
        return 1;
    }
    SHOULD_BE_RETURN 0;
}
meson-0.53.2/test cases/common/14 configure file/file_contains.py0000644000175000017500000000072313366273150026127 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import argparse

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('file', nargs=1, type=str)
    parser.add_argument('text', nargs=1, type=str)
    args = parser.parse_args()

    text = args.text[0]

    with open(args.file[0], 'r', encoding='utf-8') as f:
        for line in f:
            if line.strip() == text:
                return 0

    return 1

if __name__ == '__main__':
    sys.exit(main())
meson-0.53.2/test cases/common/14 configure file/generator-deps.py0000755000175000017500000000072213546416757026247 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os
from pathlib import Path

if len(sys.argv) != 3:
    print("Wrong amount of parameters.")

build_dir = Path(os.environ['MESON_BUILD_ROOT'])
subdir = Path(os.environ['MESON_SUBDIR'])
outputf = Path(sys.argv[1])

with outputf.open('w') as ofile:
    ofile.write("#define ZERO_RESULT 0\n")

depf = Path(sys.argv[2])
if not depf.exists():
    with depf.open('w') as ofile:
        ofile.write("{}: depfile\n".format(outputf.name))
meson-0.53.2/test cases/common/14 configure file/generator-without-input-file.py0000755000175000017500000000050613366273150031055 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os
from pathlib import Path

if len(sys.argv) != 2:
    print("Wrong amount of parameters.")

build_dir = Path(os.environ['MESON_BUILD_ROOT'])
subdir = Path(os.environ['MESON_SUBDIR'])
outputf = Path(sys.argv[1])

with outputf.open('w') as ofile:
    ofile.write("#define ZERO_RESULT 0\n")
meson-0.53.2/test cases/common/14 configure file/generator.py0000755000175000017500000000057213366273150025305 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os
from pathlib import Path

if len(sys.argv) != 3:
    print("Wrong amount of parameters.")

build_dir = Path(os.environ['MESON_BUILD_ROOT'])
subdir = Path(os.environ['MESON_SUBDIR'])
inputf = Path(sys.argv[1])
outputf = Path(sys.argv[2])

assert(inputf.exists())

with outputf.open('w') as ofile:
    ofile.write("#define ZERO_RESULT 0\n")
meson-0.53.2/test cases/common/14 configure file/installed_files.txt0000644000175000017500000000016513366273150026642 0ustar  jpakkanejpakkane00000000000000usr/share/appdir/config2.h
usr/share/appdir/config2b.h
usr/share/appdireh/config2-1.h
usr/share/appdirok/config2-2.h
meson-0.53.2/test cases/common/14 configure file/invalid-utf8.bin.in0000644000175000017500000000001213366273150026340 0ustar  jpakkanejpakkane00000000000000Šwmeson-0.53.2/test cases/common/14 configure file/meson.build0000644000175000017500000002202113605171320025065 0ustar  jpakkanejpakkane00000000000000project('configure file test', 'c')

conf = configuration_data()

conf.set('var', 'mystring')
conf.set('other', 'string 2')
conf.set('second', ' bonus')
conf.set('BE_TRUE', true)

assert(conf.get('var') == 'mystring', 'Get function is not working.')
assert(conf.get('var', 'default') == 'mystring', 'Get function is not working.')
assert(conf.get('notthere', 'default') == 'default', 'Default value getting is not working.')

cfile = configure_file(input : 'config.h.in',
  output : 'config.h',
  configuration : conf)

e = executable('inctest', 'prog.c',
# Note that you should NOT do this. Don't add generated headers here
# This tests that we do the right thing even if people add in conf files
# to their sources.
  cfile)
test('inctest', e)

# Test if we can also pass files() as input
configure_file(input : files('config.h.in'),
  output : 'config2.h',
  configuration : conf)

# Now generate a header file with an external script.
genprog = import('python3').find_python()
scriptfile = '@0@/generator.py'.format(meson.current_source_dir())
ifile = '@0@/dummy.dat'.format(meson.current_source_dir())
ofile = '@0@/config2.h'.format(meson.current_build_dir())

check_file = find_program('check_file.py')
# Configure in source root with command and absolute paths
outf = configure_file(input : 'dummy.dat',
  output : 'config2.h',
  command : [genprog, scriptfile,  ifile, ofile],
  install_dir : 'share/appdir')
ret = run_command(check_file, outf)
if ret.returncode() != 0
  error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
endif

# Same again as before, but an input file should not be required in
# this case where we use a command/script to generate the output file.
genscript2b = '@0@/generator-without-input-file.py'.format(meson.current_source_dir())
ofile2b = '@0@/config2b.h'.format(meson.current_build_dir())
outf = configure_file(
  output : 'config2b.h',
  command : [genprog, genscript2b, ofile2b],
  install_dir : 'share/appdir')
ret = run_command(check_file, outf)
if ret.returncode() != 0
  error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
endif

genscript2deps = '@0@/generator-deps.py'.format(meson.current_source_dir())
ofile2deps = '@0@/config2deps.h'.format(meson.current_build_dir())
outf = configure_file(
  output : 'config2deps.h',
  depfile : 'depfile.d',
  command : [genprog, genscript2deps, ofile2deps, '@DEPFILE@'])
ret = run_command(check_file, outf)
if ret.returncode() != 0
  error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
endif

found_script = find_program('generator.py')
# More configure_file tests in here
subdir('subdir')

test('inctest2', executable('prog2', 'prog2.c'))

# Generate a conf file without an input file.

dump = configuration_data()
dump.set_quoted('SHOULD_BE_STRING', 'string', description : 'A string')
dump.set_quoted('SHOULD_BE_STRING2', 'A "B" C')
dump.set_quoted('SHOULD_BE_STRING3', 'A "" C')
dump.set_quoted('SHOULD_BE_STRING4', 'A " C')
dump.set('SHOULD_BE_RETURN', 'return')
dump.set('SHOULD_BE_DEFINED', true)
dump.set('SHOULD_BE_UNDEFINED', false)
dump.set('SHOULD_BE_ONE', 1)
dump.set('SHOULD_BE_ZERO', 0, description : 'Absolutely zero')
dump.set('SHOULD_BE_QUOTED_ONE', '"1"')

dump.set_quoted('INTEGER_AS_STRING', '12')
if dump.get_unquoted('INTEGER_AS_STRING').to_int() == 12
  dump.set('SHOULD_BE_UNQUOTED_STRING', dump.get_unquoted('SHOULD_BE_STRING'))
endif

configure_file(output : 'config3.h',
  configuration : dump)

test('Configless.', executable('dumpprog', 'dumpprog.c'))


# Config file generation in a loop with @BASENAME@ substitution
dump = configuration_data()
dump.set('ZERO', 0)
config_templates = files(['config4a.h.in', 'config4b.h.in'])
foreach config_template : config_templates
  configure_file(input : config_template, output : '@BASENAME@', configuration : dump)
endforeach

test('Substituted', executable('prog4', 'prog4.c'))

# Test `capture` keyword

basename_py = find_program('basename.py')
file_contains_py = find_program('file_contains.py')
test_string = 'hello world'
test_input_file = join_paths(meson.current_build_dir(), test_string)
run_command(find_program('touch.py'), test_input_file)
configs = [
    # no input
    configure_file(command: [ basename_py, test_string ], capture: true, output: 'capture test 1'),
    # with input
    configure_file(input: test_input_file, command: [ basename_py, '@INPUT@' ], capture: true, output: 'capture test 2'),
]
foreach c : configs
    test('@0@'.format(c), file_contains_py, args: [ c, test_string ])
endforeach

# Test variable is substituted only once
conf5 = configuration_data()
conf5.set('var', '@var2@')
conf5.set('var2', 'error')
configure_file(
  input : 'config5.h.in',
  output : '@BASENAME@',
  configuration : conf5)
test('test5', executable('prog5', 'prog5.c'))

# Test escaping
conf6 = configuration_data()
conf6.set('var1', 'foo')
conf6.set('var2', 'bar')
configure_file(
  input : 'config6.h.in',
  output : '@BASENAME@',
  configuration : conf6)
test('test6', executable('prog6', 'prog6.c'))

# test empty install dir string
cfile = configure_file(input : 'config.h.in',
  output : 'do_not_get_installed.h',
  install_dir : '',
  configuration : conf)

# test install_dir : false (deprecated)
cfile = configure_file(input : 'config.h.in',
  output : 'do_not_get_installed_please.h',
  install_dir : false,
  configuration : conf)

# test intsall_dir with install: false
cfile = configure_file(input : 'config.h.in',
  output : 'do_not_get_installed_in_install_dir.h',
  install : false,
  install_dir : 'share/appdir',
  configuration : conf)

# Test escaping with cmake format
conf7 = configuration_data()
conf7.set('var1', 'foo')
conf7.set('var2', 'bar')
configure_file(
  input : 'config7.h.in',
  output : '@BASENAME@',
  format : 'cmake',
  configuration : conf7)
test('test7', executable('prog7', 'prog7.c'))

# Test copying of an empty configuration data object
inf = 'invalid-utf8.bin.in'
outf = configure_file(input : inf,
  output : 'invalid-utf8.bin',
  copy: true)
ret = run_command(check_file, inf, outf)
if ret.returncode() != 0
  error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
endif

# Test copy of a binary file
outf = configure_file(input : inf,
  output : 'somebinary.bin',
  copy : true)
ret = run_command(check_file, inf, outf)
if ret.returncode() != 0
  error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
endif

# Test non isolatin1 encoded input file which fails to decode with utf-8
conf8 = configuration_data()
conf8.set('var', 'foo')
configure_file(
  input : 'config8.h.in',
  output : '@BASENAME@',
  encoding : 'koi8-r',
  configuration : conf8)

# Test that passing an empty configuration_data() object to a file with
# #mesondefine substitutions does not print the warning.
configure_file(
  input: 'nosubst-nocopy1.txt.in',
  output: 'nosubst-nocopy1.txt',
  configuration : configuration_data())

# test that passing an empty configuration_data() object to a file with
# @foo@ substitutions does not print the warning.
configure_file(
  input: 'nosubst-nocopy2.txt.in',
  output: 'nosubst-nocopy2.txt',
  configuration : configuration_data())

# test that passing a configured file object to test() works, and that passing
# an empty configuration_data() object to a file that leads to no substitutions
# prints a warning (see unit tests)
test_file = configure_file(
  input: 'test.py.in',
  output: 'test.py',
  configuration: configuration_data())

# Test that overwriting an existing file creates a warning.
configure_file(
  input: 'test.py.in',
  output: 'double_output.txt',
  configuration: conf)
configure_file(
  input: 'test.py.in',
  output: 'double_output.txt',
  configuration: conf)

# Test that the same file name in a different subdir will not create a warning
configure_file(
  input: 'test.py.in',
  output: 'no_write_conflict.txt',
  configuration: conf)

# Test that @BASENAME@ is substituted before checking and does not create a warning.
configure_file(
  input: 'differentafterbasename1.in',
  output: '@BASENAME@',
  configuration: conf
)
configure_file(
  input: 'differentafterbasename2.in',
  output: '@BASENAME@',
  configuration: conf
)

# Test that @BASENAME@ is substituted before checking and does create a warning on conflict.
configure_file(
  input: 'sameafterbasename.in',
  output: '@BASENAME@',
  configuration: conf
)
configure_file(
  input: 'sameafterbasename.in2',
  output: '@BASENAME@',
  configuration: conf
)

test('configure-file', test_file)

cdata = configuration_data()
cdata.set('invalid_value', ['array'])

# Dictionaries

cdata = configuration_data({
  'A_STRING' : '"foo"',
  'A_INT' : 42,
  'A_DEFINED' : true,
  'A_UNDEFINED' : false,
})

configure_file(output : 'config9a.h',
  configuration : cdata,
)

configure_file(output : 'config9b.h',
  configuration : {
    'B_STRING' : '"foo"',
    'B_INT' : 42,
    'B_DEFINED' : true,
    'B_UNDEFINED' : false,
  }
)

test('test9', executable('prog9', 'prog9.c'))

check_inputs = find_program('check_inputs.py')
configure_file(output : 'check_inputs.txt',
  input : ['prog.c', files('prog2.c', 'prog4.c')],
  command : [check_inputs, '@OUTPUT@', '@INPUT0@', '@INPUT@', files('prog5.c')]
)
meson-0.53.2/test cases/common/14 configure file/nosubst-nocopy1.txt.in0000644000175000017500000000002513366273150027164 0ustar  jpakkanejpakkane00000000000000#mesondefine FOO_BAR
meson-0.53.2/test cases/common/14 configure file/nosubst-nocopy2.txt.in0000644000175000017500000000001213366273150027161 0ustar  jpakkanejpakkane00000000000000@FOO_BAR@
meson-0.53.2/test cases/common/14 configure file/prog.c0000644000175000017500000000043313571777336024066 0ustar  jpakkanejpakkane00000000000000#include 
/* config.h must not be in quotes:
 * https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html
 */
#include 

#ifdef SHOULD_BE_UNDEF
#error "FAIL!"
#endif

int main(void) {
#ifndef BE_TRUE
    return 1;
#else
    return strcmp(MESSAGE, "mystring");
#endif
}
meson-0.53.2/test cases/common/14 configure file/prog2.c0000644000175000017500000000010013571777336024137 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    return ZERO_RESULT;
}
meson-0.53.2/test cases/common/14 configure file/prog4.c0000644000175000017500000000013613571777336024152 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
    return RESULTA + RESULTB;
}
meson-0.53.2/test cases/common/14 configure file/prog5.c0000644000175000017500000000014313571777336024151 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
    return strcmp(MESSAGE, "@var2@");
}
meson-0.53.2/test cases/common/14 configure file/prog6.c0000644000175000017500000000045213571777336024155 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
    return strcmp(MESSAGE1, "foo")
        || strcmp(MESSAGE2, "@var1@")
        || strcmp(MESSAGE3, "\\foo")
        || strcmp(MESSAGE4, "\\@var1@")
        || strcmp(MESSAGE5, "@var1bar")
        || strcmp(MESSAGE6, "\\ @ @ \\@ \\@");
}
meson-0.53.2/test cases/common/14 configure file/prog7.c0000644000175000017500000000041013571777336024150 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
    return strcmp(MESSAGE1, "foo")
        || strcmp(MESSAGE2, "${var1}")
        || strcmp(MESSAGE3, "\\foo")
        || strcmp(MESSAGE4, "\\${var1}")
        || strcmp(MESSAGE5, "\\ ${ ${ \\${ \\${");
}
meson-0.53.2/test cases/common/14 configure file/prog9.c0000644000175000017500000000056313571777336024163 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include 

#if defined(A_UNDEFINED) || defined(B_UNDEFINED)
#error "Should not be defined"
#endif

#if !defined(A_DEFINED) || !defined(B_DEFINED)
#error "Should be defined"
#endif

int main(void) {
    return strcmp(A_STRING, "foo")
        || strcmp(B_STRING, "foo")
        || A_INT != 42
        || B_INT != 42;
}
meson-0.53.2/test cases/common/14 configure file/sameafterbasename.in0000644000175000017500000000000013403223104026701 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/14 configure file/sameafterbasename.in20000644000175000017500000000000013403223104026763 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/14 configure file/subdir/0000755000175000017500000000000013625242361024224 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/14 configure file/subdir/meson.build0000644000175000017500000000246213366273150026374 0ustar  jpakkanejpakkane00000000000000# Configure in subdir with absolute paths for input and relative for output
configure_file(input : '../dummy.dat',
  output : 'config2-1.h',
  command : [genprog, scriptfile,  ifile, 'config2-1.h'],
  install_dir : 'share/appdireh')
run_command(check_file, join_paths(meson.current_build_dir(), 'config2-1.h'))

# Configure in subdir with files() for input and relative for output
configure_file(input : '../dummy.dat',
  output : 'config2-2.h',
  command : [genprog, scriptfile, files('../dummy.dat'), 'config2-2.h'],
  install_dir : 'share/appdirok')
run_command(check_file, join_paths(meson.current_build_dir(), 'config2-2.h'))

# Configure in subdir with string templates for input and output
configure_file(input : '../dummy.dat',
  output : 'config2-3.h',
  command : [found_script,  '@INPUT@', '@OUTPUT@'])
run_command(check_file, join_paths(meson.current_build_dir(), 'config2-3.h'))

# Test that overwriting an existing file creates a warning.
configure_file(
  input: '../test.py.in',
  output: 'double_output2.txt',
  configuration: conf
)
configure_file(
  input: '../test.py.in',
  output: 'double_output2.txt',
  configuration: conf
)

# Test that the same file name in a different subdir will not create a warning
configure_file(
  input: '../test.py.in',
  output: 'no_write_conflict.txt',
  configuration: conf
)
meson-0.53.2/test cases/common/14 configure file/test.py.in0000644000175000017500000000005713366273150024676 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
sys.exit(0)
meson-0.53.2/test cases/common/14 configure file/touch.py0000644000175000017500000000050613366273150024433 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import argparse
from pathlib import Path

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('files', nargs='*', type=str)
    args = parser.parse_args()

    for filepath in args.files:
        Path(filepath).touch()

if __name__ == '__main__':
    sys.exit(main())
meson-0.53.2/test cases/common/140 empty build file/0000755000175000017500000000000013625242361023251 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/140 empty build file/meson.build0000644000175000017500000000010413605171514025405 0ustar  jpakkanejpakkane00000000000000project('subdir with empty meson.build test', 'c')
subdir('subdir')
meson-0.53.2/test cases/common/140 empty build file/subdir/0000755000175000017500000000000013625242361024541 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/140 empty build file/subdir/meson.build0000644000175000017500000000000013531533273026672 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/0000755000175000017500000000000013625242361022654 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/exe/0000755000175000017500000000000013625242361023435 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/exe/meson.build0000644000175000017500000000011113531533273025571 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', '../prog.c', link_with : sh_func2_linked_func1)
meson-0.53.2/test cases/common/141 whole archive/exe2/0000755000175000017500000000000013625242361023517 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/exe2/meson.build0000644000175000017500000000011013531533273025652 0ustar  jpakkanejpakkane00000000000000exe2 = executable('prog2', '../prog.c', link_with : sh_only_link_whole)
meson-0.53.2/test cases/common/141 whole archive/exe3/0000755000175000017500000000000013625242361023520 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/exe3/meson.build0000644000175000017500000000011013531533273025653 0ustar  jpakkanejpakkane00000000000000exe3 = executable('prog3', '../prog.c', link_with : sh_func2_dep_func1)
meson-0.53.2/test cases/common/141 whole archive/exe4/0000755000175000017500000000000013625242361023521 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/exe4/meson.build0000644000175000017500000000011513531533273025661 0ustar  jpakkanejpakkane00000000000000exe4 = executable('prog4', '../prog.c', link_with : sh_func2_transdep_func1)
meson-0.53.2/test cases/common/141 whole archive/func1.c0000644000175000017500000000011413571777336024047 0ustar  jpakkanejpakkane00000000000000#define BUILDING_DLL

#include

int func1(void) {
    return 42;
}
meson-0.53.2/test cases/common/141 whole archive/func2.c0000644000175000017500000000011413571777336024050 0ustar  jpakkanejpakkane00000000000000#define BUILDING_DLL

#include

int func2(void) {
    return 42;
}
meson-0.53.2/test cases/common/141 whole archive/meson.build0000644000175000017500000000317313605171517025024 0ustar  jpakkanejpakkane00000000000000project('whole archive', 'c')

add_project_arguments('-I' + meson.source_root(), language : 'c')

cc = meson.get_compiler('c')

if cc.get_id() == 'msvc'
  if cc.version().version_compare('<19')
    error('MESON_SKIP_TEST link_whole only works on VS2015 or newer.')
  endif
endif

# Test 1: link_whole keeps all symbols
# Make static func1
subdir('st_func1')
# Make shared func2 linking whole func1 archive
subdir('sh_func2_linked_func1')
# Link exe with shared library only
subdir('exe')
# Test that both func1 and func2 are accessible from shared library
test('prog', exe)

# Test 2: link_whole can be used instead of source list, see #2180
# Make static func2
subdir('st_func2')
# Link both func1 and func2 into same shared library
# which does not have any sources other than 2 static libraries
subdir('sh_only_link_whole')
# Link exe2 with shared library only
subdir('exe2')
# Test that both func1 and func2 are accessible from shared library
test('prog2', exe2)

# Test 3: link_whole can be used in declare_dependency()
func1_dep = declare_dependency(link_whole : [st_func1])
# Use dependency to link func1 into shared library
subdir('sh_func2_dep_func1')
# Link exe3 with shared library
subdir('exe3')
# Test that both func1 and func2 are accessible from shared library
test('prog3', exe3)

# Test 4: link_whole can be used in transitive declare_dependency()
func1_trans_dep = declare_dependency(dependencies : func1_dep)
# Use transitive dependency to link func1 into shared library
subdir('sh_func2_transdep_func1')
# Link exe4 with shared library
subdir('exe4')
# Test that both func1 and func2 are accessible from shared library
test('prog4', exe4)
meson-0.53.2/test cases/common/141 whole archive/mylib.h0000644000175000017500000000074313571777336024164 0ustar  jpakkanejpakkane00000000000000#pragma once

/* Both funcs here for simplicity. */

#if defined _WIN32 || defined __CYGWIN__
#if defined BUILDING_DLL
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #define DLL_PUBLIC __declspec(dllimport)
#endif
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC func1(void);
int DLL_PUBLIC func2(void);
meson-0.53.2/test cases/common/141 whole archive/prog.c0000644000175000017500000000010413571777336024001 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    return func1() - func2();
}
meson-0.53.2/test cases/common/141 whole archive/sh_func2_dep_func1/0000755000175000017500000000000013625242361026307 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/sh_func2_dep_func1/meson.build0000644000175000017500000000045513531533273030456 0ustar  jpakkanejpakkane00000000000000# Same as sh_func2_linked_func1, # func2.c does not depend on func1(),
# so without link_whole compiler would throw func1() away.
# This is the same version of the test with a dependency object instead.
sh_func2_dep_func1 = shared_library('sh_func2_dep_func1', '../func2.c', dependencies : func1_dep)
meson-0.53.2/test cases/common/141 whole archive/sh_func2_linked_func1/0000755000175000017500000000000013625242361027005 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/sh_func2_linked_func1/meson.build0000644000175000017500000000031713531533273031151 0ustar  jpakkanejpakkane00000000000000# Nothing in func2.c uses func1, so the linker would throw it
# away and thus linking the exe would fail.
sh_func2_linked_func1 = shared_library('sh_func2_linked_func1', '../func2.c', link_whole : st_func1)
meson-0.53.2/test cases/common/141 whole archive/sh_func2_transdep_func1/0000755000175000017500000000000013625242361027357 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/sh_func2_transdep_func1/meson.build0000644000175000017500000000043613531533273031525 0ustar  jpakkanejpakkane00000000000000# Same as sh_func2_dep_func1 but dependency is transitive.
# func2.c does not have any reference to func1() so without link_whole compiler
# should throw func1() out.
sh_func2_transdep_func1 = shared_library(
  'sh_func2_transdep_func1', '../func2.c',
  dependencies : func1_trans_dep)
meson-0.53.2/test cases/common/141 whole archive/sh_only_link_whole/0000755000175000017500000000000013625242361026542 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/sh_only_link_whole/meson.build0000644000175000017500000000013513531533273030704 0ustar  jpakkanejpakkane00000000000000sh_only_link_whole = shared_library('sh_only_link_whole', link_whole : [st_func1, st_func2])
meson-0.53.2/test cases/common/141 whole archive/st_func1/0000755000175000017500000000000013625242361024376 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/st_func1/meson.build0000644000175000017500000000006413531533273026541 0ustar  jpakkanejpakkane00000000000000st_func1 = static_library('st_func1', '../func1.c')
meson-0.53.2/test cases/common/141 whole archive/st_func2/0000755000175000017500000000000013625242361024377 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/141 whole archive/st_func2/meson.build0000644000175000017500000000006413531533273026542 0ustar  jpakkanejpakkane00000000000000st_func2 = static_library('st_func2', '../func2.c')
meson-0.53.2/test cases/common/142 C and CPP link/0000755000175000017500000000000013625242361022363 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/142 C and CPP link/dummy.c0000644000175000017500000000000013531533273023651 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/142 C and CPP link/foo.c0000644000175000017500000000121413531533273023311 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "foo.h"

int forty_two(void) {
    return 42;
}
meson-0.53.2/test cases/common/142 C and CPP link/foo.cpp0000644000175000017500000000171313531533273023655 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include 

const int cnums[] = {0, 61};

/* Provided by foobar.c */
extern "C" int get_number_index (void);

template
std::vector makeVector(const T (&data)[N])
{
    return std::vector(data, data+N);
}

namespace {
    std::vector numbers = makeVector(cnums);
}

extern "C" int six_one(void) {
    return numbers[get_number_index ()];
}
meson-0.53.2/test cases/common/142 C and CPP link/foo.h0000644000175000017500000000115113531533273023316 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

int forty_two(void);
meson-0.53.2/test cases/common/142 C and CPP link/foo.hpp0000644000175000017500000000125413531533273023662 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef __cplusplus
extern "C" {
#endif

int six_one(void);

#ifdef __cplusplus
}
#endif
meson-0.53.2/test cases/common/142 C and CPP link/foobar.c0000644000175000017500000000141513531533273024001 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "foo.h"
#include "foo.hpp"
#include "foobar.h"

int get_number_index (void) {
  return 1;
}

void mynumbers(int nums[]) {
    nums[0] = forty_two();
    nums[1] = six_one();
}
meson-0.53.2/test cases/common/142 C and CPP link/foobar.h0000644000175000017500000000116013531533273024003 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

void mynumbers(int nums[]);
meson-0.53.2/test cases/common/142 C and CPP link/meson.build0000644000175000017500000000671613605171521024534 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017 Dylan Baker
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

project('C and C++ static link test', ['c', 'cpp'])

# Verify that adding link arguments works.
add_global_link_arguments('', language : 'c')
add_project_link_arguments('', language : 'c')

libc = static_library('cfoo', ['foo.c', 'foo.h'])

# Test that linking C libs to external static C++ libs uses the C++ linker
# Since we can't depend on the test system to provide this, we create one
# ourselves at configure time and then 'find' it with cxx.find_library().
cxx = meson.get_compiler('cpp')

if cxx.get_argument_syntax() == 'msvc'
  if cxx.get_id() == 'msvc'
    static_linker = find_program('lib')
  elif cxx.get_id() == 'clang-cl'
    static_linker = find_program('llvm-lib')
  elif cxx.get_id() == 'intel-cl'
    static_linker = find_program('xilib')
  else
     error('unable to determine static linker to use with this compiler')
  endif
  compile_cmd = ['/c', '@INPUT@', '/Fo@OUTPUT@']
  stlib_cmd = [static_linker, '/OUT:@OUTPUT@', '@INPUT@']
else
 picflag = []
 if not ['darwin', 'windows'].contains(host_machine.system())
    picflag = ['-fPIC']
  endif
  compile_cmd = ['-c', picflag, '@INPUT@', '-o', '@OUTPUT@']
  stlib_cmd = ['ar', 'csr', '@OUTPUT@', '@INPUT@']
endif

foo_cpp_o = configure_file(
  input : 'foo.cpp',
  output : 'foo.cpp.o',
  command : cxx.cmd_array() + compile_cmd)

configure_file(
  input : foo_cpp_o,
  output : 'libstcppext.a',
  command : stlib_cmd)

libstcppext = cxx.find_library('stcppext', dirs : meson.current_build_dir())
lib_type_name = libstcppext.type_name()
assert(lib_type_name == 'library', 'type name is ' + lib_type_name)

libfooext = shared_library(
  'fooext',
  ['foobar.c', 'foobar.h'],
  link_with : libc,
  dependencies : libstcppext,
)

# Test that linking C libs to internal static C++ libs uses the C++ linker
libcpp = static_library('cppfoo', ['foo.cpp', 'foo.hpp'])

libfoo = shared_library(
  'foo',
  ['foobar.c', 'foobar.h'],
  link_with : [libc, libcpp],
)

# Test that link_whole is also honored
#
# VS2010 lacks the /WHOLEARCHIVE option that later versions of MSVC support, so
# don't run this tests on that backend.
if not (cxx.get_id() == 'msvc' and cxx.version().version_compare('<19'))
  libfoowhole = shared_library(
    'foowhole',
    ['foobar.c', 'foobar.h'],
    link_whole : [libc, libcpp],
  )
endif

# Test sublinking (linking C and C++, then linking that to C)
libfoo_static = static_library(
  'foo_static',
  ['foobar.c', 'foobar.h'],
  link_with : [libc, libcpp],
)

libsub = shared_library(
  'sub',
  ['sub.c', 'sub.h'],
  link_with : libfoo_static,
)

if not (cxx.get_id() == 'msvc' and cxx.version().version_compare('<19'))
  libsubwhole = shared_library(
    'subwhole',
    ['sub.c', 'sub.h'],
    link_whole : libfoo_static,
  )
endif

# Test that it really is recursive
libsub_static = static_library(
  'sub_static',
  ['sub.c', 'sub.h'],
  link_with : libfoo_static,
)

libsubsub = shared_library(
  'subsub',
  ['dummy.c'],
  link_with : libsub_static,
)
meson-0.53.2/test cases/common/142 C and CPP link/sub.c0000644000175000017500000000121313531533273023316 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "sub.h"

float a_half(void) {
    return .5;
}
meson-0.53.2/test cases/common/142 C and CPP link/sub.h0000644000175000017500000000115013531533273023323 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

float a_half(void);
meson-0.53.2/test cases/common/143 mesonintrospect from scripts/0000755000175000017500000000000013625242361025766 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/143 mesonintrospect from scripts/check_env.py0000644000175000017500000000107013531533273030264 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys
import shlex

do_print = False

if len(sys.argv) > 1:
    do_print = bool(sys.argv[1])

if 'MESONINTROSPECT' not in os.environ:
    raise RuntimeError('MESONINTROSPECT not found')

mesonintrospect = os.environ['MESONINTROSPECT']

introspect_arr = shlex.split(mesonintrospect)

# print(mesonintrospect)
# print(introspect_arr)

some_executable = introspect_arr[0]

if not os.path.isfile(some_executable):
    raise RuntimeError('{!r} does not exist'.format(mesonintrospect))

if do_print:
    print(some_executable, end='')
meson-0.53.2/test cases/common/143 mesonintrospect from scripts/check_introspection.py0000644000175000017500000000071013531533273032374 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import shlex
import subprocess


if 'MESONINTROSPECT' not in os.environ:
    raise RuntimeError('MESONINTROSPECT not found')
if 'MESON_BUILD_ROOT' not in os.environ:
    raise RuntimeError('MESON_BUILD_ROOT not found')

mesonintrospect = os.environ['MESONINTROSPECT']
introspect_arr = shlex.split(mesonintrospect)

buildroot = os.environ['MESON_BUILD_ROOT']

subprocess.check_output([*introspect_arr, '--all', buildroot])
meson-0.53.2/test cases/common/143 mesonintrospect from scripts/meson.build0000644000175000017500000000053013605171521030123 0ustar  jpakkanejpakkane00000000000000project('mesonintrospect from scripts', 'c')

python = import('python3').find_python()

ret = run_command(python, ['check_env.py', '1'])
if ret.returncode() == 0
  find_program(ret.stdout())
else
  message(ret.stdout())
  message(ret.stderr())
endif

meson.add_postconf_script('check_introspection.py')
meson.add_install_script('check_env.py')
meson-0.53.2/test cases/common/144 custom target multiple outputs/0000755000175000017500000000000013625242361026240 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/144 custom target multiple outputs/generator.py0000755000175000017500000000050213531533273030601 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os

if len(sys.argv) != 3:
    print(sys.argv[0], '', '')

name = sys.argv[1]
odir = sys.argv[2]

with open(os.path.join(odir, name + '.h'), 'w') as f:
    f.write('int func();\n')
with open(os.path.join(odir, name + '.sh'), 'w') as f:
    f.write('#!/bin/bash')
meson-0.53.2/test cases/common/144 custom target multiple outputs/installed_files.txt0000644000175000017500000000014013531533273032136 0ustar  jpakkanejpakkane00000000000000usr/include/diff.h
usr/include/first.h
usr/bin/diff.sh
usr/bin/second.sh
opt/same.h
opt/same.sh
meson-0.53.2/test cases/common/144 custom target multiple outputs/meson.build0000644000175000017500000000165613605171523030411 0ustar  jpakkanejpakkane00000000000000project('multiple outputs install', 'c')

gen = find_program('generator.py')

custom_target('different-install-dirs',
  output : ['diff.h', 'diff.sh'],
  command : [gen, 'diff', '@OUTDIR@'],
  install : true,
  install_dir : [join_paths(get_option('prefix'), get_option('includedir')),
                 join_paths(get_option('prefix'), get_option('bindir'))])

custom_target('same-install-dir',
  output : ['same.h', 'same.sh'],
  command : [gen, 'same', '@OUTDIR@'],
  install : true,
  install_dir : '/opt')

custom_target('only-install-first',
  output : ['first.h', 'first.sh'],
  command : [gen, 'first', '@OUTDIR@'],
  install : true,
  install_dir : [join_paths(get_option('prefix'), get_option('includedir')), false])

custom_target('only-install-second',
  output : ['second.h', 'second.sh'],
  command : [gen, 'second', '@OUTDIR@'],
  install : true,
  install_dir : [false, join_paths(get_option('prefix'), get_option('bindir'))])
meson-0.53.2/test cases/common/145 special characters/0000755000175000017500000000000013625242361023660 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/145 special characters/check_quoting.py0000644000175000017500000000106213531533273027055 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

expected = {
    'newline': '\n',
    'dollar': '$',
    'colon': ':',
    'space': ' ',
    'multi1': '  ::$$  ::$$',
    'multi2': '  ::$$\n\n  \n\n::$$',
}

output = None

for arg in sys.argv[1:]:
    try:
        name, value = arg.split('=', 1)
    except ValueError:
        output = arg
        continue

    if expected[name] != value:
        raise RuntimeError('{!r} is {!r} but should be {!r}'.format(name, value, expected[name]))

if output is not None:
    with open(output, 'w') as f:
        f.write('Success!')
meson-0.53.2/test cases/common/145 special characters/installed_files.txt0000644000175000017500000000004313531533273027560 0ustar  jpakkanejpakkane00000000000000usr/share/result
usr/share/result2
meson-0.53.2/test cases/common/145 special characters/meson.build0000644000175000017500000000135213605171524026023 0ustar  jpakkanejpakkane00000000000000project('ninja special characters' ,'c')

python = import('python3').find_python()

# Without newlines, this should appear directly in build.ninja.
gen = custom_target('gen',
  command : [
    python,
    files('check_quoting.py'),
    'dollar=$',
    'colon=:',
    'space= ',
    '''multi1=  ::$$  ::$$''',
    '@OUTPUT@'],
  output : 'result',
  install : true,
  install_dir : get_option('datadir'))

# With newlines, this should go through the exe wrapper.
gen2 = custom_target('gen2',
  command : [
    python,
    files('check_quoting.py'),
    '''newline=
''',
    'dollar=$',
    'colon=:',
    'space= ',
    '''multi2=  ::$$

  

::$$''',
    '@OUTPUT@'],
  output : 'result2',
  install : true,
  install_dir : get_option('datadir'))
meson-0.53.2/test cases/common/146 nested links/0000755000175000017500000000000013625242361022524 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/146 nested links/meson.build0000644000175000017500000000030013605171525024660 0ustar  jpakkanejpakkane00000000000000project('test', 'c')

libxserver_dri3 = []
libxserver = [ libxserver_dri3 ]

executable('Xephyr', 'xephyr.c', link_with: [ libxserver ])

executable('Zephyr', 'xephyr.c', link_args: [[], []])
meson-0.53.2/test cases/common/146 nested links/xephyr.c0000644000175000017500000000004113571777336024221 0ustar  jpakkanejpakkane00000000000000int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/147 list of file sources/0000755000175000017500000000000013625242361024046 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/147 list of file sources/foo0000644000175000017500000000001213531533273024546 0ustar  jpakkanejpakkane00000000000000some text
meson-0.53.2/test cases/common/147 list of file sources/gen.py0000644000175000017500000000025613531533273025175 0ustar  jpakkanejpakkane00000000000000import shutil
import sys

if __name__ == '__main__':
    if len(sys.argv) != 3:
        raise Exception('Requires exactly 2 args')
    shutil.copy2(sys.argv[1], sys.argv[2])
meson-0.53.2/test cases/common/147 list of file sources/meson.build0000644000175000017500000000042213605171525026207 0ustar  jpakkanejpakkane00000000000000project('test', 'c')

mod_py = import('python3')
python = mod_py.find_python()

test_target = custom_target(
  'test_target',
  input : [files('gen.py'), files('foo')],
  output : 'bar',
  command : [python, '@INPUT0@', '@INPUT1@', '@OUTPUT@'],
  build_by_default : true,
)
meson-0.53.2/test cases/common/148 link depends custom target/0000755000175000017500000000000013625242361025245 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/148 link depends custom target/foo.c0000644000175000017500000000034613571777336026216 0ustar  jpakkanejpakkane00000000000000#include 

int main(void) {
  const char *fn = DEPFILE;
  FILE *f = fopen(fn, "r");
  if (!f) {
    printf("could not open %s", fn);
    return 1;
  }
  else {
    printf("successfully opened %s", fn);
  }

  return 0;
}
meson-0.53.2/test cases/common/148 link depends custom target/make_file.py0000755000175000017500000000016313531533273027537 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3
import sys

with open(sys.argv[1], 'w') as f:
    print('# this file does nothing', file=f)
meson-0.53.2/test cases/common/148 link depends custom target/meson.build0000644000175000017500000000105713605171526027414 0ustar  jpakkanejpakkane00000000000000project('link_depends_custom_target', 'c')

if meson.backend().startswith('vs')
  # FIXME: Broken on the VS backends
  error('MESON_SKIP_TEST see https://github.com/mesonbuild/meson/issues/1799')
endif

cmd = find_program('make_file.py')

dep_file = custom_target('gen_dep',
        command: [cmd, '@OUTPUT@'],
        output: 'dep_file')

exe = executable('foo', 'foo.c',
        link_depends: dep_file,
        c_args: ['-DDEPFILE="' + dep_file.full_path()+ '"'])

# check that dep_file exists, which means that link_depends target ran
test('runtest', exe)
meson-0.53.2/test cases/common/149 recursive linking/0000755000175000017500000000000013625242361023567 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/3rdorderdeps/0000755000175000017500000000000013625242361026167 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/3rdorderdeps/lib.c.in0000644000175000017500000000024313531533273027506 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"

int get_@DEPENDENCY@dep_value (void);

SYMBOL_EXPORT
int get_@LIBTYPE@@DEPENDENCY@dep_value (void) {
  return get_@DEPENDENCY@dep_value ();
}
meson-0.53.2/test cases/common/149 recursive linking/3rdorderdeps/main.c.in0000644000175000017500000000046213571777336027705 0ustar  jpakkanejpakkane00000000000000#include 

#include "../lib.h"

SYMBOL_IMPORT int get_@LIBTYPE@@DEPENDENCY@dep_value (void);

int main(void) {
  int val;

  val = get_@LIBTYPE@@DEPENDENCY@dep_value ();
  if (val != @VALUE@) {
    printf("@LIBTYPE@@DEPENDENCY@ was %i instead of @VALUE@\n", val);
    return -1;
  }
  return 0;
}
meson-0.53.2/test cases/common/149 recursive linking/3rdorderdeps/meson.build0000644000175000017500000000306713531533273030340 0ustar  jpakkanejpakkane00000000000000dep3_libs = []

# Permutate all combinations of shared and static libraries up to three levels
# executable -> shared -> static -> shared (etc)
foreach dep2 : ['sh', 'st']
  foreach dep1 : ['sh', 'st']
    foreach libtype : ['sh', 'st']
      name = libtype + dep1 + dep2
      if dep2 == 'sh'
        libret = 1
      elif dep2 == 'st'
        libret = 2
      else
        error('Unknown dep2 "@0@"'.format(dep2))
      endif

      if libtype == 'sh'
        target = 'shared_library'
        build_args = []
      elif libtype == 'st'
        target = 'static_library'
        build_args = ['-DMESON_STATIC_BUILD']
      else
        error('Unknown libtype "@0@"'.format(libtype))
      endif

      cdata = configuration_data()
      cdata.set('DEPENDENCY', dep1 + dep2)
      cdata.set('LIBTYPE', libtype)
      cdata.set('VALUE', libret)

      lib_c = configure_file(input : 'lib.c.in',
                             output : name + '-lib.c',
                             configuration : cdata)
      dep = get_variable(dep1 + dep2 + 'dep')
      dep3_lib = build_target(name, lib_c, link_with : dep,
                              target_type : target,
                              c_args : build_args)
      dep3_libs += [dep3_lib]

      main_c = configure_file(input : 'main.c.in',
                              output : name + '-main.c',
                              configuration : cdata)
      dep3_bin = executable(name, main_c, link_with : dep3_lib,
                            c_args : build_args)
      test(name + 'test', dep3_bin)
    endforeach
  endforeach
endforeach
meson-0.53.2/test cases/common/149 recursive linking/circular/0000755000175000017500000000000013625242361025373 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/circular/lib1.c0000644000175000017500000000017413531533273026371 0ustar  jpakkanejpakkane00000000000000int get_st2_prop (void);
int get_st3_prop (void);

int get_st1_value (void) {
  return get_st2_prop () + get_st3_prop ();
}
meson-0.53.2/test cases/common/149 recursive linking/circular/lib2.c0000644000175000017500000000017413531533273026372 0ustar  jpakkanejpakkane00000000000000int get_st1_prop (void);
int get_st3_prop (void);

int get_st2_value (void) {
  return get_st1_prop () + get_st3_prop ();
}
meson-0.53.2/test cases/common/149 recursive linking/circular/lib3.c0000644000175000017500000000017413531533273026373 0ustar  jpakkanejpakkane00000000000000int get_st1_prop (void);
int get_st2_prop (void);

int get_st3_value (void) {
  return get_st1_prop () + get_st2_prop ();
}
meson-0.53.2/test cases/common/149 recursive linking/circular/main.c0000644000175000017500000000077413571777336026512 0ustar  jpakkanejpakkane00000000000000#include 

#include "../lib.h"

int get_st1_value (void);
int get_st2_value (void);
int get_st3_value (void);

int main(void) {
  int val;

  val = get_st1_value ();
  if (val != 5) {
    printf("st1 value was %i instead of 5\n", val);
    return -1;
  }
  val = get_st2_value ();
  if (val != 4) {
    printf("st2 value was %i instead of 4\n", val);
    return -2;
  }
  val = get_st3_value ();
  if (val != 3) {
    printf("st3 value was %i instead of 3\n", val);
    return -3;
  }
  return 0;
}
meson-0.53.2/test cases/common/149 recursive linking/circular/meson.build0000644000175000017500000000034413531533273027537 0ustar  jpakkanejpakkane00000000000000st1 = static_library('st1', 'lib1.c', 'prop1.c')
st2 = static_library('st2', 'lib2.c', 'prop2.c')
st3 = static_library('st3', 'lib3.c', 'prop3.c')

test('circular', executable('circular', 'main.c', link_with : [st1, st2, st3]))
meson-0.53.2/test cases/common/149 recursive linking/circular/prop1.c0000644000175000017500000000005013531533273026574 0ustar  jpakkanejpakkane00000000000000int get_st1_prop (void) {
  return 1;
}
meson-0.53.2/test cases/common/149 recursive linking/circular/prop2.c0000644000175000017500000000005013531533273026575 0ustar  jpakkanejpakkane00000000000000int get_st2_prop (void) {
  return 2;
}
meson-0.53.2/test cases/common/149 recursive linking/circular/prop3.c0000644000175000017500000000005013531533273026576 0ustar  jpakkanejpakkane00000000000000int get_st3_prop (void) {
  return 3;
}
meson-0.53.2/test cases/common/149 recursive linking/edge-cases/0000755000175000017500000000000013625242361025567 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/edge-cases/libsto.c0000644000175000017500000000017713531533273027235 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"

int get_builto_value (void);

SYMBOL_EXPORT
int get_stodep_value (void) {
  return get_builto_value ();
}
meson-0.53.2/test cases/common/149 recursive linking/edge-cases/meson.build0000644000175000017500000000104713531533273027734 0ustar  jpakkanejpakkane00000000000000# Test https://github.com/mesonbuild/meson/issues/2096
# Note that removing 'shnodep' from link_with: makes the error go away because
# then it is added after the static library is added to the link command.
test('shared-static', executable('shstexe', 'shstmain.c', link_with : [shnodep, stshdep]))

# Static library that needs a symbol defined in an object file. This already
# works, but good to add a test case early.
stodep = static_library('stodep', 'libsto.c')
test('stodep', executable('stodep', 'stomain.c', 'stobuilt.c', link_with : stodep))
meson-0.53.2/test cases/common/149 recursive linking/edge-cases/shstmain.c0000644000175000017500000000035213571777336027600 0ustar  jpakkanejpakkane00000000000000#include 

#include "../lib.h"

int get_stshdep_value (void);

int main(void) {
  int val;

  val = get_stshdep_value ();
  if (val != 1) {
    printf("st1 value was %i instead of 1\n", val);
    return -1;
  }
  return 0;
}
meson-0.53.2/test cases/common/149 recursive linking/edge-cases/stobuilt.c0000644000175000017500000000012013531533273027572 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"


SYMBOL_EXPORT
int get_builto_value (void) {
  return 1;
}
meson-0.53.2/test cases/common/149 recursive linking/edge-cases/stomain.c0000644000175000017500000000035013571777336027422 0ustar  jpakkanejpakkane00000000000000#include 

#include "../lib.h"

int get_stodep_value (void);

int main(void) {
  int val;

  val = get_stodep_value ();
  if (val != 1) {
    printf("st1 value was %i instead of 1\n", val);
    return -1;
  }
  return 0;
}
meson-0.53.2/test cases/common/149 recursive linking/lib.h0000644000175000017500000000067613531533273024520 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32
  #ifdef MESON_STATIC_BUILD
   #define SYMBOL_EXPORT
   #define SYMBOL_IMPORT
  #else
   #define SYMBOL_IMPORT __declspec(dllimport)
   #define SYMBOL_EXPORT __declspec(dllexport)
  #endif
#else
  #define SYMBOL_IMPORT
  #if defined __GNUC__
    #define SYMBOL_EXPORT __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define SYMBOL_EXPORT
  #endif
#endif
meson-0.53.2/test cases/common/149 recursive linking/main.c0000644000175000017500000000175613571777336024707 0ustar  jpakkanejpakkane00000000000000#include 

#include "lib.h"

int get_stnodep_value (void);
int get_stshdep_value (void);
int get_ststdep_value (void);
SYMBOL_IMPORT int get_shnodep_value (void);
SYMBOL_IMPORT int get_shshdep_value (void);
SYMBOL_IMPORT int get_shstdep_value (void);

int main(void) {
  int val;

  val = get_shnodep_value ();
  if (val != 1) {
    printf("shnodep was %i instead of 1\n", val);
    return -1;
  }
  val = get_stnodep_value ();
  if (val != 2) {
    printf("stnodep was %i instead of 2\n", val);
    return -2;
  }
  val = get_shshdep_value ();
  if (val != 1) {
    printf("shshdep was %i instead of 1\n", val);
    return -3;
  }
  val = get_shstdep_value ();
  if (val != 2) {
    printf("shstdep was %i instead of 2\n", val);
    return -4;
  }
  val = get_stshdep_value ();
  if (val != 1) {
    printf("shstdep was %i instead of 1\n", val);
    return -5;
  }
  val = get_ststdep_value ();
  if (val != 2) {
    printf("ststdep was %i instead of 2\n", val);
    return -6;
  }
  return 0;
}
meson-0.53.2/test cases/common/149 recursive linking/meson.build0000644000175000017500000000152613605171534025736 0ustar  jpakkanejpakkane00000000000000project('recursive dependencies', 'c')

# Test that you can link a shared executable to:
# - A shared library with no other deps
subdir('shnodep')
# - A static library with no other deps
subdir('stnodep')
# - A shared library with a shared library dep
subdir('shshdep')
# - A shared library with a static library dep
subdir('shstdep')
# - A static library with a shared library dep
subdir('stshdep')
# - A static library with a static library dep
subdir('ststdep')

test('alldeps',
     executable('alldeps', 'main.c',
                link_with : [shshdep, shstdep, ststdep, stshdep]))

# More combinations of static and shared libraries
subdir('3rdorderdeps')

# Circular dependencies between static libraries
# This requires the use of --start/end-group with GNU ld
subdir('circular')

# Various edge cases that have been reported
subdir('edge-cases')
meson-0.53.2/test cases/common/149 recursive linking/shnodep/0000755000175000017500000000000013625242361025227 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/shnodep/lib.c0000644000175000017500000000012013531533273026133 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"

SYMBOL_EXPORT
int get_shnodep_value (void) {
  return 1;
}
meson-0.53.2/test cases/common/149 recursive linking/shnodep/meson.build0000644000175000017500000000007713531533273027376 0ustar  jpakkanejpakkane00000000000000shnodep = shared_library('shnodep', 'lib.c', version: '0.0.0')
meson-0.53.2/test cases/common/149 recursive linking/shshdep/0000755000175000017500000000000013625242361025225 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/shshdep/lib.c0000644000175000017500000000020213531533273026132 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"

int get_shnodep_value (void);

SYMBOL_EXPORT
int get_shshdep_value (void) {
  return get_shnodep_value ();
}
meson-0.53.2/test cases/common/149 recursive linking/shshdep/meson.build0000644000175000017500000000010213531533273027361 0ustar  jpakkanejpakkane00000000000000shshdep = shared_library('shshdep', 'lib.c', link_with : shnodep)
meson-0.53.2/test cases/common/149 recursive linking/shstdep/0000755000175000017500000000000013625242361025241 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/shstdep/lib.c0000644000175000017500000000020213531533273026146 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"

int get_stnodep_value (void);

SYMBOL_EXPORT
int get_shstdep_value (void) {
  return get_stnodep_value ();
}
meson-0.53.2/test cases/common/149 recursive linking/shstdep/meson.build0000644000175000017500000000010213531533273027375 0ustar  jpakkanejpakkane00000000000000shstdep = shared_library('shstdep', 'lib.c', link_with : stnodep)
meson-0.53.2/test cases/common/149 recursive linking/stnodep/0000755000175000017500000000000013625242361025243 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/stnodep/lib.c0000644000175000017500000000012013531533273026147 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"

SYMBOL_EXPORT
int get_stnodep_value (void) {
  return 2;
}
meson-0.53.2/test cases/common/149 recursive linking/stnodep/meson.build0000644000175000017500000000014713531533273027410 0ustar  jpakkanejpakkane00000000000000stnodep = static_library('stnodep', 'lib.c',
                         c_args : '-DMESON_STATIC_BUILD')
meson-0.53.2/test cases/common/149 recursive linking/stshdep/0000755000175000017500000000000013625242361025241 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/stshdep/lib.c0000644000175000017500000000020213531533273026146 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"

int get_shnodep_value (void);

SYMBOL_EXPORT
int get_stshdep_value (void) {
  return get_shnodep_value ();
}
meson-0.53.2/test cases/common/149 recursive linking/stshdep/meson.build0000644000175000017500000000017413531533273027406 0ustar  jpakkanejpakkane00000000000000stshdep = static_library('stshdep', 'lib.c', link_with : shnodep,
                         c_args : '-DMESON_STATIC_BUILD')
meson-0.53.2/test cases/common/149 recursive linking/ststdep/0000755000175000017500000000000013625242361025255 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/149 recursive linking/ststdep/lib.c0000644000175000017500000000020213531533273026162 0ustar  jpakkanejpakkane00000000000000#include "../lib.h"

int get_stnodep_value (void);

SYMBOL_EXPORT
int get_ststdep_value (void) {
  return get_stnodep_value ();
}
meson-0.53.2/test cases/common/149 recursive linking/ststdep/meson.build0000644000175000017500000000017413531533273027422 0ustar  jpakkanejpakkane00000000000000ststdep = static_library('ststdep', 'lib.c', link_with : stnodep,
                         c_args : '-DMESON_STATIC_BUILD')
meson-0.53.2/test cases/common/15 if/0000755000175000017500000000000013625242361020452 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/15 if/meson.build0000644000175000017500000000136613605171315022620 0ustar  jpakkanejpakkane00000000000000project('if test', 'c')

var1 = true
set_variable('var2', false)

if var1
  exe = executable('prog', 'prog.c')
endif

if var2
  exe = executable('breakbreakbreak', 'crashing.c')
endif

test('iftest', exe)

if not is_variable('var1')
  error('Is_variable fail.')
endif

if is_variable('nonexisting')
  error('Is_variable fail 2.')
endif

if not get_variable('var1', false)
  error('Get_variable fail.')
endif

if get_variable('nonexisting', false)
  error('Get_variable fail.')
endif


# Now test elseif

t = true
f = false

if true
  message('Ok.')
elif true
  error('Error')
else
  error('Error')
endif

if f
  error('Error.')
elif t
  message('Ok')
else
  error('Error')
endif

if f
  error('Error.')
elif false
  error('Error')
else
  message('Ok')
endif
meson-0.53.2/test cases/common/15 if/prog.c0000644000175000017500000000003513571777336021602 0ustar  jpakkanejpakkane00000000000000int main(void) { return 0; }
meson-0.53.2/test cases/common/150 library at root/0000755000175000017500000000000013625242362023132 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/150 library at root/lib.c0000644000175000017500000000014613531533273024045 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
__declspec(dllexport)
#endif
int fn(void) {
    return -1;
}
meson-0.53.2/test cases/common/150 library at root/main/0000755000175000017500000000000013625242362024056 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/150 library at root/main/main.c0000644000175000017500000000007613571777336025167 0ustar  jpakkanejpakkane00000000000000extern int fn(void);

int main(void) {
    return 1 + fn();
}
meson-0.53.2/test cases/common/150 library at root/main/meson.build0000644000175000017500000000011513531533273026215 0ustar  jpakkanejpakkane00000000000000exe = executable('main', 'main.c', link_with : lib)
test('stuff works', exe)
meson-0.53.2/test cases/common/150 library at root/meson.build0000644000175000017500000000011513605171532025267 0ustar  jpakkanejpakkane00000000000000project('lib@root', 'c')
lib = shared_library('lib', 'lib.c')
subdir('main')
meson-0.53.2/test cases/common/151 simd/0000755000175000017500000000000013625242362021072 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/151 simd/fallback.c0000644000175000017500000000017513531533273023000 0ustar  jpakkanejpakkane00000000000000#include

void increment_fallback(float arr[4]) {
    int i;
    for(i=0; i<4; i++) {
        arr[i]++;
    }
}
meson-0.53.2/test cases/common/151 simd/include/0000755000175000017500000000000013625242362022515 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/151 simd/include/simdheader.h0000644000175000017500000000004513531533273024772 0ustar  jpakkanejpakkane00000000000000#pragma once

#define I_CAN_HAZ_SIMD
meson-0.53.2/test cases/common/151 simd/meson.build0000644000175000017500000000223113605171535023233 0ustar  jpakkanejpakkane00000000000000project('simd', 'c')

simd = import('unstable-simd')

cc = meson.get_compiler('c')

cdata = configuration_data()

if not meson.is_cross_build() and host_machine.cpu_family() == 'arm' and cc.get_id() == 'clang'
  message('Adding -march=armv7 because assuming that this build happens on Raspbian.')
  message('Its Clang seems to be misconfigured and does not support NEON by default.')
  add_project_arguments('-march=armv7', language : 'c')
endif

if cc.get_id() == 'msvc' and cc.version().version_compare('<17')
  error('MESON_SKIP_TEST VS2010 produces broken binaries on x86.')
endif

# FIXME add [a, b] = function()
rval = simd.check('mysimds',
  mmx : 'simd_mmx.c',
  sse : 'simd_sse.c',
  sse2 : 'simd_sse2.c',
  sse3 : 'simd_sse3.c',
  ssse3 : 'simd_ssse3.c',
  sse41 : 'simd_sse41.c',
  sse42 : 'simd_sse42.c',
  avx : 'simd_avx.c',
  avx2 : 'simd_avx2.c',
  neon : 'simd_neon.c',
  compiler : cc,
  include_directories : include_directories('include'))

simdlibs = rval[0]
cdata.merge_from(rval[1])

configure_file(output : 'simdconfig.h',
  configuration : cdata)

p = executable('simdtest', 'simdchecker.c', 'fallback.c',
  link_with : simdlibs)

test('simdtest', p)

meson-0.53.2/test cases/common/151 simd/simd_avx.c0000644000175000017500000000176613571777336023100 0ustar  jpakkanejpakkane00000000000000#include

#ifndef I_CAN_HAZ_SIMD
#error The correct internal header was not used
#endif

#include
#include
#include

#ifdef _MSC_VER
#include
int avx_available(void) {
  return 1;
}
#else
#include
#include

#ifdef __APPLE__
/*
 * Apple ships a broken __builtin_cpu_supports and
 * some machines in the CI farm seem to be too
 * old to have AVX so just always return 0 here.
 */
int avx_available(void) { return 0; }
#else

int avx_available(void) {
    return __builtin_cpu_supports("avx");
}
#endif
#endif

void increment_avx(float arr[4]) {
    double darr[4];
    darr[0] = arr[0];
    darr[1] = arr[1];
    darr[2] = arr[2];
    darr[3] = arr[3];
    __m256d val = _mm256_loadu_pd(darr);
    __m256d one = _mm256_set1_pd(1.0);
    __m256d result = _mm256_add_pd(val, one);
    _mm256_storeu_pd(darr, result);
    arr[0] = (float)darr[0];
    arr[1] = (float)darr[1];
    arr[2] = (float)darr[2];
    arr[3] = (float)darr[3];
}
meson-0.53.2/test cases/common/151 simd/simd_avx2.c0000644000175000017500000000160713571777336023154 0ustar  jpakkanejpakkane00000000000000#include
#include
#include

/*
 * FIXME add proper runtime detection for VS.
 */

#ifdef _MSC_VER
#include
int avx2_available(void) {
    return 0;
}
#else
#include
#include

#if defined(__APPLE__)
int avx2_available(void) { return 0; }
#else
int avx2_available(void) {
    return __builtin_cpu_supports("avx2");
}
#endif
#endif

void increment_avx2(float arr[4]) {
    double darr[4];
    darr[0] = arr[0];
    darr[1] = arr[1];
    darr[2] = arr[2];
    darr[3] = arr[3];
    __m256d val = _mm256_loadu_pd(darr);
    __m256d one = _mm256_set1_pd(1.0);
    __m256d result = _mm256_add_pd(val, one);
    _mm256_storeu_pd(darr, result);
    one = _mm256_permute4x64_pd(one, 66); /* A no-op, just here to use AVX2. */
    arr[0] = (float)darr[0];
    arr[1] = (float)darr[1];
    arr[2] = (float)darr[2];
    arr[3] = (float)darr[3];
}
meson-0.53.2/test cases/common/151 simd/simd_mmx.c0000644000175000017500000000266413571777336023101 0ustar  jpakkanejpakkane00000000000000#include
#include

#include

#ifdef _MSC_VER
#include
int mmx_available(void) {
  return 1;
}
/* Contrary to MSDN documentation, MMX intrinsics
 * just plain don't work.
 */
void increment_mmx(float arr[4]) {
  arr[0]++;
  arr[1]++;
  arr[2]++;
  arr[3]++;
}
#elif defined(__MINGW32__)
int mmx_available(void) {
  return 1;
}
/* MinGW does not seem to ship with MMX or it is broken.
 */
void increment_mmx(float arr[4]) {
  arr[0]++;
  arr[1]++;
  arr[2]++;
  arr[3]++;
}
#else
#include
#include

#if defined(__APPLE__)
int mmx_available(void) { return 1; }
#else
int mmx_available(void) {
    return __builtin_cpu_supports("mmx");
}
#endif
void increment_mmx(float arr[4]) {
    /* Super ugly but we know that values in arr are always small
     * enough to fit in int16;
     */
    int i;
    __m64 packed = _mm_set_pi16(arr[3], arr[2], arr[1], arr[0]);
    __m64 incr = _mm_set1_pi16(1);
    __m64 result = _mm_add_pi16(packed, incr);
    /* Should be
     * int64_t unpacker = _m_to_int64(result);
     * but it does not exist on 32 bit platforms for some reason.
     */
    int64_t unpacker = (int64_t)(result);
    _mm_empty();
    for(i=0; i<4; i++) {
      /* This fails on GCC 8 when optimizations are enabled.
       * Disable it. Patches welcome to fix this.
      arr[i] = (float)(unpacker & ((1<<16)-1));
        unpacker >>= 16;
      */
      arr[i] += 1.0f;
    }
}

#endif
meson-0.53.2/test cases/common/151 simd/simd_neon.c0000644000175000017500000000067513571777336023237 0ustar  jpakkanejpakkane00000000000000#include
#include

#include
#include

int neon_available(void) {
    return 1; /* Incorrect, but I don't know how to check this properly. */
}

void increment_neon(float arr[4]) {
    float32x2_t a1, a2, one;
    a1 = vld1_f32(arr);
    a2 = vld1_f32(&arr[2]);
    one = vdup_n_f32(1.0);
    a1 = vadd_f32(a1, one);
    a2 = vadd_f32(a2, one);
    vst1_f32(arr, a1);
    vst1_f32(&arr[2], a2);
}
meson-0.53.2/test cases/common/151 simd/simd_sse.c0000644000175000017500000000101113571777336023053 0ustar  jpakkanejpakkane00000000000000#include
#include

#ifdef _MSC_VER
#include
int sse_available(void) {
  return 1;
}
#else

#include
#include
#include

#if defined(__APPLE__)
int sse_available(void) { return 1; }
#else
int sse_available(void) {
    return __builtin_cpu_supports("sse");
}
#endif
#endif

void increment_sse(float arr[4]) {
    __m128 val = _mm_load_ps(arr);
    __m128 one = _mm_set_ps1(1.0);
    __m128 result = _mm_add_ps(val, one);
    _mm_storeu_ps(arr, result);
}
meson-0.53.2/test cases/common/151 simd/simd_sse2.c0000644000175000017500000000142713571777336023150 0ustar  jpakkanejpakkane00000000000000#include
#include
#include

#ifdef _MSC_VER
int sse2_available(void) {
  return 1;
}

#else
#include
#include

#if defined(__APPLE__)
int sse2_available(void) { return 1; }
#else
int sse2_available(void) {
    return __builtin_cpu_supports("sse2");
}
#endif
#endif

void increment_sse2(float arr[4]) {
    ALIGN_16 double darr[4];
    __m128d val1 = _mm_set_pd(arr[0], arr[1]);
    __m128d val2 = _mm_set_pd(arr[2], arr[3]);
    __m128d one = _mm_set_pd(1.0, 1.0);
    __m128d result = _mm_add_pd(val1, one);
    _mm_store_pd(darr, result);
    result = _mm_add_pd(val2, one);
    _mm_store_pd(&darr[2], result);
    arr[0] = (float)darr[1];
    arr[1] = (float)darr[0];
    arr[2] = (float)darr[3];
    arr[3] = (float)darr[2];
}

meson-0.53.2/test cases/common/151 simd/simd_sse3.c0000644000175000017500000000162313571777336023147 0ustar  jpakkanejpakkane00000000000000#include
#include

#ifdef _MSC_VER
#include
int sse3_available(void) {
    return 1;
}
#else

#include
#include
#include

#if defined(__APPLE__)
int sse3_available(void) { return 1; }
#else
int sse3_available(void) {
    return __builtin_cpu_supports("sse3");
}
#endif
#endif

void increment_sse3(float arr[4]) {
    ALIGN_16 double darr[4];
    __m128d val1 = _mm_set_pd(arr[0], arr[1]);
    __m128d val2 = _mm_set_pd(arr[2], arr[3]);
    __m128d one = _mm_set_pd(1.0, 1.0);
    __m128d result = _mm_add_pd(val1, one);
    _mm_store_pd(darr, result);
    result = _mm_add_pd(val2, one);
    _mm_store_pd(&darr[2], result);
    result = _mm_hadd_pd(val1, val2); /* This does nothing. Only here so we use an SSE3 instruction. */
    arr[0] = (float)darr[1];
    arr[1] = (float)darr[0];
    arr[2] = (float)darr[3];
    arr[3] = (float)darr[2];
}
meson-0.53.2/test cases/common/151 simd/simd_sse41.c0000644000175000017500000000160713571777336023233 0ustar  jpakkanejpakkane00000000000000#include
#include

#include

#ifdef _MSC_VER
#include

int sse41_available(void) {
  return 1;
}

#else
#include
#include

#if defined(__APPLE__)
int sse41_available(void) { return 1; }
#else
int sse41_available(void) {
    return __builtin_cpu_supports("sse4.1");
}
#endif
#endif

void increment_sse41(float arr[4]) {
    ALIGN_16 double darr[4];
    __m128d val1 = _mm_set_pd(arr[0], arr[1]);
    __m128d val2 = _mm_set_pd(arr[2], arr[3]);
    __m128d one = _mm_set_pd(1.0, 1.0);
    __m128d result = _mm_add_pd(val1, one);
    result = _mm_ceil_pd(result); /* A no-op, only here to use a SSE4.1 intrinsic. */
    _mm_store_pd(darr, result);
    result = _mm_add_pd(val2, one);
    _mm_store_pd(&darr[2], result);
    arr[0] = (float)darr[1];
    arr[1] = (float)darr[0];
    arr[2] = (float)darr[3];
    arr[3] = (float)darr[2];
}
meson-0.53.2/test cases/common/151 simd/simd_sse42.c0000644000175000017500000000160213571777336023227 0ustar  jpakkanejpakkane00000000000000#include
#include
#include

#ifdef _MSC_VER
#include

int sse42_available(void) {
  return 1;
}

#else

#include
#include

#ifdef __APPLE__
int sse42_available(void) {
    return 1;
}
#else
int sse42_available(void) {
    return __builtin_cpu_supports("sse4.2");
}
#endif

#endif

void increment_sse42(float arr[4]) {
    ALIGN_16 double darr[4];
    __m128d val1 = _mm_set_pd(arr[0], arr[1]);
    __m128d val2 = _mm_set_pd(arr[2], arr[3]);
    __m128d one = _mm_set_pd(1.0, 1.0);
    __m128d result = _mm_add_pd(val1, one);
    _mm_store_pd(darr, result);
    result = _mm_add_pd(val2, one);
    _mm_store_pd(&darr[2], result);
    _mm_crc32_u32(42, 99); /* A no-op, only here to use an SSE4.2 instruction. */
    arr[0] = (float)darr[1];
    arr[1] = (float)darr[0];
    arr[2] = (float)darr[3];
    arr[3] = (float)darr[2];
}
meson-0.53.2/test cases/common/151 simd/simd_ssse3.c0000644000175000017500000000211213571777336023324 0ustar  jpakkanejpakkane00000000000000#include
#include

#include
#include

#ifdef _MSC_VER
#include

int ssse3_available(void) {
  return 1;
}

#else

#include
#include

int ssse3_available(void) {
#ifdef __APPLE__
    return 1;
#elif defined(__clang__)
    /* https://github.com/numpy/numpy/issues/8130 */
    return __builtin_cpu_supports("sse4.1");
#else
    return __builtin_cpu_supports("ssse3");
#endif
}

#endif

void increment_ssse3(float arr[4]) {
    ALIGN_16 double darr[4];
    __m128d val1 = _mm_set_pd(arr[0], arr[1]);
    __m128d val2 = _mm_set_pd(arr[2], arr[3]);
    __m128d one = _mm_set_pd(1.0, 1.0);
    __m128d result = _mm_add_pd(val1, one);
    __m128i tmp1, tmp2;
    tmp1 = tmp2 = _mm_set1_epi16(0);
    _mm_store_pd(darr, result);
    result = _mm_add_pd(val2, one);
    _mm_store_pd(&darr[2], result);
    tmp1 = _mm_hadd_epi32(tmp1, tmp2); /* This does nothing. Only here so we use an SSSE3 instruction. */
    arr[0] = (float)darr[1];
    arr[1] = (float)darr[0];
    arr[2] = (float)darr[3];
    arr[3] = (float)darr[2];
}
meson-0.53.2/test cases/common/151 simd/simdchecker.c0000644000175000017500000000663413571777336023546 0ustar  jpakkanejpakkane00000000000000#include
#include
#include

typedef void (*simd_func)(float*);

int check_simd_implementation(float *four,
        const float *four_initial,
        const char *simd_type,
        const float *expected,
        simd_func fptr,
        const int blocksize) {
    int rv = 0;
    memcpy(four, four_initial, blocksize*sizeof(float));
    printf("Using %s.\n", simd_type);
    fptr(four);
    for(int i=0; i

#ifdef _MSC_VER
#define ALIGN_16 __declspec(align(16))
#else
#include
#define ALIGN_16 alignas(16)
#endif


/* Yes, I do know that arr[4] decays into a pointer
 * as a function argument. Don't do this in real code
 * but for this test it is ok.
 */

void increment_fallback(float arr[4]);

#if HAVE_MMX
int mmx_available(void);
void increment_mmx(float arr[4]);
#endif

#if HAVE_SSE
int sse_available(void);
void increment_sse(float arr[4]);
#endif

#if HAVE_SSE2
int sse2_available(void);
void increment_sse2(float arr[4]);
#endif

#if HAVE_SSE3
int sse3_available(void);
void increment_sse3(float arr[4]);
#endif

#if HAVE_SSSE3
int ssse3_available(void);
void increment_ssse3(float arr[4]);
#endif

#if HAVE_SSE41
int sse41_available(void);
void increment_sse41(float arr[4]);
#endif

#if HAVE_SSE42
int sse42_available(void);
void increment_sse42(float arr[4]);
#endif

#if HAVE_AVX
int avx_available(void);
void increment_avx(float arr[4]);
#endif

#if HAVE_AVX2
int avx2_available(void);
void increment_avx2(float arr[4]);
#endif

#if HAVE_NEON
int neon_available(void);
void increment_neon(float arr[4]);
#endif

#if HAVE_ALTIVEC
int altivec_available(void);
void increment_altivec(float arr[4]);
#endif

/* And so on. */
meson-0.53.2/test cases/common/152 shared module resolving symbol in executable/0000755000175000017500000000000013625242362030623 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/152 shared module resolving symbol in executable/meson.build0000644000175000017500000000170313605171534032766 0ustar  jpakkanejpakkane00000000000000project('shared module resolving symbol in executable', 'c')

# The shared module contains a reference to the symbol 'func_from_executable',
# which is always provided by the executable which loads it.  This symbol can be
# resolved at run-time by an ELF loader.  But when building PE/COFF objects, all
# symbols must be resolved at link-time, so an implib is generated for the
# executable, and the shared module linked with it.
#
# See testcase 125 for an example of the more complex portability gymnastics
# required if we do not know (at link-time) what provides the symbol.

cc = meson.get_compiler('c')
if cc.get_id() == 'pgi'
  error('MESON_SKIP_TEST PGI has its own unique set of macros that would need to be handled')
endif

dl = meson.get_compiler('c').find_library('dl', required: false)
e = executable('prog', 'prog.c', dependencies: dl, export_dynamic: true)
m = shared_module('module', 'module.c', link_with: e)
test('test', e, args: m.full_path())
meson-0.53.2/test cases/common/152 shared module resolving symbol in executable/module.c0000644000175000017500000000061513531533273032256 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

extern int func_from_executable(void);

int DLL_PUBLIC func(void) {
   return func_from_executable();
}
meson-0.53.2/test cases/common/152 shared module resolving symbol in executable/prog.c0000644000175000017500000000211013571777336031746 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#ifdef _WIN32
#include 
#else
#include 
#endif

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

typedef int (*fptr) (void);

int DLL_PUBLIC
func_from_executable(void)
{
  return 42;
}

int main(int argc, char **argv)
{
  int expected, actual;
  fptr importedfunc;

  if (argc=0) {};  // noop

#ifdef _WIN32
  HMODULE h = LoadLibraryA(argv[1]);
#else
  void *h = dlopen(argv[1], RTLD_NOW);
#endif
  assert(h != NULL);

#ifdef _WIN32
  importedfunc = (fptr) GetProcAddress (h, "func");
#else
  importedfunc = (fptr) dlsym(h, "func");
#endif
  assert(importedfunc != NULL);
  assert(importedfunc != func_from_executable);

  actual = (*importedfunc)();
  expected = func_from_executable();
  assert(actual == expected);

#ifdef _WIN32
  FreeLibrary(h);
#else
  dlclose(h);
#endif

  return 0;
}
meson-0.53.2/test cases/common/153 dotinclude/0000755000175000017500000000000013625242362022272 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/153 dotinclude/dotproc.c0000644000175000017500000000025513571777336024130 0ustar  jpakkanejpakkane00000000000000#include"stdio.h"

#ifndef WRAPPER_INCLUDED
#error The wrapper stdio.h was not included.
#endif

int main(void) {
    printf("Eventually I got printed.\n");
    return 0;
}
meson-0.53.2/test cases/common/153 dotinclude/meson.build0000644000175000017500000000015013605171536024432 0ustar  jpakkanejpakkane00000000000000project('dotinclude', 'c')

executable('dotproc', 'dotproc.c',
  implicit_include_directories : false)

meson-0.53.2/test cases/common/153 dotinclude/stdio.h0000644000175000017500000000022713531533273023566 0ustar  jpakkanejpakkane00000000000000// There is no #pragma once because we _want_ to cause an eternal loop
// if this wrapper invokes itself.

#define WRAPPER_INCLUDED

#include
meson-0.53.2/test cases/common/154 reserved targets/0000755000175000017500000000000013625242362023412 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/all/0000755000175000017500000000000013625242362024162 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/all/meson.build0000644000175000017500000000004413531533273026322 0ustar  jpakkanejpakkane00000000000000executable('test-all', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/benchmark/0000755000175000017500000000000013625242362025344 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/benchmark/meson.build0000644000175000017500000000005213531533273027503 0ustar  jpakkanejpakkane00000000000000executable('test-benchmark', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/clean/0000755000175000017500000000000013625242362024474 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/clean/meson.build0000644000175000017500000000004613531533273026636 0ustar  jpakkanejpakkane00000000000000executable('test-clean', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/clean-ctlist/0000755000175000017500000000000013625242362025774 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/clean-ctlist/meson.build0000644000175000017500000000005513531533273030136 0ustar  jpakkanejpakkane00000000000000executable('test-clean-ctlist', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/clean-gcda/0000755000175000017500000000000013625242362025370 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/clean-gcda/meson.build0000644000175000017500000000005313531533273027530 0ustar  jpakkanejpakkane00000000000000executable('test-clean-gcda', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/clean-gcno/0000755000175000017500000000000013625242362025420 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/clean-gcno/meson.build0000644000175000017500000000005313531533273027560 0ustar  jpakkanejpakkane00000000000000executable('test-clean-gcno', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/coverage/0000755000175000017500000000000013625242362025205 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/coverage/meson.build0000644000175000017500000000005113531533273027343 0ustar  jpakkanejpakkane00000000000000executable('test-coverage', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/coverage-html/0000755000175000017500000000000013625242362026147 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/coverage-html/meson.build0000644000175000017500000000005613531533273030312 0ustar  jpakkanejpakkane00000000000000executable('test-coverage-html', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/coverage-text/0000755000175000017500000000000013625242362026167 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/coverage-text/meson.build0000644000175000017500000000005613531533273030332 0ustar  jpakkanejpakkane00000000000000executable('test-coverage-text', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/coverage-xml/0000755000175000017500000000000013625242362026003 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/coverage-xml/meson.build0000644000175000017500000000005513531533273030145 0ustar  jpakkanejpakkane00000000000000executable('test-coverage-xml', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/dist/0000755000175000017500000000000013625242362024355 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/dist/meson.build0000644000175000017500000000004513531533273026516 0ustar  jpakkanejpakkane00000000000000executable('test-dist', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/distcheck/0000755000175000017500000000000013625242362025353 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/distcheck/meson.build0000644000175000017500000000005213531533273027512 0ustar  jpakkanejpakkane00000000000000executable('test-distcheck', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/install/0000755000175000017500000000000013625242362025060 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/install/meson.build0000644000175000017500000000005013531533273027215 0ustar  jpakkanejpakkane00000000000000executable('test-install', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/meson.build0000644000175000017500000000155713605171542025563 0ustar  jpakkanejpakkane00000000000000project('reserved target names', 'c')
        # FIXME: Setting this causes it to leak to all other tests
        #default_options : ['b_coverage=true']

subdir('all')
subdir('benchmark')
subdir('clean')
subdir('clean-ctlist')
subdir('clean-gcda')
subdir('clean-gcno')
subdir('coverage')
subdir('coverage-html')
subdir('coverage-text')
subdir('coverage-xml')
subdir('dist')
subdir('distcheck')
subdir('install')
# We don't have a 'PHONY' directory because Windows and OSX
# choke horribly when there are two entries with the same
# name but different case.
subdir('phony')
subdir('reconfigure')
subdir('scan-build')
subdir('test')
subdir('uninstall')

subdir('runtarget')

py3 = import('python3').find_python()

custom_target('ctlist-test', output : 'out.txt',
              command : [py3, '-c', 'print("")'],
              capture : true,
              build_by_default : true)
meson-0.53.2/test cases/common/154 reserved targets/phony/0000755000175000017500000000000013625242362024547 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/phony/meson.build0000644000175000017500000000004613531533273026711 0ustar  jpakkanejpakkane00000000000000executable('test-phony', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/reconfigure/0000755000175000017500000000000013625242362025722 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/reconfigure/meson.build0000644000175000017500000000005413531533273030063 0ustar  jpakkanejpakkane00000000000000executable('test-reconfigure', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/runtarget/0000755000175000017500000000000013625242362025425 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/runtarget/meson.build0000644000175000017500000000016513531533273027571 0ustar  jpakkanejpakkane00000000000000configure_file(output : 'config.h', configuration: configuration_data())
run_target('runtarget', command : ['echo'])
meson-0.53.2/test cases/common/154 reserved targets/scan-build/0000755000175000017500000000000013625242362025433 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/scan-build/meson.build0000644000175000017500000000005313531533273027573 0ustar  jpakkanejpakkane00000000000000executable('test-scan-build', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/test/0000755000175000017500000000000013625242362024371 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/test/meson.build0000644000175000017500000000004513531533273026532 0ustar  jpakkanejpakkane00000000000000executable('test-test', '../test.c')
meson-0.53.2/test cases/common/154 reserved targets/test.c0000644000175000017500000000003713571777336024553 0ustar  jpakkanejpakkane00000000000000int main(void) {
  return 0;
}
meson-0.53.2/test cases/common/154 reserved targets/uninstall/0000755000175000017500000000000013625242362025423 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/154 reserved targets/uninstall/meson.build0000644000175000017500000000005213531533273027562 0ustar  jpakkanejpakkane00000000000000executable('test-uninstall', '../test.c')
meson-0.53.2/test cases/common/155 duplicate source names/0000755000175000017500000000000013625242362024461 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/155 duplicate source names/dir1/0000755000175000017500000000000013625242362025320 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/155 duplicate source names/dir1/file.c0000644000175000017500000000042213571777336026417 0ustar  jpakkanejpakkane00000000000000extern int dir2;
extern int dir2_dir1;
extern int dir3;
extern int dir3_dir1;

int main(void) {
    if (dir2 != 20)
        return 1;
    if (dir2_dir1 != 21)
        return 1;
    if (dir3 != 30)
        return 1;
    if (dir3_dir1 != 31)
        return 1;
    return 0;
}
meson-0.53.2/test cases/common/155 duplicate source names/dir1/meson.build0000644000175000017500000000003313531533273027456 0ustar  jpakkanejpakkane00000000000000sources += files('file.c')
meson-0.53.2/test cases/common/155 duplicate source names/dir2/0000755000175000017500000000000013625242362025321 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/155 duplicate source names/dir2/dir1/0000755000175000017500000000000013625242362026160 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/155 duplicate source names/dir2/dir1/file.c0000644000175000017500000000002413531533273027237 0ustar  jpakkanejpakkane00000000000000int dir2_dir1 = 21;
meson-0.53.2/test cases/common/155 duplicate source names/dir2/file.c0000644000175000017500000000001713531533273026402 0ustar  jpakkanejpakkane00000000000000int dir2 = 20;
meson-0.53.2/test cases/common/155 duplicate source names/dir2/meson.build0000644000175000017500000000005213531533273027460 0ustar  jpakkanejpakkane00000000000000sources += files('file.c', 'dir1/file.c')
meson-0.53.2/test cases/common/155 duplicate source names/dir3/0000755000175000017500000000000013625242362025322 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/155 duplicate source names/dir3/dir1/0000755000175000017500000000000013625242362026161 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/155 duplicate source names/dir3/dir1/file.c0000644000175000017500000000002413531533273027240 0ustar  jpakkanejpakkane00000000000000int dir3_dir1 = 31;
meson-0.53.2/test cases/common/155 duplicate source names/dir3/file.c0000644000175000017500000000001713531533273026403 0ustar  jpakkanejpakkane00000000000000int dir3 = 30;
meson-0.53.2/test cases/common/155 duplicate source names/dir3/meson.build0000644000175000017500000000006513531533273027465 0ustar  jpakkanejpakkane00000000000000lib = static_library('lib', 'file.c', 'dir1/file.c')
meson-0.53.2/test cases/common/155 duplicate source names/meson.build0000644000175000017500000000023413605171540026617 0ustar  jpakkanejpakkane00000000000000project('proj', 'c')

sources = []
subdir('dir1')
subdir('dir2')
subdir('dir3')
executable('a.out', sources : sources, objects : lib.extract_all_objects())
meson-0.53.2/test cases/common/156 index customtarget/0000755000175000017500000000000013625242362023754 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/156 index customtarget/check_args.py0000644000175000017500000000043713531533273026423 0ustar  jpakkanejpakkane00000000000000#!python3

import sys
from pathlib import Path

def main():
    if len(sys.argv) != 2:
        print(sys.argv)
        return 1
    if sys.argv[1] != 'gen.c':
        print(sys.argv)
        return 2
    Path('foo').touch()

    return 0

if __name__ == '__main__':
    sys.exit(main())
meson-0.53.2/test cases/common/156 index customtarget/gen_sources.py0000644000175000017500000000233413531533273026644 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import textwrap

HEADER = textwrap.dedent('''\
    void stringify(int foo, char * buffer);
    ''')

CODE = textwrap.dedent('''\
    #include 

    #ifndef WORKS
    # error "This shouldn't have been included"
    #endif

    void stringify(int foo, char * buffer) {
        sprintf(buffer, "%i", foo);
    }
    ''')


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--header')
    parser.add_argument('--code')
    args = parser.parse_args()

    with open(args.header, 'w') as f:
        f.write(HEADER)

    with open(args.code, 'w') as f:
        f.write(CODE)


if __name__ == '__main__':
    main()
meson-0.53.2/test cases/common/156 index customtarget/lib.c0000644000175000017500000000124313531533273024666 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gen.h"

void func(char * buffer) {
    stringify(1, buffer);
}
meson-0.53.2/test cases/common/156 index customtarget/meson.build0000644000175000017500000000352113605171542026116 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

project('custom_target_index', 'c', default_options : 'c_std=c89')

py_mod = import('python3')
prog_python = py_mod.find_python()

gen = custom_target(
  'gen.[ch]',
  input : 'gen_sources.py',
  output : ['gen.c', 'gen.h'],
  command : [prog_python, '@INPUT@', '--header', '@OUTPUT1@', '--code', '@OUTPUT0@'],
)

has_not_changed = false
if is_disabler(gen)
    has_not_changed = true
else
    has_not_changed = true
endif

assert(has_not_changed, 'Custom target has changed.')

assert(not is_disabler(gen), 'Custom target is a disabler.')

lib = static_library(
  'libfoo',
  ['lib.c', gen[1]],
)

has_not_changed = false
if is_disabler(lib)
    has_not_changed = true
else
    has_not_changed = true
endif

assert(has_not_changed, 'Static library has changed.')

assert(not is_disabler(lib), 'Static library is a disabler.')

custom_target(
  'foo',
  input: gen[0],
  output: 'foo',
  command: [find_program('check_args.py'), '@INPUT@'],
)

subdir('subdir')

gen = disabler()

assert(is_disabler(gen), 'Generator is not a disabler.')

lib = static_library(
  'libfoo',
  ['lib.c', gen[1]],
)

assert(is_disabler(lib), 'Static library is not a disabler.')

if lib.found()
  lib_disabled = false
else
  lib_disabled = true
endif

assert(lib_disabled, 'Static library was not disabled.')
meson-0.53.2/test cases/common/156 index customtarget/subdir/0000755000175000017500000000000013625242362025244 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/156 index customtarget/subdir/foo.c0000644000175000017500000000126713531533273026201 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gen.h"

int main(void) {
    char buf[50];
    stringify(10, buf);
    return 0;
}
meson-0.53.2/test cases/common/156 index customtarget/subdir/meson.build0000644000175000017500000000123113531533273027403 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

foo = executable(
  'foo',
  ['foo.c', gen[0], gen[1]],
  c_args : '-DWORKS',
)
meson-0.53.2/test cases/common/157 wrap file should not failed/0000755000175000017500000000000013625242362025262 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/meson.build0000644000175000017500000000036413605171542027426 0ustar  jpakkanejpakkane00000000000000project('mainproj', 'c',
  default_options : ['wrap_mode=nodownload'],
)

subproject('zlib')
subproject('foo')

executable('grabprog', files('src/subprojects/prog.c'))
executable('grabprog2', files('src/subprojects/foo/prog2.c'))
subdir('src')
meson-0.53.2/test cases/common/157 wrap file should not failed/src/0000755000175000017500000000000013625242362026051 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/src/meson.build0000644000175000017500000000015713531533273030216 0ustar  jpakkanejpakkane00000000000000executable('grabprog3', files('subprojects/prog.c'))
executable('grabprog4', files('subprojects/foo/prog2.c'))
meson-0.53.2/test cases/common/157 wrap file should not failed/src/subprojects/0000755000175000017500000000000013625242362030414 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/src/subprojects/foo/0000755000175000017500000000000013625242362031177 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/src/subprojects/foo/prog2.c0000644000175000017500000000026613571777336032416 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("Do not have a file layout like this in your own projects.\n");
    printf("This is only to test that this works.\n");
    return 0;
}
meson-0.53.2/test cases/common/157 wrap file should not failed/src/subprojects/prog.c0000644000175000017500000000026613571777336031551 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("Do not have a file layout like this in your own projects.\n");
    printf("This is only to test that this works.\n");
    return 0;
}
meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/0000755000175000017500000000000013625242362027625 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/0000755000175000017500000000000013625242362030704 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c0000644000175000017500000000005013571777336031644 0ustar  jpakkanejpakkane00000000000000int dummy_func(void) {
    return 42;
}
meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build0000644000175000017500000000010313546416757033055 0ustar  jpakkanejpakkane00000000000000project('shared lib', 'c')
libfoo = shared_library('foo', 'foo.c')
meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/foo.wrap0000644000175000017500000000056613531533273031312 0ustar  jpakkanejpakkane00000000000000[wrap-file]
directory = foo-1.0

source_url = http://something.invalid
source_filename = foo-1.0.tar.xz
source_hash = ae5fc03185654f76b459db16ca25809703f8821aeb39a433902244bb479c4b79
lead_directory_missing = true

patch_url = https://something.invalid/patch
patch_filename = foo-1.0-patch.tar.xz
patch_hash = 8f2e286a4b190228d4e0c25ddc91195449cfb5e5c52006355838964b244037da
meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/0000755000175000017500000000000013625242362032204 5ustar  jpakkanejpakkane00000000000000././@LongLink0000000000000000000000000000015500000000000011216 Lustar  00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/foo-1.0-patch.tar.xzmeson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/foo-1.0-patc0000644000175000017500000000035013531533273034131 0ustar  jpakkanejpakkane00000000000000ż7zXZęÖ“F!t/å£ą	’§]3ģZ1łkE爩ļ—āŻóG£˜ILŹ;Žč‘<’>Šł;mU|Å«„(¾ŻDÉf­Žąf4oQZ‰Ó¾™ø„G惓Ēx”AŽh~?Fķ!=!Žä凁m뛽™Ä'_K¾r”‰Uc@ÓØĘZŒmS.߇9R{$Cb„Ó쪘²EūĻķo}2Õ[Ѥß#‘z9>čQŒ‹Õ™3\ü‹Vś?ņdİÆ:šDĖĆ€ą,?Ÿ±ÄgūYZ././@LongLink0000000000000000000000000000014700000000000011217 Lustar  00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/foo-1.0.tar.xzmeson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/foo-1.0.tar.0000644000175000017500000000026413531533273034053 0ustar  jpakkanejpakkane00000000000000ż7zXZęÖ“F!t/å£ą’q]3ģ\cjz"ŠxÄIœęĀŹüxK‰Hū_ŅmM$ån„Åūīg/ˆźzP>YD“©¢ż™Į†õ\gž	c:—ćz͉U^_&n‰7ÆO—®*#Šol"‰/1Vl©če·
£VŁ.œŪ“?nÓx­½‰-‘p€ ļd­±ÄgūYZ././@LongLink0000000000000000000000000000015600000000000011217 Lustar  00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-wrap.zipmeson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-80000644000175000017500000000000613531533273033674 0ustar  jpakkanejpakkane00000000000000dummy
././@LongLink0000000000000000000000000000015200000000000011213 Lustar  00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.tar.gzmeson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.t0000644000175000017500000000000613531533273033771 0ustar  jpakkanejpakkane00000000000000dummy
meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/zlib-1.2.8/0000755000175000017500000000000013625242362031231 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/zlib-1.2.8/foo.c0000644000175000017500000000005013571777336032171 0ustar  jpakkanejpakkane00000000000000int dummy_func(void) {
    return 42;
}
meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/zlib-1.2.8/meson.build0000644000175000017500000000007213531533273033372 0ustar  jpakkanejpakkane00000000000000project('shared lib', 'c')
shared_library('foo', 'foo.c')
meson-0.53.2/test cases/common/157 wrap file should not failed/subprojects/zlib.wrap0000644000175000017500000000061713531533273031464 0ustar  jpakkanejpakkane00000000000000[wrap-file]
directory = zlib-1.2.8

source_url = http://zlib.net/fossils/zlib-1.2.8.tar.gz
source_filename = zlib-1.2.8.tar.gz
source_hash = 36658cb768a54c1d4dec43c3116c27ed893e88b02ecfcb44f2166f9c0b7f2a0d

patch_url = https://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.8/8/get_zip
patch_filename = zlib-1.2.8-8-wrap.zip
patch_hash = 17c52a0e0c59ce926d3959005d5cd8178c6c7e2c9a4a1304279a8320c955ac60
meson-0.53.2/test cases/common/158 includedir subproj/0000755000175000017500000000000013625242362023734 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/158 includedir subproj/meson.build0000644000175000017500000000017513605171544026102 0ustar  jpakkanejpakkane00000000000000project('include dir in subproj test', 'c')


subproject('inctest')


exe = executable('prog', 'prog.c')

test('dummy', exe)
meson-0.53.2/test cases/common/158 includedir subproj/prog.c0000644000175000017500000000003713571777336025065 0ustar  jpakkanejpakkane00000000000000int main(void) {
  return 0;
}
meson-0.53.2/test cases/common/158 includedir subproj/subprojects/0000755000175000017500000000000013625242351026275 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/158 includedir subproj/subprojects/inctest/0000755000175000017500000000000013625242362027750 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/158 includedir subproj/subprojects/inctest/include/0000755000175000017500000000000013625242362031373 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/158 includedir subproj/subprojects/inctest/include/incfile.h0000644000175000017500000000005413531533273033154 0ustar  jpakkanejpakkane00000000000000
/* file which is used in the subproject */
meson-0.53.2/test cases/common/158 includedir subproj/subprojects/inctest/meson.build0000644000175000017500000000044313531533273032113 0ustar  jpakkanejpakkane00000000000000
project('subproj with includedir', 'c')



compile_check = '''
#include "incfile.h"
'''

if not meson.get_compiler('c').compiles(compile_check, name : 'include in subproj',
                                        include_directories: include_directories('include'))
  error('failed')
endif
meson-0.53.2/test cases/common/159 subproject dir name collision/0000755000175000017500000000000013625242362025742 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/159 subproject dir name collision/a.c0000644000175000017500000000027713571777336026352 0ustar  jpakkanejpakkane00000000000000#include
char func_b(void);
char func_c(void);

int main(void) {
    if(func_b() != 'b') {
        return 1;
    }
    if(func_c() != 'c') {
        return 2;
    }
    return 0;
}
meson-0.53.2/test cases/common/159 subproject dir name collision/custom_subproject_dir/0000755000175000017500000000000013625242351032350 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/159 subproject dir name collision/custom_subproject_dir/B/0000755000175000017500000000000013625242362032533 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/159 subproject dir name collision/custom_subproject_dir/B/b.c0000644000175000017500000000065413571777336033143 0ustar  jpakkanejpakkane00000000000000#include
char func_c(void);

#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

char DLL_PUBLIC func_b(void) {
    if(func_c() != 'c') {
        exit(3);
    }
    return 'b';
}
meson-0.53.2/test cases/common/159 subproject dir name collision/custom_subproject_dir/B/meson.build0000644000175000017500000000015413531533273034675 0ustar  jpakkanejpakkane00000000000000project('B', 'c')
C = subproject('C')
c = C.get_variable('c')
b = shared_library('b', 'b.c', link_with : c)
meson-0.53.2/test cases/common/159 subproject dir name collision/custom_subproject_dir/C/0000755000175000017500000000000013625242362032534 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/159 subproject dir name collision/custom_subproject_dir/C/c.c0000644000175000017500000000052413571777336033141 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

char DLL_PUBLIC func_c(void) {
    return 'c';
}
meson-0.53.2/test cases/common/159 subproject dir name collision/custom_subproject_dir/C/meson.build0000644000175000017500000000006113531533273034673 0ustar  jpakkanejpakkane00000000000000project('C', 'c')
c = shared_library('c', 'c.c')
meson-0.53.2/test cases/common/159 subproject dir name collision/meson.build0000644000175000017500000000035613605171547030114 0ustar  jpakkanejpakkane00000000000000project('A', 'c', subproject_dir:'custom_subproject_dir')

B = subproject('B')
b = B.get_variable('b')

C = subproject('C')
c = C.get_variable('c')

subdir('other_subdir')

a = executable('a', 'a.c', link_with : [b, c])
test('a test', a)
meson-0.53.2/test cases/common/159 subproject dir name collision/other_subdir/0000755000175000017500000000000013625242362030433 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/159 subproject dir name collision/other_subdir/custom_subproject_dir/0000755000175000017500000000000013625242362035043 5ustar  jpakkanejpakkane00000000000000././@LongLink0000000000000000000000000000015400000000000011215 Lustar  00000000000000meson-0.53.2/test cases/common/159 subproject dir name collision/other_subdir/custom_subproject_dir/other.cmeson-0.53.2/test cases/common/159 subproject dir name collision/other_subdir/custom_subproject_dir/0000644000175000017500000000062413571777336035065 0ustar  jpakkanejpakkane00000000000000#include

#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

char DLL_PUBLIC func_b(void) {
    if('c' != 'c') {
        exit(3);
    }
    return 'b';
}
meson-0.53.2/test cases/common/159 subproject dir name collision/other_subdir/meson.build0000644000175000017500000000010113531533273032565 0ustar  jpakkanejpakkane00000000000000other = shared_library('other', 'custom_subproject_dir/other.c')
meson-0.53.2/test cases/common/16 else/0000755000175000017500000000000013625242362021006 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/16 else/meson.build0000644000175000017500000000023513605171316023146 0ustar  jpakkanejpakkane00000000000000project('else test', 'c')

var = false

if var
  exe = executable('break', 'break.c')
else
  exe = executable('prog', 'prog.c')
endif

test('elsetest', exe)
meson-0.53.2/test cases/common/16 else/prog.c0000644000175000017500000000003513571777336022135 0ustar  jpakkanejpakkane00000000000000int main(void) { return 0; }
meson-0.53.2/test cases/common/160 config tool variable/0000755000175000017500000000000013625242362024107 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/160 config tool variable/meson.build0000644000175000017500000000205513605171546026256 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

project('config tool variable', 'cpp')


dep_llvm = dependency('llvm', method : 'config-tool', required : false)
if not dep_llvm.found()
  error('MESON_SKIP_TEST LLVM not installed.')
endif

includedir = dep_llvm.get_configtool_variable('includedir')
includedir = join_paths(includedir, 'llvm')
if host_machine.system() == 'windows'
  cmd = run_command(['dir', includedir])
else
  cmd = run_command(['ls', includedir])
endif

assert(cmd.returncode() == 0, 'did not run successfully')
meson-0.53.2/test cases/common/161 custom target subdir depend files/0000755000175000017500000000000013625242363026475 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/161 custom target subdir depend files/copyfile.py0000644000175000017500000000013413531533273030656 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import shutil

shutil.copyfile(sys.argv[1], sys.argv[2])
meson-0.53.2/test cases/common/161 custom target subdir depend files/meson.build0000644000175000017500000000020413605171546030635 0ustar  jpakkanejpakkane00000000000000project('custom target subdir depend files', 'c')

copy = find_program('copyfile.py')

subdir('subdir')

executable('foo', foo_src)
meson-0.53.2/test cases/common/161 custom target subdir depend files/subdir/0000755000175000017500000000000013625242363027765 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/161 custom target subdir depend files/subdir/dep.dat0000644000175000017500000000003413531533273031223 0ustar  jpakkanejpakkane00000000000000You can depend on this file.meson-0.53.2/test cases/common/161 custom target subdir depend files/subdir/foo.c.in0000644000175000017500000000012613571777336031335 0ustar  jpakkanejpakkane00000000000000#include 

int main(void) {
    printf("foo is working.\n");
    return 0;
}
meson-0.53.2/test cases/common/161 custom target subdir depend files/subdir/meson.build0000644000175000017500000000022513531533273032125 0ustar  jpakkanejpakkane00000000000000foo_src = custom_target('foo_src',
  depend_files : 'dep.dat',
  input : 'foo.c.in',
  output : 'foo.c',
  command : [copy, '@INPUT@', '@OUTPUT@']
)
meson-0.53.2/test cases/common/162 external program shebang parsing/0000755000175000017500000000000013625242363026427 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/162 external program shebang parsing/input.txt0000644000175000017500000000002013531533273030316 0ustar  jpakkanejpakkane00000000000000some stuff here
meson-0.53.2/test cases/common/162 external program shebang parsing/main.c0000644000175000017500000000242713537776255027542 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include 
#include 
#include 
#include 

#ifdef _WIN32
 #include 
 #include 
#else
 #include 
#endif

/* Who cares about stack sizes in test programs anyway */
#define LINE_LENGTH 4096

static int
intrp_copyfile (char * src, char * dest)
{
#ifdef _WIN32
  if (!CopyFile (src, dest, FALSE))
    return 1;
  return 0;
#else
  return execlp ("cp", "cp", src, dest, NULL);
#endif
}

static void
parser_get_line (FILE * f, char line[LINE_LENGTH])
{
  if (!fgets (line, LINE_LENGTH, f))
    fprintf (stderr, "%s\n", strerror (errno));
}

int
main (int argc, char * argv[])
{
  FILE *f = NULL;
  char line[LINE_LENGTH];

  if (argc != 4) {
    fprintf (stderr, "Invalid number of arguments: %i\n", argc);
    goto err;
  }

  if ((f = fopen (argv[1], "r")) == NULL) {
    fprintf (stderr, "%s\n", strerror (errno));
    goto err;
  }

  parser_get_line (f, line);

  if (!line || line[0] != '#' || line[1] != '!') {
    fprintf (stderr, "Invalid script\n");
    goto err;
  }

  parser_get_line (f, line);

  if (!line || strncmp (line, "copy", 4) != 0) {
    fprintf (stderr, "Syntax error: %s\n", line);
    goto err;
  }

  return intrp_copyfile (argv[2], argv[3]);

err:
  fclose (f);
  return 1;
}
meson-0.53.2/test cases/common/162 external program shebang parsing/meson.build0000644000175000017500000000121513605171547030573 0ustar  jpakkanejpakkane00000000000000project('shebang parsing', 'c')

interpreter = executable('aninterp', 'main.c', native : true)

cdata = configuration_data()
cdata.set('INTRP', interpreter.full_path())

f = configure_file(input : 'script.int.in',
                   output : 'script.int',
                   configuration : cdata)

# Test that parsing a shebang with spaces works properly. See `man execve`,
# specifically the section on "Interpreter scripts" and the one under "NOTES".
script = find_program(f)

custom_target('interpthis',
  input : 'input.txt',
  output : 'output.txt',
  depends : interpreter,
  command : [script, '@INPUT@', '@OUTPUT@'],
  build_by_default : true)
meson-0.53.2/test cases/common/162 external program shebang parsing/script.int.in0000644000175000017500000000003413531533273031050 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env @INTRP@
copy
meson-0.53.2/test cases/common/163 disabler/0000755000175000017500000000000013625242363021727 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/163 disabler/meson.build0000644000175000017500000000660313605171552024075 0ustar  jpakkanejpakkane00000000000000project('dolphin option', 'c')

d = disabler()

full_path = d.full_path()
assert(is_disabler(full_path), 'Method call is not a disabler')

d2 = dependency(d)
d3 = (d == d2)
d4 = d + 0
d5 = d2 or true

has_not_changed = false
if is_disabler(d)
    has_not_changed = true
else
    has_not_changed = true
endif
assert(has_not_changed, 'Disabler has changed.')

assert(is_disabler(d), 'Disabler was not identified correctly.')
assert(is_disabler(d2), 'Function laundered disabler was not identified correctly.')
assert(is_disabler(d3), 'Disabler comparison should yield disabler.')
assert(is_disabler(d4), 'Disabler addition should yield disabler.')
assert(is_disabler(d5), 'Disabler logic op should yield disabler.')

assert(d, 'Disabler did not cause this to be skipped.')
assert(d2, 'Function laundered disabler did not cause this to be skipped.')
assert(d3, 'Disabler comparison should yield disabler and thus this would not be called.')
assert(d4, 'Disabler addition should yield disabler and thus this would not be called.')
assert(d5, 'Disabler logic op should yield disabler and thus this would not be called.')

number = 0

if d
  number = 1
else
  number = 2
endif

has_not_changed = false
if is_disabler(number)
    has_not_changed = true
else
    has_not_changed = true
endif
assert(has_not_changed, 'Number has changed.')

assert(not is_disabler(number), 'Number should not be a disabler.')
assert(number == 0, 'Plain if handled incorrectly, value should be 0 but is @0@'.format(number))

if d.found()
  number = 1
else
  number = 2
endif

assert(number == 2, 'If found handled incorrectly, value should be 2 but is @0@'.format(number))

dep = dependency('notfounddep', required : false, disabler : true)
app = executable('myapp', 'notfound.c', dependencies : [dep])
assert(is_disabler(app), 'App is not a disabler.')
app = executable('myapp', 'notfound.c', dependencies : [[dep]])
assert(is_disabler(app), 'App is not a disabler.')

cc = meson.get_compiler('c')
dep = cc.find_library('notfounddep', required : false, disabler : true)
app = executable('myapp', 'notfound.c', dependencies : [dep])
assert(is_disabler(app), 'App is not a disabler.')

dep = find_program('donotfindme', required : false, disabler : true)
app = executable('myapp', 'notfound.c', dependencies : [dep])
assert(is_disabler(app), 'App is not a disabler.')

has_not_changed = false
if is_disabler(app)
    has_not_changed = true
else
    has_not_changed = true
endif
assert(has_not_changed, 'App has changed.')

if_is_disabled = true
if disabler()
  if_is_disabled = false
else
  if_is_disabled = false
endif
assert(if_is_disabled, 'Disabler in "if condition" must skip both blocks')

if not disabler()
  if_is_disabled = false
else
  if_is_disabled = false
endif
assert(if_is_disabled, 'Disabler in "if not condition" must skip both blocks')

if disabler() == 1
  if_is_disabled = false
else
  if_is_disabled = false
endif
assert(if_is_disabled, 'Disabler in "if a==b" must skip both blocks')

loops = 0
disablers = 0
foreach i : [true, disabler(), true]
  loops += 1
  if is_disabler(i)
    disablers += 1
  endif
endforeach
assert(loops == 3, 'Disabler in foreach array')
assert(disablers == 1, 'Disabler in foreach array')

loops = 0
disablers = 0
foreach k, i : {'a': true, 'b': disabler(), 'c': true}
  loops += 1
  if is_disabler(i)
    disablers += 1
  endif
endforeach
assert(loops == 3, 'Disabler in foreach dict')
assert(disablers == 1, 'Disabler in foreach dict')
meson-0.53.2/test cases/common/164 array option/0000755000175000017500000000000013625242363022552 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/164 array option/meson.build0000644000175000017500000000131413605171550024710 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

project('array default options')

assert(get_option('array') == ['foo', 'bar'], 'Default value for array is not equal to choices')
meson-0.53.2/test cases/common/164 array option/meson_options.txt0000644000175000017500000000121413531533273026204 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

option(
  'array',
  type : 'array',
  choices : ['foo', 'bar'],
)
meson-0.53.2/test cases/common/165 custom target template substitution/0000755000175000017500000000000013625242363027256 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/165 custom target template substitution/checkcopy.py0000644000175000017500000000031213531533273031573 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import shutil

if '@INPUT1@' in sys.argv[1]:
    shutil.copyfile(sys.argv[2], sys.argv[3])
else:
    sys.exit('String @INPUT1@ not found in "{}"'.format(sys.argv[1]))
meson-0.53.2/test cases/common/165 custom target template substitution/foo.c.in0000644000175000017500000000012613571777336030626 0ustar  jpakkanejpakkane00000000000000#include 

int main(void) {
    printf("foo is working.\n");
    return 0;
}
meson-0.53.2/test cases/common/165 custom target template substitution/meson.build0000644000175000017500000000076013605171552031422 0ustar  jpakkanejpakkane00000000000000project('custom target template substitution', 'c')

check = find_program('checkcopy.py')

config = configuration_data()

config_file = configure_file(configuration : config, output : 'x@IN')

# Check that substitution does not find @FOO@ and then misses @INPUT0@.
# Check the resulting x@INPUT1@ is not replaced.
foo = custom_target('runcheck',
  input : [config_file, 'foo.c.in'],
  output : 'foo.c',
  command : [check, '-D@FOO@INPUT0@PUT1@', '@INPUT1@', '@OUTPUT@']
)

executable('foo', foo)
meson-0.53.2/test cases/common/166 not-found dependency/0000755000175000017500000000000013625242363024155 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/166 not-found dependency/meson.build0000644000175000017500000000071313605171553026320 0ustar  jpakkanejpakkane00000000000000project('dep-test', 'c')

dep = dependency('', required:false)
if dep.found()
  error('not-found dependency was found')
endif

assert(dep.type_name() == 'not-found', 'dependency should be of type "not-found" not ' + dep.type_name())

library('testlib', 'testlib.c', dependencies: [dep])
subdir('sub', if_found: dep)

subdep = dependency('', fallback: ['trivial', 'trivial_dep'])
missing = dependency('', fallback: ['missing', 'missing_dep'], required: false)
meson-0.53.2/test cases/common/166 not-found dependency/sub/0000755000175000017500000000000013625242363024746 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/166 not-found dependency/sub/meson.build0000644000175000017500000000006113531533273027104 0ustar  jpakkanejpakkane00000000000000error('should be disabled by subdir(if_found:)')
meson-0.53.2/test cases/common/166 not-found dependency/subprojects/0000755000175000017500000000000013625242351026515 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/166 not-found dependency/subprojects/trivial/0000755000175000017500000000000013625242363030172 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/166 not-found dependency/subprojects/trivial/meson.build0000644000175000017500000000024113531533273032330 0ustar  jpakkanejpakkane00000000000000project('trivial subproject', 'c')
trivial_lib = static_library('trivial', 'trivial.c', install: false)
trivial_dep = declare_dependency(link_with: trivial_lib)
meson-0.53.2/test cases/common/166 not-found dependency/subprojects/trivial/trivial.c0000644000175000017500000000004513571777336032024 0ustar  jpakkanejpakkane00000000000000int subfunc(void) {
    return 42;
}
meson-0.53.2/test cases/common/166 not-found dependency/testlib.c0000644000175000017500000000000013531533273025754 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/167 subdir if_found/0000755000175000017500000000000013625242363023210 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/167 subdir if_found/meson.build0000644000175000017500000000044313605171553025353 0ustar  jpakkanejpakkane00000000000000project('subdir if found', 'c')

found_dep = declare_dependency()
not_found_dep = dependency('nonexisting', required : false)

subdir('nonexisting_dir', if_found : not_found_dep)

variable = 3

subdir('subdir', if_found : found_dep)
assert(variable == 5, 'Subdir was not properly entered.')
meson-0.53.2/test cases/common/167 subdir if_found/subdir/0000755000175000017500000000000013625242363024500 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/167 subdir if_found/subdir/meson.build0000644000175000017500000000001513531533273026635 0ustar  jpakkanejpakkane00000000000000variable = 5
meson-0.53.2/test cases/common/168 default options prefix dependent defaults/0000755000175000017500000000000013625242363030244 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/168 default options prefix dependent defaults/meson.build0000644000175000017500000000017513605171555032413 0ustar  jpakkanejpakkane00000000000000project('default options prefix dependent defaults ', 'c', default_options : ['sharedstatedir=/sharedstate', 'prefix=/usr'])
meson-0.53.2/test cases/common/169 dependency factory/0000755000175000017500000000000013625242363023716 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/169 dependency factory/meson.build0000644000175000017500000000321513605171557026065 0ustar  jpakkanejpakkane00000000000000project('dependency factory', 'c', meson_version : '>=0.40')

dep = dependency('gl', method: 'pkg-config', required: false)
if dep.found() and dep.type_name() == 'pkgconfig'
  dep.get_pkgconfig_variable('prefix')
endif

dep = dependency('SDL2', method: 'pkg-config', required: false)
if dep.found() and dep.type_name() == 'pkgconfig'
  dep.get_pkgconfig_variable('prefix')
endif

dep = dependency('SDL2', method: 'config-tool', required: false)
if dep.found() and dep.type_name() == 'configtool'
  dep.get_configtool_variable('prefix')
endif

dep = dependency('Vulkan', method: 'pkg-config', required: false)
if dep.found() and dep.type_name() == 'pkgconfig'
  dep.get_pkgconfig_variable('prefix')
endif

dep = dependency('pcap', method: 'pkg-config', required: false)
if dep.found() and dep.type_name() == 'pkgconfig'
  dep.get_pkgconfig_variable('prefix')
endif

dep = dependency('pcap', method: 'config-tool', required: false)
if dep.found() and dep.type_name() == 'configtool'
  dep.get_configtool_variable('prefix')
endif

dep = dependency('cups', method: 'pkg-config', required: false)
if dep.found() and dep.type_name() == 'pkgconfig'
  dep.get_pkgconfig_variable('prefix')
endif

dep = dependency('cups', method: 'config-tool', required: false)
if dep.found() and dep.type_name() == 'configtool'
  dep.get_configtool_variable('prefix')
endif

dep = dependency('libwmf', method: 'pkg-config', required: false)
if dep.found() and dep.type_name() == 'pkgconfig'
  dep.get_pkgconfig_variable('prefix')
endif

dep = dependency('libwmf', method: 'config-tool', required: false)
if dep.found() and dep.type_name() == 'configtool'
  dep.get_configtool_variable('prefix')
endif
meson-0.53.2/test cases/common/17 comparison/0000755000175000017500000000000013625242363022232 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/17 comparison/meson.build0000644000175000017500000000623713605171322024376 0ustar  jpakkanejpakkane00000000000000project('comparison', 'c')

# Compare equality of strings

var1 = 'foo'
var2 = 'bar'

if var1 == var2
  exe1 = executable('broken', 'broken.c')
else
  exe1 = executable('prog1', 'prog.c')
endif

if var1 == var1
  exe2 = executable('prog2', 'prog.c')
else
  exe2 = executable('broken', 'broken.c')
endif

if var1 != var2
  exe3 = executable('prog3', 'prog.c')
else
  exe3 = executable('broken', 'broken.c')
endif

if var1 != var1
  exe4 = executable('broken', 'broken.c')
else
  exe4 = executable('prog4', 'prog.c')
endif

test('equalfalse', exe1)
test('equaltrue', exe2)
test('nequaltrue', exe3)
test('nequalfalse', exe4)

# Non-equality comparisons

var3 = 3
var4 = 4

if var3 < var4
  exe5 = executable('prog5', 'prog.c')
else
  exe5 = executable('broken', 'broken.c')
endif

if var3 < var3
  exe6 = executable('broken', 'broken.c')
else
  exe6 = executable('prog6', 'prog.c')
endif

if var4 > var3
  exe7 = executable('prog7', 'prog.c')
else
  exe7 = executable('broken', 'broken.c')
endif

if var3 > var3
  exe8 = executable('broken', 'broken.c')
else
  exe8 = executable('prog8', 'prog.c')
endif

if var4 <= var3
  exe9 = executable('broken', 'broken.c')
else
  exe9 = executable('prog9', 'prog.c')
endif

if var3 <= var3
  exe10 = executable('prog10', 'prog.c')
else
  exe10 = executable('broken', 'broken.c')
endif

if var3 >= var4
  exe11 = executable('broken', 'broken.c')
else
  exe11 = executable('prog11', 'prog.c')
endif

if var3 >= var3
  exe12 = executable('prog12', 'prog.c')
else
  exe12 = executable('broken', 'broken.c')
endif

test('lttrue', exe5)
test('ltfalse', exe6)
test('gttrue', exe7)
test('gtfalse', exe8)
test('lefalse', exe9)
test('letrue', exe10)
test('gefalse', exe11)
test('getrue', exe12)

# Non-elementary type comparisons

if exe1 == exe2
  exe13 = executable('broken', 'broken.c')
else
  exe13 = executable('prog13', 'prog.c')
endif

if exe1 == exe1
  exe14 = executable('prog14', 'prog.c')
else
  exe14 = executable('broken', 'broken.c')
endif

if exe1 != exe2
  exe15 = executable('prog15', 'prog.c')
else
  exe15 = executable('broken', 'broken.c')
endif

if exe1 != exe1
  exe16 = executable('broken', 'broken.c')
else
  exe16 = executable('prog16', 'prog.c')
endif

test('equalfalse', exe13)
test('equaltrue', exe14)
test('nequaltrue', exe15)
test('nequalfalse', exe16)

# Equality comparisons of different elementary types
# (these all cause warnings currently, will become an error in future)

assert([] != 'st', 'not equal')
assert([] != 1, 'not equal')
assert(2 != 'st', 'not equal')

assert(not ([] == 'st'), 'not equal')
assert(not ([] == 1), 'not equal')
assert(not (2 == 'st'), 'not equal')

# "in" and "not in" operators

assert(1 in [1, 2], '''1 should be in [1, 2]''')
assert(3 not in [1, 2], '''3 shouldn't be in [1, 2]''')
assert(not (3 in [1, 2]), '''3 shouldn't be in [1, 2]''')

assert('b' in ['a', 'b'], ''''b' should be in ['a', 'b']''')
assert('c' not in ['a', 'b'], ''''c' shouldn't be in ['a', 'b']''')

assert(exe1 in [exe1, exe2], ''''exe1 should be in [exe1, exe2]''')
assert(exe3 not in [exe1, exe2], ''''exe3 shouldn't be in [exe1, exe2]''')

assert('a' in {'a': 'b'}, '''1 should be in {'a': 'b'}''')
assert('b' not in {'a': 'b'}, '''1 should be in {'a': 'b'}''')
meson-0.53.2/test cases/common/17 comparison/prog.c0000644000175000017500000000003513571777336023360 0ustar  jpakkanejpakkane00000000000000int main(void) { return 0; }
meson-0.53.2/test cases/common/170 get project license/0000755000175000017500000000000013625242363023751 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/170 get project license/bar.c0000644000175000017500000000013513571777336024675 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I'm a main project bar.\n");
    return 0;
}
meson-0.53.2/test cases/common/170 get project license/meson.build0000644000175000017500000000030713605171557026117 0ustar  jpakkanejpakkane00000000000000project('bar', 'c', license: 'Apache')

executable('bar', 'bar.c')

license = meson.project_license()[0]
if license != 'Apache'
    error('The license should be Apache, but it is: ' + license)
endif
meson-0.53.2/test cases/common/171 yield/0000755000175000017500000000000013625242363021247 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/171 yield/meson.build0000644000175000017500000000053513605171556023417 0ustar  jpakkanejpakkane00000000000000project('yield_options', 'c')

subproject('sub')

assert(get_option('unshared_option') == 'one', 'Unshared option has wrong value in superproject.')
assert(get_option('shared_option') == 'two', 'Shared option has wrong value in superproject..')
assert(get_option('wrongtype_option') == 'three', 'Wrongtype option has wrong value in superproject..')
meson-0.53.2/test cases/common/171 yield/meson_options.txt0000644000175000017500000000025713531533273024707 0ustar  jpakkanejpakkane00000000000000option('unshared_option', type : 'string', value : 'one')
option('shared_option', type : 'string', value : 'two')
option('wrongtype_option', type : 'string', value : 'three')
meson-0.53.2/test cases/common/171 yield/subprojects/0000755000175000017500000000000013625242351023607 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/171 yield/subprojects/sub/0000755000175000017500000000000013625242363024403 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/171 yield/subprojects/sub/meson.build0000644000175000017500000000047213531533273026547 0ustar  jpakkanejpakkane00000000000000project('subbie', 'c')

assert(get_option('unshared_option') == 'three', 'Unshared option has wrong value in subproject.')
assert(get_option('shared_option') == 'two', 'Shared option has wrong value in subproject.')
assert(get_option('wrongtype_option') == true, 'Wrongtype option has wrong value in subproject.')
meson-0.53.2/test cases/common/171 yield/subprojects/sub/meson_options.txt0000644000175000017500000000033313531533273030036 0ustar  jpakkanejpakkane00000000000000option('unshared_option', type : 'string', value : 'three', yield : false)
option('shared_option', type : 'string', value : 'four', yield : true)
option('wrongtype_option', type : 'boolean', value : true, yield : true)
meson-0.53.2/test cases/common/172 subproject nested subproject dirs/0000755000175000017500000000000013625242363026650 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/0000755000175000017500000000000013625242351030305 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/0000755000175000017500000000000013625242351032650 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/0000755000175000017500000000000013625242363033740 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/a.c0000644000175000017500000000054613571777336034346 0ustar  jpakkanejpakkane00000000000000int func2(void);

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC func(void) { return func2(); }

././@LongLink0000000000000000000000000000015300000000000011214 Lustar  00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/meson.buildmeson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/meson0000644000175000017500000000023213531533273035000 0ustar  jpakkanejpakkane00000000000000project('alpha project', 'c', subproject_dir: 'var/subprojects')

b = subproject('beta')
l = shared_library('a', 'a.c', link_with : b.get_variable('lb'))
meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/var/0000755000175000017500000000000013625242351034525 5ustar  jpakkanejpakkane00000000000000././@LongLink0000000000000000000000000000016000000000000011212 Lustar  00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/var/subprojects/meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/var/s0000755000175000017500000000000013625242363034713 5ustar  jpakkanejpakkane00000000000000././@LongLink0000000000000000000000000000021000000000000011206 Lustar  00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/var/subprojects/wrap_files_might_be_heremeson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/alpha/var/s0000644000175000017500000000000213531533273034704 0ustar  jpakkanejpakkane00000000000000 
meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/beta/0000755000175000017500000000000013625242363033566 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/beta/b.c0000644000175000017500000000052313571777336034170 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC func2(void) {
    return 42;
}
././@LongLink0000000000000000000000000000015200000000000011213 Lustar  00000000000000meson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/beta/meson.buildmeson-0.53.2/test cases/common/172 subproject nested subproject dirs/contrib/subprojects/beta/meson.0000644000175000017500000000015213531533273034705 0ustar  jpakkanejpakkane00000000000000project('beta project', 'c')

lb = shared_library('b', 'b.c')
notfound = dependency('', required : false)
meson-0.53.2/test cases/common/172 subproject nested subproject dirs/meson.build0000644000175000017500000000060613605171561031013 0ustar  jpakkanejpakkane00000000000000project('gamma project', 'c', subproject_dir: 'contrib/subprojects')

a = subproject('alpha')
lib = a.get_variable('l')

# Ensure that the dependency version is not checked for a not-found dependency
notfound = dependency('', version : '>=1.0', required : false,
                      fallback : ['beta', 'notfound'])

exe = executable('prog', 'prog.c', link_with : lib)
test('basic', exe)
meson-0.53.2/test cases/common/172 subproject nested subproject dirs/prog.c0000644000175000017500000000010513571777336027774 0ustar  jpakkanejpakkane00000000000000int func(void);

int main(void) {
    return func() == 42 ? 0 : 1;
}
meson-0.53.2/test cases/common/173 preserve gendir/0000755000175000017500000000000013625242363023227 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/173 preserve gendir/base.inp0000644000175000017500000000000513531533273024643 0ustar  jpakkanejpakkane00000000000000base
meson-0.53.2/test cases/common/173 preserve gendir/com/0000755000175000017500000000000013625242351024002 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/173 preserve gendir/com/mesonbuild/0000755000175000017500000000000013625242363026146 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/173 preserve gendir/com/mesonbuild/subbie.inp0000644000175000017500000000000713531533273030123 0ustar  jpakkanejpakkane00000000000000subbie
meson-0.53.2/test cases/common/173 preserve gendir/genprog.py0000755000175000017500000000226213571777336025264 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os, sys, argparse

h_templ = '''#pragma once

int %s(void);
'''

c_templ = '''#include"%s.h"

int %s(void) {
    return 0;
}
'''

parser = argparse.ArgumentParser()
parser.add_argument('--searchdir', required=True)
parser.add_argument('--outdir', required=True)
parser.add_argument('ifiles', nargs='+')

options = parser.parse_args()

searchdir = options.searchdir
outdir = options.outdir
ifiles = options.ifiles

rel_ofiles = []

for ifile in ifiles:
    if not ifile.startswith(options.searchdir):
        sys.exit('Input file %s does not start with search dir %s.' % (ifile, searchdir))
    rel_ofile = ifile[len(searchdir):]
    if rel_ofile[0] == '/' or rel_ofile[0] == '\\':
        rel_ofile = rel_ofile[1:]
    rel_ofiles.append(os.path.splitext(rel_ofile)[0])

ofile_bases = [os.path.join(outdir, i) for i in rel_ofiles]

for i, ifile_name in enumerate(ifiles):
    proto_name = open(ifile_name).readline().strip()
    h_out = ofile_bases[i] + '.h'
    c_out = ofile_bases[i] + '.c'
    os.makedirs(os.path.split(ofile_bases[i])[0], exist_ok=True)
    open(h_out, 'w').write(h_templ % (proto_name))
    open(c_out, 'w').write(c_templ % (proto_name, proto_name))
meson-0.53.2/test cases/common/173 preserve gendir/meson.build0000644000175000017500000000064313605171562025374 0ustar  jpakkanejpakkane00000000000000project('preserve subdir', 'c')

gprog = find_program('genprog.py')

gen = generator(gprog, \
  output    : ['@BASENAME@.c', '@BASENAME@.h'],
  arguments : ['--searchdir=@CURRENT_SOURCE_DIR@', '--outdir=@BUILD_DIR@', '@INPUT@'])

generated = gen.process('base.inp', 'com/mesonbuild/subbie.inp',
  preserve_path_from : meson.current_source_dir())

e = executable('testprog', 'testprog.c', generated)
test('testprog', e)
meson-0.53.2/test cases/common/173 preserve gendir/testprog.c0000644000175000017500000000014513571777336025257 0ustar  jpakkanejpakkane00000000000000#include"base.h"
#include"com/mesonbuild/subbie.h"

int main(void) {
    return base() + subbie();
}
meson-0.53.2/test cases/common/174 source in dep/0000755000175000017500000000000013625242363022564 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/174 source in dep/bar.cpp0000644000175000017500000000010613571777336024046 0ustar  jpakkanejpakkane00000000000000extern "C" int foo(void);

int main(void) {
    return foo() != 42;
}
meson-0.53.2/test cases/common/174 source in dep/foo.c0000644000175000017500000000004113571777336023523 0ustar  jpakkanejpakkane00000000000000int foo(void) {
    return 42;
}
meson-0.53.2/test cases/common/174 source in dep/generated/0000755000175000017500000000000013625242363024522 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/174 source in dep/generated/funname0000644000175000017500000000002613531533273026073 0ustar  jpakkanejpakkane00000000000000my_wonderful_function
meson-0.53.2/test cases/common/174 source in dep/generated/genheader.py0000755000175000017500000000033313571777336027035 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

ifile = sys.argv[1]
ofile = sys.argv[2]

templ = '''#pragma once

int %s(void) {
  return 42;
}
'''

funname = open(ifile).readline().strip()

open(ofile, 'w').write(templ % funname)
meson-0.53.2/test cases/common/174 source in dep/generated/main.c0000644000175000017500000000012413571777336025624 0ustar  jpakkanejpakkane00000000000000#include"funheader.h"

int main(void) {
    return my_wonderful_function() != 42;
}
meson-0.53.2/test cases/common/174 source in dep/generated/meson.build0000644000175000017500000000042613531533273026665 0ustar  jpakkanejpakkane00000000000000fp = find_program('genheader.py')

genh = custom_target('genh',
  input : 'funname',
  output : 'funheader.h',
  command : [fp, '@INPUT@', '@OUTPUT@'])
  
dep = declare_dependency(sources : [genh])
  
e = executable('genuser', 'main.c',
  dependencies : dep)
test('genuser', e)
meson-0.53.2/test cases/common/174 source in dep/meson.build0000644000175000017500000000022113605171563024722 0ustar  jpakkanejpakkane00000000000000project('foo', 'c', 'cpp')

dep = declare_dependency(sources : 'foo.c')

executable('bar', 'bar.cpp',
  dependencies : dep)

subdir('generated')
meson-0.53.2/test cases/common/175 generator link whole/0000755000175000017500000000000013625242363024150 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/175 generator link whole/export.h0000644000175000017500000000070213531533273025640 0ustar  jpakkanejpakkane00000000000000#pragma once

#if defined BUILDING_EMBEDDED
  #define DLL_PUBLIC
#elif defined _WIN32 || defined __CYGWIN__
  #if defined BUILDING_DLL
    #define DLL_PUBLIC __declspec(dllexport)
  #else
    #define DLL_PUBLIC __declspec(dllimport)
  #endif
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif
meson-0.53.2/test cases/common/175 generator link whole/generator.py0000755000175000017500000000115413571777336026531 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import os.path
import sys


def main():
    name = os.path.splitext(os.path.basename(sys.argv[1]))[0]
    out = sys.argv[2]
    hname = os.path.join(out, name + '.h')
    cname = os.path.join(out, name + '.c')
    print(os.getcwd(), hname)
    with open(hname, 'w') as hfile:
        hfile.write('''
#pragma once
#include "export.h"
int DLL_PUBLIC {name}(void);
'''.format(name=name))
    with open(cname, 'w') as cfile:
        cfile.write('''
#include "{name}.h"
int {name}(void) {{
    return {size};
}}
'''.format(name=name, size=len(name)))


if __name__ == '__main__':
    main()
meson-0.53.2/test cases/common/175 generator link whole/main.c0000644000175000017500000000030513571777336025253 0ustar  jpakkanejpakkane00000000000000#include "meson_test_function.h"

#include 

int main(void) {
    if (meson_test_function() != 19) {
        printf("Bad meson_test_function()\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/175 generator link whole/meson.build0000644000175000017500000000431113605171564026313 0ustar  jpakkanejpakkane00000000000000project('generator link_whole', 'c')

cc = meson.get_compiler('c')
if cc.get_id() == 'msvc'
  if cc.version().version_compare('<19')
    error('MESON_SKIP_TEST link_whole only works on VS2015 or newer.')
  endif
endif

# This just generates foo.h and foo.c with int foo() defined.
gen_py = find_program('generator.py')
gen = generator(gen_py,
  output: ['@BASENAME@.h', '@BASENAME@.c'],
  arguments : ['@INPUT@', '@BUILD_DIR@'])

# Test 1: link directly into executable
srcs = gen.process('meson_test_function.tmpl')
exe = executable('exe1', [srcs, 'main.c'], c_args : '-DBUILDING_EMBEDDED')
test('test1', exe)

# Test 2: link into shared library and access from executable
srcs = gen.process('meson_test_function.tmpl')
shlib2 = shared_library('shlib2', [srcs], c_args : '-DBUILDING_DLL')
exe = executable('exe2', 'main.c',
  link_with : shlib2,
  include_directories : shlib2.private_dir_include(),
)
test('test2', exe)

# Test 3: link into static library and access from executable
srcs = gen.process('meson_test_function.tmpl')
stlib3 = static_library('stlib3', [srcs], c_args : '-DBUILDING_EMBEDDED')
exe = executable('exe3', 'main.c',
  c_args : '-DBUILDING_EMBEDDED',
  link_with : stlib3,
  include_directories : stlib3.private_dir_include(),
)
test('test3', exe)

# Test 4: link into static library, link into shared
# and access from executable. To make sure static_library
# is not dropped use pull_meson_test_function helper.
srcs = gen.process('meson_test_function.tmpl')
stlib4 = static_library('stlib4', [srcs], c_args : '-DBUILDING_DLL')
shlib4 = shared_library('shlib4', 'pull_meson_test_function.c',
  c_args : '-DBUILDING_DLL',
  link_with : stlib4,
  include_directories : stlib4.private_dir_include(),
)
exe = executable('exe4', 'main.c',
  link_with : shlib4,
  include_directories : stlib4.private_dir_include(),
)
test('test4', exe)

# Test 5: link into static library, link_whole into shared
# and access from executable
srcs = gen.process('meson_test_function.tmpl')
stlib5 = static_library('stlib5', [srcs], c_args : '-DBUILDING_DLL')
shlib5 = shared_library('shlib5', link_whole : stlib5)
exe = executable('exe5', 'main.c',
  link_with : shlib5,
  include_directories : stlib5.private_dir_include(),
)
test('test5', exe)
meson-0.53.2/test cases/common/175 generator link whole/meson_test_function.tmpl0000644000175000017500000000000013531533273031120 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/175 generator link whole/pull_meson_test_function.c0000644000175000017500000000020113571777336031443 0ustar  jpakkanejpakkane00000000000000#include "export.h"
#include "meson_test_function.h"

int DLL_PUBLIC function_puller(void) {
    return meson_test_function();
}
meson-0.53.2/test cases/common/176 initial c_args/0000755000175000017500000000000013625242363023016 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/176 initial c_args/meson.build0000644000175000017500000000047613605171565025172 0ustar  jpakkanejpakkane00000000000000project('options', 'c')

# Test passing c_args and c_link_args options from the command line.
assert(get_option('c_args') == ['-funroll-loops'],
       'Incorrect value for c_args option.')
assert(get_option('c_link_args') == ['-Dtest_harmless_but_useless_link_arg'],
       'Incorrect value for c_link_args option.')
meson-0.53.2/test cases/common/176 initial c_args/test_args.txt0000644000175000017500000000035613531533273025555 0ustar  jpakkanejpakkane00000000000000# This file is not read by meson itself, but by the test framework.
# It is not possible to pass arguments to meson from a file.
['-Dc_args=-march=native', '-Dc_args=-funroll-loops',
 '-Dc_link_args=-Dtest_harmless_but_useless_link_arg']
meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/0000755000175000017500000000000013625242363031210 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/foo.c0000644000175000017500000000005513531533273032136 0ustar  jpakkanejpakkane00000000000000int meson_test_main_foo(void) { return 10; }
meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/main.c0000644000175000017500000000053313531533273032300 0ustar  jpakkanejpakkane00000000000000#include 

int meson_test_main_foo(void);
int meson_test_subproj_foo(void);

int main(void) {
    if (meson_test_main_foo() != 10) {
        printf("Failed meson_test_main_foo\n");
        return 1;
    }
    if (meson_test_subproj_foo() != 20) {
        printf("Failed meson_test_subproj_foo\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/meson.build0000644000175000017500000000070713605171565033361 0ustar  jpakkanejpakkane00000000000000project('subproject targets', 'c')

# Idea behind this test is to create targets with identical name
# but different output files. We can do this by choosing different
# name_prefix of libraries. Target id does not depend on name_prefix.

main_foo = static_library('foo', 'foo.c', name_prefix : 'main')
subproj_foo = subproject('subproj').get_variable('foo')

exe = executable('prog', 'main.c', link_with : [main_foo, subproj_foo])
test('main test', exe)
meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/subprojects/0000755000175000017500000000000013625242351033550 5ustar  jpakkanejpakkane00000000000000././@LongLink0000000000000000000000000000015000000000000011211 Lustar  00000000000000meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/subprojects/subproj/meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/subprojects/subpr0000755000175000017500000000000013625242363034627 5ustar  jpakkanejpakkane00000000000000././@LongLink0000000000000000000000000000015500000000000011216 Lustar  00000000000000meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/subprojects/subproj/foo.cmeson-0.53.2/test cases/common/177 identical target name in subproject flat layout/subprojects/subpr0000644000175000017500000000006013531533273034624 0ustar  jpakkanejpakkane00000000000000int meson_test_subproj_foo(void) { return 20; }
././@LongLink0000000000000000000000000000016300000000000011215 Lustar  00000000000000meson-0.53.2/test cases/common/177 identical target name in subproject flat layout/subprojects/subproj/meson.buildmeson-0.53.2/test cases/common/177 identical target name in subproject flat layout/subprojects/subpr0000644000175000017500000000012713531533273034630 0ustar  jpakkanejpakkane00000000000000project('subproj', 'c')

foo = static_library('foo', 'foo.c', name_prefix : 'subproj')
meson-0.53.2/test cases/common/178 as-needed/0000755000175000017500000000000013625242363021775 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/178 as-needed/config.h0000644000175000017500000000057713531533273023423 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #if defined BUILDING_DLL
    #define DLL_PUBLIC __declspec(dllexport)
  #else
    #define DLL_PUBLIC __declspec(dllimport)
  #endif
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif
meson-0.53.2/test cases/common/178 as-needed/libA.cpp0000644000175000017500000000015613531533273023351 0ustar  jpakkanejpakkane00000000000000#define BUILDING_DLL

#include "libA.h"

namespace meson_test_as_needed {
  DLL_PUBLIC bool linked = false;
}
meson-0.53.2/test cases/common/178 as-needed/libA.h0000644000175000017500000000013113531533273023007 0ustar  jpakkanejpakkane00000000000000#include "config.h"

namespace meson_test_as_needed {
  DLL_PUBLIC extern bool linked;
}
meson-0.53.2/test cases/common/178 as-needed/libB.cpp0000644000175000017500000000044113531533273023347 0ustar  jpakkanejpakkane00000000000000#include "libA.h"

#undef DLL_PUBLIC
#define BUILDING_DLL
#include "config.h"

namespace meson_test_as_needed {
  namespace {
    bool set_linked() {
      linked = true;
      return true;
    }
    bool stub = set_linked();
  }

  DLL_PUBLIC int libB_unused_func() {
    return 0;
  }
}
meson-0.53.2/test cases/common/178 as-needed/main.cpp0000644000175000017500000000020013571777336023432 0ustar  jpakkanejpakkane00000000000000#include 

#include "libA.h"

int main(void) {
  return !meson_test_as_needed::linked ? EXIT_SUCCESS : EXIT_FAILURE;
}
meson-0.53.2/test cases/common/178 as-needed/meson.build0000644000175000017500000000067113605171570024142 0ustar  jpakkanejpakkane00000000000000project('as-needed test', 'cpp')

# Idea behind this test is to have -Wl,--as-needed prune
# away unneeded linkages, which would otherwise cause global
# static initialiser side-effects to set a boolean to true.

# Credits for portable ISO C++ idea go to sarum9in

libA = library('A', 'libA.cpp')
libB = library('B', 'libB.cpp', link_with : libA)

main_exe = executable('C', 'main.cpp', link_with : [libA, libB])
test('main test', main_exe)
meson-0.53.2/test cases/common/179 ndebug if-release enabled/0000755000175000017500000000000013625242363024765 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/179 ndebug if-release enabled/main.c0000644000175000017500000000053013531533273026052 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int meson_test_side_effect = EXIT_FAILURE;

int meson_test_set_side_effect(void) {
    meson_test_side_effect = EXIT_SUCCESS;
    return 1;
}

int main(void) {
    // meson_test_side_effect is set only if assert is executed
    assert(meson_test_set_side_effect());
    return meson_test_side_effect;
}
meson-0.53.2/test cases/common/179 ndebug if-release enabled/meson.build0000644000175000017500000000027013605171567027133 0ustar  jpakkanejpakkane00000000000000project('ndebug enabled', 'c',
        default_options : [
          'buildtype=debugoptimized',
          'b_ndebug=if-release',
        ])

test('exe', executable('main', 'main.c'))
meson-0.53.2/test cases/common/18 array/0000755000175000017500000000000013625242363021177 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/18 array/func.c0000644000175000017500000000003513571777336022311 0ustar  jpakkanejpakkane00000000000000int func(void) { return 0; }
meson-0.53.2/test cases/common/18 array/meson.build0000644000175000017500000000017313605171322023334 0ustar  jpakkanejpakkane00000000000000project('array test', 'c')

arr = [
  'func.c',
  'prog.c']

exe = executable('prog', sources : arr)
test('arr test', exe)
meson-0.53.2/test cases/common/18 array/prog.c0000644000175000017500000000007213571777336022326 0ustar  jpakkanejpakkane00000000000000extern int func(void);

int main(void) { return func(); }
meson-0.53.2/test cases/common/180 ndebug if-release disabled/0000755000175000017500000000000013625242363025132 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/180 ndebug if-release disabled/main.c0000644000175000017500000000014413531533273026220 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
    assert(0);
    return EXIT_SUCCESS;
}
meson-0.53.2/test cases/common/180 ndebug if-release disabled/meson.build0000644000175000017500000000026213605171570027273 0ustar  jpakkanejpakkane00000000000000project('ndebug disabled', 'c',
        default_options : [
          'buildtype=release',
          'b_ndebug=if-release',
        ])

test('exe', executable('main', 'main.c'))
meson-0.53.2/test cases/common/181 subproject version/0000755000175000017500000000000013625242363023770 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/181 subproject version/meson.build0000644000175000017500000000030413605171570026126 0ustar  jpakkanejpakkane00000000000000project('subproject version', 'c',
  version : '2.3.4',
  license: 'mylicense')

subproject('a')

liba_dep = dependency('a',
  fallback: ['a', 'liba_dep'],
  version: ['>= 0.30.0', '!= 0.99.0'])

meson-0.53.2/test cases/common/181 subproject version/subprojects/0000755000175000017500000000000013625242351026330 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/181 subproject version/subprojects/a/0000755000175000017500000000000013625242363026553 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/181 subproject version/subprojects/a/meson.build0000644000175000017500000000017713531533273030721 0ustar  jpakkanejpakkane00000000000000project('mysubproject', 'c',
  version : '1.0.0',
  license : 'sublicense')

liba_dep = declare_dependency (version : '1.0.0')
meson-0.53.2/test cases/common/182 subdir_done/0000755000175000017500000000000013625242364022441 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/182 subdir_done/meson.build0000644000175000017500000000040713605171572024604 0ustar  jpakkanejpakkane00000000000000# Should run, even though main.cpp does not exist and we call error in the last line.
# subdir_done jumps to end, so both lines are not executed.

project('example exit', 'cpp')

if true
  subdir_done()
endif

executable('main', 'main.cpp')
error('Unreachable')

meson-0.53.2/test cases/common/183 bothlibraries/0000755000175000017500000000000013625242364022776 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/183 bothlibraries/libfile.c0000644000175000017500000000014013571777336024557 0ustar  jpakkanejpakkane00000000000000#include "mylib.h"

DO_EXPORT int retval = 42;

DO_EXPORT int func(void) {
    return retval;
}
meson-0.53.2/test cases/common/183 bothlibraries/main.c0000644000175000017500000000017513571777336024105 0ustar  jpakkanejpakkane00000000000000#include "mylib.h"

DO_IMPORT int func(void);
DO_IMPORT int retval;

int main(void) {
    return func() == retval ? 0 : 1;
}
meson-0.53.2/test cases/common/183 bothlibraries/meson.build0000644000175000017500000000214413605171574025143 0ustar  jpakkanejpakkane00000000000000project('both libraries linking test', 'c')

both_libs = both_libraries('mylib', 'libfile.c')
exe_shared = executable('prog-shared', 'main.c', link_with : both_libs.get_shared_lib())
exe_static = executable('prog-static', 'main.c',
                        c_args : ['-DSTATIC_COMPILATION'],
                        link_with : both_libs.get_static_lib())
exe_both = executable('prog-both', 'main.c', link_with : both_libs)

test('runtest-shared', exe_shared)
test('runtest-static', exe_static)
test('runtest-both', exe_both)

# Same as above, but using build_target()
both_libs2 = build_target('mylib2', 'libfile.c', target_type: 'both_libraries')
exe_shared2 = executable('prog-shared2', 'main.c',
                         link_with : both_libs2.get_shared_lib())
exe_static2 = executable('prog-static2', 'main.c',
                         c_args : ['-DSTATIC_COMPILATION'],
                         link_with : both_libs2.get_static_lib())
exe_both2 = executable('prog-both2', 'main.c', link_with : both_libs2)

test('runtest-shared-2', exe_shared2)
test('runtest-static-2', exe_static2)
test('runtest-both-2', exe_both2)
meson-0.53.2/test cases/common/183 bothlibraries/mylib.h0000644000175000017500000000037013531533273024261 0ustar  jpakkanejpakkane00000000000000#pragma once

#ifdef _WIN32
  #ifdef STATIC_COMPILATION
    #define DO_IMPORT extern
  #else
    #define DO_IMPORT __declspec(dllimport)
  #endif
  #define DO_EXPORT __declspec(dllexport)
#else
  #define DO_IMPORT extern
  #define DO_EXPORT
#endif
meson-0.53.2/test cases/common/184 escape and unicode/0000755000175000017500000000000013625242364023540 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/184 escape and unicode/file.c.in0000644000175000017500000000014713571777336025246 0ustar  jpakkanejpakkane00000000000000#include
const char* does_it_work(void) {
    printf("{NAME}\n");
    return "yes it does";
}
meson-0.53.2/test cases/common/184 escape and unicode/file.py0000644000175000017500000000033513531533273025030 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import os

with open(sys.argv[1]) as fh:
    content = fh.read().replace("{NAME}", sys.argv[2])

with open(os.path.join(sys.argv[3]), 'w', errors='replace') as fh:
    fh.write(content)
meson-0.53.2/test cases/common/184 escape and unicode/find.py0000644000175000017500000000025213531533273025027 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys

for fh in os.listdir('.'):
    if os.path.isfile(fh):
        if fh.endswith('.c'):
            sys.stdout.write(fh + '\0')
meson-0.53.2/test cases/common/184 escape and unicode/fun.c0000644000175000017500000000004213571777336024504 0ustar  jpakkanejpakkane00000000000000int a_fun(void) {
    return 1;
}
meson-0.53.2/test cases/common/184 escape and unicode/main.c0000644000175000017500000000027513571777336024650 0ustar  jpakkanejpakkane00000000000000#include 

const char* does_it_work(void);

int a_fun(void);

int main(void) {
    if(strcmp(does_it_work(), "yes it does") != 0) {
        return -a_fun();
    }
    return 0;
}
meson-0.53.2/test cases/common/184 escape and unicode/meson.build0000644000175000017500000000211713605171574025705 0ustar  jpakkanejpakkane00000000000000project('180 escape', 'c')

gen = generator(find_program('file.py'), arguments:['@INPUT@', 'erd\u0151', '@OUTPUT@'], output: '@BASENAME@')

gen_file = gen.process('file.c.in')

find_file_list = run_command(find_program('find.py'))
assert(find_file_list.returncode() == 0, 'Didn\'t find any files.')

# Strings should support both octal \ooo and hex \xhh encodings

found_files_oct = []
foreach l : find_file_list.stdout().strip('\0').split('\000')
  found_files_oct += [files(l)]
endforeach

test('first', executable('first', found_files_oct + [gen_file]))

found_files_hex = []
foreach l : find_file_list.stdout().strip('\x00').split('\x00')
  found_files_hex += [files(l)]
endforeach

test('second', executable('second', found_files_hex + [gen_file]))

# Unrecognized and malformed escape sequences are literal

malformed = [
 [ '\c', 'c' ],
 [ '\Uabcdefghi', 'Uabcdefghi'],
 [ '\u123 ', 'u123 '],
 [ '\xqr', 'xqr'],
]

foreach m : malformed
  assert(m[0].endswith(m[1]), 'bad escape sequence had unexpected end')
  assert(m[0].startswith('\\'), 'bad escape sequence had unexpected start')
endforeach
meson-0.53.2/test cases/common/185 has link arg/0000755000175000017500000000000013625242364022372 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/185 has link arg/meson.build0000644000175000017500000000407513605171601024533 0ustar  jpakkanejpakkane00000000000000project('has link arg', 'c', 'cpp')

cc = meson.get_compiler('c')
cpp = meson.get_compiler('cpp')

if cc.get_argument_syntax() == 'msvc'
  is_arg = '/OPT:REF'
  useless = '/DEBUG'
  isnt_arg = '/iambroken'
else
  is_arg = '-Wl,-L/tmp'
  useless = '-Wl,-L/usr'
  isnt_arg = '-Wl,-iambroken'
endif

assert(cc.has_link_argument(is_arg), 'Arg that should have worked does not work.')
assert(cpp.has_link_argument(is_arg), 'Arg that should have worked does not work.')

if cc.get_id() != 'pgi'
assert(not cc.has_link_argument(isnt_arg), 'Arg that should be broken is not.')
assert(not cpp.has_link_argument(isnt_arg), 'Arg that should be broken is not.')

assert(cc.get_supported_link_arguments([is_arg, isnt_arg, useless]) == [is_arg, useless], 'Arg filtering returned different result.')
assert(cpp.get_supported_link_arguments([is_arg, isnt_arg, useless]) == [is_arg, useless], 'Arg filtering returned different result.')

# Have useless at the end to ensure that the search goes from front to back.
l1 = cc.first_supported_link_argument([isnt_arg, is_arg, isnt_arg, useless])
l2 = cc.first_supported_link_argument(isnt_arg, isnt_arg, isnt_arg)

assert(l1.length() == 1, 'First supported returned wrong result.')
assert(l1.get(0) == is_arg, 'First supported returned wrong argument.')
assert(l2.length() == 0, 'First supported did not return empty array.')

l1 = cpp.first_supported_link_argument([isnt_arg, is_arg, isnt_arg, useless])
l2 = cpp.first_supported_link_argument(isnt_arg, isnt_arg, isnt_arg)

assert(l1.length() == 1, 'First supported returned wrong result.')
assert(l1.get(0) == is_arg, 'First supported returned wrong argument.')
assert(l2.length() == 0, 'First supported did not return empty array.')

assert(not cc.has_multi_link_arguments([isnt_arg, is_arg]), 'Arg that should be broken is not.')

assert(not cc.has_link_argument('-Wl,-z,nodelete42'), 'Did not detect wrong -z linker argument')
endif

assert(cc.has_multi_link_arguments(is_arg), 'Arg that should have worked does not work.')
assert(cc.has_multi_link_arguments([useless, is_arg]), 'Arg that should have worked does not work.')
meson-0.53.2/test cases/common/186 same target name flat layout/0000755000175000017500000000000013625242364025452 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/186 same target name flat layout/foo.c0000644000175000017500000000005513531533273026377 0ustar  jpakkanejpakkane00000000000000int meson_test_main_foo(void) { return 10; }
meson-0.53.2/test cases/common/186 same target name flat layout/main.c0000644000175000017500000000053313531533273026541 0ustar  jpakkanejpakkane00000000000000#include 

int meson_test_main_foo(void);
int meson_test_subproj_foo(void);

int main(void) {
    if (meson_test_main_foo() != 10) {
        printf("Failed meson_test_main_foo\n");
        return 1;
    }
    if (meson_test_subproj_foo() != 20) {
        printf("Failed meson_test_subproj_foo\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/186 same target name flat layout/meson.build0000644000175000017500000000066013605171576027622 0ustar  jpakkanejpakkane00000000000000project('subdir targets', 'c')

# Idea behind this test is to create targets with identical name
# but different output files. We can do this by choosing different
# name_prefix of libraries. Target id does not depend on name_prefix.

main_foo = static_library('foo', 'foo.c', name_prefix : 'main')
subdir('subdir') # defines subdir_foo

exe = executable('prog', 'main.c', link_with : [main_foo, subdir_foo])
test('main test', exe)
meson-0.53.2/test cases/common/186 same target name flat layout/subdir/0000755000175000017500000000000013625242364026742 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/186 same target name flat layout/subdir/foo.c0000644000175000017500000000006013531533273027663 0ustar  jpakkanejpakkane00000000000000int meson_test_subproj_foo(void) { return 20; }
meson-0.53.2/test cases/common/186 same target name flat layout/subdir/meson.build0000644000175000017500000000010413531533273031075 0ustar  jpakkanejpakkane00000000000000subdir_foo = static_library('foo', 'foo.c', name_prefix : 'subdir')
meson-0.53.2/test cases/common/187 find override/0000755000175000017500000000000013625242364022671 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/187 find override/meson.build0000644000175000017500000000046413605171600025027 0ustar  jpakkanejpakkane00000000000000project('find program override', 'c')

gencodegen = find_program('gencodegen', required : false)

assert(not gencodegen.found(), 'gencodegen is an internal program, should not be found')

# Test the check-if-found-else-override workflow
if not gencodegen.found()
  subdir('subdir')
endif

subdir('otherdir')
meson-0.53.2/test cases/common/187 find override/otherdir/0000755000175000017500000000000013625242364024511 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/187 find override/otherdir/main.c0000644000175000017500000000012613571777336025614 0ustar  jpakkanejpakkane00000000000000int be_seeing_you(void);

int main(void) {
    return be_seeing_you() == 6 ? 0 : 1;
}
meson-0.53.2/test cases/common/187 find override/otherdir/main2.c0000644000175000017500000000013413571777336025675 0ustar  jpakkanejpakkane00000000000000int number_returner(void);

int main(void) {
    return number_returner() == 100 ? 0 : 1;
}
meson-0.53.2/test cases/common/187 find override/otherdir/meson.build0000644000175000017500000000106613571777336026672 0ustar  jpakkanejpakkane00000000000000gen = find_program('codegen') # Should use overridden value set in "subdir".

src = custom_target('arrival',
  input : 'source.desc',
  output : 'file.c',
  command : [gen, '@INPUT@', '@OUTPUT@']
  )

e = executable('six', 'main.c', src)

test('six', e)

# The same again, but this time with a program that was generated
# with configure_file.

gen = find_program('gencodegen')

src = custom_target('hundred',
  input : 'source2.desc',
  output : 'file2.c',
  command : [gen, '@INPUT@', '@OUTPUT@']
  )

e = executable('hundred', 'main2.c', src)

test('hundred', e)
meson-0.53.2/test cases/common/187 find override/otherdir/source.desc0000644000175000017500000000001613531533273026644 0ustar  jpakkanejpakkane00000000000000be_seeing_you
meson-0.53.2/test cases/common/187 find override/otherdir/source2.desc0000644000175000017500000000002013531533273026721 0ustar  jpakkanejpakkane00000000000000number_returner
meson-0.53.2/test cases/common/187 find override/subdir/0000755000175000017500000000000013625242364024161 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/187 find override/subdir/converter.py0000755000175000017500000000037213571777336026563 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import pathlib

[ifilename, ofilename] = sys.argv[1:3]

ftempl = '''int %s(void) {
    return 6;
}
'''

d = pathlib.Path(ifilename).read_text().split('\n')[0].strip()

pathlib.Path(ofilename).write_text(ftempl % d)
meson-0.53.2/test cases/common/187 find override/subdir/gencodegen.py.in0000755000175000017500000000040113571777336027250 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import pathlib

[ifilename, ofilename] = sys.argv[1:3]

ftempl = '''int %s(void) {
    return @NUMBER@;
}
'''

d = pathlib.Path(ifilename).read_text().split('\n')[0].strip()

pathlib.Path(ofilename).write_text(ftempl % d)
meson-0.53.2/test cases/common/187 find override/subdir/meson.build0000644000175000017500000000052013531533273026316 0ustar  jpakkanejpakkane00000000000000x = find_program('converter.py')

meson.override_find_program('codegen', x)

# Override a command with a generated script

cdata = configuration_data()

cdata.set('NUMBER', 100)
numprog = configure_file(input : 'gencodegen.py.in',
  output : 'gencodegen.py',
  configuration : cdata)

meson.override_find_program('gencodegen', numprog)
meson-0.53.2/test cases/common/188 partial dependency/0000755000175000017500000000000013625242364023705 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/188 partial dependency/declare_dependency/0000755000175000017500000000000013625242364027502 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/188 partial dependency/declare_dependency/headers/0000755000175000017500000000000013625242364031115 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/188 partial dependency/declare_dependency/headers/foo.c0000644000175000017500000000121113531533273032035 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#error "Included C sources that shouldn't be."
meson-0.53.2/test cases/common/188 partial dependency/declare_dependency/headers/foo.h0000644000175000017500000000115113531533273032045 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

int foo(void);
meson-0.53.2/test cases/common/188 partial dependency/declare_dependency/main.c0000644000175000017500000000133313571777336030606 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "foo.h"

int main(void) {
    int a = foo();
    if (a == 1) {
        return 0;
    } else {
        return 1;
    }
}
meson-0.53.2/test cases/common/188 partial dependency/declare_dependency/meson.build0000644000175000017500000000170613531533273031646 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2018 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

dec_sub_dep = declare_dependency(
  include_directories : include_directories('headers'),
)

dec_dep = declare_dependency(
  sources : files('headers/foo.c'),
  dependencies : dec_sub_dep,
)

sub_dep = dec_dep.partial_dependency(includes : true)

dec_exe = executable(
  'declare_dep',
  files('main.c', 'other.c'),
  dependencies : sub_dep,
)

test('Declare Dependency', dec_exe)
meson-0.53.2/test cases/common/188 partial dependency/declare_dependency/other.c0000644000175000017500000000121413531533273030763 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "foo.h"

int foo(void) {
    return 1;
}
meson-0.53.2/test cases/common/188 partial dependency/meson.build0000644000175000017500000000122313605171600026035 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2018 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

project('partial dependency', ['c', 'cpp'])

subdir('declare_dependency')
meson-0.53.2/test cases/common/189 openmp/0000755000175000017500000000000013625242364021451 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/189 openmp/main.c0000644000175000017500000000051413531533273022537 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
#ifdef _OPENMP
    if (omp_get_max_threads() == 2) {
        return 0;
    } else {
        printf("Max threads is %d not 2.\n", omp_get_max_threads());
        return 1;
    }
#else
    printf("_OPENMP is not defined; is OpenMP compilation working?\n");
    return 1;
#endif
}
meson-0.53.2/test cases/common/189 openmp/main.cpp0000644000175000017500000000054313531533273023101 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
#ifdef _OPENMP
    if (omp_get_max_threads() == 2) {
        return 0;
    } else {
        std::cout << "Max threads is " << omp_get_max_threads() << " not 2." << std::endl;
        return 1;
    }
#else
    printf("_OPENMP is not defined; is OpenMP compilation working?\n");
    return 1;
#endif
}
meson-0.53.2/test cases/common/189 openmp/main.f900000644000175000017500000000032713531533273022715 0ustar  jpakkanejpakkane00000000000000use, intrinsic :: iso_fortran_env, only: stderr=>error_unit
use omp_lib

if (omp_get_max_threads() /= 2) then
  write(stderr, *) 'Max Fortran threads is', omp_get_max_threads(), 'not 2.'
  stop 1
endif

end program
meson-0.53.2/test cases/common/189 openmp/meson.build0000644000175000017500000000350613605171603023612 0ustar  jpakkanejpakkane00000000000000project('openmp', 'c')

cc = meson.get_compiler('c')
if cc.get_id() == 'gcc' and cc.version().version_compare('<4.2.0')
  error('MESON_SKIP_TEST gcc is too old to support OpenMP.')
endif
if cc.get_id() == 'clang' and cc.version().version_compare('<3.7.0')
  error('MESON_SKIP_TEST clang is too old to support OpenMP.')
endif
if cc.get_id() == 'msvc' and cc.version().version_compare('<17')
  error('MESON_SKIP_TEST msvc is too old to support OpenMP.')
endif
if cc.get_id() == 'clang-cl'
  error('MESON_SKIP_TEST clang-cl does not support OpenMP.')
endif
if cc.get_id() == 'clang' and host_machine.system() == 'windows'
  error('MESON_SKIP_TEST Windows clang does not support OpenMP.')
endif
if host_machine.system() == 'darwin'
  error('MESON_SKIP_TEST macOS does not support OpenMP.')
endif

openmp = dependency('openmp')
env = environment()
env.set('OMP_NUM_THREADS', '2')

exec = executable('exec',
  'main.c',
  dependencies : [openmp])
test('OpenMP C', exec, env : env)

if not(build_machine.system() == 'windows' and cc.get_id() == 'pgi')
  if add_languages('cpp', required : false)
    execpp = executable('execpp',
      'main.cpp',
      dependencies : [openmp])
    test('OpenMP C++', execpp, env : env)
  endif
endif

if add_languages('fortran', required : false)
  # Mixing compilers (msvc/clang with gfortran) does not seem to work on Windows.
  if build_machine.system() != 'windows' or cc.get_id() == 'gnu'
    exef = executable('exef',
      'main.f90',
      dependencies : [openmp])
    test('OpenMP Fortran', exef, env : env)

    openmp_f = dependency('openmp', language : 'fortran')
    exe_f = executable('exe_f',
      'main.f90',
      dependencies : [openmp_f])
    test('OpenMP Fortran-specific', exe_f, env : env)
  endif
endif

# Check we can apply a version constraint
dependency('openmp', version: '>=@0@'.format(openmp.version()))
meson-0.53.2/test cases/common/19 includedir/0000755000175000017500000000000013625242364022205 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/19 includedir/include/0000755000175000017500000000000013625242364023630 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/19 includedir/include/func.h0000644000175000017500000000007313571777336024750 0ustar  jpakkanejpakkane00000000000000#ifndef FUNC_H__
#define FUNC_H__

int func(void);

#endif
meson-0.53.2/test cases/common/19 includedir/meson.build0000644000175000017500000000012513605171323024337 0ustar  jpakkanejpakkane00000000000000project('include dir test', 'c')

inc = include_directories('include')
subdir('src')
meson-0.53.2/test cases/common/19 includedir/src/0000755000175000017500000000000013625242364022774 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/19 includedir/src/func.c0000644000175000017500000000006413571777336024107 0ustar  jpakkanejpakkane00000000000000#include "func.h"

int func(void) {
    return 0;
}
meson-0.53.2/test cases/common/19 includedir/src/meson.build0000644000175000017500000000031713426772647025152 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.c', 'func.c', include_directories : inc)
test('inc test', exe)

exe2 = executable('prog2', 'prog.c', 'func.c', include_directories : [['../include']])
test('inc test 2', exe2)
meson-0.53.2/test cases/common/19 includedir/src/prog.c0000644000175000017500000000007113571777336024121 0ustar  jpakkanejpakkane00000000000000#include "func.h"

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/190 same target name/0000755000175000017500000000000013625242364023240 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/190 same target name/file.c0000644000175000017500000000004113571777336024332 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 0;
}
meson-0.53.2/test cases/common/190 same target name/meson.build0000644000175000017500000000011113605171604025367 0ustar  jpakkanejpakkane00000000000000project('same name', 'c')

static_library('foo', 'file.c')
subdir('sub')
meson-0.53.2/test cases/common/190 same target name/sub/0000755000175000017500000000000013625242364024031 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/190 same target name/sub/file2.c0000644000175000017500000000004113571777336025205 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 5;
}
meson-0.53.2/test cases/common/190 same target name/sub/meson.build0000644000175000017500000000004113531533273026164 0ustar  jpakkanejpakkane00000000000000static_library('foo', 'file2.c')
meson-0.53.2/test cases/common/191 test depends/0000755000175000017500000000000013625242364022526 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/191 test depends/gen.py0000755000175000017500000000027013531533273023651 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys


def main():
    with open(sys.argv[1], 'w') as out:
        out.write(sys.argv[2])
        out.write('\n')


if __name__ == '__main__':
    main()
meson-0.53.2/test cases/common/191 test depends/main.c0000644000175000017500000000003513531533273023612 0ustar  jpakkanejpakkane00000000000000int main(void) { return 0; }
meson-0.53.2/test cases/common/191 test depends/meson.build0000644000175000017500000000121113605171604024657 0ustar  jpakkanejpakkane00000000000000project('test depends', 'c')

gen = find_program('gen.py')

custom_dep = custom_target('custom_dep',
  build_by_default : false,
  output : 'custom_dep.txt',
  command : [gen, '@OUTPUT@', 'custom_dep'],
)

exe_dep = executable('exe_dep', 'main.c',
  build_by_default : false,
)

test_prog = find_program('test.py')
test('string dependencies', test_prog,
  args : [
    # This is declared for convenience,
    # real use case might have some obscure method
    # to find these dependencies, e.g. automatic plugin loading.
    'custom_dep.txt',
    exe_dep.full_path(),
  ],
  depends : [custom_dep, exe_dep],
  workdir : meson.current_build_dir(),
)
meson-0.53.2/test cases/common/191 test depends/test.py0000755000175000017500000000054413531533273024063 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import os.path
import sys


def main():
    print('Looking in:', os.getcwd())
    not_found = list()
    for f in sys.argv[1:]:
        if not os.path.exists(f):
            not_found.append(f)
    if not_found:
        print('Not found:', ', '.join(not_found))
        sys.exit(1)


if __name__ == '__main__':
    main()
meson-0.53.2/test cases/common/192 args flattening/0000755000175000017500000000000013625242364023215 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/192 args flattening/meson.build0000644000175000017500000000141413605171605025354 0ustar  jpakkanejpakkane00000000000000project('args flattening')

arr = get_variable('does-not-exist', ['bar', 'baz'])

assert(arr == ['bar', 'baz'], 'get_variable with array fallback is broken')

set_variable('arr', ['bar', 'baz'])

assert(arr == ['bar', 'baz'], 'set_variable(array) is broken')

conf = configuration_data()

conf.set('foo', ['bar', 'baz'])

assert(conf.get('foo') == ['bar', 'baz'], 'configuration_data.set(array) is broken')

arr = conf.get('does-not-exist', ['bar', 'baz'])

assert(arr == ['bar', 'baz'], 'configuration_data.get with array fallback is broken')

arr = meson.get_cross_property('does-not-exist', ['bar', 'baz'])

assert(arr == ['bar', 'baz'], 'meson.get_cross_property with array fallback is broken')

# Test deprecated behaviour

conf.set(['foo', 'bar'])

message(conf.get('foo'))
meson-0.53.2/test cases/common/193 dict/0000755000175000017500000000000013625242364021071 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/193 dict/meson.build0000644000175000017500000000412513605171607023234 0ustar  jpakkanejpakkane00000000000000project('dict test', 'c')

dict = {'foo' : 'bar',
        'baz' : 'foo',
        'foo bar': 'baz'}

exe = executable('prog', sources : ['prog.c'])

i = 0

foreach key, value : dict
  test('dict test @0@'.format(key), exe,
    args : [dict[key], value])
  i += 1
endforeach

assert(i == 3, 'There should be three elements in that dictionary')

empty_dict = {}

foreach key, value : empty_dict
  assert(false, 'This dict should be empty')
endforeach

d1 = empty_dict + {'a' : 'b'}
assert(d1 == {'a' : 'b'}, 'dict addition is not working')

d2 = d1 + {'a' : 'b2', 'c' : 'd'}
assert(d2 == {'a' : 'b2', 'c' : 'd'}, 'dict addition is not working')
assert(d1 == {'a' : 'b'}, 'dict should be immutable')

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')
meson-0.53.2/test cases/common/193 dict/prog.c0000644000175000017500000000017413531533273022204 0ustar  jpakkanejpakkane00000000000000#include 

int main(int argc, char **argv) {
  if (argc != 3)
    return 1;

  return strcmp(argv[1], argv[2]);
}
meson-0.53.2/test cases/common/194 check header/0000755000175000017500000000000013625242364022435 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/194 check header/meson.build0000644000175000017500000000355113605171610024574 0ustar  jpakkanejpakkane00000000000000project('check header', 'c', 'cpp')

host_system = host_machine.system()

non_existent_header = 'ouagadougou.h'

# Copy it into the builddir to ensure that it isn't found even if it's there
configure_file(input : non_existent_header,
  output : non_existent_header,
  copy: true)

fallback = ''

foreach comp : [meson.get_compiler('c'), meson.get_compiler('cpp')]
  assert(comp.check_header('stdio.h', prefix : fallback), 'Stdio missing.')

  # stdio.h doesn't actually need stdlib.h, but just test that setting the
  # prefix does not result in an error.
  assert(comp.check_header('stdio.h', prefix : '#include ' + fallback),
         'Stdio missing.')

  # Test that check_header behaves differently than has_header. The second
  # check without windows.h will fail with check_header.
  # We only do this check on MSVC because MinGW often defines its own wrappers
  # that pre-include windows.h
  if comp.get_id() == 'msvc'
    assert(comp.check_header('XInput.h', prefix : '#include ' + fallback),
           'XInput.h should not be missing on Windows')
    assert(not comp.check_header('XInput.h'), 'XInput.h needs windows.h')
  endif

  # Test that the following GCC bug doesn't happen:
  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80005
  # https://github.com/mesonbuild/meson/issues/1458
  if host_system == 'linux'
    assert(comp.check_header('linux/socket.h', prefix : fallback),
           'Could not find ')
    if comp.has_header('intrin.h', prefix : fallback)
      assert(not comp.check_header('intrin.h'),
             'intrin.h should not be usable on linux')
    endif
  endif

  # This header exists in the source and the builddir, but we still must not
  # find it since we are looking in the system directories.
  assert(not comp.check_header(non_existent_header, prefix : fallback),
         'Found non-existent header.')
endforeach
meson-0.53.2/test cases/common/194 check header/ouagadougou.h0000644000175000017500000000004313531533273025120 0ustar  jpakkanejpakkane00000000000000#define OMG_THIS_SHOULDNT_BE_FOUND
meson-0.53.2/test cases/common/195 install_mode/0000755000175000017500000000000013625242364022622 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/195 install_mode/config.h.in0000644000175000017500000000017013531533273024641 0ustar  jpakkanejpakkane00000000000000#define MESSAGE "@var@"
#define OTHER "@other@" "@second@" "@empty@"

#mesondefine BE_TRUE
#mesondefine SHOULD_BE_UNDEF
meson-0.53.2/test cases/common/195 install_mode/data_source.txt0000644000175000017500000000004013531533273025644 0ustar  jpakkanejpakkane00000000000000This is a text only input file.
meson-0.53.2/test cases/common/195 install_mode/foo.10000644000175000017500000000007013531533273023462 0ustar  jpakkanejpakkane00000000000000this is a man page of foo.1 its contents are irrelevant
meson-0.53.2/test cases/common/195 install_mode/installed_files.txt0000644000175000017500000000034713531533273026526 0ustar  jpakkanejpakkane00000000000000usr/bin/runscript.sh
usr/bin/trivialprog?exe
?msvc:usr/bin/trivialprog.pdb
usr/include/config.h
usr/include/rootdir.h
usr/libtest/libstat.a
usr/share/man/man1/foo.1
usr/share/sub1/second.dat
usr/share/sub2/stub
usr/subdir/data.dat
meson-0.53.2/test cases/common/195 install_mode/meson.build0000644000175000017500000000302513605171610024755 0ustar  jpakkanejpakkane00000000000000project('install_mode test', 'c',
  default_options : ['install_umask=027', 'libdir=libtest'])

if build_machine.system() == 'windows'
  error('MESON_SKIP_TEST: install_mode test requires a Unix-like OS')
endif

# confirm no regressions in install_data
install_data('runscript.sh',
  install_dir : get_option('bindir'),
  install_mode : ['rwxr-sr-x', 'root', 0])

# confirm no regressions in install_subdir
install_subdir('sub1',
  install_dir : 'share',
  install_mode : ['rwxr-x--t', 'root'])

install_subdir('sub2',
  install_dir : 'share')

# test install_mode in configure_file
conf = configuration_data()
conf.set('var', 'mystring')
conf.set('other', 'string 2')
conf.set('second', ' bonus')
conf.set('BE_TRUE', true)
configure_file(input : 'config.h.in',
  output : 'config.h',
  configuration : conf,
  install_dir : 'include',
  install_mode : 'rw-rwSr--')

# test install_mode in custom_target
custom_target('bindat',
  output : 'data.dat',
  input : 'data_source.txt',
  command : ['cp', '@INPUT@', '@OUTPUT@'],
  install : true,
  install_dir : 'subdir',
  install_mode : 'rw-rwSr--')

# test install_mode in install_headers
install_headers('rootdir.h',
  install_mode : 'r--r--r-T')

# test install_mode in install_man
install_man('foo.1',
  install_mode : 'r--r--r-T')

# test install_mode in executable
executable('trivialprog',
  sources : 'trivial.c',
  install : true,
  install_mode : ['rwxr-sr-x', 'root', 'root'])

# test install_mode in static_library
static_library('stat', 'stat.c',
  install : true,
  install_mode : ['rw---Sr--'])
meson-0.53.2/test cases/common/195 install_mode/rootdir.h0000644000175000017500000000007613531533273024456 0ustar  jpakkanejpakkane00000000000000/* This header goes to include dir root. */

int root_func();
meson-0.53.2/test cases/common/195 install_mode/runscript.sh0000644000175000017500000000003413531533273025202 0ustar  jpakkanejpakkane00000000000000#!/bin/sh

echo "Runscript"
meson-0.53.2/test cases/common/195 install_mode/stat.c0000644000175000017500000000003713571777336023755 0ustar  jpakkanejpakkane00000000000000int func(void) { return 933; }
meson-0.53.2/test cases/common/195 install_mode/sub1/0000755000175000017500000000000013625242364023474 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/195 install_mode/sub1/second.dat0000644000175000017500000000006613531533273025441 0ustar  jpakkanejpakkane00000000000000Test that multiple install_subdirs meld their results.meson-0.53.2/test cases/common/195 install_mode/sub2/0000755000175000017500000000000013625242364023475 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/195 install_mode/sub2/stub0000644000175000017500000000000013531533273024361 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/195 install_mode/trivial.c0000644000175000017500000000013613571777336024454 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("Trivial test is working.\n");
    return 0;
}
meson-0.53.2/test cases/common/196 subproject array version/0000755000175000017500000000000013625242364025076 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/196 subproject array version/meson.build0000644000175000017500000000011513605171610027226 0ustar  jpakkanejpakkane00000000000000project('master', 'c')

x = subproject('foo', version : ['>=1.0.0', '<2.0'])
meson-0.53.2/test cases/common/196 subproject array version/subprojects/0000755000175000017500000000000013625242351027435 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/196 subproject array version/subprojects/foo/0000755000175000017500000000000013625242364030224 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/196 subproject array version/subprojects/foo/meson.build0000644000175000017500000000004713531533273032365 0ustar  jpakkanejpakkane00000000000000project('foo', 'c', version : '1.0.0')
meson-0.53.2/test cases/common/197 feature option/0000755000175000017500000000000013625242364023076 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/197 feature option/meson.build0000644000175000017500000000351013605171612025232 0ustar  jpakkanejpakkane00000000000000project('feature user option', 'c')

feature_opts = get_option('auto_features')
required_opt = get_option('required')
optional_opt = get_option('optional')
disabled_opt = get_option('disabled')

assert(not feature_opts.enabled(), 'Should be auto option')
assert(not feature_opts.disabled(), 'Should be auto option')
assert(feature_opts.auto(), 'Should be auto option')

assert(required_opt.enabled(), 'Should be enabled option')
assert(not required_opt.disabled(), 'Should be enabled option')
assert(not required_opt.auto(), 'Should be enabled option')

assert(not optional_opt.enabled(), 'Should be auto option')
assert(not optional_opt.disabled(), 'Should be auto option')
assert(optional_opt.auto(), 'Should be auto option')

assert(not disabled_opt.enabled(), 'Should be disabled option')
assert(disabled_opt.disabled(), 'Should be disabled option')
assert(not disabled_opt.auto(), 'Should be disabled option')

dep = dependency('threads', required : required_opt)
assert(dep.found(), 'Should find required "threads" dep')

dep = dependency('threads', required : optional_opt)
assert(dep.found(), 'Should find optional "threads" dep')

dep = dependency('threads', required : disabled_opt)
assert(not dep.found(), 'Should not find disabled "threads" dep')

dep = dependency('notfounddep', required : optional_opt)
assert(not dep.found(), 'Should not find optional "notfounddep" dep')

dep = dependency('notfounddep', required : disabled_opt)
assert(not dep.found(), 'Should not find disabled "notfounddep" dep')

cc = meson.get_compiler('c')
lib = cc.find_library('m', required : disabled_opt)
assert(not lib.found(), 'Should not find "m" library')

cp = find_program('cp', required : disabled_opt)
assert(not cp.found(), 'Should not find "cp" program')

found = add_languages('cpp', required : disabled_opt)
assert(not found, 'Should not find "cpp" language')
meson-0.53.2/test cases/common/197 feature option/meson_options.txt0000644000175000017500000000042413531533273026531 0ustar  jpakkanejpakkane00000000000000option('required', type : 'feature', value : 'enabled', description : 'An required feature')
option('optional', type : 'feature', value : 'auto', description : 'An optional feature')
option('disabled', type : 'feature', value : 'disabled', description : 'A disabled feature')
meson-0.53.2/test cases/common/198 feature option disabled/0000755000175000017500000000000013625242364024627 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/198 feature option disabled/meson.build0000644000175000017500000000175513605171613026775 0ustar  jpakkanejpakkane00000000000000project('feature user option', 'c',
  default_options : ['auto_features=disabled'])

feature_opts = get_option('auto_features')
required_opt = get_option('required')
optional_opt = get_option('optional')
disabled_opt = get_option('disabled')

assert(not feature_opts.enabled(), 'Should be disabled option')
assert(feature_opts.disabled(), 'Should be disabled option')
assert(not feature_opts.auto(), 'Should be disabled option')

assert(required_opt.enabled(), 'Should be enabled option')
assert(not required_opt.disabled(), 'Should be enabled option')
assert(not required_opt.auto(), 'Should be enabled option')

assert(not optional_opt.enabled(), 'Auto feature should be disabled')
assert(optional_opt.disabled(), 'Auto feature should be disabled')
assert(not optional_opt.auto(), 'Auto feature should be disabled')

assert(not disabled_opt.enabled(), 'Should be disabled option')
assert(disabled_opt.disabled(), 'Should be disabled option')
assert(not disabled_opt.auto(), 'Should be disabled option')
meson-0.53.2/test cases/common/198 feature option disabled/meson_options.txt0000644000175000017500000000042413531533273030262 0ustar  jpakkanejpakkane00000000000000option('required', type : 'feature', value : 'enabled', description : 'An required feature')
option('optional', type : 'feature', value : 'auto', description : 'An optional feature')
option('disabled', type : 'feature', value : 'disabled', description : 'A disabled feature')
meson-0.53.2/test cases/common/199 static threads/0000755000175000017500000000000013625242364023056 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/199 static threads/lib1.c0000644000175000017500000000025313531533273024047 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32
#include
#else
#include
#endif

void *f(void) {
#if defined _WIN32
  return CreateThread;
#else
  return pthread_create;
#endif
}
meson-0.53.2/test cases/common/199 static threads/lib2.c0000644000175000017500000000006713531533273024053 0ustar  jpakkanejpakkane00000000000000extern void *f(void);

void *g(void) {
  return f();
}
meson-0.53.2/test cases/common/199 static threads/meson.build0000644000175000017500000000044413605171613025216 0ustar  jpakkanejpakkane00000000000000project('threads', 'c')

thread_dep = dependency('threads')


lib1 = static_library('lib1', 'lib1.c',
                      dependencies : thread_dep)

lib2 = static_library('lib2', 'lib2.c',
                       link_with : lib1)

executable('prog', 'prog.c',
           link_with : lib2)
meson-0.53.2/test cases/common/199 static threads/prog.c0000644000175000017500000000007513531533273024171 0ustar  jpakkanejpakkane00000000000000extern void *g(void);

int main(void) {
  g();
  return 0;
}
meson-0.53.2/test cases/common/2 cpp/0000755000175000017500000000000013625242364020555 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/2 cpp/meson.build0000644000175000017500000000156213605171303022713 0ustar  jpakkanejpakkane00000000000000project('c++ test', 'cpp')

cpp = meson.get_compiler('cpp')
if cpp.get_id() == 'intel'
  # Error out if the -std=xxx option is incorrect
  add_project_arguments('-diag-error', '10159', language : 'cpp')
elif cpp.get_id() == 'intel-cl'
  add_project_arguments('/Qdiag-error:10159', language : 'cpp')
endif

exe = executable('trivialprog', 'trivial.cc', extra_files : 'something.txt')
test('runtest', exe)

has_not_changed = false
if is_disabler(exe)
    has_not_changed = true
else
    has_not_changed = true
endif
assert(has_not_changed, 'Executable has changed.')

assert(not is_disabler(exe), 'Executable is a disabler.')

exe = executable('trivialprog', 'trivial.cc', extra_files : disabler())

assert(is_disabler(exe), 'Executable is not a disabler.')

if exe.found()
  exe_disabled = false
else
  exe_disabled = true
endif

assert(exe_disabled, 'Executable was not disabled.')
meson-0.53.2/test cases/common/2 cpp/something.txt0000644000175000017500000000010612650745767023324 0ustar  jpakkanejpakkane00000000000000This file is only here so it shows up in IDEs as part of this target.
meson-0.53.2/test cases/common/2 cpp/trivial.cc0000644000175000017500000000015313571777336022551 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
  std::cout << "C++ seems to be working." << std::endl;
  return 0;
}
meson-0.53.2/test cases/common/20 header in file list/0000755000175000017500000000000013625242364023526 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/20 header in file list/header.h0000644000175000017500000000002213605170650025115 0ustar  jpakkanejpakkane00000000000000#include
meson-0.53.2/test cases/common/20 header in file list/meson.build0000644000175000017500000000111513605171325025662 0ustar  jpakkanejpakkane00000000000000project('header in file list', 'c')

cc_id  = meson.get_compiler('c').get_id()
cc_ver = meson.get_compiler('c').version()

if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08'))
  # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
  # (correctly) thinks that the rule has multiple outputs and errors out:
  # 'depfile has multiple output paths'
  error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
endif

exe = executable('prog', 'prog.c', 'header.h')
test('basic', exe)
meson-0.53.2/test cases/common/20 header in file list/prog.c0000644000175000017500000000006213571777336024653 0ustar  jpakkanejpakkane00000000000000#include "header.h"

int main(void) { return 0; }
meson-0.53.2/test cases/common/200 generator in subdir/0000755000175000017500000000000013625242364023761 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/200 generator in subdir/com/0000755000175000017500000000000013625242351024533 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/200 generator in subdir/com/mesonbuild/0000755000175000017500000000000013625242364026700 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/200 generator in subdir/com/mesonbuild/genprog.py0000644000175000017500000000226213571777336030731 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os, sys, argparse

h_templ = '''#pragma once

int %s(void);
'''

c_templ = '''#include"%s.h"

int %s(void) {
    return 0;
}
'''

parser = argparse.ArgumentParser()
parser.add_argument('--searchdir', required=True)
parser.add_argument('--outdir', required=True)
parser.add_argument('ifiles', nargs='+')

options = parser.parse_args()

searchdir = options.searchdir
outdir = options.outdir
ifiles = options.ifiles

rel_ofiles = []

for ifile in ifiles:
    if not ifile.startswith(options.searchdir):
        sys.exit('Input file %s does not start with search dir %s.' % (ifile, searchdir))
    rel_ofile = ifile[len(searchdir):]
    if rel_ofile[0] == '/' or rel_ofile[0] == '\\':
        rel_ofile = rel_ofile[1:]
    rel_ofiles.append(os.path.splitext(rel_ofile)[0])

ofile_bases = [os.path.join(outdir, i) for i in rel_ofiles]

for i, ifile_name in enumerate(ifiles):
    proto_name = open(ifile_name).readline().strip()
    h_out = ofile_bases[i] + '.h'
    c_out = ofile_bases[i] + '.c'
    os.makedirs(os.path.split(ofile_bases[i])[0], exist_ok=True)
    open(h_out, 'w').write(h_templ % (proto_name))
    open(c_out, 'w').write(c_templ % (proto_name, proto_name))
meson-0.53.2/test cases/common/200 generator in subdir/com/mesonbuild/meson.build0000644000175000017500000000046413531533273031044 0ustar  jpakkanejpakkane00000000000000gprog = find_program('genprog.py')

gen = generator(gprog, \
  output    : ['@BASENAME@.c', '@BASENAME@.h'],
  arguments : ['--searchdir=@CURRENT_SOURCE_DIR@', '--outdir=@BUILD_DIR@', '@INPUT@'])

generated = gen.process('subbie.inp')

e = executable('testprog', 'testprog.c', generated)
test('testprog', e)
meson-0.53.2/test cases/common/200 generator in subdir/com/mesonbuild/subbie.inp0000644000175000017500000000000713531533273030654 0ustar  jpakkanejpakkane00000000000000subbie
meson-0.53.2/test cases/common/200 generator in subdir/com/mesonbuild/testprog.c0000644000175000017500000000007413571777336030730 0ustar  jpakkanejpakkane00000000000000#include"subbie.h"

int main(void) {
    return subbie();
}
meson-0.53.2/test cases/common/200 generator in subdir/meson.build0000644000175000017500000000007613605171614026123 0ustar  jpakkanejpakkane00000000000000project('generator in subdir', 'c')

subdir('com/mesonbuild')
meson-0.53.2/test cases/common/201 override with exe/0000755000175000017500000000000013625242365023452 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/201 override with exe/main2.input0000644000175000017500000000000013531533273025524 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/201 override with exe/meson.build0000644000175000017500000000075113605171616025615 0ustar  jpakkanejpakkane00000000000000project('myexe', 'c')
sub = subproject('sub')
prog = find_program('foobar')
custom1 = custom_target('custom1',
                        build_by_default : true,
                        input : [],
                        output : 'main1.c',
                        command : [prog, '@OUTPUT@'])
gen = generator(prog,
                output : '@BASENAME@.c',
                arguments : ['@OUTPUT@'])
custom2 = gen.process('main2.input')

executable('e1', custom1)
executable('e2', custom2)
meson-0.53.2/test cases/common/201 override with exe/subprojects/0000755000175000017500000000000013625242351026010 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/201 override with exe/subprojects/sub/0000755000175000017500000000000013625242365026606 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/201 override with exe/subprojects/sub/foobar.c0000644000175000017500000000047413571777336030242 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(int argc, char* argv[]) {
  assert(argc == 2);
  FILE *f = fopen(argv[1], "w");
  const char msg[] = "int main(void) {return 0;}\n";
  size_t w = fwrite(msg, 1, sizeof(msg) - 1, f);
  assert(w == sizeof(msg) - 1);
  int r = fclose(f);
  assert(r == 0);
  return 0;
}
meson-0.53.2/test cases/common/201 override with exe/subprojects/sub/meson.build0000644000175000017500000000017413531533273030747 0ustar  jpakkanejpakkane00000000000000project('sub', 'c')
foobar = executable('foobar', 'foobar.c',  native : true)
meson.override_find_program('foobar', foobar)
meson-0.53.2/test cases/common/202 subproject with features/0000755000175000017500000000000013625242365025051 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/202 subproject with features/meson.build0000644000175000017500000000200513605171616027206 0ustar  jpakkanejpakkane00000000000000project('proj', 'c')

auto_subproj = subproject('sub', required: get_option('use-subproject'))
assert(auto_subproj.found(), 'Subproject should always be buildable and thus found')

auto_dep = dependency('', fallback: ['sub', 'libSub'], required: true)
assert(auto_dep.found() == true, 'Subproject is required and foundable, dependency should be found.')

disabled_subproj = subproject('disabled_sub', required: get_option('disabled-subproject'))
assert(disabled_subproj.found() == false, 'Disabled subproject should be NOT found')

disabled_dep = dependency('', fallback: ['disabled_sub', 'libSub'], required: false)
assert(disabled_dep.found() == false, 'Subprojetc was disabled, it should never be built.')
nothing = executable('nothing', 'nothing.c', dependencies: [disabled_dep])

subproj_with_missing_dep = subproject('auto_sub_with_missing_dep', required: get_option('auto-sub-with-missing-dep'))
assert(subproj_with_missing_dep.found() == false, 'Subproject with required=auto and missing dependency should be NOT found')
meson-0.53.2/test cases/common/202 subproject with features/meson_options.txt0000644000175000017500000000030513531533273030501 0ustar  jpakkanejpakkane00000000000000option('use-subproject', type : 'feature', value : 'auto')
option('disabled-subproject', type : 'feature', value : 'disabled')
option('auto-sub-with-missing-dep', type : 'feature', value : 'auto')
meson-0.53.2/test cases/common/202 subproject with features/nothing.c0000644000175000017500000000004113571777336026671 0ustar  jpakkanejpakkane00000000000000int main(void)
{
    return 0;
}
meson-0.53.2/test cases/common/202 subproject with features/subprojects/0000755000175000017500000000000013625242351027407 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/202 subproject with features/subprojects/auto_sub_with_missing_dep/0000755000175000017500000000000013625242365034651 5ustar  jpakkanejpakkane00000000000000././@LongLink0000000000000000000000000000015600000000000011217 Lustar  00000000000000meson-0.53.2/test cases/common/202 subproject with features/subprojects/auto_sub_with_missing_dep/meson.buildmeson-0.53.2/test cases/common/202 subproject with features/subprojects/auto_sub_with_missing_dep/me0000644000175000017500000000010513531533273035166 0ustar  jpakkanejpakkane00000000000000project('sub', 'c')

dependency('no_way_this_exists', required: true)meson-0.53.2/test cases/common/202 subproject with features/subprojects/disabled_sub/0000755000175000017500000000000013625242365032034 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/202 subproject with features/subprojects/disabled_sub/lib/0000755000175000017500000000000013625242365032602 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/202 subproject with features/subprojects/disabled_sub/lib/meson.build0000644000175000017500000000020013531533273034731 0ustar  jpakkanejpakkane00000000000000lib = static_library('sub', 'sub.c')

libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)meson-0.53.2/test cases/common/202 subproject with features/subprojects/disabled_sub/lib/sub.c0000644000175000017500000000006213571777336033550 0ustar  jpakkanejpakkane00000000000000#include "sub.h"

int sub(void) {
    return 0;
}
meson-0.53.2/test cases/common/202 subproject with features/subprojects/disabled_sub/lib/sub.h0000644000175000017500000000006013531533273033535 0ustar  jpakkanejpakkane00000000000000#ifndef SUB_H
#define SUB_H

int sub();

#endif
meson-0.53.2/test cases/common/202 subproject with features/subprojects/disabled_sub/meson.build0000644000175000017500000000005313531533273034171 0ustar  jpakkanejpakkane00000000000000project('disabled_sub', 'c')

subdir('lib')meson-0.53.2/test cases/common/202 subproject with features/subprojects/sub/0000755000175000017500000000000013625242365030205 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/202 subproject with features/subprojects/sub/lib/0000755000175000017500000000000013625242365030753 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/202 subproject with features/subprojects/sub/lib/meson.build0000644000175000017500000000020013531533273033102 0ustar  jpakkanejpakkane00000000000000lib = static_library('sub', 'sub.c')
libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)
meson-0.53.2/test cases/common/202 subproject with features/subprojects/sub/lib/sub.c0000644000175000017500000000006013571777336031717 0ustar  jpakkanejpakkane00000000000000#include "sub.h"

int sub(void) {
  return 0;
}
meson-0.53.2/test cases/common/202 subproject with features/subprojects/sub/lib/sub.h0000644000175000017500000000006413571777336031730 0ustar  jpakkanejpakkane00000000000000#ifndef SUB_H
#define SUB_H

int sub(void);

#endif
meson-0.53.2/test cases/common/202 subproject with features/subprojects/sub/meson.build0000644000175000017500000000004213531533273032340 0ustar  jpakkanejpakkane00000000000000project('sub', 'c')

subdir('lib')meson-0.53.2/test cases/common/203 function attributes/0000755000175000017500000000000013625242365024133 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/203 function attributes/meson.build0000644000175000017500000000643413605171624026301 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017-2018 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

project('gcc func attributes', ['c', 'cpp'])

# For msvc these will fail because msvc doesn't support __attribute__, for
# Clang and GCC, they should pass.
c = meson.get_compiler('c')
cpp = meson.get_compiler('cpp')

if c.get_id() == 'pgi'
  error('MESON_SKIP_TEST: PGI supports its own set of features, will need a separate list for PGI to test it.')
endif

expected_result = not ['msvc', 'clang-cl', 'intel-cl'].contains(c.get_id())

# Q: Why is ifunc not in this list or any of the below lists?
# A: It's too damn hard to figure out if you actually support it, since it
#    requires both compiler and libc support, and there isn't a good way to
#    figure that out except by running the code we're trying to test.
attributes = [
  'aligned',
  'alloc_size',
  'always_inline',
  'cold',
  'const',
  'constructor',
  'constructor_priority',
  'deprecated',
  'destructor',
  'flatten',
  'format',
  'format_arg',
  'gnu_inline',
  'hot',
  'malloc',
  'noinline',
  'nonnull',
  'noreturn',
  'nothrow',
  'pure',
  'unused',
  'used',
  'warn_unused_result',
  'weak',
]

if c.get_id() != 'intel'
  # not supported by icc as of 19.0.0
  attributes += 'weakref'
endif

# These are unsupported on darwin with apple clang 9.1.0
if host_machine.system() != 'darwin'
  attributes += 'alias'
  attributes += 'visibility'
endif

if ['gcc', 'intel'].contains(c.get_id())
  # not supported by clang as of 5.0.0 (at least up to 6.0.1)
  attributes += 'artificial'
  attributes += 'error'
  attributes += 'externally_visible'
  attributes += 'leaf'
  attributes += 'noclone'
  attributes += 'optimize'
  attributes += 'warning'

  if c.get_id() == 'gcc' and c.version().version_compare('>= 7.0.0')
    attributes += 'fallthrough'
  endif
endif


foreach a : attributes
  x = c.has_function_attribute(a)
  assert(x == expected_result, '@0@: @1@'.format(c.get_id(), a))
  x = cpp.has_function_attribute(a)
  assert(x == expected_result, '@0@: @1@'.format(cpp.get_id(), a))
endforeach

win_expect = ['windows', 'cygwin'].contains(host_machine.system())
foreach a : ['dllexport', 'dllimport']
  assert(c.has_function_attribute(a) == win_expect,
         '@0@: @1@'.format(c.get_id(), a))
  assert(cpp.has_function_attribute(a) == win_expect,
         '@0@: @1@'.format(cpp.get_id(), a))
endforeach

message('checking get_supported_function_attributes')
if not ['msvc', 'clang-cl', 'intel-cl'].contains(c.get_id())
  multi_expected = attributes
else
  multi_expected = []
endif

multi_check = c.get_supported_function_attributes(attributes)
assert(multi_check == multi_expected, 'get_supported_function_arguments works (C)')
multi_check = cpp.get_supported_function_attributes(attributes)
assert(multi_check == multi_expected, 'get_supported_function_arguments works (C++)')
meson-0.53.2/test cases/common/204 broken subproject/0000755000175000017500000000000013625242365023561 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/204 broken subproject/meson.build0000644000175000017500000000011113605171617025713 0ustar  jpakkanejpakkane00000000000000project('test broken subproject')
subproject('broken', required : false)
meson-0.53.2/test cases/common/204 broken subproject/subprojects/0000755000175000017500000000000013625242351026117 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/204 broken subproject/subprojects/broken/0000755000175000017500000000000013625242365027404 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/204 broken subproject/subprojects/broken/broken.c0000644000175000017500000000003513531533273031023 0ustar  jpakkanejpakkane00000000000000#error This must not compile
meson-0.53.2/test cases/common/204 broken subproject/subprojects/broken/meson.build0000644000175000017500000000014113531533273031537 0ustar  jpakkanejpakkane00000000000000project('broken', 'c')

executable('app', 'broken.c')
assert(false, 'This subproject must fail')
meson-0.53.2/test cases/common/205 argument syntax/0000755000175000017500000000000013625242365023272 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/205 argument syntax/meson.build0000644000175000017500000000077113605171621025433 0ustar  jpakkanejpakkane00000000000000project(
  'argument syntax',
  ['c'],
)

cc = meson.get_compiler('c')

if ['gcc', 'lcc', 'clang', 'intel'].contains(cc.get_id())
  expected = 'gcc'
elif ['msvc', 'clang-cl', 'intel-cl'].contains(cc.get_id())
  expected = 'msvc'
else
  # It's possible that other compilers end up here that shouldn't
  expected = 'other'
endif

assert(cc.get_argument_syntax() == expected,
       'Wrong output for compiler @0@. expected @1@ but got @2@'.format(
         cc.get_id(), expected, cc.get_argument_syntax()))
meson-0.53.2/test cases/common/206 install name_prefix name_suffix/0000755000175000017500000000000013625242365026353 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/206 install name_prefix name_suffix/installed_files.txt0000644000175000017500000000040213571777336032264 0ustar  jpakkanejpakkane00000000000000?msvc:usr/bin/baz.pdb
?msvc:usr/bin/bowcorge.pdb
?msvc:usr/bin/foo.pdb
usr/?lib/bowcorge.stern
usr/lib/?libbaz.cheese
usr/lib/bar.a
usr/lib/bowcorge?implib
usr/lib/bowgrault.stern
usr/lib/foo?implib
usr/lib/foo?so
usr/lib/libbaz?implib
usr/lib/libqux.cheese
meson-0.53.2/test cases/common/206 install name_prefix name_suffix/libfile.c0000644000175000017500000000052113571777336030136 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC func(void) {
    return 0;
}
meson-0.53.2/test cases/common/206 install name_prefix name_suffix/meson.build0000644000175000017500000000103013605171622030502 0ustar  jpakkanejpakkane00000000000000project('library with name_prefix name_suffix test', 'c')

shared_library('foo', 'libfile.c', name_prefix: '', install : true)
static_library('bar', 'libfile.c', name_prefix: '', install : true)

shared_library('baz', 'libfile.c', name_suffix: 'cheese', install : true)
static_library('qux', 'libfile.c', name_suffix: 'cheese', install : true)

shared_library('corge', 'libfile.c', name_prefix: 'bow', name_suffix: 'stern', install : true)
static_library('grault', 'libfile.c', name_prefix: 'bow', name_suffix: 'stern', install : true)
meson-0.53.2/test cases/common/207 kwarg entry/0000755000175000017500000000000013625242365022400 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/207 kwarg entry/inc/0000755000175000017500000000000013625242365023151 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/207 kwarg entry/inc/prog.h0000644000175000017500000000005713531533273024270 0ustar  jpakkanejpakkane00000000000000#pragma once

#define MESSAGE "Hello there.\n"
meson-0.53.2/test cases/common/207 kwarg entry/installed_files.txt0000644000175000017500000000005013531533273026272 0ustar  jpakkanejpakkane00000000000000usr/bin/prog?exe
?msvc:usr/bin/prog.pdb
meson-0.53.2/test cases/common/207 kwarg entry/meson.build0000644000175000017500000000024713605171622024540 0ustar  jpakkanejpakkane00000000000000project('kwarg', 'c')

default_kwargs = {'install': true,
  'include_directories': include_directories('inc')}

executable('prog', 'prog.c',
  kwargs: default_kwargs)
meson-0.53.2/test cases/common/207 kwarg entry/prog.c0000644000175000017500000000013213571777336023522 0ustar  jpakkanejpakkane00000000000000#include
#include

int main(void) {
    printf(MESSAGE);
    return 0;
}
meson-0.53.2/test cases/common/208 custom target build by default/0000755000175000017500000000000013625242365026005 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/208 custom target build by default/docgen.py0000644000175000017500000000027613531533273027620 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys

out = sys.argv[1]

os.mkdir(out)

for name in ('a', 'b', 'c'):
    with open(os.path.join(out, name + '.txt'), 'w') as f:
        f.write(name)
meson-0.53.2/test cases/common/208 custom target build by default/installed_files.txt0000644000175000017500000000000013531533273031672 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/208 custom target build by default/meson.build0000644000175000017500000000042013605171624030140 0ustar  jpakkanejpakkane00000000000000project('custom-target-dir-install', 'c')

docgen = find_program('docgen.py')

custom_target('docgen',
  output : 'html',
  command : [docgen, '@OUTPUT@'],
  install : true,
  build_by_default : false,
  install_dir : join_paths(get_option('datadir'), 'doc/testpkgname'))
meson-0.53.2/test cases/common/209 find_library and headers/0000755000175000017500000000000013625242365024730 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/209 find_library and headers/foo.h0000644000175000017500000000001713531533273025657 0ustar  jpakkanejpakkane00000000000000#define VAL 42
meson-0.53.2/test cases/common/209 find_library and headers/meson.build0000644000175000017500000000121613605171625027070 0ustar  jpakkanejpakkane00000000000000project('find library and headers', 'c')

cc = meson.get_compiler('c')

if not cc.find_library('z', required : false).found()
  error('MESON_SKIP_TEST: zlib not found.')
endif

lib = cc.find_library('z',
  has_headers : 'foo.h',
  required : false)
assert(not lib.found(), 'Header should be missing')

lib = cc.find_library('z',
  has_headers : 'foo.h',
  header_include_directories : include_directories('.'))
assert(lib.found(), 'Header should be found')

lib = cc.find_library('z',
  has_headers : ['foo.h', 'bar.h'],
  header_include_directories : include_directories('.'),
  required : false)
assert(not lib.found(), 'One header should be missing')
meson-0.53.2/test cases/common/21 global arg/0000755000175000017500000000000013625242365022047 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/21 global arg/meson.build0000644000175000017500000000162213605171327024207 0ustar  jpakkanejpakkane00000000000000project('global arg test', 'cpp', 'c')

add_global_arguments('-DMYTHING', language : 'c', native : true)
add_global_arguments('-DMYTHING', language : 'c', native : false)
add_global_arguments('-DMYCPPTHING', language : 'cpp', native : true)
add_global_arguments('-DMYCPPTHING', language : 'cpp', native : false)

add_global_arguments('-DGLOBAL_BUILD', language : 'c', native : true)
add_global_arguments('-DGLOBAL_HOST', language : 'c', native : false)

build_c_args = ['-DARG_BUILD']
c_args = ['-DARG_HOST']

add_global_arguments('-DMYCANDCPPTHING', language: ['c', 'cpp'], native: true)
add_global_arguments('-DMYCANDCPPTHING', language: ['c', 'cpp'], native: false)

exe1 = executable('prog1', 'prog.c', c_args : build_c_args, native : true)
exe2 = executable('prog2', 'prog.c', c_args : c_args, native : false)
exe3 = executable('prog3', 'prog.cc')

test('prog1', exe1)
test('prog2', exe2)
test('prog3', exe3)
meson-0.53.2/test cases/common/21 global arg/prog.c0000644000175000017500000000146613571777336023204 0ustar  jpakkanejpakkane00000000000000#ifndef MYTHING
  #error "Global argument not set"
#endif

#ifdef MYCPPTHING
  #error "Wrong global argument set"
#endif

#ifndef MYCANDCPPTHING
  #error "Global argument not set"
#endif

#if !defined(GLOBAL_HOST) && !defined(GLOBAL_BUILD)
  #error "Neither global_host nor glogal_build is set."
#endif

#if defined(GLOBAL_HOST) && defined(GLOBAL_BUILD)
  #error "Both global build and global host set."
#endif

#ifdef GLOBAL_BUILD
  #ifndef ARG_BUILD
    #error "Global is build but arg_build is not set."
  #endif

  #ifdef ARG_HOST
    #error "Global is build but arg host is set."
  #endif
#endif

#ifdef GLOBAL_HOST
  #ifndef ARG_HOST
    #error "Global is host but arg_host is not set."
  #endif

  #ifdef ARG_BUILD
    #error "Global is host but arg_build is set."
  #endif
#endif

int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/21 global arg/prog.cc0000644000175000017500000000032713571777336023342 0ustar  jpakkanejpakkane00000000000000#ifdef MYTHING
#error "Wrong global argument set"
#endif

#ifndef MYCPPTHING
#error "Global argument not set"
#endif

#ifndef MYCANDCPPTHING
#error "Global argument not set"
#endif

int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/210 line continuation/0000755000175000017500000000000013625242365023557 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/210 line continuation/meson.build0000644000175000017500000000041213605171624025713 0ustar  jpakkanejpakkane00000000000000project('line continuation')

a = 1
b = 2

c = a \
+b
assert(c == 3, 'Line continuation is not working')

d = a + \
  b
assert(d == 3, 'Line continuation is not working')

if a == 1 and \
   b == 3
  error('Line continuation in "if" condition is not working')
endif
meson-0.53.2/test cases/common/211 cmake module/0000755000175000017500000000000013625242365022464 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/211 cmake module/cmake_project/0000755000175000017500000000000013625242365025272 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/211 cmake module/cmake_project/CMakeLists.txt0000644000175000017500000000013513531533273030026 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 2.8)
project(cmakeMeson C)

find_package(cmakeModule REQUIRED)meson-0.53.2/test cases/common/211 cmake module/installed_files.txt0000644000175000017500000000015213531533273026361 0ustar  jpakkanejpakkane00000000000000usr/lib/cmake/cmakeModule/cmakeModuleConfig.cmake
usr/lib/cmake/cmakeModule/cmakeModuleConfigVersion.cmakemeson-0.53.2/test cases/common/211 cmake module/meson.build0000644000175000017500000000154213605171632024624 0ustar  jpakkanejpakkane00000000000000project('cmakeModule', 'c', version: '1.0.0')

if build_machine.system() == 'cygwin'
  error('MESON_SKIP_TEST CMake is broken on Cygwin.')
endif

cmake_bin = find_program('cmake', required: false)
if not cmake_bin.found()
  error('MESON_SKIP_TEST CMake not installed.')
endif

cc = meson.get_compiler('c')
if cc.get_id() == 'clang-cl' and meson.backend() == 'ninja' and build_machine.system() == 'windows'
    error('MESON_SKIP_TEST CMake installation nor operational for vs2017 clangclx64ninja')
endif

cmake = import('cmake')

cmake.write_basic_package_version_file(version: '0.0.1',
   name: 'cmakeModule',
)

conf = configuration_data()
conf.set('MYVAR', 'my variable value')
conf.set_quoted('MYQUOTEDVAR', 'my quoted variable value')

cmake.configure_package_config_file(
    input: 'projectConfig.cmake.in',
    name: 'cmakeModule',
    configuration: conf,
)
meson-0.53.2/test cases/common/211 cmake module/projectConfig.cmake.in0000644000175000017500000000010413531533273026657 0ustar  jpakkanejpakkane00000000000000@PACKAGE_INIT@

set(MYVAR "@MYVAR@")
set(MYQUOTEDVAR @MYQUOTEDVAR@)
meson-0.53.2/test cases/common/212 native file path override/0000755000175000017500000000000013625242365025042 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/212 native file path override/installed_files.txt0000644000175000017500000000007413531533273030742 0ustar  jpakkanejpakkane00000000000000usr/custom_bindir/main?exe
?msvc:usr/custom_bindir/main.pdb
meson-0.53.2/test cases/common/212 native file path override/main.cpp0000644000175000017500000000012613571777336026504 0ustar  jpakkanejpakkane00000000000000#include 

int main(void) {
    std::cout << "Hello world!" << std::endl;
}
meson-0.53.2/test cases/common/212 native file path override/meson.build0000644000175000017500000000031513605171631027176 0ustar  jpakkanejpakkane00000000000000project('native file install dir override', 'cpp')

if meson.is_cross_build()
  error('MESON_SKIP_TEST cannot test native build rules in cross build')
endif

executable('main', 'main.cpp', install : true)
meson-0.53.2/test cases/common/212 native file path override/nativefile.ini0000644000175000017500000000004113531533273027661 0ustar  jpakkanejpakkane00000000000000[paths]
bindir = 'custom_bindir'
meson-0.53.2/test cases/common/213 tap tests/0000755000175000017500000000000013625242365022047 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/213 tap tests/meson.build0000644000175000017500000000106413605171630024204 0ustar  jpakkanejpakkane00000000000000project('test features', 'c')

tester = executable('tester', 'tester.c')
test('pass', tester, args : ['ok'], protocol: 'tap')
test('fail', tester, args : ['not ok'], should_fail: true, protocol: 'tap')
test('xfail', tester, args : ['not ok # todo'], protocol: 'tap')
test('xpass', tester, args : ['ok # todo'], should_fail: true, protocol: 'tap')
test('skip', tester, args : ['ok # skip'], protocol: 'tap')
test('skip failure', tester, args : ['not ok # skip'], should_fail: true, protocol: 'tap')
test('no tests', tester, args : ['1..0 # skip'], protocol: 'tap')
meson-0.53.2/test cases/common/213 tap tests/tester.c0000644000175000017500000000032013531533273023511 0ustar  jpakkanejpakkane00000000000000#include 

int main(int argc, char **argv) {
    if (argc != 2) {
        fprintf(stderr, "Incorrect number of arguments, got %i\n", argc);
        return 1;
    }
    puts(argv[1]);
    return 0;
}
meson-0.53.2/test cases/common/214 warning level 0/0000755000175000017500000000000013625242365023016 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/214 warning level 0/main.cpp0000644000175000017500000000041013531533273024436 0ustar  jpakkanejpakkane00000000000000#include 

#define PROJECT_NAME "demo"

int main(int argc, char **argv) {
    if(argc != 1) {
        std::cout << argv[0] <<  "takes no arguments.\n";
        return 1;
    }
    std::cout << "This is project " << PROJECT_NAME << ".\n";
    return 0;
}
meson-0.53.2/test cases/common/214 warning level 0/meson.build0000644000175000017500000000017613605171631025157 0ustar  jpakkanejpakkane00000000000000project('warning_level', 'cpp', default_options : ['warning_level=0'])

exe = executable('main', 'main.cpp', install : false)
meson-0.53.2/test cases/common/215 link custom/0000755000175000017500000000000013625242365022372 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/215 link custom/custom_stlib.py0000755000175000017500000000522113571777336025471 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import shutil, sys, subprocess, argparse, pathlib
import platform

parser = argparse.ArgumentParser()

parser.add_argument('--private-dir', required=True)
parser.add_argument('-o', required=True)
parser.add_argument('cmparr', nargs='+')

contents = '''#include

void flob(void) {
    printf("Now flobbing.\\n");
}
'''

def get_pic_args():
    platname = platform.system().lower()
    if platname in ['windows', 'mingw', 'darwin'] or platname.startswith('cygwin'):
        return []
    return ['-fPIC']

def generate_lib_gnulike(outfile, c_file, private_dir, compiler_array):
    if shutil.which('ar'):
        static_linker = 'ar'
    elif shutil.which('llvm-ar'):
        static_linker = 'llvm-ar'
    elif shutil.which('gcc-ar'):
        static_linker = 'gcc-ar'
    else:
        sys.exit('Could not detect a static linker.')
    o_file = c_file.with_suffix('.o')
    compile_cmd = compiler_array + ['-c', '-g', '-O2', '-o', str(o_file), str(c_file)]
    compile_cmd += get_pic_args()
    subprocess.check_call(compile_cmd)
    out_file = pathlib.Path(outfile)
    if out_file.exists():
        out_file.unlink()
    link_cmd = [static_linker, 'csr', outfile, str(o_file)]
    subprocess.check_call(link_cmd)
    return 0


def generate_lib_msvc(outfile, c_file, private_dir, compiler_array):
    static_linker = 'lib'
    o_file = c_file.with_suffix('.obj')
    compile_cmd = compiler_array + ['/MDd',
                                    '/nologo',
                                    '/ZI',
                                    '/Ob0',
                                    '/Od',
                                    '/c',
                                    '/Fo' + str(o_file),
                                    str(c_file)]
    subprocess.check_call(compile_cmd)
    out_file = pathlib.Path(outfile)
    if out_file.exists():
        out_file.unlink()
    link_cmd = [static_linker,
                '/nologo',
                '/OUT:' + str(outfile),
                str(o_file)]
    subprocess.check_call(link_cmd)
    return 0

def generate_lib(outfile, private_dir, compiler_array):
    private_dir = pathlib.Path(private_dir)
    if not private_dir.exists():
        private_dir.mkdir()
    c_file = private_dir / 'flob.c'
    c_file.write_text(contents)
    for i in compiler_array:
        if (i.endswith('cl') or i.endswith('cl.exe')) and 'clang-cl' not in i:
            return generate_lib_msvc(outfile, c_file, private_dir, compiler_array)
    return generate_lib_gnulike(outfile, c_file, private_dir, compiler_array)

if __name__ == '__main__':
    options = parser.parse_args()
    sys.exit(generate_lib(options.o, options.private_dir, options.cmparr))
meson-0.53.2/test cases/common/215 link custom/lib.c0000644000175000017500000000007213571777336023316 0ustar  jpakkanejpakkane00000000000000void flob(void);

int foo(void)
{
  flob();
  return 0;
}
meson-0.53.2/test cases/common/215 link custom/meson.build0000644000175000017500000000316213605171634024534 0ustar  jpakkanejpakkane00000000000000project('linkcustom', 'c')

# This would require passing the static linker to the build script or having
# it detect it by itself. I'm too lazy to implement it now and it is not
# really needed for testing that custom targets work. It is the responsibility
# of the custom target to produce things in the correct format.
assert(not meson.is_cross_build(),
       'MESON_SKIP_TEST cross checking not implemented.')

cc = meson.get_compiler('c')
genprog = find_program('custom_stlib.py')

clib = custom_target('linkcustom',
  output: 'libflob.a',
  command: [genprog,
            '-o', '@OUTPUT@',
            '--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())

# custom_target tests

exe = executable('prog', 'prog.c', link_with: clib)
test('linkcustom', exe)

d = declare_dependency(link_with: clib)

exe2 = executable('prog2', 'prog.c', dependencies: d)
test('linkcustom2', exe2)

# Link whole tests

exe3 = executable('prog3', 'prog.c', link_whole: clib)
test('linkwhole', exe)

d2 = declare_dependency(link_whole: clib)

exe4 = executable('prog4', 'prog.c', dependencies: d2)
test('linkwhole2', exe2)

# custom_target[i] tests

exe_i = executable('prog_i', 'prog.c', link_with: clib[0])
test('linkcustom', exe_i)

d_i = declare_dependency(link_with: clib[0])

exe2_i = executable('prog2_i', 'prog.c', dependencies: d_i)
test('linkcustom2_i', exe2_i)

shared_library('lib1', 'lib.c', link_whole: clib)

# Link whole tests

exe3_i = executable('prog3_i', 'prog.c', link_whole: clib[0])
test('linkwhole', exe)

d2_i = declare_dependency(link_whole: clib[0])

exe4_i = executable('prog4_i', 'prog.c', dependencies: d2_i)
test('linkwhole2_i', exe2_i)
meson-0.53.2/test cases/common/215 link custom/prog.c0000644000175000017500000000007713571777336023524 0ustar  jpakkanejpakkane00000000000000void flob(void);

int main(void) {
    flob();
    return 0;
}
meson-0.53.2/test cases/common/216 link custom_i single from multiple/0000755000175000017500000000000013625242365026705 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/216 link custom_i single from multiple/generate_conflicting_stlibs.py0000644000175000017500000000547713531533273035022 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import shutil, sys, subprocess, argparse, pathlib

parser = argparse.ArgumentParser()

parser.add_argument('--private-dir', required=True)
parser.add_argument('-o', nargs='+', required=True)
parser.add_argument('cmparr', nargs='+')

contents = ['''
int flob() {
    return 0;
}
''', '''
int flob() {
    return 1;
}
''']

def generate_lib_gnulike(outfile, c_file, private_dir, compiler_array):
    if shutil.which('ar'):
        static_linker = 'ar'
    elif shutil.which('llvm-ar'):
        static_linker = 'llvm-ar'
    elif shutil.which('gcc-ar'):
        static_linker = 'gcc-ar'
    else:
        sys.exit('Could not detect a static linker.')
    o_file = c_file.with_suffix('.o')
    compile_cmd = compiler_array + ['-c', '-g', '-O2', '-o', str(o_file), str(c_file)]
    subprocess.check_call(compile_cmd)
    out_file = pathlib.Path(outfile)
    if out_file.exists():
        out_file.unlink()
    link_cmd = [static_linker, 'csr', outfile, str(o_file)]
    subprocess.check_call(link_cmd)
    return 0


def generate_lib_msvc(outfile, c_file, private_dir, compiler_array):
    static_linker = 'lib'
    o_file = c_file.with_suffix('.obj')
    compile_cmd = compiler_array + ['/MDd',
                                    '/nologo',
                                    '/ZI',
                                    '/Ob0',
                                    '/Od',
                                    '/c',
                                    '/Fo' + str(o_file),
                                    str(c_file)]
    subprocess.check_call(compile_cmd)
    out_file = pathlib.Path(outfile)
    if out_file.exists():
        out_file.unlink()
    link_cmd = [static_linker,
                '/nologo',
                '/OUT:' + str(outfile),
                str(o_file)]
    subprocess.check_call(link_cmd)
    return 0

def generate_lib(outfiles, private_dir, compiler_array):
    private_dir = pathlib.Path(private_dir)
    if not private_dir.exists():
        private_dir.mkdir()

    for i, content in enumerate(contents):
        c_file = private_dir / ('flob_' + str(i + 1) + '.c')
        c_file.write_text(content)
        outfile = outfiles[i]

        cl_found = False
        for cl_arg in compiler_array:
            if (cl_arg.endswith('cl') or cl_arg.endswith('cl.exe')) and 'clang-cl' not in cl_arg:
                ret = generate_lib_msvc(outfile, c_file, private_dir, compiler_array)
                if ret > 0:
                    return ret
                else:
                    cl_found = True
                    break
        if not cl_found:
            ret = generate_lib_gnulike(outfile, c_file, private_dir, compiler_array)
            if ret > 0:
                return ret
    return 0

if __name__ == '__main__':
    options = parser.parse_args()
    sys.exit(generate_lib(options.o, options.private_dir, options.cmparr))
meson-0.53.2/test cases/common/216 link custom_i single from multiple/meson.build0000644000175000017500000000216613605171634031052 0ustar  jpakkanejpakkane00000000000000project('linkcustom', 'c')

# This would require passing the static linker to the build script or having
# it detect it by itself. I'm too lazy to implement it now and it is not
# really needed for testing that custom targets work. It is the responsibility
# of the custom target to produce things in the correct format.
assert(not meson.is_cross_build(),
       'MESON_SKIP_TEST cross checking not implemented.')

cc = meson.get_compiler('c')
genprog = find_program('generate_conflicting_stlibs.py')

clib = custom_target('linkcustom',
  output: ['libflob_1.a', 'libflob_2.a'],
  command: [genprog,
            '-o', '@OUTPUT@',
            '--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())

clib_2 = clib[1]

exe = executable('prog', 'prog.c', link_with: clib_2)
test('linkcustom', exe)

d = declare_dependency(link_with: clib_2)

exe2 = executable('prog2', 'prog.c', dependencies: d)
test('linkcustom2', exe2)

# Link whole tests

exe3 = executable('prog3', 'prog.c', link_whole: clib_2)
test('linkwhole', exe)

d2 = declare_dependency(link_whole: clib_2)

exe4 = executable('prog4', 'prog.c', dependencies: d2)
test('linkwhole2', exe2)
meson-0.53.2/test cases/common/216 link custom_i single from multiple/prog.c0000644000175000017500000000010613571777336030030 0ustar  jpakkanejpakkane00000000000000int flob(void);

int main(void) {
    return (flob() == 1 ? 0 : 1);
}
meson-0.53.2/test cases/common/217 link custom_i multiple from multiple/0000755000175000017500000000000013625242365027260 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/217 link custom_i multiple from multiple/generate_stlibs.py0000644000175000017500000000562313531533273033007 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import shutil, sys, subprocess, argparse, pathlib

parser = argparse.ArgumentParser()

parser.add_argument('--private-dir', required=True)
parser.add_argument('-o', nargs='+', required=True)
parser.add_argument('cmparr', nargs='+')

contents = ['''#include

void flob_1() {
    printf("Now flobbing #1.\\n");
}
''', '''#include

void flob_2() {
    printf("Now flobbing #2.\\n");
}
''']

def generate_lib_gnulike(outfile, c_file, private_dir, compiler_array):
    if shutil.which('ar'):
        static_linker = 'ar'
    elif shutil.which('llvm-ar'):
        static_linker = 'llvm-ar'
    elif shutil.which('gcc-ar'):
        static_linker = 'gcc-ar'
    else:
        sys.exit('Could not detect a static linker.')
    o_file = c_file.with_suffix('.o')
    compile_cmd = compiler_array + ['-c', '-g', '-O2', '-o', str(o_file), str(c_file)]
    subprocess.check_call(compile_cmd)
    out_file = pathlib.Path(outfile)
    if out_file.exists():
        out_file.unlink()
    link_cmd = [static_linker, 'csr', outfile, str(o_file)]
    subprocess.check_call(link_cmd)
    return 0


def generate_lib_msvc(outfile, c_file, private_dir, compiler_array):
    static_linker = 'lib'
    o_file = c_file.with_suffix('.obj')
    compile_cmd = compiler_array + ['/MDd',
                                    '/nologo',
                                    '/ZI',
                                    '/Ob0',
                                    '/Od',
                                    '/c',
                                    '/Fo' + str(o_file),
                                    str(c_file)]
    subprocess.check_call(compile_cmd)
    out_file = pathlib.Path(outfile)
    if out_file.exists():
        out_file.unlink()
    link_cmd = [static_linker,
                '/nologo',
                '/OUT:' + str(outfile),
                str(o_file)]
    subprocess.check_call(link_cmd)
    return 0

def generate_lib(outfiles, private_dir, compiler_array):
    private_dir = pathlib.Path(private_dir)
    if not private_dir.exists():
        private_dir.mkdir()

    for i, content in enumerate(contents):
        c_file = private_dir / ('flob_' + str(i + 1) + '.c')
        c_file.write_text(content)
        outfile = outfiles[i]

        cl_found = False
        for cl_arg in compiler_array:
            if (cl_arg.endswith('cl') or cl_arg.endswith('cl.exe')) and 'clang-cl' not in cl_arg:
                ret = generate_lib_msvc(outfile, c_file, private_dir, compiler_array)
                if ret > 0:
                    return ret
                else:
                    cl_found = True
                    break
        if not cl_found:
            ret = generate_lib_gnulike(outfile, c_file, private_dir, compiler_array)
            if ret > 0:
                return ret
    return 0

if __name__ == '__main__':
    options = parser.parse_args()
    sys.exit(generate_lib(options.o, options.private_dir, options.cmparr))
meson-0.53.2/test cases/common/217 link custom_i multiple from multiple/meson.build0000644000175000017500000000216013605171636031421 0ustar  jpakkanejpakkane00000000000000project('linkcustom', 'c')

# This would require passing the static linker to the build script or having
# it detect it by itself. I'm too lazy to implement it now and it is not
# really needed for testing that custom targets work. It is the responsibility
# of the custom target to produce things in the correct format.
assert(not meson.is_cross_build(),
       'MESON_SKIP_TEST cross checking not implemented.')

cc = meson.get_compiler('c')
genprog = find_program('generate_stlibs.py')

clib = custom_target('linkcustom',
  output: ['libflob_1.a', 'libflob_2.a'],
  command: [genprog,
            '-o', '@OUTPUT@',
            '--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())

clibs = [clib[0], clib[1]]

exe = executable('prog', 'prog.c', link_with: clibs)
test('linkcustom', exe)

d = declare_dependency(link_with: clibs)

exe2 = executable('prog2', 'prog.c', dependencies: d)
test('linkcustom2', exe2)

# Link whole tests

exe3 = executable('prog3', 'prog.c', link_whole: clibs)
test('linkwhole', exe)

d2 = declare_dependency(link_whole: clibs)

exe4 = executable('prog4', 'prog.c', dependencies: d2)
test('linkwhole2', exe2)
meson-0.53.2/test cases/common/217 link custom_i multiple from multiple/prog.c0000644000175000017500000000014413571777336030405 0ustar  jpakkanejpakkane00000000000000void flob_1(void);
void flob_2(void);

int main(void) {
    flob_1();
    flob_2();
    return 0;
}
meson-0.53.2/test cases/common/218 dependency get_variable method/0000755000175000017500000000000013625242365026131 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/218 dependency get_variable method/meson.build0000644000175000017500000000502613605171641030272 0ustar  jpakkanejpakkane00000000000000project(
  'dependency get_variable',
  ['c', 'cpp'],
)

# Just some string that nothing should return
default = 'asufoiqwjtl;adjfbpiuqwoehtl;ajdfl;ghal;sdjg'

dep = dependency('zlib', method: 'pkg-config', required : false)
if not dep.found()
  warning('Skipping pkg-config tests as zlib is not available or is not pkg-config')
else
  # Test for regular pkg-config
  # We don't know what the value will be, but we know it should be the same
  dep = dependency('zlib', method : 'pkg-config')
  assert(dep.get_pkgconfig_variable('prefix') == dep.get_variable(pkgconfig : 'prefix'),
        'Got different values from get_pkgconfig_variable and get_variable(pkgconfig: )')
  assert(dep.get_variable(pkgconfig : default, default_value : default) == default,
        'pkg-config didn\'t get default when we should have.')
  assert(dep.get_variable(pkgconfig : 'prefix', default_value : default) != default,
        'pkg-config got default when we shouldn\'t have.')
endif

dep_ct = dependency('llvm', method : 'config-tool', required : false)
if not dep_ct.found()
  warning('Skipping config-tool tests as llvm is not available or llvm-config was not found.')
else
  assert(dep_ct.get_configtool_variable('has-rtti') == dep_ct.get_variable(configtool : 'has-rtti'),
        'Got different values from get_configtool_variable and get_variable(configtool: )')
  assert(dep_ct.get_variable(configtool : default, default_value : default) == default,
        'config-tool didn\'t get default when we should have.')
  assert(dep_ct.get_variable(configtool : 'has-rtti', default_value : default) != default,
        'config-tool got default when we shouldn\'t have.')
endif

dep_cm = dependency('llvm', method : 'cmake', required : false)
if not dep_cm.found()
  warning('Skipping cmake tests as llvm is not available via the cmake finder.')
else
  if dep_ct.found()
    assert((dep_cm.get_variable(cmake : 'LLVM_ENABLE_RTTI') == 'ON') == (dep_ct.get_variable(configtool : 'has-rtti') == 'YES'),
          'RTTI information for cmake and config tools disagree')
  endif
  assert(dep_cm.get_variable(cmake : default, default_value : default) == default,
        'cmake didn\'t get default when we should have.')
  assert(dep_cm.get_variable(cmake : 'LLVM_ENABLE_RTTI', default_value : default) != default,
        'cmake config-tool got default when we shouldn\'t have.')
endif

idep = declare_dependency()
assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo', default_value : default) == default,
       'Got something other than default from an internal dependency')
meson-0.53.2/test cases/common/219 source set configuration_data/0000755000175000017500000000000013625242366026044 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/219 source set configuration_data/a.c0000644000175000017500000000012613531533273026423 0ustar  jpakkanejpakkane00000000000000#include 
#include "all.h"

int main(void)
{
    if (p) abort();
    f();
}
meson-0.53.2/test cases/common/219 source set configuration_data/all.h0000644000175000017500000000023213531533273026756 0ustar  jpakkanejpakkane00000000000000extern void f(void);
extern void g(void);
extern void h(void);
extern void undefined(void);

/* No extern here to get a common symbol */
void (*p)(void);
meson-0.53.2/test cases/common/219 source set configuration_data/f.c0000644000175000017500000000004313531533273026426 0ustar  jpakkanejpakkane00000000000000#include "all.h"

void f(void)
{
}
meson-0.53.2/test cases/common/219 source set configuration_data/g.c0000644000175000017500000000005413531533273026431 0ustar  jpakkanejpakkane00000000000000#include "all.h"

void g(void)
{
    h();
}
meson-0.53.2/test cases/common/219 source set configuration_data/meson.build0000644000175000017500000000345613605171642030212 0ustar  jpakkanejpakkane00000000000000project('a', 'c')

good = declare_dependency(link_with: static_library('good', 'g.c'))
bad = declare_dependency(link_args: 'nonexistent.a')
not_found = dependency('invalid', required: false)

source_set = import('sourceset')

sources = source_set.source_set()
sources.add(when: 'YES',  if_false: ['nope.c'])
sources.add(when: 'YES1', if_true: files('a.c'))
subdir('subdir')
sources.add(when: 'NO',   if_true: 'nope.c', if_false: ['f.c'])
sources.add(when: 'NO',   if_true: bad,      if_false: ['f.c'])

sources.add(when: 'YES2', if_true: good)

# dependencies as conditions
sources.add(when: not_found, if_true: 'nope.c')

# test add_all
sources2 = source_set.source_set()
sources2.add(when: 'YES1',  if_true: 'nope.c')
sources.add_all(when: 'NO', if_true: sources2)

# test duplicate items
sources.add(when: 'YES1',   if_true: files('a.c'))

conf1 = configuration_data()
conf1.set10('YES', true)
conf1.set10('YES1', true)
conf1.set10('YES2', false)
conf1.set10('NO', false)
result1 = sources.apply(conf1)

conf2 = configuration_data()
conf2.set10('YES', true)
conf2.set10('YES1', false)
conf2.set10('YES2', true)
conf2.set10('NO', false)
result2 = sources.apply(conf2)

# Each target will recompile the objects
executable('first', sources: result1.sources(), dependencies: result1.dependencies())
executable('second', sources: result2.sources(), dependencies: result2.dependencies())

# All target will use the same object files
if meson.is_unity()
  message('Skipping extraction test because this is a Unity build.')
else
  all_objs = static_library('all_objs', sources.all_sources())
  executable('first_via_lib', objects: all_objs.extract_objects(result1.sources()), dependencies: result1.dependencies())
  executable('second_via_lib', objects: all_objs.extract_objects(result2.sources()), dependencies: result2.dependencies())
endif
meson-0.53.2/test cases/common/219 source set configuration_data/nope.c0000644000175000017500000000005713531533273027147 0ustar  jpakkanejpakkane00000000000000#include "all.h"

void (*p)(void) = undefined;
meson-0.53.2/test cases/common/219 source set configuration_data/subdir/0000755000175000017500000000000013625242366027334 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/219 source set configuration_data/subdir/b.c0000644000175000017500000000016113531533273027713 0ustar  jpakkanejpakkane00000000000000#include 
#include "all.h"

void h(void)
{
}

int main(void)
{
    if (p) abort();
    f();
    g();
}
meson-0.53.2/test cases/common/219 source set configuration_data/subdir/meson.build0000644000175000017500000000007513531533273031474 0ustar  jpakkanejpakkane00000000000000sources.add(when: ['YES2', good], if_true: [ files('b.c') ])
meson-0.53.2/test cases/common/22 target arg/0000755000175000017500000000000013625242366022077 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/22 target arg/func.c0000644000175000017500000000021613571777336023207 0ustar  jpakkanejpakkane00000000000000#ifndef CTHING
#error "Local argument not set"
#endif

#ifdef CPPTHING
#error "Wrong local argument set"
#endif

int func(void) { return 0; }
meson-0.53.2/test cases/common/22 target arg/func2.c0000644000175000017500000000025113571777336023270 0ustar  jpakkanejpakkane00000000000000#ifdef CTHING
#error "Local C argument set in wrong target"
#endif

#ifdef CPPTHING
#error "Local CPP argument set in wrong target"
#endif

int func(void) { return 0; }
meson-0.53.2/test cases/common/22 target arg/meson.build0000644000175000017500000000034513605171327024237 0ustar  jpakkanejpakkane00000000000000project('local arg test', 'cpp', 'c')

exe1 = executable('prog', 'prog.cc', 'func.c', \
c_args   : '-DCTHING', \
cpp_args : '-DCPPTHING')
exe2 = executable('prog2', 'prog2.cc', 'func2.c')

test('prog1', exe1)
test('prog2', exe2)
meson-0.53.2/test cases/common/22 target arg/prog.cc0000644000175000017500000000025713571777336023373 0ustar  jpakkanejpakkane00000000000000#ifdef CTHING
#error "Wrong local argument set"
#endif

#ifndef CPPTHING
#error "Local argument not set"
#endif

extern "C" int func();

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/22 target arg/prog2.cc0000644000175000017500000000031213571777336023445 0ustar  jpakkanejpakkane00000000000000#ifdef CTHING
#error "Local C argument set in wrong target"
#endif

#ifdef CPPTHING
#error "Local CPP argument set in wrong target"
#endif

extern "C" int func();

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/220 source set dictionary/0000755000175000017500000000000013625242366024341 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/220 source set dictionary/a.c0000644000175000017500000000012613531533273024720 0ustar  jpakkanejpakkane00000000000000#include 
#include "all.h"

int main(void)
{
    if (p) abort();
    f();
}
meson-0.53.2/test cases/common/220 source set dictionary/all.h0000644000175000017500000000023213531533273025253 0ustar  jpakkanejpakkane00000000000000extern void f(void);
extern void g(void);
extern void h(void);
extern void undefined(void);

/* No extern here to get a common symbol */
void (*p)(void);
meson-0.53.2/test cases/common/220 source set dictionary/f.c0000644000175000017500000000004313531533273024723 0ustar  jpakkanejpakkane00000000000000#include "all.h"

void f(void)
{
}
meson-0.53.2/test cases/common/220 source set dictionary/g.c0000644000175000017500000000005413531533273024726 0ustar  jpakkanejpakkane00000000000000#include "all.h"

void g(void)
{
    h();
}
meson-0.53.2/test cases/common/220 source set dictionary/meson.build0000644000175000017500000000331413605171642026500 0ustar  jpakkanejpakkane00000000000000project('a', 'c')

good = declare_dependency(link_with: static_library('good', 'g.c'))
bad = declare_dependency(link_args: 'nonexistent.a')
not_found = dependency('invalid', required: false)

source_set = import('sourceset')

sources = source_set.source_set()
sources.add(when: 'YES',  if_false: ['nope.c'])
sources.add(when: 'YES1', if_true: files('a.c'))
subdir('subdir')
sources.add(when: 'NO',   if_true: 'nope.c', if_false: ['f.c'])
sources.add(when: 'NO',   if_true: bad,      if_false: ['f.c'])

sources.add(when: 'YES2', if_true: good)

# dependencies as conditions
sources.add(when: not_found, if_true: 'nope.c')

# test add_all
sources2 = source_set.source_set()
sources2.add(when: 'YES1',  if_true: 'nope.c')
sources.add_all(when: 'NO', if_true: sources2)

# test duplicate items
sources.add(when: 'YES1',   if_true: files('a.c'))

conf1 = {
    'YES': true,
    'YES1': true,
    'YES2': false,
    'NO': false,
}
result1 = sources.apply(conf1)

conf2 = {
    'YES': true,
    'YES1': false,
    'YES2': true,
    'NO': false,
}
result2 = sources.apply(conf2)

# Each target will recompile the objects
executable('first', sources: result1.sources(), dependencies: result1.dependencies())
executable('second', sources: result2.sources(), dependencies: result2.dependencies())

# All target will use the same object files
if meson.is_unity()
  message('Skipping extraction test because this is a Unity build.')
else
  all_objs = static_library('all_objs', sources.all_sources())
  executable('first_via_lib', objects: all_objs.extract_objects(result1.sources()), dependencies: result1.dependencies())
  executable('second_via_lib', objects: all_objs.extract_objects(result2.sources()), dependencies: result2.dependencies())
endif
meson-0.53.2/test cases/common/220 source set dictionary/nope.c0000644000175000017500000000005713531533273025444 0ustar  jpakkanejpakkane00000000000000#include "all.h"

void (*p)(void) = undefined;
meson-0.53.2/test cases/common/220 source set dictionary/subdir/0000755000175000017500000000000013625242366025631 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/220 source set dictionary/subdir/b.c0000644000175000017500000000016113531533273026210 0ustar  jpakkanejpakkane00000000000000#include 
#include "all.h"

void h(void)
{
}

int main(void)
{
    if (p) abort();
    f();
    g();
}
meson-0.53.2/test cases/common/220 source set dictionary/subdir/meson.build0000644000175000017500000000007513531533273027771 0ustar  jpakkanejpakkane00000000000000sources.add(when: ['YES2', good], if_true: [ files('b.c') ])
meson-0.53.2/test cases/common/221 source set custom target/0000755000175000017500000000000013625242366024756 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/221 source set custom target/a.c0000644000175000017500000000006713531533273025341 0ustar  jpakkanejpakkane00000000000000#include "all.h"

int main(void)
{
    f();
    g();
}
meson-0.53.2/test cases/common/221 source set custom target/all.h0000644000175000017500000000005213531533273025670 0ustar  jpakkanejpakkane00000000000000extern void f(void);
extern void g(void);
meson-0.53.2/test cases/common/221 source set custom target/cp.py0000644000175000017500000000013013531533273025720 0ustar  jpakkanejpakkane00000000000000#! /usr/bin/env python3

import sys
from shutil import copyfile
copyfile(*sys.argv[1:])
meson-0.53.2/test cases/common/221 source set custom target/f.c0000644000175000017500000000004313531533273025340 0ustar  jpakkanejpakkane00000000000000#include "all.h"

void f(void)
{
}
meson-0.53.2/test cases/common/221 source set custom target/g.c0000644000175000017500000000004313531533273025341 0ustar  jpakkanejpakkane00000000000000#include "all.h"

void g(void)
{
}
meson-0.53.2/test cases/common/221 source set custom target/meson.build0000644000175000017500000000157613605171642027125 0ustar  jpakkanejpakkane00000000000000# Try using sourceset with various kinds of generated sources

project('a', 'c')

cp = find_program('cp.py')

source_set = import('sourceset')
sources = source_set.source_set()

a_c = custom_target('gen-custom-target',
                    input: 'a.c', output: 'out_a.c',
                    command: [cp, '@INPUT@', '@OUTPUT@'])
sources.add(when: 'YES', if_true: a_c)
sources.add(when: 'YES', if_true: a_c[0])

f_c = configure_file(input: 'f.c', output: 'out_f.c', copy: true)
sources.add(when: 'YES', if_true: f_c)
sources.add(when: 'YES', if_true: f_c)

gen = generator(cp, output: 'out_@PLAINNAME@', arguments: ['@INPUT@', '@OUTPUT@'])
g_c = gen.process(files('g.c'))
sources.add(when: 'YES', if_true: g_c)
sources.add(when: 'YES', if_true: g_c)

conf1 = { 'YES': true, }
result1 = sources.apply(conf1)

executable('first', sources: result1.sources(), dependencies: result1.dependencies())
meson-0.53.2/test cases/common/222 source set realistic example/0000755000175000017500000000000013625242366025571 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/222 source set realistic example/boards/0000755000175000017500000000000013625242366027043 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/222 source set realistic example/boards/arm/0000755000175000017500000000000013625242366027622 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/222 source set realistic example/boards/arm/aarch64.cc0000644000175000017500000000027013531533273031354 0ustar  jpakkanejpakkane00000000000000#include "common.h"
#include 

void initialize_target()
{
    std::cout << ANSI_START << "some " << THE_TARGET
              << " initialization" << ANSI_END << std::endl;
}
meson-0.53.2/test cases/common/222 source set realistic example/boards/arm/arm.cc0000644000175000017500000000016113531533273030702 0ustar  jpakkanejpakkane00000000000000#include "arm.h"

const char *ARMBoard::target()
{
    return THE_TARGET;
}

void ARMBoard::some_arm_thing()
{
}
meson-0.53.2/test cases/common/222 source set realistic example/boards/arm/arm.h0000644000175000017500000000021613531533273030545 0ustar  jpakkanejpakkane00000000000000#ifndef ARM_H
#define ARM_H 1

#include "common.h"

struct ARMBoard: Board {
    const char *target();
    void some_arm_thing();
};


#endif
meson-0.53.2/test cases/common/222 source set realistic example/boards/arm/arm32.cc0000644000175000017500000000027713531533273031057 0ustar  jpakkanejpakkane00000000000000#include "common.h"
#include 

void initialize_target()
{
    std::cout << ANSI_START << "a different " << THE_TARGET
              << " initialization" << ANSI_END << std::endl;
}
meson-0.53.2/test cases/common/222 source set realistic example/boards/arm/versatilepb.cc0000644000175000017500000000047713531533273032455 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"
#include "arm.h"

struct VersatilePBBoard: ARMBoard {
    void say_hello();
};

void VersatilePBBoard::say_hello()
{
    some_arm_thing();
    std::cout << ANSI_START << "I am the versatilepb board"
              << ANSI_END << std::endl;
}

static VersatilePBBoard versatilepb;
meson-0.53.2/test cases/common/222 source set realistic example/boards/arm/virt.cc0000644000175000017500000000043413531533273031112 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"
#include "arm.h"

struct VirtBoard: ARMBoard {
    void say_hello();
};

void VirtBoard::say_hello()
{
    some_arm_thing();
    std::cout << ANSI_START << "I am the virt board"
              << ANSI_END << std::endl;
}

static VirtBoard virt;
meson-0.53.2/test cases/common/222 source set realistic example/boards/arm/xlnx_zcu102.cc0000644000175000017500000000047413531533273032227 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"
#include "arm.h"

struct XlnxZCU102Board: ARMBoard {
    void say_hello();
};

void XlnxZCU102Board::say_hello()
{
    some_arm_thing();
    std::cout << ANSI_START << "I am the xlnx_zcu102 board"
              << ANSI_END << std::endl;
}

static XlnxZCU102Board xlnx_zcu102;
meson-0.53.2/test cases/common/222 source set realistic example/boards/meson.build0000644000175000017500000000073513531533273031206 0ustar  jpakkanejpakkane00000000000000specific.add(when: 'TARGET_ARM',         if_true: files('arm/arm.cc', 'arm/arm32.cc'))
specific.add(when: 'TARGET_AARCH64',     if_true: files('arm/arm.cc', 'arm/aarch64.cc'))
specific.add(when: 'CONFIG_VIRT',        if_true: files('arm/virt.cc'))
specific.add(when: 'CONFIG_XLNX_ZCU102', if_true: files('arm/xlnx_zcu102.cc'))
specific.add(when: 'CONFIG_VERSATILEPB', if_true: files('arm/versatilepb.cc'))

specific.add(when: 'TARGET_X86',         if_true: files('x86/pc.cc'))
meson-0.53.2/test cases/common/222 source set realistic example/boards/x86/0000755000175000017500000000000013625242366027470 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/222 source set realistic example/boards/x86/pc.cc0000644000175000017500000000066313531533273030402 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"

struct X86Board: Board {
    const char *target();
    void say_hello();
};

const char *X86Board::target()
{
    return THE_TARGET;
}

void X86Board::say_hello()
{
    std::cout << ANSI_START << "I am a 1996 PC"
              << ANSI_END << std::endl;
}

void initialize_target()
{
    std::cout << ANSI_START << "ready, set, go"
              << ANSI_END << std::endl;
}

static X86Board pc;
meson-0.53.2/test cases/common/222 source set realistic example/common.h0000644000175000017500000000127313531533273027231 0ustar  jpakkanejpakkane00000000000000#ifndef COMMON_H
#define COMMON_H 1

/*
 * target-specific code will print in yellow, common code will print
 * in grey.
 */
#ifdef THE_TARGET
#define ANSI_START "\x1b[33;1m"
#define ANSI_END "\x1b[0m"
#else
#define ANSI_START ""
#define ANSI_END ""
#endif

void some_random_function();
void initialize_target();

struct Board {
    Board *next;
    Board();
    virtual ~Board();
    virtual void say_hello() = 0;
    virtual const char *target() = 0;
};

struct Device {
    Device *next;
    Device();
    virtual ~Device();
    virtual void say_hello() = 0;
};

struct Dependency {
    Dependency *next;
    Dependency();
    virtual ~Dependency();
    virtual void initialize() = 0;
};

#endif
meson-0.53.2/test cases/common/222 source set realistic example/config/0000755000175000017500000000000013625242366027036 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/222 source set realistic example/config/aarch640000644000175000017500000000013113531533273030200 0ustar  jpakkanejpakkane00000000000000TARGET_AARCH64=y
CONFIG_VIRT=y
CONFIG_XLNX_ZCU102=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_MMIO=y
meson-0.53.2/test cases/common/222 source set realistic example/config/arm0000644000175000017500000000006013531533273027530 0ustar  jpakkanejpakkane00000000000000TARGET_ARM=y
CONFIG_VIRT=y
CONFIG_VERSATILEPB=y
meson-0.53.2/test cases/common/222 source set realistic example/config/x860000644000175000017500000000007513531533273027404 0ustar  jpakkanejpakkane00000000000000TARGET_X86=y
CONFIG_PC=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI=y
meson-0.53.2/test cases/common/222 source set realistic example/devices/0000755000175000017500000000000013625242366027213 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/222 source set realistic example/devices/meson.build0000644000175000017500000000032513531533273031351 0ustar  jpakkanejpakkane00000000000000specific.add(when: 'CONFIG_VIRTIO',    if_true: files('virtio.cc'))
common.add(when: 'CONFIG_VIRTIO_PCI',  if_true: files('virtio-pci.cc'))
common.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.cc'))
meson-0.53.2/test cases/common/222 source set realistic example/devices/virtio-mmio.cc0000644000175000017500000000050713531533273031773 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"
#include "virtio.h"

struct VirtioMMIODevice: VirtioDevice {
    void say_hello();
};

void VirtioMMIODevice::say_hello()
{
    some_virtio_thing();
    std::cout << ANSI_START << "virtio-mmio is available"
              << ANSI_END << std::endl;
}

static VirtioMMIODevice virtio_mmio;
meson-0.53.2/test cases/common/222 source set realistic example/devices/virtio-pci.cc0000644000175000017500000000050213531533273031600 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"
#include "virtio.h"

struct VirtioPCIDevice: VirtioDevice {
    void say_hello();
};

void VirtioPCIDevice::say_hello()
{
    some_virtio_thing();
    std::cout << ANSI_START << "virtio-pci is available"
              << ANSI_END << std::endl;
}

static VirtioPCIDevice virtio_pci;
meson-0.53.2/test cases/common/222 source set realistic example/devices/virtio.cc0000644000175000017500000000015013531533273031026 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"
#include "virtio.h"

void VirtioDevice::some_virtio_thing() {
}
meson-0.53.2/test cases/common/222 source set realistic example/devices/virtio.h0000644000175000017500000000020113531533273030665 0ustar  jpakkanejpakkane00000000000000#ifndef VIRTIO_H
#define VIRTIO_H 1

#include "common.h"

struct VirtioDevice: Device {
    void some_virtio_thing();
};

#endif
meson-0.53.2/test cases/common/222 source set realistic example/main.cc0000644000175000017500000000130213571777336027032 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "common.h"

Board* boards;
Device* devices;
Dependency* deps;

Board::Board() { this->next = boards; boards = this; }
Board::~Board() {}

Device::Device() { this->next = devices; devices = this; }
Device::~Device() {}

Dependency::Dependency() { this->next = deps; deps = this; }
Dependency::~Dependency() {}

int main(void)
{
    some_random_function();
    for (auto d = deps; d; d = d->next)
        d->initialize();

    initialize_target();
    for (auto b = boards; b; b = b->next) {
        std::cout << ANSI_START << b->target() << " - " << ANSI_END;
        b->say_hello();
    }

    for (auto d = devices; d; d = d->next)
        d->say_hello();
}
meson-0.53.2/test cases/common/222 source set realistic example/meson.build0000644000175000017500000000335013612411367027727 0ustar  jpakkanejpakkane00000000000000# a sort-of realistic example that combines the sourceset and kconfig
# modules, inspired by QEMU's build system

project('sourceset-example', 'cpp', default_options: ['cpp_std=c++11'])

cppid = meson.get_compiler('cpp').get_id()
if cppid == 'pgi'
  error('MESON_SKIP_TEST: Even PGI 19.4 that claims C++17 full support, cannot handle auto x = y syntax used in this test.')
endif

ss = import('sourceset')
kconfig = import('unstable-kconfig')

zlib = declare_dependency(compile_args: '-DZLIB=1')
another = declare_dependency(compile_args: '-DANOTHER=1')
not_found = dependency('not-found', required: false)

common = ss.source_set()
specific = ss.source_set()

common.add(files('main.cc'))
common.add(when: [zlib, another], if_true: files('zlib.cc'))
common.add(when: not_found,
           if_true: files('was-found.cc'),
           if_false: files('not-found.cc'))

subdir('boards')
subdir('devices')

if meson.is_unity()
  specific.add_all(common)
  common = ss.source_set()
endif

common_lib = static_library('common', common.all_sources(),
                            dependencies: common.all_dependencies())

targets = [ 'arm', 'aarch64', 'x86' ]
target_dirs = { 'arm' : 'arm', 'aarch64' : 'arm', 'x86': 'x86' }

foreach x : targets
  config = kconfig.load('config' / x)
  target_specific = specific.apply(config, strict: false)
  target_common = common.apply(config, strict: false)
  target_deps = target_specific.dependencies() + target_common.dependencies()
  executable(x,
             objects: common_lib.extract_objects(target_common.sources()),
             sources: target_specific.sources(),
             dependencies: target_deps,
             include_directories: 'boards' / target_dirs[x],
             cpp_args: '-DTHE_TARGET="' + x + '"')
endforeach
meson-0.53.2/test cases/common/222 source set realistic example/not-found.cc0000644000175000017500000000024713531533273030010 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"

void some_random_function()
{
    std::cout << ANSI_START << "everything's alright"
              << ANSI_END << std::endl;
}
meson-0.53.2/test cases/common/222 source set realistic example/was-found.cc0000644000175000017500000000020313531533273027772 0ustar  jpakkanejpakkane00000000000000#include 

void some_random_function()
{
    std::cout << ANSI_START << "huh?"
              << ANSI_END << std::endl;
}
meson-0.53.2/test cases/common/222 source set realistic example/zlib.cc0000644000175000017500000000044713531533273027041 0ustar  jpakkanejpakkane00000000000000#include 
#include "common.h"

struct ZLibDependency : Dependency {
    void initialize();
};

void ZLibDependency::initialize() {
    if (ZLIB && ANOTHER) {
        std::cout << ANSI_START << "hello from zlib"
                  << ANSI_END << std::endl;
    }
}

ZLibDependency zlib;
meson-0.53.2/test cases/common/223 custom target input extracted objects/0000755000175000017500000000000013625242366027421 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/223 custom target input extracted objects/check_object.py0000644000175000017500000000044313531533273032373 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print(sys.argv[0], 'object', 'output')
        sys.exit(1)
    elif os.path.exists(sys.argv[1]):
        with open(sys.argv[2], 'wb') as out:
            pass
    else:
        sys.exit(1)
meson-0.53.2/test cases/common/223 custom target input extracted objects/libdir/0000755000175000017500000000000013625242366030666 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/223 custom target input extracted objects/libdir/meson.build0000644000175000017500000000012013531533273033015 0ustar  jpakkanejpakkane00000000000000objlib = static_library('object', 'source.c', override_options : ['unity=off'])
meson-0.53.2/test cases/common/223 custom target input extracted objects/libdir/source.c0000644000175000017500000000005113571777336032340 0ustar  jpakkanejpakkane00000000000000int func1_in_obj(void) {
    return 0;
}
meson-0.53.2/test cases/common/223 custom target input extracted objects/meson.build0000644000175000017500000000050713605171646031565 0ustar  jpakkanejpakkane00000000000000project('custom target input extracted objects', 'c')

checker = find_program('check_object.py')

cc = meson.get_compiler('c').cmd_array().get(-1)

subdir('libdir')

custom_target('check',
  input: objlib.extract_objects('source.c'),
  output: 'objcheck',
  command: [checker, '@INPUT@', '@OUTPUT@'],
  build_by_default: true)
meson-0.53.2/test cases/common/224 test priorities/0000755000175000017500000000000013625242366023274 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/224 test priorities/meson.build0000644000175000017500000000054413605171646025441 0ustar  jpakkanejpakkane00000000000000project('test priorities', 'c')

test_prog = find_program('testprog.py')

test('priority 0', test_prog,
     args : ['0'],
)

test('priority neg 10', test_prog,
     args : ['-10'],
     priority : -10
)

test('priority 1000', test_prog,
     args : ['1000'],
     priority : 1000
)

test('priority 50', test_prog,
     args : ['50'],
     priority : 50
)
meson-0.53.2/test cases/common/224 test priorities/testprog.py0000644000175000017500000000006713537776255025533 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

print(sys.argv[1])
meson-0.53.2/test cases/common/225 include_dir dot/0000755000175000017500000000000013625242366023174 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/225 include_dir dot/meson.build0000644000175000017500000000025613605171646025341 0ustar  jpakkanejpakkane00000000000000project('Include Here', 'c')

# The layout with the .h file in . and the .c files in src/ is critical to
# tickle the bug #5847

inc = include_directories('.')

subdir('src')meson-0.53.2/test cases/common/225 include_dir dot/rone.h0000644000175000017500000000001713537776255024321 0ustar  jpakkanejpakkane00000000000000int rOne(void);meson-0.53.2/test cases/common/225 include_dir dot/src/0000755000175000017500000000000013625242366023763 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/225 include_dir dot/src/main.c0000644000175000017500000000007113571777336025063 0ustar  jpakkanejpakkane00000000000000#include "rone.h"

int main(void) {
    return rOne();
}
meson-0.53.2/test cases/common/225 include_dir dot/src/meson.build0000644000175000017500000000017013537776255026136 0ustar  jpakkanejpakkane00000000000000t = executable(
  'main',
  ['main.c', 'rone.c'],
  include_directories : inc,
  implicit_include_directories : false,
)meson-0.53.2/test cases/common/225 include_dir dot/src/rone.c0000644000175000017500000000004013537776255025077 0ustar  jpakkanejpakkane00000000000000int rOne(void) {
    return 1;
}meson-0.53.2/test cases/common/226 include_type dependency/0000755000175000017500000000000013625242366024730 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/226 include_type dependency/meson.build0000644000175000017500000000177013605171653027075 0ustar  jpakkanejpakkane00000000000000project(
  'dependency include_type',
  ['c', 'cpp'],
)

dep = dependency('zlib', method: 'pkg-config', required : false)
if not dep.found()
  error('MESON_SKIP_TEST zlib was not found')
endif

assert(dep.include_type() == 'preserve', 'include_type must default to "preserve"')

dep_sys = dep.as_system()
assert(dep_sys.include_type() == 'system', 'as_system must return a system dep')

dep2 = dependency('zlib', method: 'pkg-config', include_type : 'system')
assert(dep2.include_type() == 'system', 'include_type must be true when set')

dep2_sys = dep2.as_system('non-system')
assert(dep2_sys.include_type() == 'non-system', 'as_system must set include_type correctly')

sp = subproject('subDep')
sp_dep = sp.get_variable('subDep_dep')
assert(sp_dep.include_type() == 'preserve', 'default is preserve')

sp_dep_sys = sp_dep.as_system('system')
assert(sp_dep_sys.include_type() == 'system', 'changing include_type works')
assert(sp_dep.include_type() == 'preserve', 'as_system must not mutate the original object')
meson-0.53.2/test cases/common/226 include_type dependency/subprojects/0000755000175000017500000000000013625242351027265 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/226 include_type dependency/subprojects/subDep/0000755000175000017500000000000013625242366030515 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/226 include_type dependency/subprojects/subDep/meson.build0000644000175000017500000000011713546416757032667 0ustar  jpakkanejpakkane00000000000000project('subDep', ['cpp'])

subDep_dep = declare_dependency(compile_args : [])
meson-0.53.2/test cases/common/227 fs module/0000755000175000017500000000000013625242366022024 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/227 fs module/a_symlink0000644000175000017500000000675413605171652023746 0ustar  jpakkanejpakkane00000000000000project('fs module test')

is_windows = build_machine.system() == 'windows'

fs = import('fs')

assert(fs.exists('meson.build'), 'Existing file reported as missing.')
assert(not fs.exists('nonexisting'), 'Nonexisting file was found.')

# When one creates a source release with sdist, Python
# does not store symlinks in the archive as native symlinks.
# Thus the extracted archive does not contain them either.
# Sadly this means that we can only execute the symlink test when
# running from a git checkout because otherwise we'd need to
# do postprocessing on the generated archive before actual release.
# That is both nonstandard an error prone and having symlinks in
# the archive would probably break on Windows anyway.
is_git_checkout = fs.exists('../../../.git')

if not is_windows and build_machine.system() != 'cygwin' and is_git_checkout
  assert(fs.is_symlink('a_symlink'), 'Symlink not detected.')
  assert(not fs.is_symlink('meson.build'), 'Regular file detected as symlink.')
endif

assert(fs.is_file('meson.build'), 'File not detected as a file.')
assert(not fs.is_file('subprojects'), 'Directory detected as a file.')
assert(not fs.is_file('nonexisting'), 'Bad path detected as a file.')

assert(fs.is_dir('subprojects'), 'Dir not detected correctly.')
assert(not fs.is_dir('meson.build'), 'File detected as a dir.')
assert(not fs.is_dir('nonexisting'), 'Bad path detected as a dir.')

assert(fs.is_dir('~'), 'expanduser not working')
assert(not fs.is_file('~'), 'expanduser not working')

original = 'foo.txt'
new = fs.replace_suffix(original, '.ini')
assert(new == 'foo.ini', 'replace_suffix failed')

original = 'foo'
new = fs.replace_suffix(original, '.ini')
assert(new == 'foo.ini', 'replace_suffix did not add suffix to suffixless file')

original = 'foo.dll.a'
new = fs.replace_suffix(original, '.so')
assert(new == 'foo.dll.so', 'replace_suffix did not only modify last suffix')

original = 'foo.dll'
new = fs.replace_suffix(original, '')
assert(new == 'foo',  'replace_suffix did not only delete last suffix')

# `/` on windows is interpreted like `.drive` which in general may not be `c:/`
# the files need not exist for fs.replace_suffix()
original = is_windows ? 'j:/foo/bar.txt' : '/foo/bar.txt'
new_check = is_windows ? 'j:\\foo\\bar.ini' : '/foo/bar.ini'

new = fs.replace_suffix(original, '.ini')
assert(new == new_check, 'absolute path replace_suffix failed')

# -- hash

md5 = fs.hash('subdir/subdirfile.txt', 'md5')
sha256 = fs.hash('subdir/subdirfile.txt', 'sha256')
assert(md5 == 'd0795db41614d25affdd548314b30b3b', 'md5sum did not match')
assert(sha256 == 'be2170b0dae535b73f6775694fffa3fd726a43b5fabea11b7342f0605917a42a', 'sha256sum did not match')

# -- size

size = fs.size('subdir/subdirfile.txt')
assert(size == 19, 'file size not found correctly')

# -- are filenames referring to the same file?
f1 = 'meson.build'
f2 = 'subdir/../meson.build'
assert(fs.is_samepath(f1, f2), 'is_samepath not detercting same files')
assert(fs.is_samepath(meson.source_root(), 'subdir/..'), 'is_samepath not detecting same directory')
assert(not fs.is_samepath(f1, 'subdir/subdirfile.txt'), 'is_samepath known bad comparison')
assert(not fs.is_samepath('not-a-path', f2), 'is_samepath should not error if path(s) do not exist')

if not is_windows and build_machine.system() != 'cygwin' and is_git_checkout
  assert(fs.is_samepath('a_symlink', 'meson.build'), 'symlink is_samepath fail')
endif

assert(fs.parent('foo/bar') == 'foo', 'failed to get dirname')
assert(fs.name('foo/bar') == 'bar', 'failed to get basename')

subdir('subdir')
meson-0.53.2/test cases/common/227 fs module/meson.build0000644000175000017500000000675413605171652024177 0ustar  jpakkanejpakkane00000000000000project('fs module test')

is_windows = build_machine.system() == 'windows'

fs = import('fs')

assert(fs.exists('meson.build'), 'Existing file reported as missing.')
assert(not fs.exists('nonexisting'), 'Nonexisting file was found.')

# When one creates a source release with sdist, Python
# does not store symlinks in the archive as native symlinks.
# Thus the extracted archive does not contain them either.
# Sadly this means that we can only execute the symlink test when
# running from a git checkout because otherwise we'd need to
# do postprocessing on the generated archive before actual release.
# That is both nonstandard an error prone and having symlinks in
# the archive would probably break on Windows anyway.
is_git_checkout = fs.exists('../../../.git')

if not is_windows and build_machine.system() != 'cygwin' and is_git_checkout
  assert(fs.is_symlink('a_symlink'), 'Symlink not detected.')
  assert(not fs.is_symlink('meson.build'), 'Regular file detected as symlink.')
endif

assert(fs.is_file('meson.build'), 'File not detected as a file.')
assert(not fs.is_file('subprojects'), 'Directory detected as a file.')
assert(not fs.is_file('nonexisting'), 'Bad path detected as a file.')

assert(fs.is_dir('subprojects'), 'Dir not detected correctly.')
assert(not fs.is_dir('meson.build'), 'File detected as a dir.')
assert(not fs.is_dir('nonexisting'), 'Bad path detected as a dir.')

assert(fs.is_dir('~'), 'expanduser not working')
assert(not fs.is_file('~'), 'expanduser not working')

original = 'foo.txt'
new = fs.replace_suffix(original, '.ini')
assert(new == 'foo.ini', 'replace_suffix failed')

original = 'foo'
new = fs.replace_suffix(original, '.ini')
assert(new == 'foo.ini', 'replace_suffix did not add suffix to suffixless file')

original = 'foo.dll.a'
new = fs.replace_suffix(original, '.so')
assert(new == 'foo.dll.so', 'replace_suffix did not only modify last suffix')

original = 'foo.dll'
new = fs.replace_suffix(original, '')
assert(new == 'foo',  'replace_suffix did not only delete last suffix')

# `/` on windows is interpreted like `.drive` which in general may not be `c:/`
# the files need not exist for fs.replace_suffix()
original = is_windows ? 'j:/foo/bar.txt' : '/foo/bar.txt'
new_check = is_windows ? 'j:\\foo\\bar.ini' : '/foo/bar.ini'

new = fs.replace_suffix(original, '.ini')
assert(new == new_check, 'absolute path replace_suffix failed')

# -- hash

md5 = fs.hash('subdir/subdirfile.txt', 'md5')
sha256 = fs.hash('subdir/subdirfile.txt', 'sha256')
assert(md5 == 'd0795db41614d25affdd548314b30b3b', 'md5sum did not match')
assert(sha256 == 'be2170b0dae535b73f6775694fffa3fd726a43b5fabea11b7342f0605917a42a', 'sha256sum did not match')

# -- size

size = fs.size('subdir/subdirfile.txt')
assert(size == 19, 'file size not found correctly')

# -- are filenames referring to the same file?
f1 = 'meson.build'
f2 = 'subdir/../meson.build'
assert(fs.is_samepath(f1, f2), 'is_samepath not detercting same files')
assert(fs.is_samepath(meson.source_root(), 'subdir/..'), 'is_samepath not detecting same directory')
assert(not fs.is_samepath(f1, 'subdir/subdirfile.txt'), 'is_samepath known bad comparison')
assert(not fs.is_samepath('not-a-path', f2), 'is_samepath should not error if path(s) do not exist')

if not is_windows and build_machine.system() != 'cygwin' and is_git_checkout
  assert(fs.is_samepath('a_symlink', 'meson.build'), 'symlink is_samepath fail')
endif

assert(fs.parent('foo/bar') == 'foo', 'failed to get dirname')
assert(fs.name('foo/bar') == 'bar', 'failed to get basename')

subdir('subdir')
meson-0.53.2/test cases/common/227 fs module/subdir/0000755000175000017500000000000013625242366023314 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/227 fs module/subdir/meson.build0000644000175000017500000000010513571777336025464 0ustar  jpakkanejpakkane00000000000000assert(fs.exists('subdirfile.txt'), 'Subdir file lookup is broken.')
meson-0.53.2/test cases/common/227 fs module/subdir/subdirfile.txt0000644000175000017500000000002313571777336026212 0ustar  jpakkanejpakkane00000000000000I have no content.
meson-0.53.2/test cases/common/227 fs module/subprojects/0000755000175000017500000000000013625242351024361 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/227 fs module/subprojects/subbie/0000755000175000017500000000000013625242366025640 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/227 fs module/subprojects/subbie/meson.build0000644000175000017500000000023113571777336030010 0ustar  jpakkanejpakkane00000000000000project('subbie')

fs = import('fs')

assert(fs.exists('subprojectfile.txt'), 'Subproject root file not found.')

subdir('subsub')

subproject('subbie')
meson-0.53.2/test cases/common/227 fs module/subprojects/subbie/subprojectfile.txt0000644000175000017500000000005113571777336031427 0ustar  jpakkanejpakkane00000000000000I'm not empty. So there's at least that.
meson-0.53.2/test cases/common/227 fs module/subprojects/subbie/subsub/0000755000175000017500000000000013625242366027143 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/227 fs module/subprojects/subbie/subsub/meson.build0000644000175000017500000000011013571777336031307 0ustar  jpakkanejpakkane00000000000000assert(fs.exists('subsubfile.txt'), 'Subproject subdir lookup failed.')
meson-0.53.2/test cases/common/227 fs module/subprojects/subbie/subsub/subsubfile.txt0000644000175000017500000000004113571777336032054 0ustar  jpakkanejpakkane00000000000000Thank you for looking inside me.
meson-0.53.2/test cases/common/23 object extraction/0000755000175000017500000000000013625242366023467 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/23 object extraction/lib.c0000644000175000017500000000004213571777336024407 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 42;
}
meson-0.53.2/test cases/common/23 object extraction/lib2.c0000644000175000017500000000004213571777336024471 0ustar  jpakkanejpakkane00000000000000int retval(void) {
  return 43;
}
meson-0.53.2/test cases/common/23 object extraction/main.c0000644000175000017500000000010513571777336024565 0ustar  jpakkanejpakkane00000000000000int func(void);

int main(void) {
    return func() == 42 ? 0 : 1;
}
meson-0.53.2/test cases/common/23 object extraction/meson.build0000644000175000017500000000116213605171327025625 0ustar  jpakkanejpakkane00000000000000project('object extraction', 'c')

if meson.is_unity()
  message('Skipping extraction test because this is a Unity build.')
else
  lib1 = shared_library('somelib', 'src/lib.c')
  lib2 = shared_library('somelib2', 'lib.c', 'lib2.c')

  obj1 = lib1.extract_objects('src/lib.c')
  obj2 = lib2.extract_objects(['lib.c'])
  obj3 = lib2.extract_objects(files('lib.c'))

  e1 = executable('main1', 'main.c', objects : obj1)
  e2 = executable('main2', 'main.c', objects : obj2)
  e3 = executable('main3', 'main.c', objects : obj3)

  test('extraction test 1', e1)
  test('extraction test 2', e2)
  test('extraction test 3', e3)
endif
meson-0.53.2/test cases/common/23 object extraction/src/0000755000175000017500000000000013625242366024256 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/23 object extraction/src/lib.c0000644000175000017500000000004213571777336025176 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 42;
}
meson-0.53.2/test cases/common/24 endian/0000755000175000017500000000000013625242366021317 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/24 endian/meson.build0000644000175000017500000000025213605171330023446 0ustar  jpakkanejpakkane00000000000000project('endian check', 'c')

if host_machine.endian() == 'big'
  add_global_arguments('-DIS_BE', language : 'c')
endif

test('endiantest', executable('prog', 'prog.c'))
meson-0.53.2/test cases/common/24 endian/prog.c0000644000175000017500000000056713571777336022454 0ustar  jpakkanejpakkane00000000000000#include

int is_big_endian(void) {
    uint32_t one = 1;
    if(*((uint8_t*) &one) == 1)
        return 0;
    return 1;
}


int main(void) {
    int is_be_check = is_big_endian();
    int is_be;
#ifdef IS_BE
    is_be = 1;
#else
    is_be = 0;
#endif
    if(is_be_check && is_be)
        return 0;
    if(!is_be_check && !is_be)
        return 0;
    return 1;
}
meson-0.53.2/test cases/common/25 library versions/0000755000175000017500000000000013625242366023357 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/25 library versions/installed_files.txt0000644000175000017500000000013213403223104027234 0ustar  jpakkanejpakkane00000000000000usr/lib/prefixsomelib.suffix
usr/lib/prefixsomelib?implib
?msvc:usr/lib/prefixsomelib.pdb
meson-0.53.2/test cases/common/25 library versions/lib.c0000644000175000017500000000052413571777336024304 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC myFunc(void) {
    return 55;
}
meson-0.53.2/test cases/common/25 library versions/meson.build0000644000175000017500000000026413605171332025513 0ustar  jpakkanejpakkane00000000000000project('library versions', 'c')

shared_library('somelib', 'lib.c',
  name_prefix : 'prefix',
  name_suffix : 'suffix',
  install_dir : 'lib',
  install : true)

subdir('subdir')
meson-0.53.2/test cases/common/25 library versions/subdir/0000755000175000017500000000000013625242366024647 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/25 library versions/subdir/meson.build0000644000175000017500000000051013366273150027002 0ustar  jpakkanejpakkane00000000000000# Test that using files generated with configure_file as sources works.
# We do this inside a subdir so that the path isn't accidentally correct
# because there is no structure in the build dir.
genlib = configure_file(input : '../lib.c',
  output : 'genlib.c',
  copy: true)
shared_library('genlib', genlib,
  install : false)
meson-0.53.2/test cases/common/26 config subdir/0000755000175000017500000000000013625242366022601 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/26 config subdir/include/0000755000175000017500000000000013625242366024224 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/26 config subdir/include/config.h.in0000644000175000017500000000011313366273150026237 0ustar  jpakkanejpakkane00000000000000#ifndef CONFIG_H_
#define CONFIG_H_

#define RETURN_VALUE @number@

#endif
meson-0.53.2/test cases/common/26 config subdir/include/meson.build0000644000175000017500000000021713366273150026363 0ustar  jpakkanejpakkane00000000000000conf_data = configuration_data()
conf_data.set('number', '0')

configure_file(input:'config.h.in', output:'config.h', configuration:conf_data)
meson-0.53.2/test cases/common/26 config subdir/meson.build0000644000175000017500000000014413605171332024732 0ustar  jpakkanejpakkane00000000000000project('subdirconfig', 'c')

inc = include_directories('include')

subdir('include')
subdir('src')
meson-0.53.2/test cases/common/26 config subdir/src/0000755000175000017500000000000013625242366023370 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/26 config subdir/src/meson.build0000644000175000017500000000013113366273150025522 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.c', include_directories : inc)
test('subdir config', exe)
meson-0.53.2/test cases/common/26 config subdir/src/prog.c0000644000175000017500000000010113571777336024505 0ustar  jpakkanejpakkane00000000000000#include "config.h"

int main(void) {
    return RETURN_VALUE;
}
meson-0.53.2/test cases/common/27 pipeline/0000755000175000017500000000000013625242366021671 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/27 pipeline/depends/0000755000175000017500000000000013625242366023313 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/27 pipeline/depends/copyrunner.py0000755000175000017500000000020513471342322026061 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, subprocess

prog, infile, outfile = sys.argv[1:]

subprocess.check_call([prog, infile, outfile])
meson-0.53.2/test cases/common/27 pipeline/depends/filecopier.c0000644000175000017500000000101113571777336025603 0ustar  jpakkanejpakkane00000000000000#include
#include

#define BUFSIZE 1024

int main(int argc, char **argv) {
    char buffer[BUFSIZE];
    size_t num_read;
    size_t num_written;
    FILE *fin = fopen(argv[1], "rb");
    FILE *fout;
    assert(argc>0);
    assert(fin);
    num_read = fread(buffer, 1, BUFSIZE, fin);
    assert(num_read > 0);
    fclose(fin);
    fout = fopen(argv[2], "wb");
    assert(fout);
    num_written = fwrite(buffer, 1, num_read, fout);
    assert(num_written == num_read);
    fclose(fout);
    return 0;
}
meson-0.53.2/test cases/common/27 pipeline/depends/libsrc.c.in0000644000175000017500000000004213571777336025350 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 42;
}
meson-0.53.2/test cases/common/27 pipeline/depends/meson.build0000644000175000017500000000047413471342322025452 0ustar  jpakkanejpakkane00000000000000runner = find_program('copyrunner.py')

copier = executable('copier', 'filecopier.c', native: true)

cg = generator(runner,
    output: ['@BASENAME@.c'],
    arguments: [copier.full_path(), '@INPUT@', '@OUTPUT@'],
    depends: copier)

test('generatordep',
    executable('gd', 'prog.c', cg.process('libsrc.c.in')))
meson-0.53.2/test cases/common/27 pipeline/depends/prog.c0000644000175000017500000000007513571777336024442 0ustar  jpakkanejpakkane00000000000000int func(void);

int main(void) {
    return func() != 42;
}
meson-0.53.2/test cases/common/27 pipeline/input_src.dat0000644000175000017500000000003513571777336024401 0ustar  jpakkanejpakkane00000000000000int func(void) { return 0; }
meson-0.53.2/test cases/common/27 pipeline/meson.build0000644000175000017500000000122513605171333024024 0ustar  jpakkanejpakkane00000000000000project('pipeline test', 'c')

# We need to run this executable locally so build it with
# the host compiler.
e1 = executable('srcgen', 'srcgen.c', native : true)

# Generate a source file that needs to be included in the build.
gen = generator(e1, \
  depfile : '@BASENAME@.d',
  output  : '@BASENAME@.c', # Line continuation inside arguments should work without needing a "\".
  arguments : ['@INPUT@', '@OUTPUT@', '@DEPFILE@'])

generated = gen.process(['input_src.dat'])

e2 = executable('prog', 'prog.c', generated)

test('pipelined', e2)

# This is in a subdirectory to make sure
# we write proper subdir paths to output.
subdir('src')

subdir('depends')
meson-0.53.2/test cases/common/27 pipeline/prog.c0000644000175000017500000000006713571777336023021 0ustar  jpakkanejpakkane00000000000000int func(void);

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/27 pipeline/src/0000755000175000017500000000000013625242366022460 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/27 pipeline/src/input_src.dat0000644000175000017500000000002213471342322025142 0ustar  jpakkanejpakkane00000000000000#include
meson-0.53.2/test cases/common/27 pipeline/src/meson.build0000644000175000017500000000045613471342322024617 0ustar  jpakkanejpakkane00000000000000e1 = executable('srcgen', 'srcgen.c', native : true)

# Generate a header file that needs to be included.
gen = generator(e1,
 output  : '@BASENAME@.h',
 arguments : ['@INPUT@', '@OUTPUT@'])

generated = gen.process('input_src.dat')

e2 = executable('prog', 'prog.c', generated)

test('pipelined', e2)
meson-0.53.2/test cases/common/27 pipeline/src/prog.c0000644000175000017500000000016613571777336023610 0ustar  jpakkanejpakkane00000000000000#include"input_src.h"

int main(void) {
    void *foo = printf;
    if(foo) {
        return 0;
    }
    return 1;
}
meson-0.53.2/test cases/common/27 pipeline/src/srcgen.c0000644000175000017500000000160513471342322024077 0ustar  jpakkanejpakkane00000000000000#include
#include

#define ARRSIZE 80

int main(int argc, char **argv) {
    char arr[ARRSIZE];
    char *ifilename;
    char *ofilename;
    FILE *ifile;
    FILE *ofile;
    size_t bytes;

    if(argc != 3) {
        fprintf(stderr, "%s  \n", argv[0]);
        return 1;
    }
    ifilename = argv[1];
    ofilename = argv[2];
    printf("%s\n", ifilename);
    ifile = fopen(ifilename, "r");
    if(!ifile) {
        fprintf(stderr, "Could not open source file %s.\n", ifilename);
        return 1;
    }
    ofile = fopen(ofilename, "w");
    if(!ofile) {
        fprintf(stderr, "Could not open target file %s\n", ofilename);
        fclose(ifile);
        return 1;
    }
    bytes = fread(arr, 1, ARRSIZE, ifile);
    assert(bytes < 80);
    assert(bytes > 0);
    fwrite(arr, 1, bytes, ofile);

    fclose(ifile);
    fclose(ofile);
    return 0;
}
meson-0.53.2/test cases/common/27 pipeline/srcgen.c0000644000175000017500000000317413366273150023320 0ustar  jpakkanejpakkane00000000000000#include
#include
#include

#define ARRSIZE 80

int main(int argc, char **argv) {
    char arr[ARRSIZE];
    char *ofilename;
    char *ifilename;
    char *dfilename;
    FILE *ifile;
    FILE *ofile;
    FILE *depfile;
    size_t bytes;
    int i;

    if(argc != 4) {
        fprintf(stderr, "%s   \n", argv[0]);
        return 1;
    }
    ifilename = argv[1];
    ofilename = argv[2];
    dfilename = argv[3];
    ifile = fopen(argv[1], "r");
    if(!ifile) {
        fprintf(stderr, "Could not open source file %s.\n", argv[1]);
        return 1;
    }
    ofile = fopen(ofilename, "w");
    if(!ofile) {
        fprintf(stderr, "Could not open target file %s\n", ofilename);
        fclose(ifile);
        return 1;
    }
    bytes = fread(arr, 1, ARRSIZE, ifile);
    assert(bytes < 80);
    assert(bytes > 0);
    fwrite(arr, 1, bytes, ofile);

    depfile = fopen(dfilename, "w");
    if(!depfile) {
        fprintf(stderr, "Could not open depfile %s\n", ofilename);
        fclose(ifile);
        fclose(ofile);
        return 1;
    }
    for(i=0; i=2.0', required : false)
assert(not prog.found(), 'Version should be too old')

prog = find_program('print-version.py', version : '>=1.0')
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')
meson-0.53.2/test cases/common/28 find program/print-version-with-prefix.py0000644000175000017500000000017413531533273030070 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

if len(sys.argv) != 2 or sys.argv[1] != '--version':
    exit(1)

print('Version: 1.0')
meson-0.53.2/test cases/common/28 find program/print-version.py0000644000175000017500000000016313531533273025622 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

if len(sys.argv) != 2 or sys.argv[1] != '--version':
    exit(1)

print('1.0')
meson-0.53.2/test cases/common/28 find program/scripts/0000755000175000017500000000000013625242366024124 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/28 find program/scripts/test_subdir.py0000644000175000017500000000004013602226377027016 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

exit(0)
meson-0.53.2/test cases/common/28 find program/source.in0000644000175000017500000000003713571777336024277 0ustar  jpakkanejpakkane00000000000000int main(void) {
  return 0;
}
meson-0.53.2/test cases/common/29 multiline string/0000755000175000017500000000000013625242366023357 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/29 multiline string/meson.build0000644000175000017500000000104413605171335025513 0ustar  jpakkanejpakkane00000000000000project('multiline string', 'c')

x = '''hello again'''
y = '''hello
again'''

if x == y
  error('Things are wrong.')
endif

multieol = '''
'''
singleeol = '\n'

if multieol != singleeol
  error('Newline quoting is broken.')
endif

# And one more for good measure.
quote1 = ''' ' '''.strip()
quote2 = '\''

if quote1 != quote2
  error('Single quote quoting is broken.')
endif

cc = meson.get_compiler('c')
prog = '''
int main(void) {
  int num = 1;
  printf("%d\n", num);
  return 0;
}'''

assert(cc.compiles(prog), 'multline test compile failed')
meson-0.53.2/test cases/common/3 static/0000755000175000017500000000000013625242366021265 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/3 static/libfile.c0000644000175000017500000000004413571777336023047 0ustar  jpakkanejpakkane00000000000000int libfunc(void) {
    return 3;
}
meson-0.53.2/test cases/common/3 static/libfile2.c0000644000175000017500000000004513571777336023132 0ustar  jpakkanejpakkane00000000000000int libfunc2(void) {
    return 4;
}
meson-0.53.2/test cases/common/3 static/meson.build0000644000175000017500000000061713605171303023421 0ustar  jpakkanejpakkane00000000000000project('static library test', 'c')

lib = static_library('mylib', get_option('source'),
  link_args : '-THISMUSTNOBEUSED') # Static linker needs to ignore all link args.

has_not_changed = false
if is_disabler(lib)
    has_not_changed = true
else
    has_not_changed = true
endif
assert(has_not_changed, 'Static library has changed.')

assert(not is_disabler(lib), 'Static library is a disabler.')
meson-0.53.2/test cases/common/3 static/meson_options.txt0000644000175000017500000000013513055371450024713 0ustar  jpakkanejpakkane00000000000000option('source', type : 'combo', choices : ['libfile.c', 'libfile2.c'], value : 'libfile.c')
meson-0.53.2/test cases/common/30 try compile/0000755000175000017500000000000013625242366022305 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/30 try compile/invalid.c0000644000175000017500000000011213571777336024103 0ustar  jpakkanejpakkane00000000000000#include
void func(void) { printf("This won't work.\n"); }
meson-0.53.2/test cases/common/30 try compile/meson.build0000644000175000017500000000152613605171336024447 0ustar  jpakkanejpakkane00000000000000project('try compile', 'c', 'cpp')

code = '''#include
void func(void) { printf("Something.\n"); }
'''

breakcode = '''#include
void func(void) { printf("This won't work.\n"); }
'''

foreach compiler : [meson.get_compiler('c'), meson.get_compiler('cpp')]
  if compiler.compiles(code, name : 'should succeed') == false
    error('Compiler ' + compiler.get_id() + ' is fail.')
  endif

  if compiler.compiles(files('valid.c'), name : 'should succeed') == false
    error('Compiler ' + compiler.get_id() + ' is fail.')
  endif

  if compiler.compiles(breakcode, name : 'should fail')
    error('Compiler ' + compiler.get_id() + ' returned true on broken code.')
  endif

  if compiler.compiles(files('invalid.c'), name : 'should fail')
    error('Compiler ' + compiler.get_id() + ' returned true on broken code.')
  endif
endforeach
meson-0.53.2/test cases/common/30 try compile/valid.c0000644000175000017500000000007613571777336023565 0ustar  jpakkanejpakkane00000000000000#include
void func(void) { printf("Something.\n"); }
meson-0.53.2/test cases/common/31 compiler id/0000755000175000017500000000000013625242366022246 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/31 compiler id/meson.build0000644000175000017500000000047213605171337024410 0ustar  jpakkanejpakkane00000000000000project('compiler_id')

foreach lang : ['c', 'cpp', 'fortran', 'objc', 'objcpp']

  if not add_languages(lang, required: false)
    continue
  endif

  comp = meson.get_compiler(lang)

  message(lang + ' compiler name is: ' + comp.get_id())

  message(lang + ' linker name is: ' + comp.get_linker_id())

endforeachmeson-0.53.2/test cases/common/32 sizeof/0000755000175000017500000000000013625242366021357 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/32 sizeof/config.h.in0000644000175000017500000000007013531533273023373 0ustar  jpakkanejpakkane00000000000000#define INTSIZE @INTSIZE@
#define WCHARSIZE @WCHARSIZE@
meson-0.53.2/test cases/common/32 sizeof/meson.build0000644000175000017500000000172613605171342023520 0ustar  jpakkanejpakkane00000000000000project('sizeof', 'c', 'cpp')

# Test with C
cc = meson.get_compiler('c')

intsize = cc.sizeof('int')
wcharsize = cc.sizeof('wchar_t', prefix : '#include')

cd = configuration_data()
cd.set('INTSIZE', intsize)
cd.set('WCHARSIZE', wcharsize)
cd.set('CONFIG', 'config.h')
configure_file(input : 'config.h.in', output : 'config.h', configuration : cd)
s = configure_file(input : 'prog.c.in', output : 'prog.c', configuration : cd)

e = executable('prog', s)
test('sizeof test', e)

# Test with C++
cpp = meson.get_compiler('cpp')

intsize = cpp.sizeof('int')
wcharsize = cpp.sizeof('wchar_t', prefix : '#include')

cdpp = configuration_data()
cdpp.set('INTSIZE', intsize)
cdpp.set('WCHARSIZE', wcharsize)
cdpp.set('CONFIG', 'config.hpp')
configure_file(input : 'config.h.in', output : 'config.hpp', configuration : cdpp)
spp = configure_file(input : 'prog.c.in', output : 'prog.cc', configuration : cdpp)

epp = executable('progpp', spp)
test('sizeof test c++', epp)
meson-0.53.2/test cases/common/32 sizeof/prog.c.in0000644000175000017500000000065613571777336023120 0ustar  jpakkanejpakkane00000000000000#include "@CONFIG@"
#include 
#include 

int main(void) {
    if(INTSIZE != sizeof(int)) {
        fprintf(stderr, "Mismatch: detected int size %d, actual size %d.\n", INTSIZE, (int)sizeof(int));
        return 1;
    }
    if(WCHARSIZE != sizeof(wchar_t)) {
        fprintf(stderr, "Mismatch: detected wchar size %d, actual size %d.\n", WCHARSIZE, (int)sizeof(wchar_t));
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/33 define10/0000755000175000017500000000000013625242366021454 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/33 define10/config.h.in0000644000175000017500000000004313531533273023470 0ustar  jpakkanejpakkane00000000000000#mesondefine ONE
#mesondefine ZERO
meson-0.53.2/test cases/common/33 define10/meson.build0000644000175000017500000000036613605171340023612 0ustar  jpakkanejpakkane00000000000000project('set10test', 'c')

conf = configuration_data()
conf.set10('ONE', true)
conf.set10('ZERO', false)

configure_file(input : 'config.h.in',
 output : 'config.h',
  configuration : conf)

exe = executable('prog', 'prog.c')
test('10test', exe)
meson-0.53.2/test cases/common/33 define10/prog.c0000644000175000017500000000034513571777336022603 0ustar  jpakkanejpakkane00000000000000#include
#include"config.h"

int main(void) {
    if(ONE != 1) {
        fprintf(stderr, "ONE is not 1.\n");
        return 1;
    }
    if(ZERO != 0) {
        fprintf(stderr, "ZERO is not 0.\n");
    }
    return 0;
}
meson-0.53.2/test cases/common/34 has header/0000755000175000017500000000000013625242366022046 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/34 has header/meson.build0000644000175000017500000000417113605171342024204 0ustar  jpakkanejpakkane00000000000000project('has header', 'c', 'cpp')

host_system = host_machine.system()

non_existent_header = 'ouagadougou.h'

# Copy it into the builddir to ensure that it isn't found even if it's there
configure_file(input : non_existent_header,
  output : non_existent_header,
  configuration : configuration_data())

# Test that the fallback to __has_include also works on all compilers
if host_system != 'darwin'
  fallbacks = ['', '\n#undef __has_include']
else
  # On Darwin's clang you can't redefine builtin macros so the above doesn't work
  fallbacks = ['']
endif

foreach fallback : fallbacks
  foreach comp : [meson.get_compiler('c'), meson.get_compiler('cpp')]
    assert(comp.has_header('stdio.h', prefix : fallback), 'Stdio missing.')

    # stdio.h doesn't actually need stdlib.h, but just test that setting the
    # prefix does not result in an error.
    assert(comp.has_header('stdio.h', prefix : '#include ' + fallback),
           'Stdio missing.')

    # XInput.h should not require type definitions from windows.h, but it does
    # require macro definitions. Specifically, it requires an arch setting for
    # VS2015 at least.
    # We only do this check on MSVC because MinGW often defines its own wrappers
    # that pre-include windows.h
    if comp.get_id() == 'msvc'
      assert(comp.has_header('XInput.h', prefix : '#include ' + fallback),
             'XInput.h should not be missing on Windows')
      assert(comp.has_header('XInput.h', prefix : '#define _X86_' + fallback),
             'XInput.h should not need windows.h')
    endif

    # Test that the following GCC bug doesn't happen:
    # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80005
    # https://github.com/mesonbuild/meson/issues/1458
    if host_system == 'linux'
      assert(comp.has_header('linux/if.h', prefix : fallback),
             'Could not find ')
    endif

    # This header exists in the source and the builddir, but we still must not
    # find it since we are looking in the system directories.
    assert(not comp.has_header(non_existent_header, prefix : fallback),
           'Found non-existent header.')
  endforeach
endforeach
meson-0.53.2/test cases/common/34 has header/ouagadougou.h0000644000175000017500000000004313531533273024527 0ustar  jpakkanejpakkane00000000000000#define OMG_THIS_SHOULDNT_BE_FOUND
meson-0.53.2/test cases/common/35 run program/0000755000175000017500000000000013625242366022317 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/35 run program/get-version.py0000644000175000017500000000004513531533273025126 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

print('1.2')
meson-0.53.2/test cases/common/35 run program/meson.build0000644000175000017500000000422313605171342024453 0ustar  jpakkanejpakkane00000000000000project('run command', version : run_command('get-version.py', check : true).stdout().strip())

if build_machine.system() == 'windows'
  c = run_command('cmd', '/c', 'echo', 'hello')
else
  c = run_command('echo', 'hello')
endif

correct = 'hello'

if c.returncode() != 0
  error('Executing echo failed.')
endif

result = c.stdout().strip()

if result != correct
  error('Getting stdout failed.')
endif

if c.stderr() != ''
  error('Extra text in stderr.')
endif

# Now the same with a script.

if build_machine.system() == 'windows'
  cs = run_command('scripts/hello.bat')
else
  cs = run_command('scripts/hello.sh')
endif

if cs.returncode() != 0
  error('Executing script failed.')
endif

if cs.stdout().strip() != correct
  error('Getting stdout failed (script).')
endif

if cs.stderr() != ''
  error('Extra text in stderr (script).')
endif

# We should be able to have files() in argument
f = files('meson.build')

if build_machine.system() == 'windows'
  c = run_command('cmd', '/c', 'echo', f)
else
  c = run_command('echo', f)
endif

if c.returncode() != 0
  error('Using files() in argument failed.')
endif

py3 = import('python3').find_python()

ret = run_command(py3, '-c', 'print("some output")')
assert(ret.returncode() == 0, 'failed to run python3: ' + ret.stderr())
assert(ret.stdout() == 'some output\n', 'failed to run python3')

ret = run_command(py3, '-c', 'print("some output")', capture : false)
assert(ret.returncode() == 0, 'failed to run python3: ' + ret.stderr())
assert(ret.stdout() == '', 'stdout is "@0@" instead of empty'.format(ret.stdout()))

c_env = environment()
c_env.append('CUSTOM_ENV_VAR', 'FOOBAR')
ret = run_command(py3, '-c', 'import os; print(os.environ.get("CUSTOM_ENV_VAR"))', env : c_env)
assert(ret.returncode() == 0, 'failed to run python3: ' + ret.stderr())
assert(ret.stdout() == 'FOOBAR\n', 'stdout is "@0@" instead of FOOBAR'.format(ret.stdout()))

dd = find_program('dd', required : false)
if dd.found()
  ret = run_command(dd, 'if=/dev/urandom', 'bs=10', 'count=1', capture: false)
  assert(ret.returncode() == 0, 'failed to run dd: ' + ret.stderr())
  assert(ret.stdout() == '', 'stdout is "@0@" instead of empty'.format(ret.stdout()))
endif
meson-0.53.2/test cases/common/35 run program/scripts/0000755000175000017500000000000013625242366024006 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/35 run program/scripts/hello.bat0000644000175000017500000000002513531533273025572 0ustar  jpakkanejpakkane00000000000000@ECHO OFF
ECHO hello
meson-0.53.2/test cases/common/35 run program/scripts/hello.sh0000755000175000017500000000002613531533273025442 0ustar  jpakkanejpakkane00000000000000#!/bin/sh

echo hello
meson-0.53.2/test cases/common/36 tryrun/0000755000175000017500000000000013625242366021427 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/36 tryrun/error.c0000644000175000017500000000003713571777336022736 0ustar  jpakkanejpakkane00000000000000int main(void) {
  return 1;
}
meson-0.53.2/test cases/common/36 tryrun/meson.build0000644000175000017500000000350413605171346023570 0ustar  jpakkanejpakkane00000000000000project('tryrun', 'c', 'cpp')

# Complex to exercise all code paths.
if meson.is_cross_build()
  if meson.has_exe_wrapper()
    compilers = [meson.get_compiler('c', native : false), meson.get_compiler('cpp', native : false)]
  else
    compilers = [meson.get_compiler('c', native : true), meson.get_compiler('cpp', native : true)]
  endif
else
  compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')]
endif

ok_code = '''#include
int main(void) {
  printf("%s\n", "stdout");
  fprintf(stderr, "%s\n", "stderr");
  return 0;
}
'''

error_code = '''int main(void) {
  return 1;
}
'''

no_compile_code = '''int main(void) {
'''

INPUTS = [
  ['String', ok_code, error_code, no_compile_code],
  ['File', files('ok.c'), files('error.c'), files('no_compile.c')],
]

foreach cc : compilers
  foreach input : INPUTS
    type = input[0]
    ok = cc.run(input[1], name : type + ' should succeed')
    err = cc.run(input[2], name : type + ' should fail')
    noc = cc.run(input[3], name : type + ' does not compile')

    if noc.compiled()
      error(type + ' compilation fail test failed.')
    else
      message(type + ' fail detected properly.')
    endif

    if ok.compiled()
      message(type + ' compilation worked.')
    else
      error(type + ' compilation did not work.')
    endif

    if ok.returncode() == 0
      message(type + ' return code ok.')
    else
      error(type + ' return code fail')
    endif

    if err.returncode() == 1
      message(type + ' bad return code ok.')
    else
      error(type + ' bad return code fail.')
    endif

    if ok.stdout().strip() == 'stdout'
      message(type + ' stdout ok.')
    else
      message(type + ' bad stdout.')
    endif

    if ok.stderr().strip() == 'stderr'
      message(type + ' stderr ok.')
    else
      message(type + ' bad stderr.')
    endif
  endforeach
endforeach
meson-0.53.2/test cases/common/36 tryrun/no_compile.c0000644000175000017500000000002113571777336023722 0ustar  jpakkanejpakkane00000000000000int main(void) {
meson-0.53.2/test cases/common/36 tryrun/ok.c0000644000175000017500000000016313571777336022216 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
  printf("%s\n", "stdout");
  fprintf(stderr, "%s\n", "stderr");
  return 0;
}
meson-0.53.2/test cases/common/37 logic ops/0000755000175000017500000000000013625242366021744 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/37 logic ops/meson.build0000644000175000017500000000207413605171345024105 0ustar  jpakkanejpakkane00000000000000project('logicopts', 'c')

t = true
f = false

if (true)
  message('Ok.')
else
  error('Not ok.')
endif

if (false)
  error('Not ok.')
else
  message('Ok.')
endif

if (f)
  error('Not ok.')
else
  message('Ok.')
endif

if (t)
  message('Ok.')
else
  error('Not ok.')
endif

if true and t
  message('Ok.')
else
  error('Not ok.')
endif

if t and false
  error('Not ok.')
else
  message('Ok.')
endif

if f and t
  error('Not ok.')
else
  message('Ok.')
endif

if f or false
  error('Not ok.')
else
  message('Ok.')
endif

if true or f
  message('Ok.')
else
  error('Not ok.')
endif

if t or true
  message('Ok.')
else
  error('Not ok.')
endif

if not true
  error('Negation failed.')
else
  message('Ok.')
endif

if not f
  message('Ok.')
else
  error('Negation failed.')
endif


if f or f or f or f or f or f or f or f or t
  message('Ok.')
else
  error('Chain of ors failed.')
endif

if t and t and t and t and t and t and t and t and f
  error('Chain of ands failed.')
else
  message('Ok.')
endif

if t and t or t
  message('Ok.')
else
  error('Combination of and-or failed.')
endif
meson-0.53.2/test cases/common/38 string operations/0000755000175000017500000000000013625242366023540 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/38 string operations/meson.build0000644000175000017500000000740713605171345025706 0ustar  jpakkanejpakkane00000000000000project('string formatting', 'c')

templ = '@0@bar@1@'

assert(templ.format('foo', 'baz') == 'foobarbaz', 'Basic string formatting is broken.')

assert('@0@'.format(1) == '1', 'String number formatting is broken.')

assert('@0@'.format(true) == 'true', 'String boolean formatting is broken.')

templ2 = '@0@'
subs2 = '42'

assert(templ2.format(subs2) == '42', 'String formatting with variables is broken.')

assert('@@0@@ @@1@@'.format(1, 2) == '@1@ @2@', 'String format is recursive.')

long = 'abcde'
prefix = 'abc'
suffix = 'cde'

assert(long.startswith(prefix), 'Prefix.')

assert(not long.startswith(suffix), 'Not prefix.')

assert(long.endswith(suffix), 'Suffix.')

assert(not long.endswith(prefix), 'Not suffix.')

assert(long.contains(prefix), 'Does not contain prefix')

assert(long.contains(suffix), 'Does not contain suffix')

assert(long.contains('bcd'), 'Does not contain middle part')

assert(not long.contains('dc'), 'Broken contains')

assert(long.to_upper() == 'ABCDE', 'Broken to_upper')

assert(long.to_upper().to_lower() == long, 'Broken to_lower')

assert('struct stat.st_foo'.underscorify() == 'struct_stat_st_foo', 'Broken underscorify')

assert('#include '.underscorify() == '_include__foo_bar_h_', 'Broken underscorify')

# case should not change, space should be replaced, numbers are ok too
assert('Do SomeThing 09'.underscorify() == 'Do_SomeThing_09', 'Broken underscorify')

assert('3'.to_int() == 3, 'String int conversion does not work.')

assert(true.to_string() == 'true', 'bool string conversion failed')
assert(false.to_string() == 'false', 'bool string conversion failed')
assert(true.to_string('yes', 'no') == 'yes', 'bool string conversion with args failed')
assert(false.to_string('yes', 'no') == 'no', 'bool string conversion with args failed')
assert('@0@'.format(true) == 'true', 'bool string formatting failed')

assert(' '.join(['a', 'b', 'c']) == 'a b c', 'join() array broken')
assert(''.join(['a', 'b', 'c']) == 'abc', 'empty join() broken')
assert(' '.join(['a']) == 'a', 'single join broken')

version_number = '1.2.8'

assert(version_number.version_compare('>=1.2.8'), 'Version_compare gt broken')
assert(not version_number.version_compare('>1.2.8'), 'Version_compare greater broken')
assert(not version_number.version_compare('<1.2.8'), 'Version_compare less broken')
assert(version_number.version_compare('<=1.2.8'), 'Version_compare le broken')
assert(version_number.version_compare('==1.2.8'), 'Version_compare eq broken')
assert(not version_number.version_compare('!=1.2.8'), 'Version_compare neq broken')

assert(version_number.version_compare('<2.0'), 'Version_compare major less broken')
assert(version_number.version_compare('>0.9'), 'Version_compare major greater broken')

assert(' spaces	tabs	'.strip() == 'spaces	tabs', 'Spaces and tabs badly stripped')
assert(''' 
multiline string	'''.strip() == '''multiline string''', 'Newlines badly stripped')
assert('"1.1.20"'.strip('"') == '1.1.20', '" badly stripped')
assert('"1.1.20"'.strip('".') == '1.1.20', '". badly stripped')
assert('"1.1.20"   '.strip('" ') == '1.1.20', '". badly stripped')

bs_c = '''\c'''
bs_bs_c = '''\\c'''
nl = '''
'''
bs_n = '''\n'''
bs_nl = '''\
'''
bs_bs_n = '''\\n'''
bs_bs_nl = '''\\
'''
bs_bs = '''\\'''
bs = '''\'''

assert('\c' == bs_c, 'Single backslash broken')
assert('\\c' == bs_c, 'Double backslash broken')
assert('\\\c' == bs_bs_c, 'Three backslash broken')
assert('\\\\c' == bs_bs_c, 'Four backslash broken')
assert('\n' == nl, 'Newline escape broken')
assert('\\n' == bs_n, 'Double backslash broken before n')
assert('\\\n' == bs_nl, 'Three backslash broken before n')
assert('\\\\n' == bs_bs_n, 'Four backslash broken before n')
assert('\\\\\n' == bs_bs_nl, 'Five backslash broken before n')
assert('\\\\' == bs_bs, 'Double-backslash broken')
assert('\\' == bs, 'Backslash broken')
meson-0.53.2/test cases/common/39 has function/0000755000175000017500000000000013625242366022450 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/39 has function/meson.build0000644000175000017500000001004613605171352024605 0ustar  jpakkanejpakkane00000000000000project('has function', 'c', 'cpp')

host_system = host_machine.system()

# This is used in the `test_compiler_check_flags_order` unit test
unit_test_args = '-I/tmp'
defines_has_builtin = '''#ifndef __has_builtin
#error "no __has_builtin"
#endif
'''
compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')]

foreach cc : compilers
  if not cc.has_function('printf', prefix : '#include',
                         args : unit_test_args)
    error('"printf" function not found (should always exist).')
  endif

  # Should also be able to detect it without specifying the header
  # We check for a different function here to make sure the result is
  # not taken from a cache (ie. the check above)
  # On MSVC fprintf is defined as an inline function in the header, so it cannot
  # be found without the include.
  if not ['msvc', 'intel-cl'].contains(cc.get_id())
    assert(cc.has_function('fprintf', args : unit_test_args),
           '"fprintf" function not found without include (on !msvc).')
  else
    assert(cc.has_function('fprintf', prefix : '#include ',
                           args : unit_test_args),
           '"fprintf" function not found with include (on msvc).')
    # Compiler intrinsics
    assert(cc.has_function('strcmp'),
           'strcmp intrinsic should have been found on MSVC')
    assert(cc.has_function('strcmp', prefix : '#include '),
           'strcmp intrinsic should have been found with #include on MSVC')
  endif

  if cc.has_function('hfkerhisadf', prefix : '#include',
                     args : unit_test_args)
    error('Found non-existent function "hfkerhisadf".')
  endif

  if cc.has_function('hfkerhisadf', args : unit_test_args)
    error('Found non-existent function "hfkerhisadf".')
  endif

  # With glibc on Linux lchmod is a stub that will always return an error,
  # we want to detect that and declare that the function is not available.
  # We can't check for the C library used here of course, but if it's not
  # implemented in glibc it's probably not implemented in any other 'slimmer'
  # C library variants either, so the check should be safe either way hopefully.
  if host_system == 'linux' or host_system == 'darwin'
    assert (cc.has_function('poll', prefix : '#include ',
                            args : unit_test_args),
            'couldn\'t detect "poll" when defined by a header')
    lchmod_prefix = '#include \n#include '
    if host_system == 'linux'
      assert (not cc.has_function('lchmod', prefix : lchmod_prefix,
                                  args : unit_test_args),
              '"lchmod" check should have failed')
    else
      # macOS and *BSD have lchmod
      assert (cc.has_function('lchmod', prefix : lchmod_prefix,
                                  args : unit_test_args),
              '"lchmod" check should have succeeded')
    endif
    # Check that built-ins are found properly both with and without headers
    assert(cc.has_function('alloca', args : unit_test_args),
           'built-in alloca must be found on ' + host_system)
    assert(cc.has_function('alloca', prefix : '#include ',
           args : unit_test_args),
           'built-in alloca must be found with #include')
    if not cc.compiles(defines_has_builtin, args : unit_test_args)
      assert(not cc.has_function('alloca',
             prefix : '#include \n#undef alloca',
             args : unit_test_args),
             'built-in alloca must not be found with #include and #undef')
    endif
  endif

  # For some functions one needs to define _GNU_SOURCE before including the
  # right headers to get them picked up. Make sure we can detect these functions
  # as well without any prefix
  if cc.has_header_symbol('sys/socket.h', 'recvmmsg',
                          prefix : '#define _GNU_SOURCE',
                          args : unit_test_args)
    # We assume that if recvmmsg exists sendmmsg does too
    assert (cc.has_function('sendmmsg', args : unit_test_args),
            'Failed to detect function "sendmmsg" (should always exist).')
  endif
endforeach
meson-0.53.2/test cases/common/4 shared/0000755000175000017500000000000013625242366021245 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/4 shared/libfile.c0000644000175000017500000000052413571777336023032 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC libfunc(void) {
    return 3;
}
meson-0.53.2/test cases/common/4 shared/meson.build0000644000175000017500000000056613605171303023404 0ustar  jpakkanejpakkane00000000000000project('shared library test', 'c')
lib = shared_library('mylib', 'libfile.c')
build_target('mylib2', 'libfile.c', target_type: 'shared_library')

has_not_changed = false
if is_disabler(lib)
    has_not_changed = true
else
    has_not_changed = true
endif
assert(has_not_changed, 'Shared library has changed.')

assert(not is_disabler(lib), 'Shared library is a disabler.')
meson-0.53.2/test cases/common/40 has member/0000755000175000017500000000000013625242366022062 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/40 has member/meson.build0000644000175000017500000000140113605171351024211 0ustar  jpakkanejpakkane00000000000000project('has member', 'c', 'cpp')

compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')]

foreach cc : compilers
  if not cc.has_member('struct tm', 'tm_sec', prefix : '#include')
    error('Did not detect member of "struct tm" that exists: "tm_sec"')
  endif

  if cc.has_member('struct tm', 'tm_nonexistent', prefix : '#include')
    error('Not existing member "tm_nonexistent" found.')
  endif

  if not cc.has_members('struct tm', 'tm_sec', 'tm_min', prefix : '#include')
    error('Did not detect members of "struct tm" that exist: "tm_sec" "tm_min"')
  endif

  if cc.has_members('struct tm', 'tm_sec', 'tm_nonexistent2', prefix : '#include')
    error('Not existing member "tm_nonexistent2" found.')
  endif
endforeach
meson-0.53.2/test cases/common/41 alignment/0000755000175000017500000000000013625242366022036 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/41 alignment/meson.build0000644000175000017500000000154413605171353024177 0ustar  jpakkanejpakkane00000000000000project('alignment', 'c', 'cpp')

compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')]

foreach cc : compilers
  # These tests should return the same value on all
  # platforms. If (and when) they don't, fix 'em up.
  if cc.alignment('char') != 1
    error('Alignment of char misdetected.')
  endif

  ptr_size = cc.sizeof('void*')
  dbl_alignment = cc.alignment('double')

  # These tests are not thorough. Doing this properly
  # would take a lot of work because it is strongly
  # platform  and compiler dependent. So just check
  # that they produce something fairly sane.

  if ptr_size == 8 or ptr_size == 4
    message('Size of ptr ok.')
  else
    error('Size of ptr misdetected.')
  endif

  if dbl_alignment == 8 or dbl_alignment == 4
    message('Alignment of double ok.')
  else
    error('Alignment of double misdetected.')
  endif
endforeach
meson-0.53.2/test cases/common/42 library chain/0000755000175000017500000000000013625242366022570 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/42 library chain/installed_files.txt0000644000175000017500000000005013531533273026461 0ustar  jpakkanejpakkane00000000000000usr/bin/prog?exe
?msvc:usr/bin/prog.pdb
meson-0.53.2/test cases/common/42 library chain/main.c0000644000175000017500000000007113571777336023670 0ustar  jpakkanejpakkane00000000000000int libfun(void);

int main(void) {
  return libfun();
}
meson-0.53.2/test cases/common/42 library chain/meson.build0000644000175000017500000000017513605171354024731 0ustar  jpakkanejpakkane00000000000000project('libchain', 'c')

subdir('subdir')
e = executable('prog', 'main.c', link_with : lib1, install : true)
test('tst', e)
meson-0.53.2/test cases/common/42 library chain/subdir/0000755000175000017500000000000013625242366024060 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/42 library chain/subdir/lib1.c0000644000175000017500000000061413571777336025066 0ustar  jpakkanejpakkane00000000000000int lib2fun(void);
int lib3fun(void);

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC libfun(void) {
  return lib2fun() + lib3fun();
}
meson-0.53.2/test cases/common/42 library chain/subdir/meson.build0000644000175000017500000000017013531533273026214 0ustar  jpakkanejpakkane00000000000000subdir('subdir2')
subdir('subdir3')

lib1 = shared_library('lib1', 'lib1.c', install : false, link_with : [lib2, lib3])
meson-0.53.2/test cases/common/42 library chain/subdir/subdir2/0000755000175000017500000000000013625242366025432 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/42 library chain/subdir/subdir2/lib2.c0000644000175000017500000000052213571777336026437 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC lib2fun(void) {
  return 0;
}
meson-0.53.2/test cases/common/42 library chain/subdir/subdir2/meson.build0000644000175000017500000000007113531533273027566 0ustar  jpakkanejpakkane00000000000000lib2 = shared_library('lib2', 'lib2.c', install : false)
meson-0.53.2/test cases/common/42 library chain/subdir/subdir3/0000755000175000017500000000000013625242366025433 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/42 library chain/subdir/subdir3/lib3.c0000644000175000017500000000052313571777336026442 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC lib3fun(void)  {
  return 0;
}
meson-0.53.2/test cases/common/42 library chain/subdir/subdir3/meson.build0000644000175000017500000000007113531533273027567 0ustar  jpakkanejpakkane00000000000000lib3 = shared_library('lib3', 'lib3.c', install : false)
meson-0.53.2/test cases/common/43 options/0000755000175000017500000000000013625242366021555 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/43 options/meson.build0000644000175000017500000000147213605171353023716 0ustar  jpakkanejpakkane00000000000000project('options', 'c')

if get_option('testoption') != 'optval'
  error('Incorrect value to test option')
endif

if get_option('other_one') != false
  error('Incorrect value to boolean option.')
endif

if get_option('combo_opt') != 'combo'
  error('Incorrect value to combo option.')
endif

if get_option('array_opt') != ['one', 'two']
  message(get_option('array_opt'))
  error('Incorrect value for array option')
endif

# If the default changes, update test cases/unit/13 reconfigure
if get_option('b_lto') != false
  error('Incorrect value in base option.')
endif

if get_option('includedir') != 'include'
  error('Incorrect value in builtin option.')
endif

if get_option('integer_opt') != 3
  error('Incorrect value in integer option.')
endif

assert(get_option('wrap_mode') == 'default', 'Wrap mode option is broken.')
meson-0.53.2/test cases/common/43 options/meson_options.txt0000644000175000017500000000067513531533273025216 0ustar  jpakkanejpakkane00000000000000option('testoption', type : 'string', value : 'optval', description : 'An option to do something')
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'combo'], value : 'combo')
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one', 'two'])
option('free_array_opt', type : 'array')
option('integer_opt', type : 'integer', min : 0, max : 5, value : 3)
meson-0.53.2/test cases/common/44 test args/0000755000175000017500000000000013625242366021757 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/44 test args/cmd_args.c0000644000175000017500000000066113531533273023701 0ustar  jpakkanejpakkane00000000000000#include
#include

int main(int argc, char **argv) {
    if(argc != 3) {
        fprintf(stderr, "Incorrect number of arguments.\n");
        return 1;
    }
    if(strcmp(argv[1], "first") != 0) {
        fprintf(stderr, "First argument is wrong.\n");
        return 1;
    }
    if(strcmp(argv[2], "second") != 0) {
        fprintf(stderr, "Second argument is wrong.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/44 test args/copyfile.py0000644000175000017500000000013413531533273024135 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import shutil

shutil.copyfile(sys.argv[1], sys.argv[2])
meson-0.53.2/test cases/common/44 test args/env2vars.c0000644000175000017500000000117213571777336023704 0ustar  jpakkanejpakkane00000000000000#include
#include
#include

int main(void) {
    if(strcmp(getenv("first"), "something-else") != 0) {
        fprintf(stderr, "First envvar is wrong. %s\n", getenv("first"));
        return 1;
    }
    if(strcmp(getenv("second"), "val2") != 0) {
        fprintf(stderr, "Second envvar is wrong.\n");
        return 1;
    }
    if(strcmp(getenv("third"), "val3:and_more") != 0) {
        fprintf(stderr, "Third envvar is wrong.\n");
        return 1;
    }
    if(strstr(getenv("PATH"), "fakepath:") != NULL) {
        fprintf(stderr, "Third envvar is wrong.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/44 test args/envvars.c0000644000175000017500000000116013571777336023617 0ustar  jpakkanejpakkane00000000000000#include
#include
#include

int main(void) {
    if(strcmp(getenv("first"), "val1") != 0) {
        fprintf(stderr, "First envvar is wrong. %s\n", getenv("first"));
        return 1;
    }
    if(strcmp(getenv("second"), "val2") != 0) {
        fprintf(stderr, "Second envvar is wrong.\n");
        return 1;
    }
    if(strcmp(getenv("third"), "val3:and_more") != 0) {
        fprintf(stderr, "Third envvar is wrong.\n");
        return 1;
    }
    if(strstr(getenv("PATH"), "fakepath:") != NULL) {
        fprintf(stderr, "Third envvar is wrong.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/44 test args/meson.build0000644000175000017500000000244513605171355024123 0ustar  jpakkanejpakkane00000000000000project('test features', 'c')

e1 = executable('cmd_args', 'cmd_args.c')
e2 = executable('envvars', 'envvars.c')
e3 = executable('env2vars', 'env2vars.c')

env = environment()
env.set('first', 'val1')
env.set('second', 'val2')
env.set('third', 'val3', 'and_more', separator: ':')
env.append('PATH', 'fakepath', separator: ':')

# Make sure environment objects are copied on assignment and we can
# change the copy without affecting the original environment object.
env2 = env
env2.set('first', 'something-else')

test('command line arguments', e1, args : ['first', 'second'])
test('environment variables', e2, env : env)
test('environment variables 2', e3, env : env2)

# https://github.com/mesonbuild/meson/issues/2211#issuecomment-327741571
env_array = ['MESONTESTING=picklerror']
testfile = files('testfile.txt')
testerpy = find_program('tester.py')
test('file arg', testerpy, args : testfile, env : env_array)

copy = find_program('copyfile.py')
tester = executable('tester', 'tester.c')
testfilect = custom_target('testfile',
                           input : testfile,
                           output : 'outfile.txt',
                           build_by_default : true,
                           command : [copy, '@INPUT@', '@OUTPUT@'])
test('custom target arg', tester, args : testfilect, env : env_array)
meson-0.53.2/test cases/common/44 test args/tester.c0000644000175000017500000000134013531533273023423 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include 
#include 

#ifndef _MSC_VER
#include 
#endif

int main(int argc, char **argv) {
    char data[10];
    int fd, size;

    if (argc != 2) {
        fprintf(stderr, "Incorrect number of arguments, got %i\n", argc);
        return 1;
    }
    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        fprintf(stderr, "First argument is wrong.\n");
        return 1;
    }

    size = read(fd, data, 8);
    if (size < 0) {
        fprintf(stderr, "Failed to read: %s\n", strerror(errno));
        return 1;
    }
    if (strncmp(data, "contents", 8) != 0) {
        fprintf(stderr, "Contents don't match, got %s\n", data);
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/44 test args/tester.py0000755000175000017500000000016613531533273023641 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

with open(sys.argv[1]) as f:
    if f.read() != 'contents\n':
        sys.exit(1)
meson-0.53.2/test cases/common/44 test args/testfile.txt0000644000175000017500000000001113531533273024323 0ustar  jpakkanejpakkane00000000000000contents
meson-0.53.2/test cases/common/45 subproject/0000755000175000017500000000000013625242366022244 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/45 subproject/installed_files.txt0000644000175000017500000000010613531533273026137 0ustar  jpakkanejpakkane00000000000000usr/bin/user?exe
?msvc:usr/bin/user.pdb
usr/share/sublib/sublib.depmf
meson-0.53.2/test cases/common/45 subproject/meson.build0000644000175000017500000000145713605171357024414 0ustar  jpakkanejpakkane00000000000000project('subproj user', 'c', 
  version : '2.3.4',
  license : 'mylicense')

assert(meson.project_name() == 'subproj user', 'Incorrect project name')

sub = subproject('sublib', version : '1.0.0')

if meson.project_version() != '2.3.4'
  error('Incorrect master project version string:' + meson.project_version())
endif

if meson.is_subproject()
  error('Claimed to be a subproject even though we are the master project.')
endif

inc = sub.get_variable('i')
lib = sub.get_variable('l')

e = executable('user', 'user.c', include_directories : inc, link_with : lib, install : true)
test('subdirtest', e)

meson.install_dependency_manifest('share/sublib/sublib.depmf')

unknown_var = sub.get_variable('does-not-exist', [])
if unknown_var != []
  error ('unexpetced fallback value for subproject.get_variable()')
endif
meson-0.53.2/test cases/common/45 subproject/subprojects/0000755000175000017500000000000013625242351024601 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/45 subproject/subprojects/sublib/0000755000175000017500000000000013625242366026067 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/45 subproject/subprojects/sublib/include/0000755000175000017500000000000013625242366027512 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/45 subproject/subprojects/sublib/include/subdefs.h0000644000175000017500000000070313571777336031330 0ustar  jpakkanejpakkane00000000000000#ifndef SUBDEFS_H_
#define SUBDEFS_H_

#if defined _WIN32 || defined __CYGWIN__
#if defined BUILDING_SUB
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #define DLL_PUBLIC __declspec(dllimport)
#endif
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC subfunc(void);

#endif
meson-0.53.2/test cases/common/45 subproject/subprojects/sublib/meson.build0000644000175000017500000000116013531533273030223 0ustar  jpakkanejpakkane00000000000000project('subproject', 'c', 
  version : '1.0.0',
  license : ['sublicense1', 'sublicense2'])

if not meson.is_subproject()
  error('Claimed to be master project even though we are a subproject.')
endif

assert(meson.project_name() == 'subproject', 'Incorrect subproject name')

if meson.project_version() != '1.0.0'
  error('Incorrect version string in subproject.')
endif

i = include_directories('include')
l = shared_library('sublib', 'sublib.c', include_directories : i, install : false,
 c_args : '-DBUILDING_SUB=2')
t = executable('simpletest', 'simpletest.c', include_directories : i, link_with : l)
test('plain', t)
meson-0.53.2/test cases/common/45 subproject/subprojects/sublib/simpletest.c0000644000175000017500000000011413571777336030432 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    return subfunc() == 42 ? 0 : 1;
}
meson-0.53.2/test cases/common/45 subproject/subprojects/sublib/sublib.c0000644000175000017500000000010513571777336027521 0ustar  jpakkanejpakkane00000000000000#include

int DLL_PUBLIC subfunc(void) {
    return 42;
}
meson-0.53.2/test cases/common/45 subproject/user.c0000644000175000017500000000044613571777336023404 0ustar  jpakkanejpakkane00000000000000#include
#include


int main(void) {
    int res;
    printf("Calling into sublib now.\n");
    res = subfunc();
    if(res == 42) {
        printf("Everything is fine.\n");
        return 0;
    } else {
        printf("Something went wrong.\n");
        return 1;
    }
}
meson-0.53.2/test cases/common/46 subproject options/0000755000175000017500000000000013625242366023721 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/46 subproject options/meson.build0000644000175000017500000000020313605171357026055 0ustar  jpakkanejpakkane00000000000000project('suboptions', 'c')

subproject('subproject')

if not get_option('opt')
  error('option unset when it should be set')
endif
meson-0.53.2/test cases/common/46 subproject options/meson_options.txt0000644000175000017500000000012313531533273027346 0ustar  jpakkanejpakkane00000000000000option('opt', type : 'boolean', value : true, description : 'main project option')
meson-0.53.2/test cases/common/46 subproject options/subprojects/0000755000175000017500000000000013625242351026256 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/46 subproject options/subprojects/subproject/0000755000175000017500000000000013625242367030445 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/46 subproject options/subprojects/subproject/meson.build0000644000175000017500000000014613531533273032603 0ustar  jpakkanejpakkane00000000000000project('subproject', 'c')

if get_option('opt')
  error('option set when it should be unset.')
endif
meson-0.53.2/test cases/common/46 subproject options/subprojects/subproject/meson_options.txt0000644000175000017500000000012213531533273034070 0ustar  jpakkanejpakkane00000000000000option('opt', type : 'boolean', value : false, description : 'subproject option')
meson-0.53.2/test cases/common/47 pkgconfig-gen/0000755000175000017500000000000013625242367022605 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/47 pkgconfig-gen/dependencies/0000755000175000017500000000000013625242367025233 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/47 pkgconfig-gen/dependencies/custom.c0000644000175000017500000000005513571777336026722 0ustar  jpakkanejpakkane00000000000000int custom_function(void) {
    return 42;
}
meson-0.53.2/test cases/common/47 pkgconfig-gen/dependencies/exposed.c0000644000175000017500000000005613571777336027060 0ustar  jpakkanejpakkane00000000000000int exposed_function(void) {
    return 42;
}
meson-0.53.2/test cases/common/47 pkgconfig-gen/dependencies/internal.c0000644000175000017500000000005713571777336027226 0ustar  jpakkanejpakkane00000000000000int internal_function(void) {
    return 42;
}
meson-0.53.2/test cases/common/47 pkgconfig-gen/dependencies/meson.build0000644000175000017500000000471713543771101027376 0ustar  jpakkanejpakkane00000000000000project('pkgconfig-gen-dependencies', 'c', version: '1.0')

pkgg = import('pkgconfig')

# libmain internally use libinternal and expose libexpose in its API
exposed_lib = shared_library('libexposed', 'exposed.c')
internal_lib = shared_library('libinternal', 'internal.c')
main_lib = both_libraries('libmain', link_with : [exposed_lib, internal_lib])
custom_lib = shared_library('custom', 'custom.c')

pkgg.generate(exposed_lib)

# Declare a few different Dependency objects
pc_dep = dependency('libfoo', version : '>=1.0')
pc_dep_dup = dependency('libfoo', version : '>= 1.0')
notfound_dep = dependency('notfound', required : false)
threads_dep = dependency('threads')
custom_dep = declare_dependency(link_with : custom_lib, compile_args : ['-DCUSTOM'])
custom2_dep = declare_dependency(link_args : ['-lcustom2'], compile_args : ['-DCUSTOM2'])

# Generate a PC file:
# - Having libmain in libraries should pull implicitly libexposed and libinternal in Libs.private
# - Having libexposed in libraries should remove it from Libs.private
# - We generated a pc file for libexposed so it should be in Requires instead of Libs
# - Having threads_dep in libraries should add '-pthread' in both Libs and Cflags
# - Having custom_dep in libraries and libraries_private should only add it in Libs
# - Having custom2_dep in libraries_private should not add its Cflags
# - Having pc_dep in libraries_private should add it in Requires.private
# - pc_dep_dup is the same library and same version, should be ignored
# - notfound_dep is not required so it shouldn't appear in the pc file.
pkgg.generate(libraries : [main_lib, exposed_lib, threads_dep, threads_dep, custom_dep, custom_dep, '-pthread'],
  libraries_private : [custom_dep, custom2_dep, custom2_dep, pc_dep, pc_dep_dup, notfound_dep],
  version : '1.0',
  name : 'dependency-test',
  filebase : 'dependency-test',
  description : 'A dependency test.'
)

pkgg.generate(
  name : 'requires-test',
  version : '1.0',
  description : 'Dependency Requires field test.',
  requires : [exposed_lib, pc_dep, 'libhello'],
)

pkgg.generate(
  name : 'requires-private-test',
  version : '1.0',
  description : 'Dependency Requires.private field test.',
  requires_private : [exposed_lib, pc_dep, 'libhello', notfound_dep],
)

# Verify that if we promote internal_lib as public dependency, it comes after
# the main library.
main_lib2 = both_libraries('libmain2', link_with : internal_lib)
pkgg.generate(main_lib2,
  libraries : internal_lib,
  filebase : 'pub-lib-order',
)
meson-0.53.2/test cases/common/47 pkgconfig-gen/installed_files.txt0000644000175000017500000000015313531533273026501 0ustar  jpakkanejpakkane00000000000000usr/include/simple.h
usr/lib/pkgconfig/simple.pc
usr/lib/pkgconfig/libfoo.pc
usr/lib/pkgconfig/libhello.pc
meson-0.53.2/test cases/common/47 pkgconfig-gen/meson.build0000644000175000017500000000256613605171357024756 0ustar  jpakkanejpakkane00000000000000project('pkgconfig-gen', 'c')

# First check we have pkg-config >= 0.29

pkgconfig = find_program('pkg-config', required: false)
if not pkgconfig.found()
  error('MESON_SKIP_TEST: pkg-config not found')
endif

v = run_command(pkgconfig, '--version').stdout().strip()
if v.version_compare('<0.29')
  error('MESON_SKIP_TEST: pkg-config version \'' + v + '\' too old')
endif

pkgg = import('pkgconfig')

lib = shared_library('simple', 'simple.c')
libver = '1.0'
h = install_headers('simple.h')

pkgg.generate(
  libraries : [lib, '-lz'],
  subdirs : '.',
  version : libver,
  name : 'libsimple',
  filebase : 'simple',
  description : 'A simple demo library.',
  requires : 'glib-2.0', # Not really, but only here to test that this works.
  requires_private : ['gio-2.0', 'gobject-2.0'],
  libraries_private : [lib, '-lz'],
)

test('pkgconfig-validation', pkgconfig,
  args: ['--validate', 'simple'],
  env: [ 'PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' ])

# Test that name_prefix='' and name='libfoo' results in '-lfoo'
lib2 = shared_library('libfoo', 'simple.c',
  name_prefix : '',
  version : libver)

pkgg.generate(
  libraries : lib2,
  name : 'libfoo',
  version : libver,
  description : 'A foo library.',
  variables : ['foo=bar', 'datadir=${prefix}/data']
)

pkgg.generate(
  name : 'libhello',
  description : 'A minimalistic pkgconfig file.',
  version : libver,
)
meson-0.53.2/test cases/common/47 pkgconfig-gen/simple.c0000644000175000017500000000010113571777336024243 0ustar  jpakkanejpakkane00000000000000#include"simple.h"

int simple_function(void) {
    return 42;
}
meson-0.53.2/test cases/common/47 pkgconfig-gen/simple.h0000644000175000017500000000011013571777336024250 0ustar  jpakkanejpakkane00000000000000#ifndef SIMPLE_H_
#define SIMPLE_H_

int simple_function(void);

#endif
meson-0.53.2/test cases/common/48 custom install dirs/0000755000175000017500000000000013625242367023753 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/48 custom install dirs/datafile.cat0000644000175000017500000000003413531533273026205 0ustar  jpakkanejpakkane00000000000000Installed cat is installed.
meson-0.53.2/test cases/common/48 custom install dirs/installed_files.txt0000644000175000017500000000045413531533273027653 0ustar  jpakkanejpakkane00000000000000usr/dib/dab/dub/prog?exe
?msvc:usr/dib/dab/dub/prog.pdb
usr/dib/dab/dub2/prog2?exe
?msvc:usr/dib/dab/dub2/prog2.pdb
usr/some/dir/sample.h
usr/some/dir2/sample.h
usr/woman/prog.1
usr/woman2/prog.1
usr/meow/datafile.cat
usr/meow2/datafile.cat
usr/woof/subdir/datafile.dog
usr/woof2/subdir/datafile.dog
meson-0.53.2/test cases/common/48 custom install dirs/meson.build0000644000175000017500000000130013605171361026100 0ustar  jpakkanejpakkane00000000000000project('custom install dirs', 'c')
executable('prog', 'prog.c', install : true, install_dir : 'dib/dab/dub')
executable('prog2', 'prog.c', install : true, install_dir : get_option('prefix') + '/dib/dab/dub2')
install_headers('sample.h', install_dir : 'some/dir')
install_headers('sample.h', install_dir : get_option('prefix') + '/some/dir2')
install_man('prog.1', install_dir : 'woman')
install_man('prog.1', install_dir : get_option('prefix') + '/woman2')
install_data('datafile.cat', install_dir : 'meow')
install_data('datafile.cat', install_dir : get_option('prefix') + '/meow2')
install_subdir('subdir', install_dir : 'woof')
install_subdir('subdir', install_dir : get_option('prefix') + '/woof2')
meson-0.53.2/test cases/common/48 custom install dirs/prog.10000644000175000017500000000001513531533273024773 0ustar  jpakkanejpakkane00000000000000Man up, you.
meson-0.53.2/test cases/common/48 custom install dirs/prog.c0000644000175000017500000000004113571777336025072 0ustar  jpakkanejpakkane00000000000000int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/48 custom install dirs/sample.h0000644000175000017500000000007413531533273025401 0ustar  jpakkanejpakkane00000000000000#ifndef SAMPLE_H
#define SAMPLE_H

int wackiness();

#endif
meson-0.53.2/test cases/common/48 custom install dirs/subdir/0000755000175000017500000000000013625242367025243 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/48 custom install dirs/subdir/datafile.dog0000644000175000017500000000003413531533273027477 0ustar  jpakkanejpakkane00000000000000Installed dog is installed.
meson-0.53.2/test cases/common/49 subproject subproject/0000755000175000017500000000000013625242367024412 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/49 subproject subproject/meson.build0000644000175000017500000000040713605171364026551 0ustar  jpakkanejpakkane00000000000000project('sub sub', 'c')

a = subproject('a')
lib = a.get_variable('l')

dependency('not-found-dep', required : false,
           version : '>=1',
           fallback : ['c', 'notfound_dep'])

exe = executable('prog', 'prog.c', link_with : lib)
test('basic', exe)
meson-0.53.2/test cases/common/49 subproject subproject/prog.c0000644000175000017500000000010513571777336025532 0ustar  jpakkanejpakkane00000000000000int func(void);

int main(void) {
    return func() == 42 ? 0 : 1;
}
meson-0.53.2/test cases/common/49 subproject subproject/subprojects/0000755000175000017500000000000013625242351026746 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/49 subproject subproject/subprojects/a/0000755000175000017500000000000013625242367027175 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/49 subproject subproject/subprojects/a/a.c0000644000175000017500000000054613571777336027577 0ustar  jpakkanejpakkane00000000000000int func2(void);

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC func(void) { return func2(); }

meson-0.53.2/test cases/common/49 subproject subproject/subprojects/a/meson.build0000644000175000017500000000015013531533273031326 0ustar  jpakkanejpakkane00000000000000project('a', 'c')

b = subproject('b')
l = shared_library('a', 'a.c', link_with : b.get_variable('lb'))
meson-0.53.2/test cases/common/49 subproject subproject/subprojects/b/0000755000175000017500000000000013625242367027176 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/49 subproject subproject/subprojects/b/b.c0000644000175000017500000000052313571777336027574 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC func2(void) {
    return 42;
}
meson-0.53.2/test cases/common/49 subproject subproject/subprojects/b/meson.build0000644000175000017500000000006313531533273031332 0ustar  jpakkanejpakkane00000000000000project('b', 'c')

lb = shared_library('b', 'b.c')
meson-0.53.2/test cases/common/49 subproject subproject/subprojects/c/0000755000175000017500000000000013625242367027177 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/49 subproject subproject/subprojects/c/meson.build0000644000175000017500000000015013531533273031330 0ustar  jpakkanejpakkane00000000000000project('not-found-dep-subproj', 'c', version : '1.0')

notfound_dep = dependency('', required : false)
meson-0.53.2/test cases/common/5 linkstatic/0000755000175000017500000000000013625242367022146 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/5 linkstatic/libfile.c0000644000175000017500000000004113571777336023724 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 0;
}
meson-0.53.2/test cases/common/5 linkstatic/libfile2.c0000644000175000017500000000004213571777336024007 0ustar  jpakkanejpakkane00000000000000int func2(void) {
    return 2;
}
meson-0.53.2/test cases/common/5 linkstatic/libfile3.c0000644000175000017500000000004213571777336024010 0ustar  jpakkanejpakkane00000000000000int func3(void) {
    return 3;
}
meson-0.53.2/test cases/common/5 linkstatic/libfile4.c0000644000175000017500000000004213571777336024011 0ustar  jpakkanejpakkane00000000000000int func4(void) {
    return 4;
}
meson-0.53.2/test cases/common/5 linkstatic/main.c0000644000175000017500000000006713571777336023252 0ustar  jpakkanejpakkane00000000000000int func(void);

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/5 linkstatic/meson.build0000644000175000017500000000035213605171306024300 0ustar  jpakkanejpakkane00000000000000project('static library linking test', 'c')

lib = build_target('mylib', 'libfile.c', 'libfile2.c', 'libfile3.c', 'libfile4.c', target_type : 'static_library')
exe = executable('prog', 'main.c', link_with : lib)

test('runtest', exe)
meson-0.53.2/test cases/common/50 same file name/0000755000175000017500000000000013625242367022607 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/50 same file name/d1/0000755000175000017500000000000013625242367023113 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/50 same file name/d1/file.c0000644000175000017500000000003713571777336024207 0ustar  jpakkanejpakkane00000000000000int func1(void) { return 42; }
meson-0.53.2/test cases/common/50 same file name/d2/0000755000175000017500000000000013625242367023114 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/50 same file name/d2/file.c0000644000175000017500000000003713571777336024210 0ustar  jpakkanejpakkane00000000000000int func2(void) { return 42; }
meson-0.53.2/test cases/common/50 same file name/meson.build0000644000175000017500000000014013605171363024737 0ustar  jpakkanejpakkane00000000000000project('samefile', 'c')

test('basic', executable('prog', 'prog.c', 'd1/file.c', 'd2/file.c'))
meson-0.53.2/test cases/common/50 same file name/prog.c0000644000175000017500000000012413571777336023730 0ustar  jpakkanejpakkane00000000000000int func1(void);
int func2(void);

int main(void) {
    return func1() - func2();
}
meson-0.53.2/test cases/common/51 file grabber/0000755000175000017500000000000013625242367022366 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/51 file grabber/a.c0000644000175000017500000000003613571777336022762 0ustar  jpakkanejpakkane00000000000000int funca(void) { return 0; }
meson-0.53.2/test cases/common/51 file grabber/b.c0000644000175000017500000000003613571777336022763 0ustar  jpakkanejpakkane00000000000000int funcb(void) { return 0; }
meson-0.53.2/test cases/common/51 file grabber/c.c0000644000175000017500000000003613571777336022764 0ustar  jpakkanejpakkane00000000000000int funcc(void) { return 0; }
meson-0.53.2/test cases/common/51 file grabber/grabber.bat0000644000175000017500000000006113531533273024452 0ustar  jpakkanejpakkane00000000000000@ECHO OFF
echo a.c
echo b.c
echo c.c
echo prog.c
meson-0.53.2/test cases/common/51 file grabber/grabber.sh0000755000175000017500000000005313531533273024322 0ustar  jpakkanejpakkane00000000000000#!/bin/sh

for i in *.c; do
  echo $i
done
meson-0.53.2/test cases/common/51 file grabber/grabber2.bat0000644000175000017500000000007513531533273024541 0ustar  jpakkanejpakkane00000000000000@ECHO OFF
echo suba.c
echo subb.c
echo subc.c
echo subprog.c
meson-0.53.2/test cases/common/51 file grabber/meson.build0000644000175000017500000000167513605171363024534 0ustar  jpakkanejpakkane00000000000000project('grabber', 'c')

# What this script does is NOT reliable. Simply adding a file in this directory
# will NOT make it automatically appear in the build. You have to manually
# re-invoke Meson (not just Ninja) for that to happen. The simplest way
# is to touch meson-private/coredata.dat.

# This is not the recommended way to do things, but if the tradeoffs are
# acceptable to you, then we're certainly not going to stop you. Just don't
# file bugs when it fails. :)

if build_machine.system() == 'windows'
  c = run_command('grabber.bat')
  grabber = find_program('grabber2.bat')
else
  c = run_command('grabber.sh')
  grabber = find_program('grabber.sh')
endif


# First test running command explicitly.
if c.returncode() != 0
  error('Executing script failed.')
endif

newline = '''
'''

sources = c.stdout().strip().split(newline)

e = executable('prog', sources)
test('grabtest', e)

# Then test using program with find_program
subdir('subdir')
meson-0.53.2/test cases/common/51 file grabber/prog.c0000644000175000017500000000015713571777336023515 0ustar  jpakkanejpakkane00000000000000int funca(void);
int funcb(void);
int funcc(void);

int main(void) {
    return funca() + funcb() + funcc();
}
meson-0.53.2/test cases/common/51 file grabber/subdir/0000755000175000017500000000000013625242367023656 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/51 file grabber/subdir/meson.build0000644000175000017500000000021213531533273026006 0ustar  jpakkanejpakkane00000000000000sc = run_command(grabber)
subsources = sc.stdout().strip().split(newline)

se = executable('subprog', subsources)
test('subgrabtest', se)
meson-0.53.2/test cases/common/51 file grabber/subdir/suba.c0000644000175000017500000000003613571777336024764 0ustar  jpakkanejpakkane00000000000000int funca(void) { return 0; }
meson-0.53.2/test cases/common/51 file grabber/subdir/subb.c0000644000175000017500000000003613571777336024765 0ustar  jpakkanejpakkane00000000000000int funcb(void) { return 0; }
meson-0.53.2/test cases/common/51 file grabber/subdir/subc.c0000644000175000017500000000003613571777336024766 0ustar  jpakkanejpakkane00000000000000int funcc(void) { return 0; }
meson-0.53.2/test cases/common/51 file grabber/subdir/subprog.c0000644000175000017500000000015713571777336025517 0ustar  jpakkanejpakkane00000000000000int funca(void);
int funcb(void);
int funcc(void);

int main(void) {
    return funca() + funcb() + funcc();
}
meson-0.53.2/test cases/common/52 custom target/0000755000175000017500000000000013625242367022644 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/52 custom target/data_source.txt0000644000175000017500000000004013531533273025663 0ustar  jpakkanejpakkane00000000000000This is a text only input file.
meson-0.53.2/test cases/common/52 custom target/depfile/0000755000175000017500000000000013625242367024254 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/52 custom target/depfile/dep.py0000755000175000017500000000056313612313307025372 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os
from glob import glob

_, srcdir, depfile, output = sys.argv

depfiles = glob(os.path.join(srcdir, '*'))

quoted_depfiles = [x.replace(' ', r'\ ') for x in depfiles]

with open(output, 'w') as f:
    f.write('I am the result of globbing.')
with open(depfile, 'w') as f:
    f.write('%s: %s\n' % (output, ' '.join(quoted_depfiles)))
meson-0.53.2/test cases/common/52 custom target/depfile/meson.build0000644000175000017500000000026213531533273026411 0ustar  jpakkanejpakkane00000000000000

mytarget = custom_target('depfile',
  output : 'dep.dat',
  depfile : 'dep.dat.d',
  command : [find_program('dep.py'), meson.current_source_dir(), '@DEPFILE@', '@OUTPUT@'],
)
meson-0.53.2/test cases/common/52 custom target/installed_files.txt0000644000175000017500000000002413531533273026535 0ustar  jpakkanejpakkane00000000000000usr/subdir/data.dat
meson-0.53.2/test cases/common/52 custom target/meson.build0000644000175000017500000000330413605171365025003 0ustar  jpakkanejpakkane00000000000000project('custom target', 'c')

python = find_program('python3', required : false)
if not python.found()
  python = find_program('python')
endif

# Note that this will not add a dependency to the compiler executable.
# Code will not be rebuilt if it changes.
comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py')
# Test that files() in command: works. The compiler just discards it.
useless = files('installed_files.txt')

mytarget = custom_target('bindat',
output : 'data.dat',
input : 'data_source.txt',
command : [python, comp, '--input=@INPUT@', '--output=@OUTPUT@', useless],
install : true,
install_dir : 'subdir'
)

has_not_changed = false
if is_disabler(mytarget)
    has_not_changed = true
else
    has_not_changed = true
endif
assert(has_not_changed, 'Custom target has changed.')

assert(not is_disabler(mytarget), 'Custom target is a disabler.')

mytarget_disabler = custom_target('bindat',
output : 'data.dat',
input : 'data_source.txt',
command : [disabler(), comp, '--input=@INPUT@', '--output=@OUTPUT@', useless],
install : true,
install_dir : 'subdir'
)

if mytarget_disabler.found()
  mytarget_disabled = false
else
  mytarget_disabled = true
endif

assert(mytarget_disabled, 'Disabled custom target should not be found.')

mytarget_disabler = custom_target('bindat',
output : 'data.dat',
input : disabler(),
command : [python, comp, '--input=@INPUT@', '--output=@OUTPUT@', useless],
install : true,
install_dir : 'subdir'
)

assert(is_disabler(mytarget_disabler), 'Disabled custom target is not a disabler.')

if mytarget_disabler.found()
  mytarget_disabled = false
else
  mytarget_disabled = true
endif

assert(mytarget_disabled, 'Disabled custom target should not be found.')

subdir('depfile')
meson-0.53.2/test cases/common/52 custom target/my_compiler.py0000755000175000017500000000113613531533273025534 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys

assert(os.path.exists(sys.argv[3]))

args = sys.argv[:-1]

if __name__ == '__main__':
    if len(args) != 3 or not args[1].startswith('--input') or \
       not args[2].startswith('--output'):
        print(args[0], '--input=input_file --output=output_file')
        sys.exit(1)
    with open(args[1].split('=')[1]) as f:
        ifile = f.read()
    if ifile != 'This is a text only input file.\n':
        print('Malformed input')
        sys.exit(1)
    with open(args[2].split('=')[1], 'w') as ofile:
        ofile.write('This is a binary output file.\n')
meson-0.53.2/test cases/common/53 custom target chain/0000755000175000017500000000000013625242367023710 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/53 custom target chain/data_source.txt0000644000175000017500000000004013531533273026727 0ustar  jpakkanejpakkane00000000000000This is a text only input file.
meson-0.53.2/test cases/common/53 custom target chain/installed_files.txt0000644000175000017500000000005213531533273027602 0ustar  jpakkanejpakkane00000000000000usr/subdir/data2.dat
usr/subdir/data3.dat
meson-0.53.2/test cases/common/53 custom target chain/meson.build0000644000175000017500000000156313605171366026055 0ustar  jpakkanejpakkane00000000000000project('custom target', 'c')

python = find_program('python3', required : false)
if not python.found()
  python = find_program('python')
endif

# files() is the correct way to do this, but some people
# do this so test that it works.
comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py')
comp2 = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler2.py')
infile = files('data_source.txt')[0]

mytarget = custom_target('bindat',
  output : 'data.dat',
  command : [python, comp, infile, '@OUTPUT@'],
)

mytarget2 = custom_target('bindat2',
  output : 'data2.dat',
  command : [python, comp2, mytarget, '@OUTPUT@'],
  install : true,
  install_dir : 'subdir'
)

mytarget3 = custom_target('bindat3',
  output : 'data3.dat',
  input : [mytarget],
  command : [python, comp2, '@INPUT@', '@OUTPUT@'],
  install : true,
  install_dir : 'subdir'
)

subdir('usetarget')
meson-0.53.2/test cases/common/53 custom target chain/my_compiler.py0000755000175000017500000000065013612313307026572 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print(sys.argv[0], 'input_file output_file')
        sys.exit(1)
    with open(sys.argv[1]) as f:
        ifile = f.read()
    if ifile != 'This is a text only input file.\n':
        print('Malformed input')
        sys.exit(1)
    with open(sys.argv[2], 'w') as ofile:
        ofile.write('This is a binary output file.\n')
meson-0.53.2/test cases/common/53 custom target chain/my_compiler2.py0000755000175000017500000000066013612313307026655 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print(sys.argv[0], 'input_file output_file')
        sys.exit(1)
    with open(sys.argv[1]) as f:
        ifile = f.read()
    if ifile != 'This is a binary output file.\n':
        print('Malformed input')
        sys.exit(1)
    with open(sys.argv[2], 'w') as ofile:
        ofile.write('This is a different binary output file.\n')
meson-0.53.2/test cases/common/53 custom target chain/usetarget/0000755000175000017500000000000013625242367025713 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/53 custom target chain/usetarget/meson.build0000644000175000017500000000026613531533273030054 0ustar  jpakkanejpakkane00000000000000e = executable('myexe', 'myexe.c')
subexe = find_program('subcomp.py')

custom_target('use_exe',
  input : e,
  output : 'subout.res',
  command : [subexe, '@INPUT@', '@OUTPUT@'],
)
meson-0.53.2/test cases/common/53 custom target chain/usetarget/myexe.c0000644000175000017500000000012113571777336027211 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I am myexe.\n");
    return 0;
}
meson-0.53.2/test cases/common/53 custom target chain/usetarget/subcomp.py0000755000175000017500000000023513612313307027725 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

with open(sys.argv[1], 'rb') as ifile:
    with open(sys.argv[2], 'w') as ofile:
        ofile.write('Everything ok.\n')
meson-0.53.2/test cases/common/54 run target/0000755000175000017500000000000013625242367022140 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/54 run target/check_exists.py0000755000175000017500000000022013531533273025156 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys

if not os.path.isfile(sys.argv[1]):
    raise Exception("Couldn't find {!r}".format(sys.argv[1]))
meson-0.53.2/test cases/common/54 run target/configure.in0000755000175000017500000000005013531533273024442 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

print('Success')meson-0.53.2/test cases/common/54 run target/converter.py0000644000175000017500000000021313531533273024510 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

with open(sys.argv[1], 'rb') as ifile, open(sys.argv[2], 'wb') as ofile:
    ofile.write(ifile.read())
meson-0.53.2/test cases/common/54 run target/fakeburner.py0000755000175000017500000000061213531533273024633 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

from __future__ import print_function

import sys

plain_arg = sys.argv[1]
_, filename, _ = plain_arg.split(':')
try:
    with open(filename, 'rb') as f:
        content = f.read()
except FileNotFoundError:
    print('Could not open file. Missing dependency?')
    sys.exit(1)
print('File opened, pretending to send it somewhere.')
print(len(content), 'bytes uploaded')
meson-0.53.2/test cases/common/54 run target/helloprinter.c0000644000175000017500000000034013531533273025003 0ustar  jpakkanejpakkane00000000000000#include

int main(int argc, char **argv) {
    if(argc != 2) {
        printf("I can not haz argument.\n");
        return 1;
    } else {
        printf("I can haz argument: %s\n", argv[1]);
    }
    return 0;
}
meson-0.53.2/test cases/common/54 run target/meson.build0000644000175000017500000000351713605171367024307 0ustar  jpakkanejpakkane00000000000000project('run target', 'c')

# Make it possible to run built programs.
# In cross builds exe_wrapper should be added if it exists.

exe = executable('helloprinter', 'helloprinter.c')
run_target('runhello',
  command : [exe, 'argument'])

converter = find_program('converter.py')

hex = custom_target('exe.hex',
  input : exe,
  output : 'exe.hex',
  command : [converter, '@INPUT@', '@OUTPUT@',
  ],
)

fakeburner = find_program('fakeburner.py')

# These emulates the Arduino flasher application. It sandwiches the filename inside
# a packed argument. Thus we need to declare it manually.
run_target('upload',
  command : [fakeburner, 'x:@0@:y'.format(exe.full_path())],
  depends : exe,
)

run_target('upload2',
  command : [fakeburner, 'x:@0@:y'.format(hex.full_path())],
  depends : hex,
)

python3 = find_program('python3', required : false)
if not python3.found()
  python3 = find_program('python')
endif

run_target('py3hi',
  command : [python3, '-c', 'print("I am Python3.")'])

run_target('check_exists',
  command : [find_program('check_exists.py'), files('helloprinter.c')])

run_target('check_exists',
  command : [find_program('check_exists.py'), files('helloprinter.c')],
  depends : disabler(),
)

run_target('check_exists',
  command : [disabler(), files('helloprinter.c')])

# What if the output of a custom_target is the command to
# execute. Obviously this will not work as hex is not an
# executable but test that the output is generated correctly.
run_target('donotrunme',
  command : hex)

# Ensure configure files can be passed
conf = configure_file(
  input: 'configure.in',
  output: 'configure',
  configuration: configuration_data()
)

run_target('configure_script',
  command : conf
)

# Target names that clash with potential builtin functionality.
run_target('ctags',
  command : converter)

run_target('clang-format',
  command : converter)
meson-0.53.2/test cases/common/55 object generator/0000755000175000017500000000000013625242367023303 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/55 object generator/meson.build0000644000175000017500000000166513605171370025446 0ustar  jpakkanejpakkane00000000000000project('object generator', 'c')

python = find_program('python3', required : false)
if not python.found()
  python = find_program('python')
endif

# Note that this will not add a dependency to the compiler executable.
# Code will not be rebuilt if it changes.
comp = '@0@/@1@'.format(meson.current_source_dir(), 'obj_generator.py')

if host_machine.system() == 'windows'
  outputname = '@BASENAME@.obj'
else
  outputname = '@BASENAME@.o'
endif

cc = meson.get_compiler('c').cmd_array().get(-1)
# Generate an object file manually.
gen = generator(python,
 output : outputname,
 arguments : [comp, cc, '@INPUT@', '@OUTPUT@'])

generated = gen.process(['source.c', 'source2.c'])

# Generate an object file with indexed OUTPUT replacement.
gen2 = generator(python,
 output : outputname,
 arguments : [comp, cc, '@INPUT@', '@OUTPUT0@'])
generated2 = gen2.process(['source3.c'])

e = executable('prog', 'prog.c', generated, generated2)

test('objgen', e)meson-0.53.2/test cases/common/55 object generator/obj_generator.py0000755000175000017500000000101313531533273026466 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# Mimic a binary that generates an object file (e.g. windres).

import sys, subprocess

if __name__ == '__main__':
    if len(sys.argv) != 4:
        print(sys.argv[0], 'compiler input_file output_file')
        sys.exit(1)
    compiler = sys.argv[1]
    ifile = sys.argv[2]
    ofile = sys.argv[3]
    if compiler.endswith('cl'):
        cmd = [compiler, '/nologo', '/MDd', '/Fo' + ofile, '/c', ifile]
    else:
        cmd = [compiler, '-c', ifile, '-o', ofile]
    sys.exit(subprocess.call(cmd))
meson-0.53.2/test cases/common/55 object generator/prog.c0000644000175000017500000000023113571777336024423 0ustar  jpakkanejpakkane00000000000000int func1_in_obj(void);
int func2_in_obj(void);
int func3_in_obj(void);

int main(void) {
    return func1_in_obj() + func2_in_obj() + func3_in_obj();
}
meson-0.53.2/test cases/common/55 object generator/source.c0000644000175000017500000000005113571777336024754 0ustar  jpakkanejpakkane00000000000000int func1_in_obj(void) {
    return 0;
}
meson-0.53.2/test cases/common/55 object generator/source2.c0000644000175000017500000000005113571777336025036 0ustar  jpakkanejpakkane00000000000000int func2_in_obj(void) {
    return 0;
}
meson-0.53.2/test cases/common/55 object generator/source3.c0000644000175000017500000000005113571777336025037 0ustar  jpakkanejpakkane00000000000000int func3_in_obj(void) {
    return 0;
}
meson-0.53.2/test cases/common/56 install script/0000755000175000017500000000000013625242367023022 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/56 install script/installed_files.txt0000644000175000017500000000021013531533273026710 0ustar  jpakkanejpakkane00000000000000usr/bin/prog?exe
?msvc:usr/bin/prog.pdb
usr/diiba/daaba/file.dat
usr/this/should/also-work.dat
usr/this/does/something-different.dat.in
meson-0.53.2/test cases/common/56 install script/meson.build0000644000175000017500000000036013605171371025155 0ustar  jpakkanejpakkane00000000000000project('custom install script', 'c')

executable('prog', 'prog.c', install : true)
meson.add_install_script('myinstall.py', 'diiba/daaba', 'file.dat')
meson.add_install_script('myinstall.py', 'this/should', 'also-work.dat')

subdir('src')
meson-0.53.2/test cases/common/56 install script/myinstall.py0000644000175000017500000000035613531533273025407 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys

prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX']

dirname = os.path.join(prefix, sys.argv[1])

os.makedirs(dirname)
with open(os.path.join(dirname, sys.argv[2]), 'w') as f:
    f.write('')
meson-0.53.2/test cases/common/56 install script/no-installed-files0000644000175000017500000000000013531533273026417 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/56 install script/prog.c0000644000175000017500000000012313571777336024142 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("This is text.\n");
    return 0;
}
meson-0.53.2/test cases/common/56 install script/src/0000755000175000017500000000000013625242367023611 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/56 install script/src/meson.build0000644000175000017500000000012113531533273025740 0ustar  jpakkanejpakkane00000000000000meson.add_install_script('myinstall.py', 'this/does', 'something-different.dat')
meson-0.53.2/test cases/common/56 install script/src/myinstall.py0000644000175000017500000000036613531533273026177 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys

prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX']

dirname = os.path.join(prefix, sys.argv[1])

os.makedirs(dirname)
with open(os.path.join(dirname, sys.argv[2] + '.in'), 'w') as f:
    f.write('')
meson-0.53.2/test cases/common/57 custom target source output/0000755000175000017500000000000013625242367025453 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/57 custom target source output/generator.py0000755000175000017500000000047113571777336030031 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os

if len(sys.argv) != 2:
    print(sys.argv[0], '')

odir = sys.argv[1]

with open(os.path.join(odir, 'mylib.h'), 'w') as f:
    f.write('int func(void);\n')
with open(os.path.join(odir, 'mylib.c'), 'w') as f:
    f.write('''int func(void) {
    return 0;
}
''')
meson-0.53.2/test cases/common/57 custom target source output/main.c0000644000175000017500000000007113571777336026552 0ustar  jpakkanejpakkane00000000000000#include"mylib.h"

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/57 custom target source output/meson.build0000644000175000017500000000031713605171373027612 0ustar  jpakkanejpakkane00000000000000project('source generation', 'c')

ct = custom_target('gen',
output : ['mylib.h', 'mylib.c'],
command : [find_program('generator.py'), '@OUTDIR@'],
)

e = executable('prog', 'main.c', ct)
test('gentest', e)
meson-0.53.2/test cases/common/58 exe static shared/0000755000175000017500000000000013625242367023351 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/58 exe static shared/meson.build0000644000175000017500000000121713605171374025511 0ustar  jpakkanejpakkane00000000000000project('statchain', 'c')

subdir('subdir')
# Test that -fPIC in c_args is also accepted (on platforms where it's permitted)
picflag = []
if not ['darwin', 'windows'].contains(host_machine.system())
  picflag = ['-fPIC']
endif
statlib2 = static_library('stat2', 'stat2.c', c_args : picflag, pic : false)
# Test that pic is needed for both direct and indirect static library
# dependencies of shared libraries (on Linux and BSD)
statlib = static_library('stat', 'stat.c', link_with : [shlib, statlib2], pic : true)
shlib2 = shared_library('shr2', 'shlib2.c', link_with : statlib)
exe = executable('prog', 'prog.c', link_with : shlib2)
test('runtest', exe)
meson-0.53.2/test cases/common/58 exe static shared/prog.c0000644000175000017500000000025413571777336024476 0ustar  jpakkanejpakkane00000000000000int shlibfunc2(void);
int statlibfunc(void);

int main(void) {
    if (statlibfunc() != 42)
        return 1;
    if (shlibfunc2() != 24)
        return 1;
    return 0;
}
meson-0.53.2/test cases/common/58 exe static shared/shlib2.c0000644000175000017500000000023413531533273024672 0ustar  jpakkanejpakkane00000000000000#include "subdir/exports.h"

int statlibfunc(void);
int statlibfunc2(void);

int DLL_PUBLIC shlibfunc2(void) {
    return statlibfunc() - statlibfunc2();
}
meson-0.53.2/test cases/common/58 exe static shared/stat.c0000644000175000017500000000016013571777336024476 0ustar  jpakkanejpakkane00000000000000#include "subdir/exports.h"

int shlibfunc(void);

int DLL_PUBLIC statlibfunc(void) {
    return shlibfunc();
}
meson-0.53.2/test cases/common/58 exe static shared/stat2.c0000644000175000017500000000005213571777336024560 0ustar  jpakkanejpakkane00000000000000int statlibfunc2(void) {
    return 18;
}
meson-0.53.2/test cases/common/58 exe static shared/subdir/0000755000175000017500000000000013625242367024641 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/58 exe static shared/subdir/exports.h0000644000175000017500000000046213531533273026513 0ustar  jpakkanejpakkane00000000000000#pragma once

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif
meson-0.53.2/test cases/common/58 exe static shared/subdir/meson.build0000644000175000017500000000005213531533273026773 0ustar  jpakkanejpakkane00000000000000shlib = shared_library('shar', 'shlib.c')
meson-0.53.2/test cases/common/58 exe static shared/subdir/shlib.c0000644000175000017500000000011013571777336026107 0ustar  jpakkanejpakkane00000000000000#include "exports.h"

int DLL_PUBLIC shlibfunc(void) {
    return 42;
}
meson-0.53.2/test cases/common/59 array methods/0000755000175000017500000000000013625242367022634 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/59 array methods/meson.build0000644000175000017500000000151013605171373024767 0ustar  jpakkanejpakkane00000000000000project('array methods', 'c')

empty = []
one = ['abc']
two = ['def', 'ghi']
combined = [empty, one, two]

if empty.contains('abc')
  error('Empty is not empty.')
endif

if one.contains('a')
  error('One claims to contain a')
endif

if not one.contains('abc')
  error('One claims to not contain abc.')
endif

if one.contains('abcd')
  error('One claims to contain abcd.')
endif

if two.contains('abc')
  error('Two claims to contain abc.')
endif

if not two.contains('def')
  error('Two claims not to contain def.')
endif

if not two.contains('ghi')
  error('Two claims not to contain ghi.')
endif

if two.contains('defg')
  error('Two claims to contain defg.')
endif

if not combined.contains('abc')
  error('Combined claims not to contain abc.')
endif

if not combined.contains('ghi')
  error('Combined claims not to contain ghi.')
endif
meson-0.53.2/test cases/common/6 linkshared/0000755000175000017500000000000013625242367022126 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/6 linkshared/cpplib.cpp0000644000175000017500000000027613571777336024121 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32
    #define DLL_PUBLIC __declspec(dllexport)
#else
    #define DLL_PUBLIC __attribute__ ((visibility ("default")))
#endif

int DLL_PUBLIC cppfunc(void) {
    return 42;
}
meson-0.53.2/test cases/common/6 linkshared/cppmain.cpp0000644000175000017500000000010313571777336024264 0ustar  jpakkanejpakkane00000000000000int cppfunc(void);

int main(void) {
    return cppfunc() != 42;
}
meson-0.53.2/test cases/common/6 linkshared/installed_files.txt0000644000175000017500000000005013366273215026021 0ustar  jpakkanejpakkane00000000000000usr/bin/prog?exe
?msvc:usr/bin/prog.pdb
meson-0.53.2/test cases/common/6 linkshared/libfile.c0000644000175000017500000000052113571777336023707 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int DLL_PUBLIC func(void) {
    return 0;
}
meson-0.53.2/test cases/common/6 linkshared/main.c0000644000175000017500000000027113571777336023227 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_IMPORT __declspec(dllimport)
#else
  #define DLL_IMPORT
#endif

int DLL_IMPORT func(void);

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/6 linkshared/meson.build0000644000175000017500000000075113605171307024264 0ustar  jpakkanejpakkane00000000000000project('shared library linking test', 'c', 'cpp')

lib = shared_library('mylib',
 'libfile.c' # Split to different lines before and after the comma to test parser.
 , install : false) # Don't install libraries in common tests; the path is platform-specific
exe = executable('prog', 'main.c', link_with : lib, install : true)

test('runtest', exe)

cpplib = shared_library('mycpplib', 'cpplib.cpp')
cppexe = executable('cppprog', 'cppmain.cpp', link_with : cpplib)
test('cpptest', cppexe)
meson-0.53.2/test cases/common/60 custom header generator/0000755000175000017500000000000013625242367024554 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/60 custom header generator/input.def0000644000175000017500000000000213605170534026355 0ustar  jpakkanejpakkane000000000000000
meson-0.53.2/test cases/common/60 custom header generator/makeheader.py0000644000175000017500000000050213605170534027203 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

# NOTE: this file does not have the executable bit set. This tests that
# Meson can automatically parse shebang lines.

import sys

template = '#define RET_VAL %s\n'
with open(sys.argv[1]) as f:
    output = template % (f.readline().strip(), )
with open(sys.argv[2], 'w') as f:
    f.write(output)
meson-0.53.2/test cases/common/60 custom header generator/meson.build0000644000175000017500000000153513605171374026717 0ustar  jpakkanejpakkane00000000000000project('custom header generator', 'c')

cc_id  = meson.get_compiler('c').get_id()
cc_ver = meson.get_compiler('c').version()

if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08'))
  # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
  # (correctly) thinks that the rule has multiple outputs and errors out:
  # 'depfile has multiple output paths'
  error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
endif

gen = find_program('makeheader.py')

generated_h = custom_target('makeheader.py',
  output : 'myheader.lh', # Suffix not .h to ensure this works with custom suffixes, too.
  input : 'input.def',
  command : [gen, '@INPUT0@', '@OUTPUT0@', files('somefile.txt')])

prog = executable('prog', 'prog.c', generated_h)
test('gentest', prog)
meson-0.53.2/test cases/common/60 custom header generator/prog.c0000644000175000017500000000007613571777336025703 0ustar  jpakkanejpakkane00000000000000#include"myheader.lh"

int main(void) {
    return RET_VAL;
}
meson-0.53.2/test cases/common/60 custom header generator/somefile.txt0000644000175000017500000000000013605170534027100 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/61 multiple generators/0000755000175000017500000000000013625242367024050 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/61 multiple generators/data2.dat0000644000175000017500000000000213531533273025520 0ustar  jpakkanejpakkane000000000000002
meson-0.53.2/test cases/common/61 multiple generators/main.cpp0000644000175000017500000000013213571777336025505 0ustar  jpakkanejpakkane00000000000000#include"source1.h"
#include"source2.h"

int main(void) {
    return func1() + func2();
}
meson-0.53.2/test cases/common/61 multiple generators/meson.build0000644000175000017500000000057713605171377026223 0ustar  jpakkanejpakkane00000000000000project('trickier generator', 'cpp')

comp = find_program('mygen.py')
subdir('subdir')

generated2 = custom_target('generated2',
  output : ['source2.h', 'source2.cpp'],
  input : 'data2.dat',
  command : [comp, '@INPUT0@', '@OUTDIR@'])

exe = executable('prog', 'main.cpp', generated, generated2,
  include_directories : include_directories('subdir'))
  test('generated test', exe)
meson-0.53.2/test cases/common/61 multiple generators/mygen.py0000755000175000017500000000066713531533273025550 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os

if len(sys.argv) != 3:
    print("You is fail.")
    sys.exit(1)

with open(sys.argv[1]) as f:
    val = f.read().strip()
outdir = sys.argv[2]

outhdr = os.path.join(outdir, 'source%s.h' % val)
outsrc = os.path.join(outdir, 'source%s.cpp' % val)

with open(outhdr, 'w') as f:
    f.write('int func%s();\n' % val)
with open(outsrc, 'w') as f:
    f.write('''int func%s() {
    return 0;
}
''' % val)
meson-0.53.2/test cases/common/61 multiple generators/subdir/0000755000175000017500000000000013625242367025340 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/61 multiple generators/subdir/data.dat0000644000175000017500000000000213531533273026726 0ustar  jpakkanejpakkane000000000000001
meson-0.53.2/test cases/common/61 multiple generators/subdir/meson.build0000644000175000017500000000021413531533273027472 0ustar  jpakkanejpakkane00000000000000generated = custom_target('generated',
output : ['source1.h', 'source1.cpp'],
input : 'data.dat',
command : [comp, '@INPUT0@', '@OUTDIR@'])
meson-0.53.2/test cases/common/62 install subdir/0000755000175000017500000000000013625242367023003 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/installed_files.txt0000644000175000017500000000050313571777336026714 0ustar  jpakkanejpakkane00000000000000usr/share/dircheck/fifth.dat
usr/share/dircheck/seventh.dat
usr/share/dircheck/ninth.dat
usr/share/eighth.dat
usr/share/fourth.dat
usr/share/sixth.dat
usr/share/sub1/data1.dat
usr/share/sub1/second.dat
usr/share/sub1/third.dat
usr/share/sub1/sub2/data2.dat
usr/share/sub2/one.dat
usr/share/sub2/dircheck/excluded-three.dat
meson-0.53.2/test cases/common/62 install subdir/meson.build0000644000175000017500000000123113605171376025141 0ustar  jpakkanejpakkane00000000000000project('install a whole subdir', 'c',
  default_options : ['install_umask=preserve'])

# A subdir with an exclusion:
install_subdir('sub2',
  exclude_files : ['excluded-three.dat'],
  exclude_directories : ['excluded'],
  install_dir : 'share')

subdir('subdir')
# A subdir with write perms only for the owner
# and read-list perms for owner and group
install_subdir('sub1', install_dir : 'share', install_mode : ['rwxr-x--t', 'root'])
install_subdir('sub/sub1', install_dir : 'share')

# strip_directory
install_subdir('sub_elided', install_dir : 'share', strip_directory : true)
install_subdir('nested_elided/sub', install_dir : 'share', strip_directory : true)
meson-0.53.2/test cases/common/62 install subdir/nested_elided/0000755000175000017500000000000013625242351025564 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/nested_elided/sub/0000755000175000017500000000000013625242367026364 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/nested_elided/sub/dircheck/0000755000175000017500000000000013625242367030140 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/nested_elided/sub/dircheck/ninth.dat0000644000175000017500000000005313571777336031761 0ustar  jpakkanejpakkane00000000000000Nested file under nested elided directory.
meson-0.53.2/test cases/common/62 install subdir/nested_elided/sub/eighth.dat0000644000175000017500000000004113531533273030314 0ustar  jpakkanejpakkane00000000000000File in nested elided directory.
meson-0.53.2/test cases/common/62 install subdir/sub/0000755000175000017500000000000013625242351023565 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub/sub1/0000755000175000017500000000000013625242367024446 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub/sub1/third.dat0000644000175000017500000000005013531533273026240 0ustar  jpakkanejpakkane00000000000000This is a third data file for sub1 dir.
meson-0.53.2/test cases/common/62 install subdir/sub1/0000755000175000017500000000000013625242367023655 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub1/second.dat0000644000175000017500000000006613531533273025617 0ustar  jpakkanejpakkane00000000000000Test that multiple install_subdirs meld their results.meson-0.53.2/test cases/common/62 install subdir/sub2/0000755000175000017500000000000013625242367023656 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub2/dircheck/0000755000175000017500000000000013625242367025432 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub2/dircheck/excluded-three.dat0000644000175000017500000000000013531533273031007 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub2/excluded/0000755000175000017500000000000013625242367025453 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub2/excluded/two.dat0000644000175000017500000000000013531533273026737 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub2/excluded-three.dat0000644000175000017500000000000013531533273027233 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub2/one.dat0000644000175000017500000000000013531533273025112 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub_elided/0000755000175000017500000000000013625242367025102 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub_elided/dircheck/0000755000175000017500000000000013625242367026656 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/sub_elided/dircheck/fifth.dat0000644000175000017500000000005313531533273030441 0ustar  jpakkanejpakkane00000000000000Data file in a subdir of elided directory.
meson-0.53.2/test cases/common/62 install subdir/sub_elided/fourth.dat0000644000175000017500000000007413531533273027077 0ustar  jpakkanejpakkane00000000000000Test that this file is installed directly into install_dir.
meson-0.53.2/test cases/common/62 install subdir/subdir/0000755000175000017500000000000013625242367024273 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/subdir/meson.build0000644000175000017500000000034613531533273026433 0ustar  jpakkanejpakkane00000000000000install_subdir('sub1', install_dir : 'share',
  # This mode will be overridden by the mode set in the outer install_subdir
  install_mode : 'rwxr-x---')

install_subdir('sub_elided', install_dir : 'share', strip_directory : true)
meson-0.53.2/test cases/common/62 install subdir/subdir/sub1/0000755000175000017500000000000013625242367025145 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/subdir/sub1/data1.dat0000644000175000017500000000004113531533273026617 0ustar  jpakkanejpakkane00000000000000This is a data file in a subdir.
meson-0.53.2/test cases/common/62 install subdir/subdir/sub1/sub2/0000755000175000017500000000000013625242367026020 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/subdir/sub1/sub2/data2.dat0000644000175000017500000000005013531533273027473 0ustar  jpakkanejpakkane00000000000000This is a data file in a deeper subdir.
meson-0.53.2/test cases/common/62 install subdir/subdir/sub_elided/0000755000175000017500000000000013625242367026372 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/subdir/sub_elided/dircheck/0000755000175000017500000000000013625242367030146 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/62 install subdir/subdir/sub_elided/dircheck/seventh.dat0000644000175000017500000000003113531533273032301 0ustar  jpakkanejpakkane00000000000000Nested file in a subdir.
meson-0.53.2/test cases/common/62 install subdir/subdir/sub_elided/sixth.dat0000644000175000017500000000003513531533273030214 0ustar  jpakkanejpakkane00000000000000Elide test file in a subdir.
meson-0.53.2/test cases/common/63 foreach/0000755000175000017500000000000013625242367021474 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/63 foreach/installed_files.txt0000644000175000017500000000017613531533273025375 0ustar  jpakkanejpakkane00000000000000usr/bin/prog1?exe
?msvc:usr/bin/prog1.pdb
usr/bin/prog2?exe
?msvc:usr/bin/prog2.pdb
usr/bin/prog3?exe
?msvc:usr/bin/prog3.pdb
meson-0.53.2/test cases/common/63 foreach/meson.build0000644000175000017500000000171413605171377023641 0ustar  jpakkanejpakkane00000000000000project('foreach', 'c')

tests = [['test1', 'prog1', 'prog1.c'],
  ['test2', 'prog2', 'prog2.c', 'fallback'],
  ['test3', 'prog3', 'prog3.c', 'urgh']]

assert(tests[0].get(3, 'fallbck') == 'fallbck', 'array #1 fallback did not match')
assert(tests[1].get(3, 'failbk') == 'fallback', 'array #2 value did not match')
assert(tests[2].get(3, 'urgh') == 'urgh', 'array #3 value did not match')

foreach i : tests
  test(i.get(0), executable(i.get(1), i.get(2), install : true))

  # Ensure that changing the tests variable does not
  # affect ongoing iteration in the foreach loop.
  #
  # Being able to do that would make Meson Turing complete and
  # we definitely don't want that.
  tests = ['test4', 'prog4', 'prog4.c']
endforeach

items = ['a', 'continue', 'b', 'break', 'c']
result = []
foreach i : items
  if i == 'continue'
    continue
  elif i == 'break'
    break
  endif
  result += i
endforeach

assert(result == ['a', 'b'], 'Continue or break in foreach failed')
meson-0.53.2/test cases/common/63 foreach/prog1.c0000644000175000017500000000012613571777336022700 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("This is test #1.\n");
    return 0;
}
meson-0.53.2/test cases/common/63 foreach/prog2.c0000644000175000017500000000012613571777336022701 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("This is test #2.\n");
    return 0;
}
meson-0.53.2/test cases/common/63 foreach/prog3.c0000644000175000017500000000012613571777336022702 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("This is test #3.\n");
    return 0;
}
meson-0.53.2/test cases/common/64 number arithmetic/0000755000175000017500000000000013625242367023470 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/64 number arithmetic/meson.build0000644000175000017500000000364113605171377025636 0ustar  jpakkanejpakkane00000000000000project('number arithmetic', 'c')

if 6 + 4 != 10
  error('Number addition is broken')
endif
if 6 - 4 != 2
  error('Number subtraction is broken')
endif

if 6 * 4 != 24
  error('Number multiplication is broken')
endif
if 16 / 4 != 4
  error('Number division is broken')
endif

#if (1 / 3) * 3 != 1
#  error('Float interconversion broken')
#endif
if (5 / 3) * 3 != 3
  error('Integer division is broken')
endif

assert((5 % 2) == 1, 'Integer modulo (odd) is broken')
assert((4 % 2) == 0, 'Integer modulo (even) is broken')

if 2 * 1 % 2 != 0
  error('Modulo precedence with multiplication is broken')
endif
if 2 + 1 % 2 != 3
  error('Modulo precedence with addition is broken')
endif
if 9 / 9 % 2 != 1
  error('Modulo precedence with division is broken')
endif
if 9 - 9 % 2 != 8
  error('Modulo precedence with subtraction is broken')
endif

assert(2.is_even(), 'int is_even() broken for even value')
assert(not(2.is_odd()), 'int is_odd() broken for even value')
assert(not(3.is_even()), 'int is_even() broken for odd value')
assert(3.is_odd(), 'int is_odd() broken for odd value')

assert(3 < 4, 'Lt broken')
assert(not(4 < 3), 'Lt broken')
assert(3 <= 4, 'Lte broken')
assert(not(4 <= 3), 'Lte broken')
assert(3 <= 3, 'Lte broken')

assert(4 > 3, 'Gt broken')
assert(not(3 > 4), 'Gt broken')
assert(4 >= 3, 'Gte broken')
assert(not(3 >= 4), 'Gte broken')
assert(3 >= 3, 'Gte broken')

assert(true.to_int() == 1,'bool to_int() broken')
assert(false.to_int() == 0,'bool to_int() broken')

hex_255 = 0xff
hex2_255 = 0XFF

assert(hex_255 == 255, 'Hex parsing is broken.')
assert(hex2_255 == 255, 'Uppercase hex parsing is broken.')

bin_123 = 0b1111011
bin2_123 = 0B1111011

assert(bin_123 == 123, 'Bin number parsing is broken.')
assert(bin2_123 == 123, 'Uppercase bin number parsing is broken.')

oct_493 = 0o755
oct2_493 = 0O755

assert(oct_493 == 493, 'Oct number parsing is broken.')
assert(oct2_493 == 493, 'Uppercase oct number parsing is broken.')
meson-0.53.2/test cases/common/65 string arithmetic/0000755000175000017500000000000013625242367023507 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/65 string arithmetic/meson.build0000644000175000017500000000046113605171401025636 0ustar  jpakkanejpakkane00000000000000project('string arithmetic', 'c')

if 'foo' + 'bar' != 'foobar'
  error('String concatenation is broken')
endif

if 'foo' + 'bar' + 'baz' != 'foobarbaz'
  error('Many-string concatenation is broken')
endif

a = 'a'
b = 'b'

if a + b + 'c' != 'abc'
  error('String concat with variables is broken.')
endif
meson-0.53.2/test cases/common/66 array arithmetic/0000755000175000017500000000000013625242367023320 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/66 array arithmetic/meson.build0000644000175000017500000000062613605171402025453 0ustar  jpakkanejpakkane00000000000000project('array arithmetic', 'c')

array1 = ['foo', 'bar']
array2 = ['qux', 'baz']

if array1 + array2 != ['foo', 'bar', 'qux', 'baz']
  error('Array concatenation is broken')
endif
if array2 + array1 != ['qux', 'baz', 'foo', 'bar']
  error('Array concatenation is broken')
endif

if array1 + array1 + array1 != ['foo', 'bar', 'foo', 'bar', 'foo', 'bar']
  error('Many-array concatenation is broken')
endif
meson-0.53.2/test cases/common/67 arithmetic bidmas/0000755000175000017500000000000013625242367023442 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/67 arithmetic bidmas/meson.build0000644000175000017500000000057513605171402025600 0ustar  jpakkanejpakkane00000000000000project('arithmetic bidmas', 'c')

if 5 * 3 - 6 / 2 + 1 != 13
  error('Arithmetic bidmas broken')
endif
if 5 * (3 - 6 / 2) + 1 != 1
  error('Arithmetic bidmas with brackets broken')
endif

if 5 * 12 / 2 * 3 != 90
  error('Sequential multiplication and division broken')
endif
if 5 * (12 / (2 * 3)) != 10
  error('Sequential multiplication and division with brackets broken')
endif
meson-0.53.2/test cases/common/68 build always/0000755000175000017500000000000013625242367022452 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/68 build always/main.c0000644000175000017500000000017013571777336023551 0ustar  jpakkanejpakkane00000000000000#include
#include"version.h"

int main(void) {
    printf("Version is %s.\n", version_string);
    return 0;
}
meson-0.53.2/test cases/common/68 build always/meson.build0000644000175000017500000000046013605171403024602 0ustar  jpakkanejpakkane00000000000000project('run always', 'c')

version = '1.0.0'

vgen = find_program('version_gen.py')

version_src = custom_target('Version string',
input : 'version.c.in',
output : 'version.c',
command : [vgen, '@INPUT@', '@OUTPUT@', version],
build_always : true,
)

executable('versionprinter', 'main.c', version_src)
meson-0.53.2/test cases/common/68 build always/version.c.in0000644000175000017500000000007713531533273024707 0ustar  jpakkanejpakkane00000000000000#include"version.h"

const char *version_string = "@VERSION@";
meson-0.53.2/test cases/common/68 build always/version.h0000644000175000017500000000005213531533273024300 0ustar  jpakkanejpakkane00000000000000#pragma once

const char *version_string;
meson-0.53.2/test cases/common/68 build always/version_gen.py0000755000175000017500000000147013531533273025342 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os, subprocess

def generate(infile, outfile, fallback):
    workdir = os.path.split(infile)[0]
    if workdir == '':
        workdir = '.'
    try:
        version = subprocess.check_output(['git', 'describe'], cwd=workdir).decode().strip()
    except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
        version = fallback
    with open(infile) as f:
        newdata = f.read().replace('@VERSION@', version)
    try:
        with open(outfile) as f:
            olddata = f.read()
        if olddata == newdata:
            return
    except OSError:
        pass
    with open(outfile, 'w') as f:
        f.write(newdata)

if __name__ == '__main__':
    infile = sys.argv[1]
    outfile = sys.argv[2]
    fallback = sys.argv[3]
    generate(infile, outfile, fallback)
meson-0.53.2/test cases/common/69 vcstag/0000755000175000017500000000000013625242367021362 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/69 vcstag/meson.build0000644000175000017500000000102413605171405023511 0ustar  jpakkanejpakkane00000000000000project('vcstag', 'c')

version_src = vcs_tag(input : 'vcstag.c.in',
output : 'vcstag.c',
fallback : '1.0.0')

version_src_custom = vcs_tag(input : 'vcstag.c.in',
output : 'vcstag-custom.c',
command : ['git', 'show-ref', '-s', 'refs/heads/master'],
fallback : '1.0.0')

version_src_fallback = vcs_tag(input : 'vcstag.c.in',
output : 'vcstag-fallback.c')

executable('tagprog', 'tagprog.c', version_src)
executable('tagprog-custom', 'tagprog.c', version_src_custom)
executable('tagprog-fallback', 'tagprog.c', version_src_fallback)

meson-0.53.2/test cases/common/69 vcstag/tagprog.c0000644000175000017500000000016113571777336023200 0ustar  jpakkanejpakkane00000000000000#include

const char *vcstag;

int main(void) {
    printf("Version is %s\n", vcstag);
    return 0;
}

meson-0.53.2/test cases/common/69 vcstag/vcstag.c.in0000644000175000017500000000004313531533273023412 0ustar  jpakkanejpakkane00000000000000const char *vcstag = "@VCS_TAG@";

meson-0.53.2/test cases/common/7 mixed/0000755000175000017500000000000013625242367021111 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/7 mixed/func.c0000644000175000017500000000007013571777336022216 0ustar  jpakkanejpakkane00000000000000int func(void) {
    int class = 0;
    return class;
}
meson-0.53.2/test cases/common/7 mixed/main.cc0000644000175000017500000000013213571777336022351 0ustar  jpakkanejpakkane00000000000000extern "C" int func();

class BreakPlainCCompiler;

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/7 mixed/meson.build0000644000175000017500000000015213605171307023242 0ustar  jpakkanejpakkane00000000000000project('mixed C and C++', 'c', 'cpp')
exe = executable('prog', 'main.cc', 'func.c')
test('mixtest', exe)
meson-0.53.2/test cases/common/70 modules/0000755000175000017500000000000013625242367021533 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/70 modules/meson.build0000644000175000017500000000011713605171405023664 0ustar  jpakkanejpakkane00000000000000project('module test', 'c')

modtest = import('modtest')
modtest.print_hello()
meson-0.53.2/test cases/common/71 should fail/0000755000175000017500000000000013625242367022256 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/71 should fail/failing.c0000644000175000017500000000004113571777336024037 0ustar  jpakkanejpakkane00000000000000int main(void) {
    return 1;
}
meson-0.53.2/test cases/common/71 should fail/meson.build0000644000175000017500000000015413605171406024411 0ustar  jpakkanejpakkane00000000000000project('should fail', 'c')

exe = executable('prog', 'failing.c')
test('failing', exe, should_fail : true)
meson-0.53.2/test cases/common/72 configure file in custom target/0000755000175000017500000000000013625242367026077 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/72 configure file in custom target/inc/0000755000175000017500000000000013625242367026650 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/72 configure file in custom target/inc/confdata.in0000644000175000017500000000001013531533273030741 0ustar  jpakkanejpakkane00000000000000@VALUE@
meson-0.53.2/test cases/common/72 configure file in custom target/inc/meson.build0000644000175000017500000000022113531533273031000 0ustar  jpakkanejpakkane00000000000000cdata = configuration_data()
cdata.set('VALUE', '42')

cfile = configure_file(input : 'confdata.in',
output : 'confdata',
configuration : cdata)
meson-0.53.2/test cases/common/72 configure file in custom target/meson.build0000644000175000017500000000011013605171406030222 0ustar  jpakkanejpakkane00000000000000project('conf file in custom target', 'c')

subdir('inc')
subdir('src')
meson-0.53.2/test cases/common/72 configure file in custom target/src/0000755000175000017500000000000013625242367026666 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/72 configure file in custom target/src/meson.build0000644000175000017500000000102513531533273031021 0ustar  jpakkanejpakkane00000000000000custom_target('thing',
output : 'final.dat',
input : cfile,
command : [find_program('mycompiler.py'), '@INPUT@', '@OUTPUT@'])

# Test usage of a `configure_file` as part of the command list
py3 = find_program('python3', required : false)
if not py3.found()
  # Maybe 'python' is Python 3
  py3 = find_program('python')
endif

compiler = configure_file(input : 'mycompiler.py',
  output : 'mycompiler2.py',
  copy: true)

custom_target('thing2',
output : 'final2.dat',
input : cfile,
command : [py3, compiler, '@INPUT@', '@OUTPUT@'])
meson-0.53.2/test cases/common/72 configure file in custom target/src/mycompiler.py0000644000175000017500000000032213531533273031410 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

with open(sys.argv[1]) as ifile:
    if ifile.readline().strip() != '42':
        print('Incorrect input')
with open(sys.argv[2], 'w') as ofile:
    ofile.write('Success\n')
meson-0.53.2/test cases/common/73 external test program/0000755000175000017500000000000013625242367024300 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/73 external test program/meson.build0000644000175000017500000000014213605171410026423 0ustar  jpakkanejpakkane00000000000000project('test is external', 'c')

test('external', find_program('mytest.py'), args : ['correct'])
meson-0.53.2/test cases/common/73 external test program/mytest.py0000755000175000017500000000032313531533273026173 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

from __future__ import print_function

import sys

if sys.argv[1] == 'correct':
    print('Argument is correct.')
    sys.exit(0)
print('Argument is incorrect:', sys.argv[1])
sys.exit(1)
meson-0.53.2/test cases/common/74 ctarget dependency/0000755000175000017500000000000013625242367023617 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/74 ctarget dependency/gen1.py0000755000175000017500000000035513531533273025024 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import time, sys

# Make sure other script runs first if dependency
# is missing.
time.sleep(0.5)

with open(sys.argv[1], 'r') as f:
    contents = f.read()
with open(sys.argv[2], 'w') as f:
    f.write(contents)
meson-0.53.2/test cases/common/74 ctarget dependency/gen2.py0000755000175000017500000000035213531533273025022 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os
from glob import glob

files = glob(os.path.join(sys.argv[1], '*.tmp'))
assert(len(files) == 1)

with open(files[0], 'r') as ifile, open(sys.argv[2], 'w') as ofile:
    ofile.write(ifile.read())
meson-0.53.2/test cases/common/74 ctarget dependency/input.dat0000644000175000017500000000003113531533273025435 0ustar  jpakkanejpakkane00000000000000This is a piece of text.
meson-0.53.2/test cases/common/74 ctarget dependency/meson.build0000644000175000017500000000105613605171411025750 0ustar  jpakkanejpakkane00000000000000project('custom target dependency', 'c')

# Sometimes custom targets do not take input files
# but instead do globbing or some similar wackiness.
# In this case we need to be able to specify a
# manual dependency between two custom targets,
# if one needs to be run before the other.

g1 = find_program('gen1.py')
g2 = find_program('gen2.py')

c1 = custom_target('medput',
input : 'input.dat',
output : 'medput.tmp',
command : [g1, '@INPUT@', '@OUTPUT@'])

custom_target('output',
output : 'output.dat',
command : [g2, '@OUTDIR@', '@OUTPUT@'],
depends : c1)
meson-0.53.2/test cases/common/75 shared subproject/0000755000175000017500000000000013625242367023477 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/75 shared subproject/a.c0000644000175000017500000000027713571777336024102 0ustar  jpakkanejpakkane00000000000000#include
char func_b(void);
char func_c(void);

int main(void) {
    if(func_b() != 'b') {
        return 1;
    }
    if(func_c() != 'c') {
        return 2;
    }
    return 0;
}
meson-0.53.2/test cases/common/75 shared subproject/meson.build0000644000175000017500000000025613605171414025634 0ustar  jpakkanejpakkane00000000000000project('A', 'c')

B = subproject('B')
b = B.get_variable('b')

C = subproject('C')
c = C.get_variable('c')

a = executable('a', 'a.c', link_with : [b, c])
test('a test', a)
meson-0.53.2/test cases/common/75 shared subproject/subprojects/0000755000175000017500000000000013625242351026033 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/75 shared subproject/subprojects/B/0000755000175000017500000000000013625242367026223 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/75 shared subproject/subprojects/B/b.c0000644000175000017500000000065513571777336026627 0ustar  jpakkanejpakkane00000000000000#include
#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif


char func_c(void);

char DLL_PUBLIC func_b(void) {
    if(func_c() != 'c') {
        exit(3);
    }
    return 'b';
}
meson-0.53.2/test cases/common/75 shared subproject/subprojects/B/meson.build0000644000175000017500000000015413531533273030360 0ustar  jpakkanejpakkane00000000000000project('B', 'c')
C = subproject('C')
c = C.get_variable('c')
b = shared_library('b', 'b.c', link_with : c)
meson-0.53.2/test cases/common/75 shared subproject/subprojects/C/0000755000175000017500000000000013625242367026224 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/75 shared subproject/subprojects/C/c.c0000644000175000017500000000052413571777336026624 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

char DLL_PUBLIC func_c(void) {
    return 'c';
}
meson-0.53.2/test cases/common/75 shared subproject/subprojects/C/meson.build0000644000175000017500000000006113531533273030356 0ustar  jpakkanejpakkane00000000000000project('C', 'c')
c = shared_library('c', 'c.c')
meson-0.53.2/test cases/common/76 shared subproject 2/0000755000175000017500000000000013625242367023622 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/76 shared subproject 2/a.c0000644000175000017500000000027713571777336024225 0ustar  jpakkanejpakkane00000000000000#include
char func_b(void);
char func_c(void);

int main(void) {
    if(func_b() != 'b') {
        return 1;
    }
    if(func_c() != 'c') {
        return 2;
    }
    return 0;
}
meson-0.53.2/test cases/common/76 shared subproject 2/meson.build0000644000175000017500000000036413605171414025757 0ustar  jpakkanejpakkane00000000000000project('A', 'c')

# Same as the previous test but use C and B in
# the opposite order.

C = subproject('C')
c = C.get_variable('c')

B = subproject('B')
b = B.get_variable('b')

a = executable('a', 'a.c', link_with : [b, c])
test('a test', a)
meson-0.53.2/test cases/common/76 shared subproject 2/subprojects/0000755000175000017500000000000013625242351026156 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/76 shared subproject 2/subprojects/B/0000755000175000017500000000000013625242367026346 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/76 shared subproject 2/subprojects/B/b.c0000644000175000017500000000065413571777336026751 0ustar  jpakkanejpakkane00000000000000#include
char func_c(void);

#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

char DLL_PUBLIC func_b(void) {
    if(func_c() != 'c') {
        exit(3);
    }
    return 'b';
}
meson-0.53.2/test cases/common/76 shared subproject 2/subprojects/B/meson.build0000644000175000017500000000015413531533273030503 0ustar  jpakkanejpakkane00000000000000project('B', 'c')
C = subproject('C')
c = C.get_variable('c')
b = shared_library('b', 'b.c', link_with : c)
meson-0.53.2/test cases/common/76 shared subproject 2/subprojects/C/0000755000175000017500000000000013625242367026347 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/76 shared subproject 2/subprojects/C/c.c0000644000175000017500000000052413571777336026747 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

char DLL_PUBLIC func_c(void) {
    return 'c';
}
meson-0.53.2/test cases/common/76 shared subproject 2/subprojects/C/meson.build0000644000175000017500000000006113531533273030501 0ustar  jpakkanejpakkane00000000000000project('C', 'c')
c = shared_library('c', 'c.c')
meson-0.53.2/test cases/common/77 file object/0000755000175000017500000000000013625242367022240 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/77 file object/lib.c0000644000175000017500000000004113571777336023156 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 0;
}
meson-0.53.2/test cases/common/77 file object/meson.build0000644000175000017500000000023713605171414024374 0ustar  jpakkanejpakkane00000000000000project('file object', 'c')

prog0 = files('prog.c')
lib0 = files('lib.c')
test('fobj', executable('fobj', prog0, lib0))

subdir('subdir1')
subdir('subdir2')

meson-0.53.2/test cases/common/77 file object/prog.c0000644000175000017500000000037113571777336023365 0ustar  jpakkanejpakkane00000000000000#include

int func(void); /* Files in different subdirs return different values. */

int main(void) {
    if(func() == 0) {
        printf("Iz success.\n");
    } else {
        printf("Iz fail.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/77 file object/subdir1/0000755000175000017500000000000013625242367023611 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/77 file object/subdir1/lib.c0000644000175000017500000000004113571777336024527 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 1;
}
meson-0.53.2/test cases/common/77 file object/subdir1/meson.build0000644000175000017500000000036313531533273025750 0ustar  jpakkanejpakkane00000000000000prog1 = files('prog.c')
lib1 = files('lib.c')

test('subdir0', executable('subdir0', prog0, lib1), should_fail : true)
test('subdir1', executable('subdir1', prog1, lib0), should_fail : true)

test('subdir2', executable('subdir2', prog1, lib1))meson-0.53.2/test cases/common/77 file object/subdir1/prog.c0000644000175000017500000000027713571777336024743 0ustar  jpakkanejpakkane00000000000000#include

int func(void);

int main(void) {
    if(func() == 1) {
        printf("Iz success.\n");
    } else {
        printf("Iz fail.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/77 file object/subdir2/0000755000175000017500000000000013625242367023612 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/77 file object/subdir2/lib.c0000644000175000017500000000004113571777336024530 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 2;
}
meson-0.53.2/test cases/common/77 file object/subdir2/meson.build0000644000175000017500000000036313531533273025751 0ustar  jpakkanejpakkane00000000000000prog2 = files('prog.c')
lib2 = files('lib.c')

test('subdir3', executable('subdir3', prog1, lib2), should_fail : true)
test('subdir4', executable('subdir4', prog2, lib1), should_fail : true)

test('subdir4', executable('subdir5', prog2, lib2))meson-0.53.2/test cases/common/77 file object/subdir2/prog.c0000644000175000017500000000027713571777336024744 0ustar  jpakkanejpakkane00000000000000#include

int func(void);

int main(void) {
    if(func() == 2) {
        printf("Iz success.\n");
    } else {
        printf("Iz fail.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/78 custom subproject dir/0000755000175000017500000000000013625242370024277 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/78 custom subproject dir/a.c0000644000175000017500000000027713571777336024710 0ustar  jpakkanejpakkane00000000000000#include
char func_b(void);
char func_c(void);

int main(void) {
    if(func_b() != 'b') {
        return 1;
    }
    if(func_c() != 'c') {
        return 2;
    }
    return 0;
}
meson-0.53.2/test cases/common/78 custom subproject dir/custom_subproject_dir/0000755000175000017500000000000013625242351030706 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/78 custom subproject dir/custom_subproject_dir/B/0000755000175000017500000000000013625242370031070 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/78 custom subproject dir/custom_subproject_dir/B/b.c0000644000175000017500000000065413571777336031501 0ustar  jpakkanejpakkane00000000000000#include
char func_c(void);

#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

char DLL_PUBLIC func_b(void) {
    if(func_c() != 'c') {
        exit(3);
    }
    return 'b';
}
meson-0.53.2/test cases/common/78 custom subproject dir/custom_subproject_dir/B/meson.build0000644000175000017500000000015413531533273033233 0ustar  jpakkanejpakkane00000000000000project('B', 'c')
C = subproject('C')
c = C.get_variable('c')
b = shared_library('b', 'b.c', link_with : c)
meson-0.53.2/test cases/common/78 custom subproject dir/custom_subproject_dir/C/0000755000175000017500000000000013625242370031071 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/78 custom subproject dir/custom_subproject_dir/C/c.c0000644000175000017500000000052413571777336031477 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

char DLL_PUBLIC func_c(void) {
    return 'c';
}
meson-0.53.2/test cases/common/78 custom subproject dir/custom_subproject_dir/C/meson.build0000644000175000017500000000006113531533273033231 0ustar  jpakkanejpakkane00000000000000project('C', 'c')
c = shared_library('c', 'c.c')
meson-0.53.2/test cases/common/78 custom subproject dir/meson.build0000644000175000017500000000032613605171416026442 0ustar  jpakkanejpakkane00000000000000project('A', 'c', subproject_dir:'custom_subproject_dir')

B = subproject('B')
b = B.get_variable('b')

C = subproject('C')
c = C.get_variable('c')

a = executable('a', 'a.c', link_with : [b, c])
test('a test', a)
meson-0.53.2/test cases/common/79 has type/0000755000175000017500000000000013625242370021603 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/79 has type/meson.build0000644000175000017500000000054113605171420023740 0ustar  jpakkanejpakkane00000000000000project('has type', 'c', 'cpp')

compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')]

foreach cc : compilers
  if not cc.has_type('time_t', prefix : '#include')
    error('Did not detect type that exists.')
  endif

  if cc.has_type('no_time_t', prefix : '#include')
    error('Not existing type found.')
  endif
endforeach
meson-0.53.2/test cases/common/8 install/0000755000175000017500000000000013625242370021444 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/8 install/installed_files.txt0000644000175000017500000000007613366273215025355 0ustar  jpakkanejpakkane00000000000000usr/bin/prog?exe
?msvc:usr/bin/prog.pdb
usr/libtest/libstat.a
meson-0.53.2/test cases/common/8 install/meson.build0000644000175000017500000000026013605171307023603 0ustar  jpakkanejpakkane00000000000000project('install test', 'c', default_options : ['libdir=libtest'])

stlib = static_library('stat', 'stat.c', install : true)
exe = executable('prog', 'prog.c', install : true)
meson-0.53.2/test cases/common/8 install/prog.c0000644000175000017500000000004113571777336022571 0ustar  jpakkanejpakkane00000000000000int main(void) {
    return 0;
}
meson-0.53.2/test cases/common/8 install/stat.c0000644000175000017500000000003713571777336022602 0ustar  jpakkanejpakkane00000000000000int func(void) { return 933; }
meson-0.53.2/test cases/common/80 extract from nested subdir/0000755000175000017500000000000013625242370025170 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/80 extract from nested subdir/meson.build0000644000175000017500000000024313605171417027332 0ustar  jpakkanejpakkane00000000000000project('Extract objects from subdirs.', 'c')

if meson.is_unity()
  message('Unity build: skipping incompatible test')
else
  subdir('src')
  subdir('tst')
endif
meson-0.53.2/test cases/common/80 extract from nested subdir/src/0000755000175000017500000000000013625242370025757 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/80 extract from nested subdir/src/first/0000755000175000017500000000000013625242370027106 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/80 extract from nested subdir/src/first/lib_first.c0000644000175000017500000000004513571777336031245 0ustar  jpakkanejpakkane00000000000000int first(void) {
    return 1001;
}
meson-0.53.2/test cases/common/80 extract from nested subdir/src/first/meson.build0000644000175000017500000000006713531533273031254 0ustar  jpakkanejpakkane00000000000000first_lib = shared_library('first_lib', 'lib_first.c')
meson-0.53.2/test cases/common/80 extract from nested subdir/src/meson.build0000644000175000017500000000002013531533273030112 0ustar  jpakkanejpakkane00000000000000subdir('first')
meson-0.53.2/test cases/common/80 extract from nested subdir/tst/0000755000175000017500000000000013625242370026002 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/80 extract from nested subdir/tst/first/0000755000175000017500000000000013625242370027131 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/80 extract from nested subdir/tst/first/exe_first.c0000644000175000017500000000010013571777336031273 0ustar  jpakkanejpakkane00000000000000int first(void);

int main(void) {
    return first() - 1001;
}
meson-0.53.2/test cases/common/80 extract from nested subdir/tst/first/meson.build0000644000175000017500000000021013531533273031265 0ustar  jpakkanejpakkane00000000000000first_exe = executable('first_exe', 'exe_first.c',
  objects : first_lib.extract_objects('lib_first.c'))

test('first_test', first_exe)
meson-0.53.2/test cases/common/80 extract from nested subdir/tst/meson.build0000644000175000017500000000002013531533273030135 0ustar  jpakkanejpakkane00000000000000subdir('first')
meson-0.53.2/test cases/common/81 internal dependency/0000755000175000017500000000000013625242370023772 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/81 internal dependency/meson.build0000644000175000017500000000010313605171420026121 0ustar  jpakkanejpakkane00000000000000project('internal dependency', 'c')

subdir('proj1')
subdir('src')
meson-0.53.2/test cases/common/81 internal dependency/proj1/0000755000175000017500000000000013625242370025025 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/81 internal dependency/proj1/include/0000755000175000017500000000000013625242370026450 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/81 internal dependency/proj1/include/proj1.h0000644000175000017500000000012613571777336027672 0ustar  jpakkanejpakkane00000000000000#pragma once

void proj1_func1(void);
void proj1_func2(void);
void proj1_func3(void);
meson-0.53.2/test cases/common/81 internal dependency/proj1/meson.build0000644000175000017500000000043713531533273027174 0ustar  jpakkanejpakkane00000000000000incdirs = include_directories('include')

p1lib = static_library('proj1', 'proj1f1.c',
  include_directories : incdirs
)

indirect_source = files('proj1f2.c')

proj1_dep = declare_dependency(include_directories : incdirs,
  link_with : p1lib,
  sources : ['proj1f3.c', indirect_source])
meson-0.53.2/test cases/common/81 internal dependency/proj1/proj1f1.c0000644000175000017500000000014113571777336026466 0ustar  jpakkanejpakkane00000000000000#include
#include

void proj1_func1(void) {
    printf("In proj1_func1.\n");
}
meson-0.53.2/test cases/common/81 internal dependency/proj1/proj1f2.c0000644000175000017500000000014113571777336026467 0ustar  jpakkanejpakkane00000000000000#include
#include

void proj1_func2(void) {
    printf("In proj1_func2.\n");
}
meson-0.53.2/test cases/common/81 internal dependency/proj1/proj1f3.c0000644000175000017500000000014113571777336026470 0ustar  jpakkanejpakkane00000000000000#include
#include

void proj1_func3(void) {
    printf("In proj1_func3.\n");
}
meson-0.53.2/test cases/common/81 internal dependency/src/0000755000175000017500000000000013625242370024561 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/81 internal dependency/src/main.c0000644000175000017500000000025213571777336025667 0ustar  jpakkanejpakkane00000000000000#include
#include

int main(void) {
    printf("Now calling into library.\n");
    proj1_func1();
    proj1_func2();
    proj1_func3();
    return 0;
}
meson-0.53.2/test cases/common/81 internal dependency/src/meson.build0000644000175000017500000000012713531533273026724 0ustar  jpakkanejpakkane00000000000000exe = executable('projtest', 'main.c', dependencies : proj1_dep)
test('projtest', exe)
meson-0.53.2/test cases/common/82 same basename/0000755000175000017500000000000013625242370022541 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/82 same basename/exe1.c0000644000175000017500000000006713571777336023571 0ustar  jpakkanejpakkane00000000000000int func(void);

int main(void) {
    return func();
}
meson-0.53.2/test cases/common/82 same basename/exe2.c0000644000175000017500000000010413571777336023562 0ustar  jpakkanejpakkane00000000000000int func(void);

int main(void) {
    return func() == 1 ? 0 : 1;
}
meson-0.53.2/test cases/common/82 same basename/lib.c0000644000175000017500000000070413571777336023473 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

#if defined SHAR
int DLL_PUBLIC func(void) {
    return 1;
}
#elif defined STAT
int func(void) {
    return 0;
}
#else
#error "Missing type definition."
#endif

meson-0.53.2/test cases/common/82 same basename/meson.build0000644000175000017500000000060513605171422024701 0ustar  jpakkanejpakkane00000000000000project('same basename', 'c')

subdir('sharedsub')
subdir('staticsub')

# Use the same source file to check that each top level target
# has its own unique working directory. If they don't
# then the .o files will clobber each other.

exe1 = executable('name', 'exe1.c', link_with : stlib)
exe2 = executable('name2', 'exe2.c', link_with : shlib)

test('static', exe1)
test('shared', exe2)
meson-0.53.2/test cases/common/82 same basename/sharedsub/0000755000175000017500000000000013625242370024521 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/82 same basename/sharedsub/meson.build0000644000175000017500000000007613531533273026667 0ustar  jpakkanejpakkane00000000000000shlib = shared_library('name', '../lib.c', c_args : '-DSHAR')
meson-0.53.2/test cases/common/82 same basename/staticsub/0000755000175000017500000000000013625242370024542 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/82 same basename/staticsub/meson.build0000644000175000017500000000025613531533273026710 0ustar  jpakkanejpakkane00000000000000# On Windows a static lib is now libfoo.a, so it does not conflict with foo.lib
# from the shared library above
stlib = static_library('name', '../lib.c', c_args : '-DSTAT')
meson-0.53.2/test cases/common/83 declare dep/0000755000175000017500000000000013625242370022211 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/83 declare dep/entity/0000755000175000017500000000000013625242370023525 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/83 declare dep/entity/entity.h0000644000175000017500000000007613571777336025234 0ustar  jpakkanejpakkane00000000000000#pragma once

int entity_func1(void);
int entity_func2(void);
meson-0.53.2/test cases/common/83 declare dep/entity/entity1.c0000644000175000017500000000021713571777336025305 0ustar  jpakkanejpakkane00000000000000#include"entity.h"

#ifdef USING_ENT
#error "Entity use flag leaked into entity compilation."
#endif

int entity_func1(void) {
    return 5;
}
meson-0.53.2/test cases/common/83 declare dep/entity/entity2.c0000644000175000017500000000007513571777336025310 0ustar  jpakkanejpakkane00000000000000#include

int entity_func2(void) {
    return 9;
}
meson-0.53.2/test cases/common/83 declare dep/entity/meson.build0000644000175000017500000000060713531533273025673 0ustar  jpakkanejpakkane00000000000000entity_lib = static_library('entity', 'entity1.c')

entity_dep = declare_dependency(link_with : [[entity_lib]],
  include_directories : [['.']],
  sources : 'entity2.c',
  compile_args : ['-DUSING_ENT=1'],
  version : '1.2.3',
  link_args : []) # No simple way of testing linker flags :(.

assert(entity_dep.version().version_compare('==1.2.3'), 'Declare_dep has incorrect version string.')
meson-0.53.2/test cases/common/83 declare dep/main.c0000644000175000017500000000051213571777336023316 0ustar  jpakkanejpakkane00000000000000#include
#include

#ifndef USING_ENT
#error "Entity use flag not used for compilation."
#endif

int main(void) {
    if(entity_func1() != 5) {
        printf("Error in func1.\n");
        return 1;
    }
    if(entity_func2() != 9) {
        printf("Error in func2.\n");
        return 2;
    }
    return 0;
}
meson-0.53.2/test cases/common/83 declare dep/meson.build0000644000175000017500000000130113605171423024344 0ustar  jpakkanejpakkane00000000000000project('declare dependency', 'c')

subdir('entity')

exe = executable('dep_user', 'main.c',
  dependencies : entity_dep)
test('dep', exe)

# just to make sure [] works as a no-op dep here
executable('dummy', 'main.c',
  dependencies : [entity_dep, []])

# simple case
declare_dependency(dependencies : entity_dep)

# nested deps should be flattened
declare_dependency(dependencies : [entity_dep])
declare_dependency(dependencies : [[entity_dep]])

# check that [] properly works as a no-op dep in declare_dependency() too
declare_dependency(dependencies : [])
declare_dependency(dependencies : [[]])
declare_dependency(dependencies : [entity_dep, []])
declare_dependency(dependencies : [[], entity_dep])
meson-0.53.2/test cases/common/84 extract all/0000755000175000017500000000000013625242370022265 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/84 extract all/extractor.h0000644000175000017500000000012213571777336024463 0ustar  jpakkanejpakkane00000000000000#pragma once

int func1(void);
int func2(void);
int func3(void);
int func4(void);
meson-0.53.2/test cases/common/84 extract all/four.c0000644000175000017500000000007113571777336023421 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"

int func4(void) {
    return 4;
}
meson-0.53.2/test cases/common/84 extract all/meson.build0000644000175000017500000000110413605171423024421 0ustar  jpakkanejpakkane00000000000000project('extract all', 'c')

a = static_library('a', 'one.c', 'two.c')
b = static_library('b', 'three.c', 'four.c')
c = static_library('c', objects : [a.extract_all_objects(), b.extract_all_objects()])
d = static_library('d', objects : [a.extract_all_objects(), b.extract_all_objects(), c.extract_all_objects()])
d_recursive = static_library('d_recursive', objects : [c.extract_all_objects(recursive : true)])

e = executable('proggie', 'prog.c', link_with : d)
test('extall', e)

e = executable('proggie_recursive', 'prog.c', link_with : d_recursive)
test('extall_recursive', e)
meson-0.53.2/test cases/common/84 extract all/one.c0000644000175000017500000000007113571777336023227 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"

int func1(void) {
    return 1;
}
meson-0.53.2/test cases/common/84 extract all/prog.c0000644000175000017500000000031213571777336023413 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"
#include

int main(void) {
    if((1+2+3+4) != (func1() + func2() + func3() + func4())) {
        printf("Arithmetic is fail.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/84 extract all/three.c0000644000175000017500000000007113571777336023555 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"

int func3(void) {
    return 3;
}
meson-0.53.2/test cases/common/84 extract all/two.c0000644000175000017500000000007113571777336023257 0ustar  jpakkanejpakkane00000000000000#include"extractor.h"

int func2(void) {
    return 2;
}
meson-0.53.2/test cases/common/85 add language/0000755000175000017500000000000013625242370022357 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/85 add language/meson.build0000644000175000017500000000044113605171425024520 0ustar  jpakkanejpakkane00000000000000project('add language', 'c')

test('C', executable('cprog', 'prog.c'))

assert(add_languages('cpp'), 'Add_languages returned false on success')
assert(not add_languages('klingon', required : false), 'Add_languages returned true on failure.')

test('C++', executable('cppprog', 'prog.cc'))
meson-0.53.2/test cases/common/85 add language/prog.c0000644000175000017500000000012313571777336023505 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I am plain C.\n");
    return 0;
}
meson-0.53.2/test cases/common/85 add language/prog.cc0000644000175000017500000000013413531533273023634 0ustar  jpakkanejpakkane00000000000000#include

int main(int, char**) {
    std::cout << "I am C++.\n";
    return 0;
}
meson-0.53.2/test cases/common/86 identical target name in subproject/0000755000175000017500000000000013625242370026720 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/86 identical target name in subproject/bar.c0000644000175000017500000000013513571777336027646 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I'm a main project bar.\n");
    return 0;
}
meson-0.53.2/test cases/common/86 identical target name in subproject/meson.build0000644000175000017500000000025613605171425031065 0ustar  jpakkanejpakkane00000000000000project('toplevel bar', 'c')

subproject('foo')

executable('bar', 'bar.c')
run_target('nop', command : ['true'])
custom_target('cus', output: ['cus.c'], command : ['true'])
meson-0.53.2/test cases/common/86 identical target name in subproject/subprojects/0000755000175000017500000000000013625242351031262 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/86 identical target name in subproject/subprojects/foo/0000755000175000017500000000000013625242370032046 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/86 identical target name in subproject/subprojects/foo/bar.c0000644000175000017500000000013313571777336032772 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I'm a subproject bar.\n");
    return 0;
}
meson-0.53.2/test cases/common/86 identical target name in subproject/subprojects/foo/meson.build0000644000175000017500000000022513531533273034210 0ustar  jpakkanejpakkane00000000000000project('subfoo', 'c')

executable('bar', 'bar.c')
run_target('nop', command : ['true'])
custom_target('cus', output: ['cus.c'], command : ['true'])
meson-0.53.2/test cases/common/87 plusassign/0000755000175000017500000000000013625242370022255 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/87 plusassign/meson.build0000644000175000017500000000225713605171426024426 0ustar  jpakkanejpakkane00000000000000project('plusassign', 'c')

x = []

x += 'a'

if x.length() != 1
  error('Incorrect append')
endif

if x[0] != 'a'
  error('Incorrect append 2.')
endif

y = x

x += 'b'

if y.length() != 1
  error('Immutability broken.')
endif

if y[0] != 'a'
  error('Immutability broken 2.')
endif

if x.length() != 2
  error('Incorrect append 3')
endif

if x[0] != 'a'
  error('Incorrect append 4.')
endif

if x[1] != 'b'
  error('Incorrect append 5.')
endif

# Now with evil added: append yourself.

x += x

if x.length() != 4
  error('Incorrect selfappend.')
endif

# += on strings

bra = 'bra'
foo = 'A'
foo += bra
foo += 'cada'
foo += bra
assert (foo == 'Abracadabra', 'string += failure [@0@]'.format(foo))
assert (bra == 'bra', 'string += modified right argument!')
foo += ' ' + foo
assert (foo == 'Abracadabra Abracadabra', 'string += failure [@0@]'.format(foo))

# += on ints

foo = 5
foo += 6
assert (foo == 11, 'int += failure [@0@]'.format(foo))
bar = 99
foo += bar
assert (foo == 110, 'int += failure [@0@]'.format(foo))
assert (bar == 99, 'int += modified right argument"')
bar += foo + 1
assert (bar == 210, 'int += failure [@0@]'.format(bar))
assert (foo == 110, 'int += modified right argument"')
meson-0.53.2/test cases/common/88 skip subdir/0000755000175000017500000000000013625242370022305 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/88 skip subdir/meson.build0000644000175000017500000000005713605171426024452 0ustar  jpakkanejpakkane00000000000000project('foo', 'c')

subdir('subdir1/subdir2')
meson-0.53.2/test cases/common/88 skip subdir/subdir1/0000755000175000017500000000000013625242370023656 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/88 skip subdir/subdir1/meson.build0000644000175000017500000000004413531533273026017 0ustar  jpakkanejpakkane00000000000000error('This should not be called.')
meson-0.53.2/test cases/common/88 skip subdir/subdir1/subdir2/0000755000175000017500000000000013625242370025230 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/88 skip subdir/subdir1/subdir2/meson.build0000644000175000017500000000004213531533273027367 0ustar  jpakkanejpakkane00000000000000message('I\'m in subdir subdir.')
meson-0.53.2/test cases/common/89 private include/0000755000175000017500000000000013625242370023145 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/89 private include/meson.build0000644000175000017500000000007713605171430025307 0ustar  jpakkanejpakkane00000000000000project('access private', 'c')

subdir('stlib')
subdir('user')
meson-0.53.2/test cases/common/89 private include/stlib/0000755000175000017500000000000013625242370024262 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/89 private include/stlib/compiler.py0000755000175000017500000000102013571777336026461 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os

assert(len(sys.argv) == 3)

h_templ = '''#pragma once
unsigned int %s(void);
'''

c_templ = '''#include"%s.h"

unsigned int %s(void) {
  return 0;
}
'''

ifile = sys.argv[1]
outdir = sys.argv[2]

base = os.path.splitext(os.path.split(ifile)[-1])[0]

cfile = os.path.join(outdir, base + '.c')
hfile = os.path.join(outdir, base + '.h')

c_code = c_templ % (base, base)
h_code = h_templ % base

with open(cfile, 'w') as f:
    f.write(c_code)
with open(hfile, 'w') as f:
    f.write(h_code)
meson-0.53.2/test cases/common/89 private include/stlib/foo1.def0000644000175000017500000000000013531533273025575 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/89 private include/stlib/foo2.def0000644000175000017500000000000013531533273025576 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/89 private include/stlib/meson.build0000644000175000017500000000045213531533273026426 0ustar  jpakkanejpakkane00000000000000genbin = find_program('compiler.py')

gen = generator(genbin,
  output : ['@BASENAME@.h', '@BASENAME@.c'],
  arguments : ['@INPUT@', '@BUILD_DIR@']
  )

defs = ['foo1.def', 'foo2.def']
generated = gen.process(defs)

stlib = static_library('st', generated)
st_priv_inc = stlib.private_dir_include()
meson-0.53.2/test cases/common/89 private include/user/0000755000175000017500000000000013625242370024123 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/89 private include/user/libuser.c0000644000175000017500000000012213571777336025746 0ustar  jpakkanejpakkane00000000000000#include"foo1.h"
#include"foo2.h"

int main(void) {
    return foo1() + foo2();
}
meson-0.53.2/test cases/common/89 private include/user/meson.build0000644000175000017500000000017113531533273026265 0ustar  jpakkanejpakkane00000000000000exe = executable('libuser', 'libuser.c',
  link_with : stlib,
  include_directories : st_priv_inc)

test('libuser', exe)
meson-0.53.2/test cases/common/9 header install/0000755000175000017500000000000013625242370022656 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/9 header install/installed_files.txt0000644000175000017500000000014213016624375026560 0ustar  jpakkanejpakkane00000000000000usr/include/rootdir.h
usr/include/subdir/subdir.h
usr/include/vanished.h
usr/include/fileheader.h
meson-0.53.2/test cases/common/9 header install/meson.build0000644000175000017500000000036413605171311025015 0ustar  jpakkanejpakkane00000000000000project('header install')

as_array = ['subdir.h']

subdir('vanishing_subdir')
subdir('sub')

h1 = install_headers('rootdir.h')
h2 = install_headers(as_array, subdir : 'subdir')
h3 = install_headers(subheader)
h4 = install_headers(disabler())

meson-0.53.2/test cases/common/9 header install/rootdir.h0000644000175000017500000000007612650745767024533 0ustar  jpakkanejpakkane00000000000000/* This header goes to include dir root. */

int root_func();
meson-0.53.2/test cases/common/9 header install/sub/0000755000175000017500000000000013625242370023447 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/9 header install/sub/fileheader.h0000644000175000017500000000007113016624375025711 0ustar  jpakkanejpakkane00000000000000#pragma once

#define LIFE "Is life! Na naa, naa-na na."
meson-0.53.2/test cases/common/9 header install/sub/meson.build0000644000175000017500000000004313016624375025611 0ustar  jpakkanejpakkane00000000000000subheader = files('fileheader.h')

meson-0.53.2/test cases/common/9 header install/subdir.h0000644000175000017500000000011212650745767024330 0ustar  jpakkanejpakkane00000000000000/* This file goes to subdirectory of include root. */

int subdir_func();
meson-0.53.2/test cases/common/9 header install/vanishing_subdir/0000755000175000017500000000000013625242370026214 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/9 header install/vanishing_subdir/meson.build0000644000175000017500000000003612650745767030374 0ustar  jpakkanejpakkane00000000000000install_headers('vanished.h')
meson-0.53.2/test cases/common/9 header install/vanishing_subdir/vanished.h0000644000175000017500000000022112650745767030200 0ustar  jpakkanejpakkane00000000000000#pragma once

/* This is a header in a subdirectory. Make sure it installs into
 * /prefix/include and not /prefix/include/vanishing_subdir.
 */
meson-0.53.2/test cases/common/90 default options/0000755000175000017500000000000013625242370023157 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/90 default options/meson.build0000644000175000017500000000226413605171431025322 0ustar  jpakkanejpakkane00000000000000project('default options', 'cpp', 'c', default_options : [
  'prefix=/absoluteprefix',
  'buildtype=debugoptimized',
  'cpp_std=c++11',
  'cpp_eh=none',
  'warning_level=3',
  ])

assert(get_option('buildtype') == 'debugoptimized', 'Build type default value wrong.')

cpp_eh = get_option('cpp_eh')
assert(cpp_eh == 'none', 'EH value is "' + cpp_eh + '" instead of "none"')
cpp_std = get_option('cpp_std')
assert(cpp_std == 'c++11', 'C++ std value is "' + cpp_std + '" instead of c++11.')

w_level = get_option('warning_level')
assert(w_level == '3', 'warning level "' + w_level + '" instead of "3"')

# FIXME. Since we no longer accept invalid options to c_std etc,
# there is no simple way to test this. Gcc does not seem to expose
# the C std used in a preprocessor token so we can't check for it.
# Think of a way to fix this.
#
# # Verify that project args are not used when told not to.
# # MSVC plain C does not have a simple arg to test so skip it.
# if cpp.get_id() != 'msvc'
#   cc = meson.get_compiler('c')
#   assert(not cc.compiles('int foobar;'), 'Default arg not used in test.')
#   assert(cc.compiles('int foobar;', no_builtin_args : true), 'No_builtin did not disable builtins.')
# endif
meson-0.53.2/test cases/common/91 dep fallback/0000755000175000017500000000000013625242370022350 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/91 dep fallback/gensrc.py0000644000175000017500000000013413531533273024202 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import shutil

shutil.copyfile(sys.argv[1], sys.argv[2])
meson-0.53.2/test cases/common/91 dep fallback/meson.build0000644000175000017500000000152113605171433024510 0ustar  jpakkanejpakkane00000000000000project('dep fallback', 'c')

bob = dependency('boblib', fallback : ['boblib', 'bob_dep'], required: false,
  default_options : 'warning_level=1')
if not bob.found()
    error('Bob is actually needed')
endif
# boblib subproject exists, but sita_dep doesn't exist
sita = dependency('sitalib', fallback : ['boblib', 'sita_dep'], required: false)
# jimmylib subproject doesn't exist
jimmy = dependency('jimmylib', fallback : ['jimmylib', 'jimmy_dep'], required: false)
# dummylib subproject fails to configure
dummy = dependency('dummylib', fallback : ['dummylib', 'dummy_dep'], required: false)

gensrc_py = find_program('gensrc.py')
gensrc = custom_target('gensrc.c',
  input : 'tester.c',
  output : 'gensrc.c',
  command : [gensrc_py, '@INPUT@', '@OUTPUT@'])

exe = executable('bobtester',
  [gensrc],
  dependencies : bob)

test('bobtester', exe)
meson-0.53.2/test cases/common/91 dep fallback/subprojects/0000755000175000017500000000000013625242351024712 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/91 dep fallback/subprojects/boblib/0000755000175000017500000000000013625242370026144 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/91 dep fallback/subprojects/boblib/bob.c0000644000175000017500000000015613571777336027073 0ustar  jpakkanejpakkane00000000000000#include"bob.h"

#ifdef _MSC_VER
__declspec(dllexport)
#endif
const char* get_bob(void) {
    return "bob";
}
meson-0.53.2/test cases/common/91 dep fallback/subprojects/boblib/bob.h0000644000175000017500000000012613571777336027075 0ustar  jpakkanejpakkane00000000000000#pragma once

#ifdef _MSC_VER
__declspec(dllimport)
#endif
const char* get_bob(void);
meson-0.53.2/test cases/common/91 dep fallback/subprojects/boblib/genbob.py0000644000175000017500000000012613531533273027752 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

with open(sys.argv[1], 'w') as f:
    f.write('')
meson-0.53.2/test cases/common/91 dep fallback/subprojects/boblib/meson.build0000644000175000017500000000066713531533273030320 0ustar  jpakkanejpakkane00000000000000project('bob', 'c')

gensrc_py = find_program('genbob.py')
genbob_h = custom_target('genbob.h',
  output : 'genbob.h',
  command : [gensrc_py, '@OUTPUT@'])
genbob_c = custom_target('genbob.c',
  output : 'genbob.c',
  command : [gensrc_py, '@OUTPUT@'])

boblib = library('bob', ['bob.c', genbob_c])
bobinc = include_directories('.')

bob_dep = declare_dependency(link_with : boblib,
  sources : [genbob_h],
  include_directories : bobinc)
meson-0.53.2/test cases/common/91 dep fallback/subprojects/dummylib/0000755000175000017500000000000013625242370026535 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/91 dep fallback/subprojects/dummylib/meson.build0000644000175000017500000000014713531533273030702 0ustar  jpakkanejpakkane00000000000000project('dummylib', 'c')

dummy_dep = declare_dependency()
error('this subproject fails to configure')
meson-0.53.2/test cases/common/91 dep fallback/tester.c0000644000175000017500000000041313571777336024037 0ustar  jpakkanejpakkane00000000000000#include"bob.h"
#include"genbob.h"
#include
#include

int main(void) {
    if(strcmp("bob", get_bob()) == 0) {
        printf("Bob is indeed bob.\n");
    } else {
        printf("ERROR: bob is not bob.\n");
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/92 default library/0000755000175000017500000000000013625242370023132 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/92 default library/ef.cpp0000644000175000017500000000014413531533273024230 0ustar  jpakkanejpakkane00000000000000#include"ef.h"

DLL_PUBLIC Ef::Ef() : x(99) {
}

int DLL_PUBLIC Ef::get_x() const {
    return x;
}
meson-0.53.2/test cases/common/92 default library/ef.h0000644000175000017500000000062613531533273023702 0ustar  jpakkanejpakkane00000000000000#pragma once

#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

class Ef {
private:
    int x;

public:

    DLL_PUBLIC Ef();
    int DLL_PUBLIC get_x() const;
};
meson-0.53.2/test cases/common/92 default library/eftest.cpp0000644000175000017500000000036513531533273025135 0ustar  jpakkanejpakkane00000000000000#include"ef.h"

#include

int main(int, char **) {
    Ef var;
    if(var.get_x() == 99) {
        std::cout << "All is fine.\n";
        return 0;
    } else {
        std::cout << "Something went wrong.\n";
        return 1;
    }
}
meson-0.53.2/test cases/common/92 default library/meson.build0000644000175000017500000000051613605171433025275 0ustar  jpakkanejpakkane00000000000000project('default library', 'cpp')

flib = library('ef', 'ef.cpp')
exe = executable('eftest', 'eftest.cpp', link_with : flib)
test('eftest', exe)

# Same as above, but using build_target()
flib2 = build_target('ef2', 'ef.cpp', target_type: 'library')
exe2 = executable('eftest2', 'eftest.cpp', link_with : flib2)
test('eftest2', exe2)
meson-0.53.2/test cases/common/93 selfbuilt custom/0000755000175000017500000000000013625242370023346 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/93 selfbuilt custom/data.dat0000644000175000017500000000002313531533273024745 0ustar  jpakkanejpakkane00000000000000generated_function
meson-0.53.2/test cases/common/93 selfbuilt custom/mainprog.cpp0000644000175000017500000000011413571777336025701 0ustar  jpakkanejpakkane00000000000000#include"data.h"

int main(void) {
    return generated_function() != 52;
}
meson-0.53.2/test cases/common/93 selfbuilt custom/meson.build0000644000175000017500000000057613605171435025521 0ustar  jpakkanejpakkane00000000000000project('selfbuilt custom', 'cpp')

# Build an exe and use it in a custom target
# whose output is used to build a different exe.

tool = executable('tool', 'tool.cpp', native : true)

hfile = custom_target('datah',
  output : 'data.h',
  input : 'data.dat',
  command : [tool, '@INPUT@', '@OUTPUT@'],
)

main = executable('mainprog', 'mainprog.cpp', hfile)

test('maintest', main)
meson-0.53.2/test cases/common/93 selfbuilt custom/tool.cpp0000644000175000017500000000133713531533273025034 0ustar  jpakkanejpakkane00000000000000#include
#include
#include

using namespace std;

const char prefix[] = "int ";
const char suffix[] = " () {\n    return 52;}\n";

int main(int argc, char **argv) {
    if(argc != 3) {
        cout << "You is fail.\n";
        return 1;
    }
    ifstream is(argv[1], ifstream::binary);
    if(!is) {
        cout << "Opening input file failed.\n";
        return 1;
    }
    string funcname;
    is >> funcname;
    ofstream os(argv[2], ofstream::binary);
    if(!os) {
        cout << "Opening output file failed.\n";
        return 1;
    }
    os << prefix << funcname << suffix;
    os.close();
    if(!os.good()) {
        cout << "Writing data out failed.\n";
        return 1;
    }
    return 0;
}
meson-0.53.2/test cases/common/94 gen extra/0000755000175000017500000000000013625242370021740 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/94 gen extra/meson.build0000644000175000017500000000217513605171436024111 0ustar  jpakkanejpakkane00000000000000project('extra args in gen', 'c')

prog = find_program('srcgen.py')

gen = generator(prog,
  output : '@BASENAME@.c',
  arguments : ['--input=@INPUT@', '--output=@OUTPUT@', '@EXTRA_ARGS@'])

g1 = gen.process('name.dat')
g2 = gen.process('name.dat', extra_args: '--upper')

test('basic', executable('basic', 'plain.c', g1))
test('upper', executable('upper', 'upper.c', g2))

prog2 = find_program('srcgen2.py')
basename_gen = generator(prog2,
  output : ['@BASENAME@.tab.c', '@BASENAME@.tab.h'],
  arguments : ['@BUILD_DIR@', '@BASENAME@', '@INPUT@'])

basename_src = basename_gen.process('name.l')

test('basename', executable('basename', basename_src))

plainname_gen = generator(prog2,
  output : ['@PLAINNAME@.tab.c', '@PLAINNAME@.tab.h'],
  arguments : ['@BUILD_DIR@', '@PLAINNAME@', '@INPUT@'])

plainname_src = plainname_gen.process('name.l')

test('plainname', executable('plainname', plainname_src))

prog3 = find_program('srcgen3.py')
capture_gen = generator(prog3,
  output : ['@BASENAME@.yy.c'],
  arguments : ['@INPUT@'],
  capture : true)

capture_src = capture_gen.process('name.l')

test('capture', executable('capture', capture_src))
meson-0.53.2/test cases/common/94 gen extra/name.dat0000644000175000017500000000001213531533273023344 0ustar  jpakkanejpakkane00000000000000bob_mcbob
meson-0.53.2/test cases/common/94 gen extra/name.l0000644000175000017500000000003513571777336023052 0ustar  jpakkanejpakkane00000000000000int main(void) {
return 0;
}
meson-0.53.2/test cases/common/94 gen extra/plain.c0000644000175000017500000000010113571777336023216 0ustar  jpakkanejpakkane00000000000000int bob_mcbob(void);

int main(void) {
    return bob_mcbob();
}
meson-0.53.2/test cases/common/94 gen extra/srcgen.py0000755000175000017500000000124613605170651023601 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--input', dest='input',
                    help='the input file')
parser.add_argument('--output', dest='output',
                    help='the output file')
parser.add_argument('--upper', dest='upper', action='store_true', default=False,
                    help='Convert to upper case.')

c_templ = '''int %s(void) {
    return 0;
}
'''

options = parser.parse_args(sys.argv[1:])

with open(options.input) as f:
    funcname = f.readline().strip()
if options.upper:
    funcname = funcname.upper()

with open(options.output, 'w') as f:
    f.write(c_templ % funcname)
meson-0.53.2/test cases/common/94 gen extra/srcgen2.py0000644000175000017500000000130313531533273023653 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import os
import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('target_dir',
                    help='the target dir')
parser.add_argument('stem',
                    help='the stem')
parser.add_argument('input',
                    help='the input file')

options = parser.parse_args(sys.argv[1:])

with open(options.input) as f:
    content = f.read()


output_c = os.path.join(options.target_dir, options.stem + ".tab.c")
with open(output_c, 'w') as f:
    f.write(content)


output_h = os.path.join(options.target_dir, options.stem + ".tab.h")
h_content = '''#pragma once

int myfun(void);
'''
with open(output_h, 'w') as f:
    f.write(h_content)
meson-0.53.2/test cases/common/94 gen extra/srcgen3.py0000644000175000017500000000043113531533273023655 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('input',
                    help='the input file')

options = parser.parse_args(sys.argv[1:])

with open(options.input) as f:
    content = f.read().strip()

print(content)
meson-0.53.2/test cases/common/94 gen extra/upper.c0000644000175000017500000000010113571777336023246 0ustar  jpakkanejpakkane00000000000000int BOB_MCBOB(void);

int main(void) {
    return BOB_MCBOB();
}
meson-0.53.2/test cases/common/95 benchmark/0000755000175000017500000000000013625242370022016 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/95 benchmark/delayer.c0000644000175000017500000000056013571777336023627 0ustar  jpakkanejpakkane00000000000000/* Simple prog that sleeps for a random time. */

#include
#include
#if defined(_WIN32)
#include
#endif

int main(void) {
    srand(time(NULL));
#if !defined(_WIN32)
    struct timespec t;
    t.tv_sec = 0;
    t.tv_nsec = 199999999.0*rand()/RAND_MAX;
    nanosleep(&t, NULL);
#else
    Sleep(50.0*rand()/RAND_MAX);
#endif
    return 0;
}
meson-0.53.2/test cases/common/95 benchmark/meson.build0000644000175000017500000000020013605171437024153 0ustar  jpakkanejpakkane00000000000000project('benchmark', 'c')

delayer = executable('delayer', 'delayer.c', c_args : '-D_GNU_SOURCE')
benchmark('delayer', delayer)
meson-0.53.2/test cases/common/96 test workdir/0000755000175000017500000000000013625242370022506 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/96 test workdir/meson.build0000644000175000017500000000026613605171440024651 0ustar  jpakkanejpakkane00000000000000project('test workdir', 'c')

exe = executable('opener', 'opener.c')

test('basic', exe, workdir : meson.source_root())
test('shouldfail', exe, should_fail : true)

subdir('subdir')
meson-0.53.2/test cases/common/96 test workdir/opener.c0000644000175000017500000000031413571777336024157 0ustar  jpakkanejpakkane00000000000000// This test only succeeds if run in the source root dir.

#include

int main(void) {
    FILE *f = fopen("opener.c", "r");
    if(f) {
        fclose(f);
        return 0;
    }
    return 1;
}
meson-0.53.2/test cases/common/96 test workdir/subdir/0000755000175000017500000000000013625242370023776 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/96 test workdir/subdir/checker.py0000755000175000017500000000011213531533273025752 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

data = open(sys.argv[1], 'rb').read()
meson-0.53.2/test cases/common/96 test workdir/subdir/meson.build0000644000175000017500000000020613531533273026137 0ustar  jpakkanejpakkane00000000000000exe2 = executable('dummy', '../opener.c')
test('subdir', find_program('checker.py'),
  workdir : meson.source_root(),
  args: [exe2])
meson-0.53.2/test cases/common/97 suites/0000755000175000017500000000000013625242370021402 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/97 suites/exe1.c0000644000175000017500000000012513571777336022425 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I am test exe1.\n");
    return 0;
}
meson-0.53.2/test cases/common/97 suites/exe2.c0000644000175000017500000000012513571777336022426 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I am test exe2.\n");
    return 0;
}
meson-0.53.2/test cases/common/97 suites/meson.build0000644000175000017500000000031513605171441023541 0ustar  jpakkanejpakkane00000000000000project('multiple test suites', 'c')

subproject('sub')

exe1 = executable('exe1', 'exe1.c')
exe2 = executable('exe2', 'exe2.c')

test('exe1', exe1)
test('exe2', exe2, suite : ['suite2', 'super-special'])
meson-0.53.2/test cases/common/97 suites/subprojects/0000755000175000017500000000000013625242351023744 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/97 suites/subprojects/sub/0000755000175000017500000000000013625242370024536 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/97 suites/subprojects/sub/meson.build0000644000175000017500000000025113531533273026677 0ustar  jpakkanejpakkane00000000000000project('subproject test suites', 'c')

sub1 = executable('sub1', 'sub1.c')
sub2 = executable('sub2', 'sub2.c')

test('sub1', sub1)
test('sub2', sub2, suite : 'suite2')
meson-0.53.2/test cases/common/97 suites/subprojects/sub/sub1.c0000644000175000017500000000012513571777336025571 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I am test sub1.\n");
    return 0;
}
meson-0.53.2/test cases/common/97 suites/subprojects/sub/sub2.c0000644000175000017500000000012513571777336025572 0ustar  jpakkanejpakkane00000000000000#include

int main(void) {
    printf("I am test sub2.\n");
    return 0;
}
meson-0.53.2/test cases/common/98 threads/0000755000175000017500000000000013625242370021521 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/98 threads/meson.build0000644000175000017500000000046713605171443023672 0ustar  jpakkanejpakkane00000000000000project('threads', 'cpp', 'c',
  default_options : ['cpp_std=c++11'])

threaddep = dependency('threads')

test('cppthreadtest',
  executable('cppthreadprog', 'threadprog.cpp',
    dependencies : threaddep
  )
)

test('cthreadtest',
  executable('cthreadprog', 'threadprog.c',
    dependencies : threaddep
  )
)
meson-0.53.2/test cases/common/98 threads/threadprog.c0000644000175000017500000000135113571777336024043 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32

#include
#include

DWORD WINAPI thread_func(void) {
    printf("Printing from a thread.\n");
    return 0;
}

int main(void) {
    DWORD id;
    HANDLE th;
    printf("Starting thread.\n");
    th = CreateThread(NULL, 0, thread_func, NULL, 0, &id);
    WaitForSingleObject(th, INFINITE);
    printf("Stopped thread.\n");
    return 0;
}
#else

#include
#include

void* main_func(void) {
    printf("Printing from a thread.\n");
    return NULL;
}

int main(void) {
    pthread_t thread;
    int rc;
    printf("Starting thread.\n");
    rc = pthread_create(&thread, NULL, main_func, NULL);
    rc = pthread_join(thread, NULL);
    printf("Stopped thread.\n");
    return rc;
}

#endif
meson-0.53.2/test cases/common/98 threads/threadprog.cpp0000644000175000017500000000156013571777336024405 0ustar  jpakkanejpakkane00000000000000/* On Windows not all versions of VS support C++11 and
 * some (most?) versions of mingw don't support std::thread,
 * even though they do support c++11. Since we only care about
 * threads working, do the test with raw win threads.
 */

#if defined _WIN32

#include
#include

DWORD WINAPI thread_func(LPVOID) {
    printf("Printing from a thread.\n");
    return 0;
}

int main(void) {
    printf("Starting thread.\n");
    HANDLE th;
    DWORD id;
    th = CreateThread(NULL, 0, thread_func, NULL, 0, &id);
    WaitForSingleObject(th, INFINITE);
    printf("Stopped thread.\n");
    return 0;
}
#else

#include
#include

void main_func(void) {
    printf("Printing from a thread.\n");
}

int main(void) {
    printf("Starting thread.\n");
    std::thread th(main_func);
    th.join();
    printf("Stopped thread.\n");
    return 0;
}

#endif
meson-0.53.2/test cases/common/99 manygen/0000755000175000017500000000000013625242370021526 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/99 manygen/depuser.c0000644000175000017500000000035313571777336023361 0ustar  jpakkanejpakkane00000000000000#include"gen_func.h"

int main(void) {
    unsigned int i = (unsigned int) gen_func_in_lib();
    unsigned int j = (unsigned int) gen_func_in_obj();
    unsigned int k = (unsigned int) gen_func_in_src();
    return (int)(i + j + k);
}
meson-0.53.2/test cases/common/99 manygen/meson.build0000644000175000017500000000046013605171443023670 0ustar  jpakkanejpakkane00000000000000project('manygen', 'c')

if meson.is_cross_build()
  # FIXME error out with skip message once cross test runner
  # recognizes it.
  message('Not running this test during cross build.')
else
  subdir('subdir')

  exe = executable('depuser', 'depuser.c',
    generated)

  test('depuser test', exe)
endif
meson-0.53.2/test cases/common/99 manygen/subdir/0000755000175000017500000000000013625242370023016 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/common/99 manygen/subdir/funcinfo.def0000644000175000017500000000001113531533273025276 0ustar  jpakkanejpakkane00000000000000gen_func
meson-0.53.2/test cases/common/99 manygen/subdir/manygen.py0000755000175000017500000000353013612313307025025 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

from __future__ import print_function

# Generates a static library, object file, source
# file and a header file.

import sys, os
import subprocess

with open(sys.argv[1]) as f:
    funcname = f.readline().strip()
outdir = sys.argv[2]
buildtype_args = sys.argv[3]
compiler_type = sys.argv[4]
compiler = sys.argv[5:]

if not os.path.isdir(outdir):
    print('Outdir does not exist.')
    sys.exit(1)

if compiler_type == 'msvc':
    libsuffix = '.lib'
    is_vs = True
    if any(['clang-cl' in c for c in compiler]):
        linker = 'llvm-lib'
    else:
        linker = 'lib'
else:
    libsuffix = '.a'
    is_vs = False
    linker = 'ar'

objsuffix = '.o'

outo = os.path.join(outdir, funcname + objsuffix)
outa = os.path.join(outdir, funcname + libsuffix)
outh = os.path.join(outdir, funcname + '.h')
outc = os.path.join(outdir, funcname + '.c')

tmpc = 'diibadaaba.c'
tmpo = 'diibadaaba' + objsuffix

with open(outc, 'w') as f:
    f.write('''#include"%s.h"
int %s_in_src(void) {
  return 0;
}
''' % (funcname, funcname))

with open(outh, 'w') as f:
    f.write('''#pragma once
int %s_in_lib(void);
int %s_in_obj(void);
int %s_in_src(void);
''' % (funcname, funcname, funcname))

with open(tmpc, 'w') as f:
    f.write('''int %s_in_obj(void) {
  return 0;
}
''' % funcname)

if is_vs:
    subprocess.check_call(compiler + ['/nologo', '/c', buildtype_args, '/Fo' + outo, tmpc])
else:
    subprocess.check_call(compiler + ['-c', '-o', outo, tmpc])

with open(tmpc, 'w') as f:
    f.write('''int %s_in_lib() {
  return 0;
}
''' % funcname)

if is_vs:
    subprocess.check_call(compiler + ['/nologo', '/c', '/Fo' + tmpo, tmpc])
    subprocess.check_call([linker, '/NOLOGO', '/OUT:' + outa, tmpo])
else:
    subprocess.check_call(compiler + ['-c', '-o', tmpo, tmpc])
    subprocess.check_call([linker, 'csr', outa, tmpo])

os.unlink(tmpo)
os.unlink(tmpc)
meson-0.53.2/test cases/common/99 manygen/subdir/meson.build0000644000175000017500000000163113531533273025162 0ustar  jpakkanejpakkane00000000000000gen = files('manygen.py')
py3_bin = import('python3').find_python()

buildtype = get_option('buildtype')
buildtype_args = '-Dfooxxx' # a useless compiler argument
cc = meson.get_compiler('c')
if cc.get_argument_syntax() == 'msvc'
  # We need our manually generated code to use the same CRT as the executable.
  # Taken from compilers.py since build files do not have access to this.
  if buildtype == 'debug'
    buildtype_args = '/MDd'
  elif buildtype == 'debugoptimized'
    buildtype_args = '/MDd'
  elif buildtype == 'release'
    buildtype_args = '/MD'
  endif
  outfiles = ['gen_func.lib', 'gen_func.c', 'gen_func.h', 'gen_func.o']
else
  outfiles = ['gen_func.a', 'gen_func.c', 'gen_func.h', 'gen_func.o']
endif

generated = custom_target('manygen',
  output : outfiles,
  input : ['funcinfo.def'],
  command : [py3_bin, gen[0], '@INPUT@', '@OUTDIR@', buildtype_args, cc.get_argument_syntax(), cc.cmd_array()],
)
meson-0.53.2/test cases/csharp/0000755000175000017500000000000013625242351017635 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/csharp/1 basic/0000755000175000017500000000000013625242370021040 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/csharp/1 basic/installed_files.txt0000644000175000017500000000005013403223104024721 0ustar  jpakkanejpakkane00000000000000usr/bin/prog.exe
?msvc:usr/bin/prog.pdb
meson-0.53.2/test cases/csharp/1 basic/meson.build0000644000175000017500000000015213605171775023210 0ustar  jpakkanejpakkane00000000000000project('simple c#', 'cs')

e = executable('prog', 'prog.cs', 'text.cs', install : true)
test('basic', e)
meson-0.53.2/test cases/csharp/1 basic/prog.cs0000644000175000017500000000023713340206727022340 0ustar  jpakkanejpakkane00000000000000using System;

public class Prog {
    static public void Main () {
        TextGetter tg = new TextGetter();
        Console.WriteLine(tg.getText());
    }
}
meson-0.53.2/test cases/csharp/1 basic/text.cs0000644000175000017500000000016013340206727022350 0ustar  jpakkanejpakkane00000000000000using System;

public class TextGetter {
    public String getText() {
        return "C# is working.";
    }
}
meson-0.53.2/test cases/csharp/2 library/0000755000175000017500000000000013625242370021424 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/csharp/2 library/helper.cs0000644000175000017500000000017312650745767023252 0ustar  jpakkanejpakkane00000000000000using System;

public class Helper {
    public void print() {
        Console.WriteLine("Library class called.");
    }
}
meson-0.53.2/test cases/csharp/2 library/installed_files.txt0000644000175000017500000000016213403223104025311 0ustar  jpakkanejpakkane00000000000000usr/bin/prog.exe
?msvc:usr/bin/prog.pdb
?msvc:usr/bin/helper.dll
?msvc:usr/bin/helper.pdb
?gcc:usr/lib/helper.dll
meson-0.53.2/test cases/csharp/2 library/meson.build0000644000175000017500000000070213605171776023576 0ustar  jpakkanejpakkane00000000000000project('C# library', 'cs')

python3 = import('python3').find_python()
generated_sources = custom_target('gen_sources',
    input: 'helper.cs',
    output: 'helper.cs',
    command: [python3, '-c',
      'import shutil, sys; shutil.copyfile(sys.argv[1], sys.argv[2])',
      '@INPUT@', '@OUTPUT@']
)

l = shared_library('helper', generated_sources, install : true)

e = executable('prog', 'prog.cs', link_with : l, install : true)
test('libtest', e)
meson-0.53.2/test cases/csharp/2 library/prog.cs0000644000175000017500000000020012650745767022731 0ustar  jpakkanejpakkane00000000000000using System;

public class Prog {
    static public void Main () {
        Helper h = new Helper();
        h.print();
    }
}
meson-0.53.2/test cases/csharp/3 resource/0000755000175000017500000000000013625242370021610 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/csharp/3 resource/TestRes.resx0000644000175000017500000000360212650745767024124 0ustar  jpakkanejpakkane00000000000000

  
    
      
        
          
            
              
                
                
              
              
              
              
            
          
          
            
              
                
              
              
            
          
        
      
    
  
text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Hello from resources!
  meson-0.53.2/test cases/csharp/3 resource/meson.build0000644000175000017500000000016613605171776023766 0ustar  jpakkanejpakkane00000000000000project('C# resource', 'cs')

e = executable('resprog', 'resprog.cs',
resources : 'TestRes.resx')

test('restest', e)
meson-0.53.2/test cases/csharp/3 resource/resprog.cs0000644000175000017500000000040212650745767023633 0ustar  jpakkanejpakkane00000000000000using System;
using System.Resources;

public class Prog {

    static public void Main () {
        ResourceManager res = new ResourceManager(typeof(TestRes));
        Console.WriteLine(res.GetString("message"));
    }

    internal class TestRes {
    }
}
meson-0.53.2/test cases/csharp/4 external dep/0000755000175000017500000000000013625242370022335 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/csharp/4 external dep/hello.txt0000644000175000017500000000001513340206727024175 0ustar  jpakkanejpakkane00000000000000Hello World!
meson-0.53.2/test cases/csharp/4 external dep/installed_files.txt0000644000175000017500000000002113366273215026234 0ustar  jpakkanejpakkane00000000000000usr/bin/prog.exe
meson-0.53.2/test cases/csharp/4 external dep/meson.build0000644000175000017500000000052113605171776024506 0ustar  jpakkanejpakkane00000000000000project('C# external library', 'cs')
glib_sharp_2 = dependency('glib-sharp-2.0', required : false)

if not glib_sharp_2.found()
  error('MESON_SKIP_TEST glib# not found.')
endif

e = executable('prog', 'prog.cs', dependencies: glib_sharp_2, install : true)
test('libtest', e, args: [join_paths(meson.current_source_dir(), 'hello.txt')])
meson-0.53.2/test cases/csharp/4 external dep/prog.cs0000644000175000017500000000025113340206727023631 0ustar  jpakkanejpakkane00000000000000using System;
using GLib;

public class Prog {
    static public void Main (string[] args) {
        Console.WriteLine(GLib.FileUtils.GetFileContents(args[0]));
    }
}
meson-0.53.2/test cases/cuda/0000755000175000017500000000000013625242351017271 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/1 simple/0000755000175000017500000000000013625242370020704 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/1 simple/meson.build0000644000175000017500000000015113426772647023061 0ustar  jpakkanejpakkane00000000000000project('simple', 'cuda', version : '1.0.0')

exe = executable('prog', 'prog.cu')
test('cudatest', exe)

meson-0.53.2/test cases/cuda/1 simple/prog.cu0000644000175000017500000000244513602226377022215 0ustar  jpakkanejpakkane00000000000000#include 

int main(void) {
    int cuda_devices = 0;
    std::cout << "CUDA version: " << CUDART_VERSION << "\n";
    cudaGetDeviceCount(&cuda_devices);
    if(cuda_devices == 0) {
        std::cout << "No Cuda hardware found. Exiting.\n";
        return 0;
    }
    std::cout << "This computer has " << cuda_devices << " Cuda device(s).\n";
    cudaDeviceProp props;
    cudaGetDeviceProperties(&props, 0);
    std::cout << "Properties of device 0.\n\n";

    std::cout << "  Name:            " << props.name << "\n";
    std::cout << "  Global memory:   " << props.totalGlobalMem << "\n";
    std::cout << "  Shared memory:   " << props.sharedMemPerBlock << "\n";
    std::cout << "  Constant memory: " << props.totalConstMem << "\n";
    std::cout << "  Block registers: " << props.regsPerBlock << "\n";

    std::cout << "  Warp size:         " << props.warpSize << "\n";
    std::cout << "  Threads per block: " << props.maxThreadsPerBlock << "\n";
    std::cout << "  Max block dimensions: [ " << props.maxThreadsDim[0] << ", " << props.maxThreadsDim[1]  << ", " << props.maxThreadsDim[2] << " ]" << "\n";
    std::cout << "  Max grid dimensions:  [ " << props.maxGridSize[0] << ", " << props.maxGridSize[1]  << ", " << props.maxGridSize[2] << " ]" << "\n";
    std::cout << "\n";

    return 0;
}

meson-0.53.2/test cases/cuda/10 cuda dependency/0000755000175000017500000000000013625242370022506 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/10 cuda dependency/c/0000755000175000017500000000000013625242370022730 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/10 cuda dependency/c/meson.build0000644000175000017500000000013313571777336025106 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.c', dependencies: dependency('cuda'))
test('cudatest', exe)
meson-0.53.2/test cases/cuda/10 cuda dependency/c/prog.c0000644000175000017500000000053313602226377024050 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}

int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        printf("No CUDA hardware found. Exiting.\n");
        return 0;
    }

    printf("Found %i CUDA devices.\n", n);
    return 0;
}
meson-0.53.2/test cases/cuda/10 cuda dependency/cpp/0000755000175000017500000000000013625242370023270 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/10 cuda dependency/cpp/meson.build0000644000175000017500000000013413571777336025447 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.cc', dependencies: dependency('cuda'))
test('cudatest', exe)
meson-0.53.2/test cases/cuda/10 cuda dependency/cpp/prog.cc0000644000175000017500000000055413571777336024571 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}

int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No CUDA hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << " CUDA devices.\n";
    return 0;
}
meson-0.53.2/test cases/cuda/10 cuda dependency/meson.build0000644000175000017500000000015313571777336024666 0ustar  jpakkanejpakkane00000000000000project('cuda dependency', 'c', 'cpp')

subdir('c')
subdir('cpp')
subdir('modules')
subdir('version_reqs')
meson-0.53.2/test cases/cuda/10 cuda dependency/modules/0000755000175000017500000000000013625242370024156 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/10 cuda dependency/modules/meson.build0000644000175000017500000000016113571777336026335 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.cc', dependencies: dependency('cuda', modules: ['cublas']))
test('cudatest', exe)
meson-0.53.2/test cases/cuda/10 cuda dependency/modules/prog.cc0000644000175000017500000000136513571777336025460 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}

int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No CUDA hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << " CUDA devices.\n";

    cublasHandle_t handle;
    if (cublasCreate(&handle) != CUBLAS_STATUS_SUCCESS) {
        std::cout << "cuBLAS initialization failed. Exiting.\n";
        return -1;
    }

    std::cout << "Initialized cuBLAS\n";
    if (cublasDestroy(handle) != CUBLAS_STATUS_SUCCESS) {
        std::cout << "cuBLAS de-initialization failed. Exiting.\n";
        return -1;
    }

    return 0;
}
meson-0.53.2/test cases/cuda/10 cuda dependency/version_reqs/0000755000175000017500000000000013625242370025225 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/10 cuda dependency/version_reqs/meson.build0000644000175000017500000000023013571777336027401 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.cc', dependencies: dependency('cuda', version: ['>=8.5', '<10'], required: false, disabler: true))
test('cudatest', exe)
meson-0.53.2/test cases/cuda/10 cuda dependency/version_reqs/prog.cc0000644000175000017500000000135513571777336026526 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}

int main(void) {
    std::cout << "Compiled against CUDA version: " << CUDART_VERSION << "\n";
    int runtime_version = 0;
    cudaError_t r = cudaRuntimeGetVersion(&runtime_version);
    if (r != cudaSuccess) {
        std::cout << "Couldn't obtain CUDA runtime version (error " << r << "). Exiting.\n";
        return -1;
    }
    std::cout << "CUDA runtime version: " << runtime_version << "\n";

    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No CUDA hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << " CUDA devices.\n";
    return 0;
}
meson-0.53.2/test cases/cuda/11 cuda dependency (nvcc)/0000755000175000017500000000000013625242370023542 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/11 cuda dependency (nvcc)/meson.build0000644000175000017500000000011513571777336025720 0ustar  jpakkanejpakkane00000000000000project('cuda dependency', 'cuda')

subdir('modules')
subdir('version_reqs')
meson-0.53.2/test cases/cuda/11 cuda dependency (nvcc)/modules/0000755000175000017500000000000013625242370025212 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/11 cuda dependency (nvcc)/modules/meson.build0000644000175000017500000000016113571777336027371 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.cu', dependencies: dependency('cuda', modules: ['cublas']))
test('cudatest', exe)
meson-0.53.2/test cases/cuda/11 cuda dependency (nvcc)/modules/prog.cu0000644000175000017500000000136513602226377026523 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}

int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No CUDA hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << " CUDA devices.\n";

    cublasHandle_t handle;
    if (cublasCreate(&handle) != CUBLAS_STATUS_SUCCESS) {
        std::cout << "cuBLAS initialization failed. Exiting.\n";
        return -1;
    }

    std::cout << "Initialized cuBLAS\n";
    if (cublasDestroy(handle) != CUBLAS_STATUS_SUCCESS) {
        std::cout << "cuBLAS de-initialization failed. Exiting.\n";
        return -1;
    }

    return 0;
}
meson-0.53.2/test cases/cuda/11 cuda dependency (nvcc)/version_reqs/0000755000175000017500000000000013625242370026261 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/11 cuda dependency (nvcc)/version_reqs/meson.build0000644000175000017500000000022213571777336030436 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.cu', dependencies: dependency('cuda', version: ['>=10.1'], required: false, disabler: true))
test('cudatest', exe)
meson-0.53.2/test cases/cuda/11 cuda dependency (nvcc)/version_reqs/prog.cu0000644000175000017500000000147113625260317027565 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}

int main(void) {
    std::cout << "Compiled against CUDA version: " << CUDART_VERSION << "\n";

    int runtime_version = 0;
    switch (cudaError_t r = cudaRuntimeGetVersion(&runtime_version)) {
        case cudaSuccess:
            std::cout << "CUDA runtime version: " << runtime_version << "\n";
            break;
        case cudaErrorNoDevice:
            std::cout << "No CUDA hardware found. Exiting.\n";
            return 0;
        default:
            std::cout << "Couldn't obtain CUDA runtime version (error " << r << "). Exiting.\n";
            return -1;
    }

    int n = cuda_devices();
    std::cout << "Found " << n << " CUDA devices.\n";
    return 0;
}
meson-0.53.2/test cases/cuda/12 cuda dependency (mixed)/0000755000175000017500000000000013625242370023720 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/12 cuda dependency (mixed)/kernel.cu0000644000175000017500000000015713602226377025540 0ustar  jpakkanejpakkane00000000000000#include 

__global__ void kernel (void){
}

void do_cuda_stuff(void) {
  kernel<<<1,1>>>();
}
meson-0.53.2/test cases/cuda/12 cuda dependency (mixed)/meson.build0000644000175000017500000000025213571777336026100 0ustar  jpakkanejpakkane00000000000000project('cuda dependency', 'cpp', 'cuda')

exe = executable('prog', 'prog.cpp', 'kernel.cu', dependencies: dependency('cuda', modules: ['cublas']))
test('cudatest', exe)
meson-0.53.2/test cases/cuda/12 cuda dependency (mixed)/prog.cpp0000644000175000017500000000144613602226377025404 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include 

void do_cuda_stuff(void);

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}

int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No CUDA hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << " CUDA devices.\n";

    do_cuda_stuff();

    cublasHandle_t handle;
    if (cublasCreate(&handle) != CUBLAS_STATUS_SUCCESS) {
        std::cout << "cuBLAS initialization failed. Exiting.\n";
        return -1;
    }

    std::cout << "Initialized cuBLAS\n";
    if (cublasDestroy(handle) != CUBLAS_STATUS_SUCCESS) {
        std::cout << "cuBLAS de-initialization failed. Exiting.\n";
        return -1;
    }

    return 0;
}
meson-0.53.2/test cases/cuda/2 split/0000755000175000017500000000000013625242370020547 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/2 split/lib.cu0000644000175000017500000000024613602226377021654 0ustar  jpakkanejpakkane00000000000000#include 
#include 

__global__ void kernel (void){
}

int do_cuda_stuff(void) {
  kernel<<<1,1>>>();

  printf("Hello, World!\n");
  return 0;
}

meson-0.53.2/test cases/cuda/2 split/main.cpp0000644000175000017500000000013313602226377022200 0ustar  jpakkanejpakkane00000000000000#include

int do_cuda_stuff(void);

int main(void) {
  return do_cuda_stuff();
}
meson-0.53.2/test cases/cuda/2 split/meson.build0000644000175000017500000000017213426772647022727 0ustar  jpakkanejpakkane00000000000000project('simple', 'cuda', 'cpp')

exe = executable('prog', 'main.cpp', 'lib.cu')
test('cudatest', exe)

subdir('static')

meson-0.53.2/test cases/cuda/2 split/static/0000755000175000017500000000000013625242370022036 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/2 split/static/lib.cu0000644000175000017500000000024213426772647023151 0ustar  jpakkanejpakkane00000000000000#include 
#include 

__global__ void kernel (void){
}

int do_cuda_stuff() {
  kernel<<<1,1>>>();

  printf("Hello, World!\n");
  return 0;
}

meson-0.53.2/test cases/cuda/2 split/static/libsta.cu0000644000175000017500000000024213426772647023661 0ustar  jpakkanejpakkane00000000000000#include 
#include 

__global__ void kernel (void){
}

int do_cuda_stuff() {
  kernel<<<1,1>>>();

  printf("Hello, World!\n");
  return 0;
}

meson-0.53.2/test cases/cuda/2 split/static/main_static.cpp0000644000175000017500000000013313602226377025036 0ustar  jpakkanejpakkane00000000000000#include

int do_cuda_stuff(void);

int main(void) {
  return do_cuda_stuff();
}
meson-0.53.2/test cases/cuda/2 split/static/meson.build0000644000175000017500000000020213426772647024210 0ustar  jpakkanejpakkane00000000000000l = static_library('clib', 'lib.cu')
exe = executable('staexe', 'main_static.cpp',
  link_with : l)
test('static Cuda test', exe)
meson-0.53.2/test cases/cuda/3 cudamodule/0000755000175000017500000000000013625242370021537 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/3 cudamodule/meson.build0000644000175000017500000000111413426772653023711 0ustar  jpakkanejpakkane00000000000000project('cudamodule', 'cuda', version : '1.0.0')

nvcc = meson.get_compiler('cuda')
cuda = import('unstable-cuda')

arch_flags     = cuda.nvcc_arch_flags(nvcc, 'Auto', detected: ['3.0'])
arch_readable  = cuda.nvcc_arch_readable(nvcc, 'Auto', detected: ['3.0'])
driver_version = cuda.min_driver_version(nvcc)

message('NVCC version:   ' + nvcc.version())
message('NVCC flags:     ' + ' '.join(arch_flags))
message('NVCC readable:  ' + ' '.join(arch_readable))
message('Driver version: >=' + driver_version)

exe = executable('prog', 'prog.cu', cuda_args: arch_flags)
test('cudatest', exe)
meson-0.53.2/test cases/cuda/3 cudamodule/prog.cu0000644000175000017500000000244513602226377023050 0ustar  jpakkanejpakkane00000000000000#include 

int main(void) {
    int cuda_devices = 0;
    std::cout << "CUDA version: " << CUDART_VERSION << "\n";
    cudaGetDeviceCount(&cuda_devices);
    if(cuda_devices == 0) {
        std::cout << "No Cuda hardware found. Exiting.\n";
        return 0;
    }
    std::cout << "This computer has " << cuda_devices << " Cuda device(s).\n";
    cudaDeviceProp props;
    cudaGetDeviceProperties(&props, 0);
    std::cout << "Properties of device 0.\n\n";

    std::cout << "  Name:            " << props.name << "\n";
    std::cout << "  Global memory:   " << props.totalGlobalMem << "\n";
    std::cout << "  Shared memory:   " << props.sharedMemPerBlock << "\n";
    std::cout << "  Constant memory: " << props.totalConstMem << "\n";
    std::cout << "  Block registers: " << props.regsPerBlock << "\n";

    std::cout << "  Warp size:         " << props.warpSize << "\n";
    std::cout << "  Threads per block: " << props.maxThreadsPerBlock << "\n";
    std::cout << "  Max block dimensions: [ " << props.maxThreadsDim[0] << ", " << props.maxThreadsDim[1]  << ", " << props.maxThreadsDim[2] << " ]" << "\n";
    std::cout << "  Max grid dimensions:  [ " << props.maxGridSize[0] << ", " << props.maxGridSize[1]  << ", " << props.maxGridSize[2] << " ]" << "\n";
    std::cout << "\n";

    return 0;
}

meson-0.53.2/test cases/cuda/4 shared/0000755000175000017500000000000013625242370020664 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/4 shared/main.cu0000644000175000017500000000057413602226377022153 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "shared/kernels.h"


int main(void) {
    int cuda_devices = 0;
    cudaGetDeviceCount(&cuda_devices);
    if(cuda_devices == 0) {
        printf("No Cuda hardware found. Exiting.\n");
        return 0;
    }

    if(run_tests() != 0){
        printf("CUDA tests failed! Exiting.\n");
        return 0;
    }

    return 0;
}
meson-0.53.2/test cases/cuda/4 shared/meson.build0000644000175000017500000000022413436043746023032 0ustar  jpakkanejpakkane00000000000000project('simple', 'cuda', version : '1.0.0')

subdir('shared')

exe = executable('prog', 'main.cu', dependencies: libkernels)
test('cudatest', exe)
meson-0.53.2/test cases/cuda/4 shared/shared/0000755000175000017500000000000013625242370022132 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/4 shared/shared/kernels.cu0000644000175000017500000000032213436043746024131 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "kernels.h"


TAG_HIDDEN __global__ void kernel (void){
}

TAG_PUBLIC int run_tests(void) {
  kernel<<<1,1>>>();

  return (int)cudaDeviceSynchronize();
}

meson-0.53.2/test cases/cuda/4 shared/shared/kernels.h0000644000175000017500000000423213436043746023755 0ustar  jpakkanejpakkane00000000000000/* Include Guard */
#ifndef SHARED_KERNELS_H
#define SHARED_KERNELS_H

/**
 * Includes
 */

#include 


/**
 * Defines
 */

/**
 * When building a library, it is a good idea to expose as few as possible
 * internal symbols (functions, objects, data structures). Not only does it
 * prevent users from relying on private portions of the library that are
 * subject to change without any notice, but it can have performance
 * advantages:
 *
 *   - It can make shared libraries link faster at dynamic-load time.
 *   - It can make internal function calls faster by bypassing the PLT.
 *
 * Thus, the compilation should by default hide all symbols, while the API
 * headers will explicitly mark public the few symbols the users are permitted
 * to use with a PUBLIC tag. We also define a HIDDEN tag, since it may be
 * required to explicitly tag certain C++ types as visible in order for
 * exceptions to function correctly.
 *
 * Additional complexity comes from non-POSIX-compliant systems, which
 * artificially impose a requirement on knowing whether we are building or
 * using a DLL.
 *
 * The above commentary and below code is inspired from
 *                   'https://gcc.gnu.org/wiki/Visibility'
 */

#if   defined(_WIN32) || defined(__CYGWIN__)
# define TAG_ATTRIBUTE_EXPORT __declspec(dllexport)
# define TAG_ATTRIBUTE_IMPORT __declspec(dllimport)
# define TAG_ATTRIBUTE_HIDDEN
#elif __GNUC__ >= 4
# define TAG_ATTRIBUTE_EXPORT __attribute__((visibility("default")))
# define TAG_ATTRIBUTE_IMPORT __attribute__((visibility("default")))
# define TAG_ATTRIBUTE_HIDDEN __attribute__((visibility("hidden")))
#else
# define TAG_ATTRIBUTE_EXPORT
# define TAG_ATTRIBUTE_IMPORT
# define TAG_ATTRIBUTE_HIDDEN
#endif

#if TAG_IS_SHARED
# if TAG_IS_BUILDING
#  define TAG_PUBLIC TAG_ATTRIBUTE_EXPORT
# else
#  define TAG_PUBLIC TAG_ATTRIBUTE_IMPORT
# endif
# define  TAG_HIDDEN TAG_ATTRIBUTE_HIDDEN
#else
# define  TAG_PUBLIC
# define  TAG_HIDDEN
#endif
#define   TAG_STATIC static




/* Extern "C" Guard */
#ifdef __cplusplus
extern "C" {
#endif



/* Function Prototypes */
TAG_PUBLIC int run_tests(void);



/* End Extern "C" and Include Guard */
#ifdef __cplusplus
}
#endif
#endif
meson-0.53.2/test cases/cuda/4 shared/shared/meson.build0000644000175000017500000000050613436043746024303 0ustar  jpakkanejpakkane00000000000000libkernels = shared_library('kernels', 'kernels.cu',
                            cuda_args: ['-DTAG_IS_SHARED=1', '-DTAG_IS_BUILDING=1'],
                            gnu_symbol_visibility: 'hidden')
libkernels = declare_dependency(compile_args: ['-DTAG_IS_SHARED=1'],
                                link_with:    libkernels)
meson-0.53.2/test cases/cuda/5 threads/0000755000175000017500000000000013625242370021051 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/5 threads/main.cu0000644000175000017500000000057413602226377022340 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "shared/kernels.h"


int main(void) {
    int cuda_devices = 0;
    cudaGetDeviceCount(&cuda_devices);
    if(cuda_devices == 0) {
        printf("No Cuda hardware found. Exiting.\n");
        return 0;
    }

    if(run_tests() != 0){
        printf("CUDA tests failed! Exiting.\n");
        return 0;
    }

    return 0;
}
meson-0.53.2/test cases/cuda/5 threads/meson.build0000644000175000017500000000030513436043746023217 0ustar  jpakkanejpakkane00000000000000project('simple', 'cuda', version : '1.0.0')

subdir('shared')

thread_dep = dependency('threads')
exe = executable('prog', 'main.cu', dependencies: [libkernels, thread_dep])
test('cudatest', exe)
meson-0.53.2/test cases/cuda/5 threads/shared/0000755000175000017500000000000013625242370022317 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/5 threads/shared/kernels.cu0000644000175000017500000000032213436043746024316 0ustar  jpakkanejpakkane00000000000000#include 
#include 
#include "kernels.h"


TAG_HIDDEN __global__ void kernel (void){
}

TAG_PUBLIC int run_tests(void) {
  kernel<<<1,1>>>();

  return (int)cudaDeviceSynchronize();
}

meson-0.53.2/test cases/cuda/5 threads/shared/kernels.h0000644000175000017500000000423213436043746024142 0ustar  jpakkanejpakkane00000000000000/* Include Guard */
#ifndef SHARED_KERNELS_H
#define SHARED_KERNELS_H

/**
 * Includes
 */

#include 


/**
 * Defines
 */

/**
 * When building a library, it is a good idea to expose as few as possible
 * internal symbols (functions, objects, data structures). Not only does it
 * prevent users from relying on private portions of the library that are
 * subject to change without any notice, but it can have performance
 * advantages:
 *
 *   - It can make shared libraries link faster at dynamic-load time.
 *   - It can make internal function calls faster by bypassing the PLT.
 *
 * Thus, the compilation should by default hide all symbols, while the API
 * headers will explicitly mark public the few symbols the users are permitted
 * to use with a PUBLIC tag. We also define a HIDDEN tag, since it may be
 * required to explicitly tag certain C++ types as visible in order for
 * exceptions to function correctly.
 *
 * Additional complexity comes from non-POSIX-compliant systems, which
 * artificially impose a requirement on knowing whether we are building or
 * using a DLL.
 *
 * The above commentary and below code is inspired from
 *                   'https://gcc.gnu.org/wiki/Visibility'
 */

#if   defined(_WIN32) || defined(__CYGWIN__)
# define TAG_ATTRIBUTE_EXPORT __declspec(dllexport)
# define TAG_ATTRIBUTE_IMPORT __declspec(dllimport)
# define TAG_ATTRIBUTE_HIDDEN
#elif __GNUC__ >= 4
# define TAG_ATTRIBUTE_EXPORT __attribute__((visibility("default")))
# define TAG_ATTRIBUTE_IMPORT __attribute__((visibility("default")))
# define TAG_ATTRIBUTE_HIDDEN __attribute__((visibility("hidden")))
#else
# define TAG_ATTRIBUTE_EXPORT
# define TAG_ATTRIBUTE_IMPORT
# define TAG_ATTRIBUTE_HIDDEN
#endif

#if TAG_IS_SHARED
# if TAG_IS_BUILDING
#  define TAG_PUBLIC TAG_ATTRIBUTE_EXPORT
# else
#  define TAG_PUBLIC TAG_ATTRIBUTE_IMPORT
# endif
# define  TAG_HIDDEN TAG_ATTRIBUTE_HIDDEN
#else
# define  TAG_PUBLIC
# define  TAG_HIDDEN
#endif
#define   TAG_STATIC static




/* Extern "C" Guard */
#ifdef __cplusplus
extern "C" {
#endif



/* Function Prototypes */
TAG_PUBLIC int run_tests(void);



/* End Extern "C" and Include Guard */
#ifdef __cplusplus
}
#endif
#endif
meson-0.53.2/test cases/cuda/5 threads/shared/meson.build0000644000175000017500000000050613436043746024470 0ustar  jpakkanejpakkane00000000000000libkernels = shared_library('kernels', 'kernels.cu',
                            cuda_args: ['-DTAG_IS_SHARED=1', '-DTAG_IS_BUILDING=1'],
                            gnu_symbol_visibility: 'hidden')
libkernels = declare_dependency(compile_args: ['-DTAG_IS_SHARED=1'],
                                link_with:    libkernels)
meson-0.53.2/test cases/cuda/6 std/0000755000175000017500000000000013625242370020212 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/6 std/main.cu0000644000175000017500000000055513602226377021500 0ustar  jpakkanejpakkane00000000000000#include 
#include 

auto cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}


int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No Cuda hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << "Cuda devices.\n";
    return 0;
}
meson-0.53.2/test cases/cuda/6 std/meson.build0000644000175000017500000000021713543771101022352 0ustar  jpakkanejpakkane00000000000000project('C++ std', 'cuda', version : '1.0.0', default_options : ['cuda_std=c++14'])

exe = executable('prog', 'main.cu')
test('cudatest', exe)
meson-0.53.2/test cases/cuda/7 static vs runtime/0000755000175000017500000000000013625242370022765 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/7 static vs runtime/main.cu0000644000175000017500000000055413602226377024252 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}


int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No Cuda hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << "Cuda devices.\n";
    return 0;
}
meson-0.53.2/test cases/cuda/7 static vs runtime/meson.build0000644000175000017500000000023013543771101025120 0ustar  jpakkanejpakkane00000000000000project('static msvc runtime', 'cuda', version : '1.0.0', default_options : ['b_vscrt=mtd'])

exe = executable('prog', 'main.cu')
test('cudatest', exe)
meson-0.53.2/test cases/cuda/8 release/0000755000175000017500000000000013625242370021042 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/8 release/main.cu0000644000175000017500000000055413602226377022327 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}


int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No Cuda hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << "Cuda devices.\n";
    return 0;
}
meson-0.53.2/test cases/cuda/8 release/meson.build0000644000175000017500000000022213543771101023176 0ustar  jpakkanejpakkane00000000000000project('release', 'cuda', version : '1.0.0', default_options : ['buildtype=release'])

exe = executable('prog', 'main.cu')
test('cudatest', exe)
meson-0.53.2/test cases/cuda/9 optimize for space/0000755000175000017500000000000013625242370023106 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/cuda/9 optimize for space/main.cu0000644000175000017500000000055413602226377024373 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int cuda_devices(void) {
    int result = 0;
    cudaGetDeviceCount(&result);
    return result;
}


int main(void) {
    int n = cuda_devices();
    if (n == 0) {
        std::cout << "No Cuda hardware found. Exiting.\n";
        return 0;
    }

    std::cout << "Found " << n << "Cuda devices.\n";
    return 0;
}
meson-0.53.2/test cases/cuda/9 optimize for space/meson.build0000644000175000017500000000023213543771101025243 0ustar  jpakkanejpakkane00000000000000project('optimize for space', 'cuda', version : '1.0.0', default_options : ['optimization=s'])

exe = executable('prog', 'main.cu')
test('cudatest', exe)
meson-0.53.2/test cases/d/0000755000175000017500000000000013625242351016600 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/1 simple/0000755000175000017500000000000013625242370020213 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/1 simple/app.d0000644000175000017500000000013112756306660021142 0ustar  jpakkanejpakkane00000000000000
import std.stdio;
import utils;

void main ()
{
    printGreeting ("a Meson D test");
}
meson-0.53.2/test cases/d/1 simple/installed_files.txt0000644000175000017500000000002712756306660024123 0ustar  jpakkanejpakkane00000000000000usr/bin/dsimpleapp?exe
meson-0.53.2/test cases/d/1 simple/meson.build0000644000175000017500000000016513605172072022356 0ustar  jpakkanejpakkane00000000000000project('D Simple Test', 'd')

e = executable('dsimpleapp', ['app.d', 'utils.d'], install : true)
test('apptest', e)
meson-0.53.2/test cases/d/1 simple/utils.d0000644000175000017500000000020412756306660021523 0ustar  jpakkanejpakkane00000000000000
import std.stdio;
import std.string : format;

void printGreeting (string name)
{
    writeln ("Hello, I am %s.".format (name));
}
meson-0.53.2/test cases/d/10 d cpp/0000755000175000017500000000000013625242370017770 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/10 d cpp/cppmain.cpp0000644000175000017500000000054613366273150022132 0ustar  jpakkanejpakkane00000000000000extern "C" int rt_init();
extern "C" int rt_term();
extern void print_hello(int i);

int main(int, char**) {
    // initialize D runtime
    if (!rt_init())
        return 1;
    
    print_hello(1);
    
    // terminate D runtime, each initialize call
    // must be paired with a terminate call.
    if (!rt_term())
        return 1;
    
    return 0;
}
meson-0.53.2/test cases/d/10 d cpp/dmain.d0000644000175000017500000000011313340206727021220 0ustar  jpakkanejpakkane00000000000000extern (C++) void print_hello(int i);

void main() {
    print_hello(1);
}
meson-0.53.2/test cases/d/10 d cpp/libfile.cpp0000644000175000017500000000017513340206727022105 0ustar  jpakkanejpakkane00000000000000#include

void print_hello(int i) {
    std::cout << "Hello. Here is a number printed with C++: " << i << ".\n";
}
meson-0.53.2/test cases/d/10 d cpp/libfile.d0000644000175000017500000000017313351440011021530 0ustar  jpakkanejpakkane00000000000000import std.stdio;

extern (C++) void print_hello(int i) {
    writefln("Hello. Here is a number printed with D: %d", i);
}
meson-0.53.2/test cases/d/10 d cpp/meson.build0000644000175000017500000000050313605172107022126 0ustar  jpakkanejpakkane00000000000000project('d and c++', 'd', 'cpp')

cpp = meson.get_compiler('cpp')

if cpp.get_id() == 'clang'
  error('MESON_SKIP_TEST combining Clang C++ with GDC produces broken executables.')
endif

e1 = executable('dcpp', 'dmain.d', 'libfile.cpp')
test('dcpp', e1)

e2 = executable('cppd', 'cppmain.cpp', 'libfile.d')
test('cppd', e2)
meson-0.53.2/test cases/d/11 dub/0000755000175000017500000000000013625242370017555 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/11 dub/meson.build0000644000175000017500000000144613366273150021726 0ustar  jpakkanejpakkane00000000000000project('dub-example', 'd')

dub_exe = find_program('dub', required : false)
if not dub_exe.found()
  error('MESON_SKIP_TEST: Dub not found')
endif

urld_dep = dependency('urld', method: 'dub')

test_exe = executable('test-urld', 'test.d', dependencies: urld_dep)
test('test urld', test_exe)

# If you want meson to generate/update a dub.json file
dlang = import('dlang')
dlang.generate_dub_file(meson.project_name().to_lower(), meson.source_root(),
                        authors: 'Meson Team',
                        description: 'Test executable',
                        copyright: 'Copyright Ā© 2018, Meson Team',
                        license: 'MIT',
                        sourceFiles: 'test.d',
                        targetType: 'executable',
                        dependencies: urld_dep
)meson-0.53.2/test cases/d/11 dub/test.d0000644000175000017500000000041313366273150020701 0ustar  jpakkanejpakkane00000000000000import std.stdio;
import url;

void main() {
    URL url;
    with (url) {
        scheme = "soap.beep";
        host = "beep.example.net";
        port = 1772;
        path = "/serverinfo/info";
    queryParams.add("token", "my-api-token");
    }
    writeln(url);
}meson-0.53.2/test cases/d/2 static library/0000755000175000017500000000000013625242370021637 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/2 static library/app.d0000644000175000017500000000015312756306660022572 0ustar  jpakkanejpakkane00000000000000
import libstuff;

void main ()
{
    immutable ret = printLibraryString ("foo");
    assert (ret == 4);
}
meson-0.53.2/test cases/d/2 static library/installed_files.txt0000644000175000017500000000004512756306660025547 0ustar  jpakkanejpakkane00000000000000usr/bin/app_s?exe
usr/lib/libstuff.a
meson-0.53.2/test cases/d/2 static library/libstuff.d0000644000175000017500000000023412756306660023630 0ustar  jpakkanejpakkane00000000000000
import std.stdio;
import std.string : format;

int printLibraryString (string str)
{
    writeln ("Static Library says: %s".format (str));
    return 4;
}
meson-0.53.2/test cases/d/2 static library/meson.build0000644000175000017500000000030513605172072023776 0ustar  jpakkanejpakkane00000000000000project('D Static Library', 'd')

lstatic = static_library('stuff', 'libstuff.d', install : true)
es = executable('app_s', 'app.d', link_with : lstatic, install : true)
test('linktest_static', es)
meson-0.53.2/test cases/d/3 shared library/0000755000175000017500000000000013625242371021620 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/3 shared library/app.d0000644000175000017500000000015312756306660022552 0ustar  jpakkanejpakkane00000000000000
import libstuff;

void main ()
{
    immutable ret = printLibraryString ("foo");
    assert (ret == 4);
}
meson-0.53.2/test cases/d/3 shared library/installed_files.txt0000644000175000017500000000016513366273215025527 0ustar  jpakkanejpakkane00000000000000usr/bin/app_d?exe
?msvc:usr/bin/stuff.dll
?msvc:usr/lib/stuff.lib
?gcc:usr/lib/libstuff.so
usr/lib/pkgconfig/test.pc
meson-0.53.2/test cases/d/3 shared library/libstuff.d0000644000175000017500000000035413366273150023606 0ustar  jpakkanejpakkane00000000000000import std.stdio;
import std.string : format;

export int printLibraryString (string str)
{
    writeln ("Library says: %s".format (str));
    return 4;
}

version (Windows)
{
    import core.sys.windows.dll;
    mixin SimpleDllMain;
}
meson-0.53.2/test cases/d/3 shared library/libstuff.di0000644000175000017500000000006713366273150023760 0ustar  jpakkanejpakkane00000000000000module libstuff;

int printLibraryString (string str);
meson-0.53.2/test cases/d/3 shared library/meson.build0000644000175000017500000000117213605172072023761 0ustar  jpakkanejpakkane00000000000000project('D Shared Library', 'd')

dc = meson.get_compiler('d')
if dc.get_id() == 'gcc'
  if dc.version().version_compare('< 8')
    error('MESON_SKIP_TEST: GDC < 8.0 can not build shared libraries')
  endif
endif

ldyn = shared_library('stuff', 'libstuff.d', install : true)
ed = executable('app_d', 'app.d', link_with : ldyn, install : true)
test('linktest_dyn', ed)

# test D attributes for pkg-config
pkgc = import('pkgconfig')
pkgc.generate(name: 'test',
          libraries: ldyn,
          subdirs: 'd/stuff',
          description: 'A test of D attributes to pkgconfig.generate.',
          d_module_versions: ['Use_Static']
)
meson-0.53.2/test cases/d/4 library versions/0000755000175000017500000000000013625242371022223 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/4 library versions/installed_files.txt0000644000175000017500000000077613366273150026140 0ustar  jpakkanejpakkane00000000000000?gcc:usr/lib/libsome.so
?gcc:usr/lib/libsome.so.0
?gcc:usr/lib/libsome.so.1.2.3
?gcc:usr/lib/libnoversion.so
?gcc:usr/lib/libonlyversion.so
?gcc:usr/lib/libonlyversion.so.1
?gcc:usr/lib/libonlyversion.so.1.4.5
?gcc:usr/lib/libonlysoversion.so
?gcc:usr/lib/libonlysoversion.so.5
?msvc:usr/bin/noversion.dll
?msvc:usr/bin/onlysoversion-5.dll
?msvc:usr/bin/onlyversion-1.dll
?msvc:usr/bin/some-0.dll
?msvc:usr/lib/noversion.lib
?msvc:usr/lib/onlysoversion.lib
?msvc:usr/lib/onlyversion.lib
?msvc:usr/lib/some.lib
meson-0.53.2/test cases/d/4 library versions/lib.d0000644000175000017500000000036313366273150023141 0ustar  jpakkanejpakkane00000000000000
import std.stdio;
import std.string : format;

@safe
export int printLibraryString (string str)
{
    writeln ("Library says: %s".format (str));
    return 4;
}

version (Windows)
{
    import core.sys.windows.dll;
    mixin SimpleDllMain;
}
meson-0.53.2/test cases/d/4 library versions/meson.build0000644000175000017500000000106513605172074024367 0ustar  jpakkanejpakkane00000000000000project('D library versions', 'd')

dc = meson.get_compiler('d')
if dc.get_id() == 'gcc'
  if dc.version().version_compare('< 8')
    error('MESON_SKIP_TEST: GDC < 8.0 can not build shared libraries')
  endif
endif

shared_library('some', 'lib.d',
  version : '1.2.3',
  soversion : '0',
  install : true)

shared_library('noversion', 'lib.d',
  install : true)

shared_library('onlyversion', 'lib.d',
  version : '1.4.5',
  install : true)

shared_library('onlysoversion', 'lib.d',
  # Also test that int soversion is acceptable
  soversion : 5,
  install : true)
meson-0.53.2/test cases/d/5 mixed/0000755000175000017500000000000013625242371020035 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/5 mixed/app.d0000644000175000017500000000021712756306660020770 0ustar  jpakkanejpakkane00000000000000
extern(C) int printLibraryString(const char *str);

void main ()
{
    immutable ret = printLibraryString ("C foo");
    assert (ret == 3);
}
meson-0.53.2/test cases/d/5 mixed/installed_files.txt0000644000175000017500000000023413571777336023754 0ustar  jpakkanejpakkane00000000000000usr/bin/appdc_d?exe
usr/bin/appdc_s?exe
usr/lib/libstuff.a
?gcc:usr/lib/libstuff.so
?msvc:usr/bin/stuff.dll
?msvc:usr/bin/stuff.pdb
?msvc:usr/lib/stuff.lib
meson-0.53.2/test cases/d/5 mixed/libstuff.c0000644000175000017500000000064512756306660022032 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

#include 

int DLL_PUBLIC printLibraryString(const char *str)
{
    printf("C library says: %s", str);
    return 3;
}
meson-0.53.2/test cases/d/5 mixed/meson.build0000644000175000017500000000055113605172077022203 0ustar  jpakkanejpakkane00000000000000project('Mixing C and D', 'd', 'c')

ldyn = shared_library('stuff', 'libstuff.c', install : true)
ed = executable('appdc_d', 'app.d', link_with : ldyn, install : true)
test('linktest_cdyn', ed)

lstatic = static_library('stuff', 'libstuff.c', install : true)
es = executable('appdc_s', 'app.d', link_with : lstatic, install : true)
test('linktest_cstatic', es)
meson-0.53.2/test cases/d/6 unittest/0000755000175000017500000000000013625242371020607 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/6 unittest/app.d0000644000175000017500000000130213340206727021527 0ustar  jpakkanejpakkane00000000000000
import std.stdio;

uint getFour ()
{
    auto getTwo ()
    {
        return 1 + 1;
    }

    return getTwo () + getTwo ();
}

void main ()
{
    import core.stdc.stdlib : exit;

    writeln ("Four: ", getFour ());
    exit (4);
}

unittest
{
    writeln ("TEST");
    import core.stdc.stdlib : exit;
    import second_unit;

    assert (getFour () > 2);
    assert (getFour () == 4);

    // this is a regression test for https://github.com/mesonbuild/meson/issues/3337
    secondModuleTestFunc ();

    // we explicitly terminate here to give the unittest program a different exit
    // code than the main application has.
    // (this prevents the regular main() from being executed)
    exit (0);
}
meson-0.53.2/test cases/d/6 unittest/installed_files.txt0000644000175000017500000000002112756306660024510 0ustar  jpakkanejpakkane00000000000000usr/bin/dapp?exe
meson-0.53.2/test cases/d/6 unittest/meson.build0000644000175000017500000000036513605172077022760 0ustar  jpakkanejpakkane00000000000000project('D Unittests', 'd')

e = executable('dapp', ['app.d', 'second_unit.d'], install : true)
test('dapp_run', e, should_fail: true)

e_test = executable('dapp_test', ['app.d', 'second_unit.d'],
    d_unittest: true)
test('dapp_test', e_test)
meson-0.53.2/test cases/d/6 unittest/second_unit.d0000644000175000017500000000022313340206727023262 0ustar  jpakkanejpakkane00000000000000
void secondModuleTestFunc ()
{
    import std.stdio : writeln;

    version (unittest)
        writeln ("Hello!");
    else
        assert (0);
}
meson-0.53.2/test cases/d/7 multilib/0000755000175000017500000000000013625242371020552 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/7 multilib/app.d0000644000175000017500000000017513076164167021510 0ustar  jpakkanejpakkane00000000000000
import say1;
import say2;

void main ()
{
    assert (sayHello1 ("Dave") == 4);
    assert (sayHello2 ("HAL 9000") == 8);
}
meson-0.53.2/test cases/d/7 multilib/installed_files.txt0000644000175000017500000000042213366273150024453 0ustar  jpakkanejpakkane00000000000000usr/bin/app_d?exe
?gcc:usr/lib/libsay1.so
?gcc:usr/lib/libsay1.so.0
?gcc:usr/lib/libsay1.so.1.2.3
?gcc:usr/lib/libsay2.so
?gcc:usr/lib/libsay2.so.1
?gcc:usr/lib/libsay2.so.1.2.4
?msvc:usr/bin/say1-0.dll
?msvc:usr/bin/say2-1.dll
?msvc:usr/lib/say1.lib
?msvc:usr/lib/say2.lib
meson-0.53.2/test cases/d/7 multilib/meson.build0000644000175000017500000000105513605172103022706 0ustar  jpakkanejpakkane00000000000000project('D Multiple Versioned Shared Libraries', 'd')

dc = meson.get_compiler('d')
if dc.get_id() == 'gcc'
  if dc.version().version_compare('< 8')
    error('MESON_SKIP_TEST: GDC < 8.0 can not build shared libraries')
  endif
endif

ldyn1 = shared_library('say1',
    'say1.d',
    install: true,
    version : '1.2.3',
    soversion : '0'
)
ldyn2 = shared_library('say2',
    'say2.d',
    install: true,
    version : '1.2.4',
    soversion : '1'
)

ed = executable('app_d', 'app.d', link_with: [ldyn1, ldyn2], install: true)
test('multilink_test', ed)
meson-0.53.2/test cases/d/7 multilib/say1.d0000644000175000017500000000035413366273150021577 0ustar  jpakkanejpakkane00000000000000
import std.stdio;
import std.string : format;

export int sayHello1 (string str)
{
    writeln ("Hello %s from library 1.".format (str));
    return 4;
}

version (Windows)
{
    import core.sys.windows.dll;
    mixin SimpleDllMain;
}
meson-0.53.2/test cases/d/7 multilib/say1.di0000644000175000017500000000003413366273150021743 0ustar  jpakkanejpakkane00000000000000int sayHello1 (string str);
meson-0.53.2/test cases/d/7 multilib/say2.d0000644000175000017500000000035413366273150021600 0ustar  jpakkanejpakkane00000000000000
import std.stdio;
import std.string : format;

export int sayHello2 (string str)
{
    writeln ("Hello %s from library 2.".format (str));
    return 8;
}

version (Windows)
{
    import core.sys.windows.dll;
    mixin SimpleDllMain;
}
meson-0.53.2/test cases/d/7 multilib/say2.di0000644000175000017500000000003413366273150021744 0ustar  jpakkanejpakkane00000000000000int sayHello2 (string str);
meson-0.53.2/test cases/d/8 has multi arguments/0000755000175000017500000000000013625242371022606 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/8 has multi arguments/meson.build0000644000175000017500000000101113605172101024730 0ustar  jpakkanejpakkane00000000000000project('D has arguments test', 'd')

compiler = meson.get_compiler('d')

assert(compiler.compiles('int i;'), 'Basic code test does not compile: ' + compiler.get_id())
assert(compiler.has_multi_arguments(['-I.', '-J.']), 'Multi argument test does not work: ' + compiler.get_id())
assert(compiler.has_argument('-I.'), 'Basic argument test does not work: ' + compiler.get_id())
assert(compiler.has_argument('-flag_a_d_compiler_definitely_does_not_have') == false, 'Basic argument test does not work: ' + compiler.get_id())
meson-0.53.2/test cases/d/9 features/0000755000175000017500000000000013625242371020551 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/9 features/app.d0000644000175000017500000000325213403223104021463 0ustar  jpakkanejpakkane00000000000000
import std.stdio;
import std.array : split;
import std.string : strip;

import extra;

auto getMenu ()
{
    auto foods = import ("food.txt").strip.split ("\n");
    return foods;
}

auto getPeople ()
{
    return import ("people.txt").strip.split ("\n");
}

void main (string[] args)
{
    import std.array : join;
    import core.stdc.stdlib : exit;

    immutable request = args[1];
    if (request == "menu") {
        version (No_Menu) {
        } else {
            writeln ("On the menu: ", getMenu.join (", "));
            exit (0);
        }
    }

    version (With_People) {
        if (request == "people") {
            writeln ("People: ", getPeople.join (", "));

            // only exit successfully if the second module also had its module version set.
            // this checks for issue https://github.com/mesonbuild/meson/issues/3337
            if (secondModulePeopleVersionSet ())
                exit (0);
            exit (1);
        }
    }
    
    version (With_VersionInteger)
        version(3) exit(0);

    version (With_Debug)
        debug exit(0);
    
    version (With_DebugInteger)
        debug(3) exit(0);
    
    version (With_DebugIdentifier)
        debug(DebugIdentifier) exit(0);
    
    version (With_DebugAll) {
        int dbg = 0;
        debug dbg++;
        debug(2) dbg++;
        debug(3) dbg++;
        debug(4) dbg++;
        debug(DebugIdentifier) dbg++;
        
        if (dbg == 5)
            exit(0);
    }

    // we fail here
    exit (1);
}

unittest
{
    writeln ("TEST");
    import core.stdc.stdlib : exit;

    writeln(getMenu);
    assert (getMenu () == ["Spam", "Eggs", "Spam", "Baked Beans", "Spam", "Spam"]);

    exit (0);
}
meson-0.53.2/test cases/d/9 features/data/0000755000175000017500000000000013625242371021462 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/d/9 features/data/food.txt0000644000175000017500000000004513340206727023150 0ustar  jpakkanejpakkane00000000000000Spam
Eggs
Spam
Baked Beans
Spam
Spam
meson-0.53.2/test cases/d/9 features/data/people.txt0000644000175000017500000000003513340206727023504 0ustar  jpakkanejpakkane00000000000000Rick
Morty
Summer
Beth
Jerry
meson-0.53.2/test cases/d/9 features/extra.d0000644000175000017500000000020413340206727022034 0ustar  jpakkanejpakkane00000000000000
auto secondModulePeopleVersionSet ()
{
    version (With_People) {
        return true;
    } else {
        return false;
    }
}
meson-0.53.2/test cases/d/9 features/meson.build0000644000175000017500000000605513605172114022714 0ustar  jpakkanejpakkane00000000000000project('D Features', 'd', default_options : ['debug=false'])

# ONLY FOR BACKWARDS COMPATIBILITY.
# DO NOT DO THIS IN NEW CODE!
# USE include_directories() INSTEAD OF BUILDING
# STRINGS TO PATHS MANUALLY!
data_dir = join_paths(meson.current_source_dir(), 'data')

test_src = ['app.d', 'extra.d']

e_plain_bcompat = executable('dapp_menu_bcompat',
    test_src,
    d_import_dirs: [data_dir]
)
test('dapp_menu_t_fail_bcompat', e_plain_bcompat, should_fail: true)
test('dapp_menu_t_bcompat', e_plain_bcompat, args: ['menu'])

# directory for data
# This is the correct way to do this.
data_dir = include_directories('data')

e_plain = executable('dapp_menu',
    test_src,
    d_import_dirs: [data_dir]
)
test('dapp_menu_t_fail', e_plain, should_fail: true)
test('dapp_menu_t', e_plain, args: ['menu'])


# test feature versions and string imports
e_versions = executable('dapp_versions',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['No_Menu', 'With_People']
)
test('dapp_versions_t_fail', e_versions, args: ['menu'], should_fail: true)
test('dapp_versions_t', e_versions, args: ['people'])

# test everything and unittests
e_test = executable('dapp_test',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['No_Menu', 'With_People'],
    d_unittest: true
)
test('dapp_test', e_test)

# test version level
e_version_int = executable('dapp_version_int',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['With_VersionInteger', 3],
)
test('dapp_version_int_t', e_version_int, args: ['debug'])

# test version level failure
e_version_int_fail = executable('dapp_version_int_fail',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['With_VersionInteger', 2],
)
test('dapp_version_int_t_fail', e_version_int_fail, args: ['debug'], should_fail: true)

# test debug conditions: disabled
e_no_debug = executable('dapp_no_debug',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['With_Debug'],
)
test('dapp_no_debug_t_fail', e_no_debug, args: ['debug'], should_fail: true)

# test debug conditions: enabled
e_debug = executable('dapp_debug',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['With_Debug'],
    d_debug: 1,
)
test('dapp_debug_t', e_debug, args: ['debug'])

# test debug conditions: integer
e_debug_int = executable('dapp_debug_int',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['With_DebugInteger'],
    d_debug: 3,
)
test('dapp_debug_int_t', e_debug_int, args: ['debug'])

# test debug conditions: identifier
e_debug_ident = executable('dapp_debug_ident',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['With_DebugIdentifier'],
    d_debug: 'DebugIdentifier',
)
test('dapp_debug_ident_t', e_debug_ident, args: ['debug'])

# test with all debug conditions at once, and with redundant values
e_debug_all = executable('dapp_debug_all',
    test_src,
    d_import_dirs: [data_dir],
    d_module_versions: ['With_DebugAll'],
    d_debug: ['4', 'DebugIdentifier', 2, 'DebugIdentifierUnused'],
)
test('dapp_debug_all_t', e_debug_all, args: ['debug'])
meson-0.53.2/test cases/failing/0000755000175000017500000000000013625242352017767 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/1 project not first/0000755000175000017500000000000013625242371023450 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/1 project not first/meson.build0000644000175000017500000000016112650745767025626 0ustar  jpakkanejpakkane00000000000000var = 'assignment before project() call'
project('no worky', 'c')

test('not run', executable('prog', 'prog.c'))
meson-0.53.2/test cases/failing/1 project not first/prog.c0000644000175000017500000000005612650745767024602 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; }
meson-0.53.2/test cases/failing/10 out of bounds/0000755000175000017500000000000013625242371022640 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/10 out of bounds/meson.build0000644000175000017500000000005712650745767025022 0ustar  jpakkanejpakkane00000000000000project('out of bounds', 'c')

x = []
y = x[0]
meson-0.53.2/test cases/failing/11 object arithmetic/0000755000175000017500000000000013625242371023552 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/11 object arithmetic/meson.build0000644000175000017500000000006512650745767025733 0ustar  jpakkanejpakkane00000000000000project('object arithmetic', 'c')

foo = '5' + meson
meson-0.53.2/test cases/failing/12 string arithmetic/0000755000175000017500000000000013625242371023613 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/12 string arithmetic/meson.build0000644000175000017500000000006112650745767025770 0ustar  jpakkanejpakkane00000000000000project('string arithmetic', 'c')

foo = 'a' + 3
meson-0.53.2/test cases/failing/13 array arithmetic/0000755000175000017500000000000013625242371023424 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/13 array arithmetic/meson.build0000644000175000017500000000006712650745767025607 0ustar  jpakkanejpakkane00000000000000project('array arithmetic', 'c')

foo = ['a', 'b'] * 3
meson-0.53.2/test cases/failing/14 invalid option name/0000755000175000017500000000000013625242371024015 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/14 invalid option name/meson.build0000644000175000017500000000002412650745767026171 0ustar  jpakkanejpakkane00000000000000project('foo', 'c')
meson-0.53.2/test cases/failing/14 invalid option name/meson_options.txt0000644000175000017500000000007013074426732027452 0ustar  jpakkanejpakkane00000000000000option('invalid:name', type : 'boolean', value : false)
meson-0.53.2/test cases/failing/15 kwarg before arg/0000755000175000017500000000000013625242371023266 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/15 kwarg before arg/meson.build0000644000175000017500000000011112650745767025437 0ustar  jpakkanejpakkane00000000000000project('kwarg before arg', 'c')

executable(sources : 'prog.c', 'prog')
meson-0.53.2/test cases/failing/15 kwarg before arg/prog.c0000644000175000017500000000005612650745767024420 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; }
meson-0.53.2/test cases/failing/16 extract from subproject/0000755000175000017500000000000013625242371024736 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/16 extract from subproject/main.c0000644000175000017500000000012213571777336026037 0ustar  jpakkanejpakkane00000000000000int sub_lib_method(void);

int main(void) {
    return 1337 - sub_lib_method();
}
meson-0.53.2/test cases/failing/16 extract from subproject/meson.build0000644000175000017500000000033012650745767027112 0ustar  jpakkanejpakkane00000000000000project('extract subproject object', 'c')

sub = subproject('sub_project')
lib = sub.get_variable('lib')

exe = executable('exe', 'main.c',
  objects : lib.extract_objects('sub_lib.c'))

test('extraction test', exe)
meson-0.53.2/test cases/failing/16 extract from subproject/subprojects/0000755000175000017500000000000013625242351027277 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/16 extract from subproject/subprojects/sub_project/0000755000175000017500000000000013625242371031620 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/16 extract from subproject/subprojects/sub_project/meson.build0000644000175000017500000000014612650745767034001 0ustar  jpakkanejpakkane00000000000000project('extract subproject object -- subproject', 'c')

lib = shared_library('sub_lib', 'sub_lib.c')
meson-0.53.2/test cases/failing/16 extract from subproject/subprojects/sub_project/sub_lib.c0000644000175000017500000000005212650745767033416 0ustar  jpakkanejpakkane00000000000000int sub_lib_method() {
    return 1337;
}
meson-0.53.2/test cases/failing/17 same target/0000755000175000017500000000000013625242371022374 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/17 same target/file.c0000644000175000017500000000003113340206727023450 0ustar  jpakkanejpakkane00000000000000int func() { return 0; }
meson-0.53.2/test cases/failing/17 same target/meson.build0000644000175000017500000000013513340206727024534 0ustar  jpakkanejpakkane00000000000000project('same target', 'c')

static_library('foo', 'file.c')
static_library('foo', 'file.c')
meson-0.53.2/test cases/failing/18 wrong plusassign/0000755000175000017500000000000013625242371023506 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/18 wrong plusassign/meson.build0000644000175000017500000000005112650745767025662 0ustar  jpakkanejpakkane00000000000000project('false plusassign', 'c')

3 += 4
meson-0.53.2/test cases/failing/19 target clash/0000755000175000017500000000000013625242371022543 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/19 target clash/clash.c0000644000175000017500000000013712650745767024020 0ustar  jpakkanejpakkane00000000000000#include

int main(int argc, char **argv) {
    printf("Clash 2.\n");
    return 0;
}
meson-0.53.2/test cases/failing/19 target clash/meson.build0000644000175000017500000000075213074426732024714 0ustar  jpakkanejpakkane00000000000000project('clash', 'c')

# This setup causes a namespace clash when two Meson targets would
# produce a Ninja targets with the same name. It only works on
# unix, because on Windows the target has a '.exe' suffix.
#
# This test might fail to work on different backends or when
# output location is redirected.

if host_machine.system() == 'windows' or host_machine.system() == 'cygwin'
  error('This is expected.')
endif

executable('clash', 'clash.c')
run_target('clash', 'echo', 'clash 1')
meson-0.53.2/test cases/failing/2 missing file/0000755000175000017500000000000013625242371022463 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/2 missing file/meson.build0000644000175000017500000000007612650745767024646 0ustar  jpakkanejpakkane00000000000000project('missing file', 'c')

executable('prog', 'missing.c')
meson-0.53.2/test cases/failing/20 version/0000755000175000017500000000000013625242371021657 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/20 version/meson.build0000644000175000017500000000007512650745767024041 0ustar  jpakkanejpakkane00000000000000project('version mismatch', 'c', meson_version : '>100.0.0')
meson-0.53.2/test cases/failing/21 subver/0000755000175000017500000000000013625242371021501 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/21 subver/meson.build0000644000175000017500000000010212650745767023652 0ustar  jpakkanejpakkane00000000000000project('master', 'c')

x = subproject('foo', version : '>1.0.0')
meson-0.53.2/test cases/failing/21 subver/subprojects/0000755000175000017500000000000013625242351024042 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/21 subver/subprojects/foo/0000755000175000017500000000000013625242371024627 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/21 subver/subprojects/foo/meson.build0000644000175000017500000000004712650745767027010 0ustar  jpakkanejpakkane00000000000000project('foo', 'c', version : '1.0.0')
meson-0.53.2/test cases/failing/22 assert/0000755000175000017500000000000013625242371021475 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/22 assert/meson.build0000644000175000017500000000007412650745767023656 0ustar  jpakkanejpakkane00000000000000project('failing assert', 'c')

assert(false, 'I am fail.')
meson-0.53.2/test cases/failing/23 rel testdir/0000755000175000017500000000000013625242371022416 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/23 rel testdir/meson.build0000644000175000017500000000015212650745767024574 0ustar  jpakkanejpakkane00000000000000project('nonabs workdir', 'c')

exe = executable('simple', 'simple.c')
test('simple', exe, workdir : '.')
meson-0.53.2/test cases/failing/23 rel testdir/simple.c0000644000175000017500000000006212650745767024067 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) {
    return 0;
}
meson-0.53.2/test cases/failing/24 int conversion/0000755000175000017500000000000013625242371023136 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/24 int conversion/meson.build0000644000175000017500000000006613366273150025303 0ustar  jpakkanejpakkane00000000000000project('int conversion', 'c')

'notanumber'.to_int()
meson-0.53.2/test cases/failing/25 badlang/0000755000175000017500000000000013625242371021567 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/25 badlang/meson.build0000644000175000017500000000006613366273150023734 0ustar  jpakkanejpakkane00000000000000project('badlang', 'c')

add_languages('nonexisting')
meson-0.53.2/test cases/failing/26 output subdir/0000755000175000017500000000000013625242371023011 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/26 output subdir/foo.in0000644000175000017500000000001613366273150024122 0ustar  jpakkanejpakkane00000000000000Nothing here.
meson-0.53.2/test cases/failing/26 output subdir/meson.build0000644000175000017500000000014513366273150025154 0ustar  jpakkanejpakkane00000000000000project('outdir path', 'c')

configure_file(input : 'foo.in',
  output : 'subdir/foo',
  copy: true)
meson-0.53.2/test cases/failing/26 output subdir/subdir/0000755000175000017500000000000013625242371024301 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/26 output subdir/subdir/dummy.txt0000644000175000017500000000006713366273150026201 0ustar  jpakkanejpakkane00000000000000I'm only here because Git is stupid about empty dirs.

meson-0.53.2/test cases/failing/27 noprog use/0000755000175000017500000000000013625242371022262 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/27 noprog use/meson.build0000644000175000017500000000030713366273150024425 0ustar  jpakkanejpakkane00000000000000project('using not found exe', 'c')

nope = find_program('nonexisting', required : false)

custom_target( 'aa',
  input: 'meson.build',
  output: 'foobar',
  command: [nope, '@INPUT@', '@OUTPUT@']
)
meson-0.53.2/test cases/failing/28 no crossprop/0000755000175000017500000000000013625242371022631 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/28 no crossprop/meson.build0000644000175000017500000000011713366273150024773 0ustar  jpakkanejpakkane00000000000000project('no crossprop', 'c')

message(meson.get_cross_property('nonexisting'))
meson-0.53.2/test cases/failing/29 nested ternary/0000755000175000017500000000000013625242371023132 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/29 nested ternary/meson.build0000644000175000017500000000007713366273150025301 0ustar  jpakkanejpakkane00000000000000project('nested ternary', 'c')

x = true ? (false ? 1 : 0) : 2
meson-0.53.2/test cases/failing/3 missing subdir/0000755000175000017500000000000013625242371023035 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/3 missing subdir/meson.build0000644000175000017500000000005212650745767025212 0ustar  jpakkanejpakkane00000000000000project('subdir', 'c')

subdir('missing')
meson-0.53.2/test cases/failing/30 invalid man extension/0000755000175000017500000000000013625242371024352 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/30 invalid man extension/meson.build0000644000175000017500000000006713366273150026520 0ustar  jpakkanejpakkane00000000000000project('man install', 'c')
m1 = install_man('foo.a1')
meson-0.53.2/test cases/failing/31 no man extension/0000755000175000017500000000000013625242371023341 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/31 no man extension/meson.build0000644000175000017500000000006413366273150025504 0ustar  jpakkanejpakkane00000000000000project('man install', 'c')
m1 = install_man('foo')
meson-0.53.2/test cases/failing/32 exe static shared/0000755000175000017500000000000013625242371023455 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/32 exe static shared/meson.build0000644000175000017500000000055613366273150025626 0ustar  jpakkanejpakkane00000000000000project('statchain', 'c')

host_system = host_machine.system()
if host_system == 'windows' or host_system == 'darwin'
  error('Test only fails on Linux and BSD')
endif

statlib = static_library('stat', 'stat.c', pic : false)
shlib2 = shared_library('shr2', 'shlib2.c', link_with : statlib)
exe = executable('prog', 'prog.c', link_with : shlib2)
test('runtest', exe)
meson-0.53.2/test cases/failing/32 exe static shared/prog.c0000644000175000017500000000026513366273150024574 0ustar  jpakkanejpakkane00000000000000int shlibfunc2();
int statlibfunc();

int main(int argc, char **argv) {
    if (statlibfunc() != 42)
        return 1;
    if (shlibfunc2() != 24)
        return 1;
    return 0;
}
meson-0.53.2/test cases/failing/32 exe static shared/shlib2.c0000644000175000017500000000056013366273150025006 0ustar  jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

int statlibfunc(void);

int DLL_PUBLIC shlibfunc2(void) {
    return 24;
}
meson-0.53.2/test cases/failing/32 exe static shared/stat.c0000644000175000017500000000004513366273150024574 0ustar  jpakkanejpakkane00000000000000int statlibfunc() {
    return 42;
}
meson-0.53.2/test cases/failing/33 non-root subproject/0000755000175000017500000000000013625242371024112 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/33 non-root subproject/meson.build0000644000175000017500000000006413366273150026255 0ustar  jpakkanejpakkane00000000000000project('non-root subproject', 'c')

subdir('some')
meson-0.53.2/test cases/failing/33 non-root subproject/some/0000755000175000017500000000000013625242371025055 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/33 non-root subproject/some/meson.build0000644000175000017500000000011313366273150027213 0ustar  jpakkanejpakkane00000000000000dependency('definitely-doesnt-exist', fallback : ['someproj', 'some_dep'])
meson-0.53.2/test cases/failing/34 dependency not-required then required/0000755000175000017500000000000013625242371027434 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/34 dependency not-required then required/meson.build0000644000175000017500000000021713366273150031577 0ustar  jpakkanejpakkane00000000000000project('dep-test', 'c', version : '1.0')

foo_dep = dependency('foo-bar-xyz-12.3', required : false)
bar_dep = dependency('foo-bar-xyz-12.3')
meson-0.53.2/test cases/failing/35 project argument after target/0000755000175000017500000000000013625242371026002 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/35 project argument after target/exe.c0000644000175000017500000000006213366273150026726 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) {
    return 0;
}
meson-0.53.2/test cases/failing/35 project argument after target/meson.build0000644000175000017500000000036713366273150030153 0ustar  jpakkanejpakkane00000000000000project('project argument after target failing', 'c',
  version : '2.3.4',
  license : 'mylicense')

add_project_arguments('-DPROJECT_OPTION', language: 'c')
e = executable('exe', 'exe.c')
add_project_arguments('-DPROJECT_OPTION1', language: 'c')
meson-0.53.2/test cases/failing/36 pkgconfig dependency impossible conditions/0000755000175000017500000000000013625242371030530 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/36 pkgconfig dependency impossible conditions/meson.build0000644000175000017500000000014613366273150032674 0ustar  jpakkanejpakkane00000000000000project('impossible-dep-test', 'c', version : '1.0')

dependency('zlib', version : ['>=1.0', '<1.0'])
meson-0.53.2/test cases/failing/37 has function external dependency/0000755000175000017500000000000013625242371026465 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/37 has function external dependency/meson.build0000644000175000017500000000040013366273150030622 0ustar  jpakkanejpakkane00000000000000project('has function ext dep', 'c')

cc = meson.get_compiler('c')

mylib = shared_library('mylib', 'mylib.c')
mylib_dep = declare_dependency(link_with : mylib)
# Only external dependencies can work here
cc.has_function('malloc', dependencies : mylib_dep)
meson-0.53.2/test cases/failing/37 has function external dependency/mylib.c0000644000175000017500000000004113366273150027741 0ustar  jpakkanejpakkane00000000000000int testfunc(void) { return 0; }
meson-0.53.2/test cases/failing/38 libdir must be inside prefix/0000755000175000017500000000000013625242371025502 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/38 libdir must be inside prefix/meson.build0000644000175000017500000000010713366273150027643 0ustar  jpakkanejpakkane00000000000000project('libdir prefix', 'c',
  default_options : ['libdir=/opt/lib'])
meson-0.53.2/test cases/failing/39 prefix absolute/0000755000175000017500000000000013625242371023300 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/39 prefix absolute/meson.build0000644000175000017500000000011413366273150025437 0ustar  jpakkanejpakkane00000000000000project('prefix-abs', 'c',
  default_options : ['prefix=some/path/notabs'])
meson-0.53.2/test cases/failing/4 missing meson.build/0000755000175000017500000000000013625242371023765 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/4 missing meson.build/meson.build0000644000175000017500000000006612650745767026147 0ustar  jpakkanejpakkane00000000000000project('missing meson.build', 'c')

subdir('subdir')
meson-0.53.2/test cases/failing/4 missing meson.build/subdir/0000755000175000017500000000000013625242371025255 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/4 missing meson.build/subdir/dummy.txt0000644000175000017500000000007312650745767027167 0ustar  jpakkanejpakkane00000000000000This needs to be here because Git can't handle empty dirs.
meson-0.53.2/test cases/failing/40 kwarg assign/0000755000175000017500000000000013625242372022555 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/40 kwarg assign/dummy.c0000644000175000017500000000006413366273150024054 0ustar  jpakkanejpakkane00000000000000const char* dummy() {
    return "I do nothing.";
}
meson-0.53.2/test cases/failing/40 kwarg assign/meson.build0000644000175000017500000000012113366273150024711 0ustar  jpakkanejpakkane00000000000000project('assign in kwarg', 'c')

executable('prog', 'dummy.c', args = 'prog.c')

meson-0.53.2/test cases/failing/40 kwarg assign/prog.c0000644000175000017500000000006213366273150023666 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) {
    return 0;
}
meson-0.53.2/test cases/failing/41 custom target plainname many inputs/0000755000175000017500000000000013625242372027134 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/41 custom target plainname many inputs/1.txt0000644000175000017500000000000213366273150030025 0ustar  jpakkanejpakkane000000000000001
meson-0.53.2/test cases/failing/41 custom target plainname many inputs/2.txt0000644000175000017500000000000213366273150030026 0ustar  jpakkanejpakkane000000000000002
meson-0.53.2/test cases/failing/41 custom target plainname many inputs/catfiles.py0000644000175000017500000000027013366273150031277 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

out = sys.argv[-1]
with open(out, 'wb') as o:
    for infile in sys.argv[1:-1]:
        with open(infile, 'rb') as f:
            o.write(f.read())
meson-0.53.2/test cases/failing/41 custom target plainname many inputs/meson.build0000644000175000017500000000033513366273150031277 0ustar  jpakkanejpakkane00000000000000project('plain name many inputs', 'c')

catfiles = find_program('catfiles.py')

custom_target('plainname-inputs',
  input : ['1.txt', '2.txt'],
  output : '@PLAINNAME@.dat',
  command : [catfiles, '@INPUT@', '@OUTPUT@'])
meson-0.53.2/test cases/failing/42 custom target outputs not matching install_dirs/0000755000175000017500000000000013625242372031470 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/42 custom target outputs not matching install_dirs/generator.py0000755000175000017500000000066613366273150034043 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys, os

if len(sys.argv) != 3:
    print(sys.argv[0], '', '')

name = sys.argv[1]
odir = sys.argv[2]

with open(os.path.join(odir, name + '.h'), 'w') as f:
    f.write('int func();\n')
with open(os.path.join(odir, name + '.c'), 'w') as f:
    f.write('int main(int argc, char *argv[]) { return 0; }')
with open(os.path.join(odir, name + '.sh'), 'w') as f:
    f.write('#!/bin/bash')
././@LongLink0000000000000000000000000000014700000000000011217 Lustar  00000000000000meson-0.53.2/test cases/failing/42 custom target outputs not matching install_dirs/installed_files.txtmeson-0.53.2/test cases/failing/42 custom target outputs not matching install_dirs/installed_files.t0000644000175000017500000000014013366273150035011 0ustar  jpakkanejpakkane00000000000000usr/include/diff.h
usr/include/first.h
usr/bin/diff.sh
usr/bin/second.sh
opt/same.h
opt/same.sh
meson-0.53.2/test cases/failing/42 custom target outputs not matching install_dirs/meson.build0000644000175000017500000000064413366273150033636 0ustar  jpakkanejpakkane00000000000000project('outputs not matching install_dirs', 'c')

gen = find_program('generator.py')

if meson.backend() != 'ninja'
  error('Failing manually, test is only for the ninja backend')
endif

custom_target('too-few-install-dirs',
  output : ['toofew.h', 'toofew.c', 'toofew.sh'],
  command : [gen, 'toofew', '@OUTDIR@'],
  install : true,
  install_dir : [join_paths(get_option('prefix'), get_option('includedir')), false])
meson-0.53.2/test cases/failing/43 project name colon/0000755000175000017500000000000013625242372023642 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/43 project name colon/meson.build0000644000175000017500000000002713366273150026003 0ustar  jpakkanejpakkane00000000000000project('name with :')
meson-0.53.2/test cases/failing/44 abs subdir/0000755000175000017500000000000013625242372022217 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/44 abs subdir/bob/0000755000175000017500000000000013625242372022761 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/44 abs subdir/bob/meson.build0000644000175000017500000000004413366273150025121 0ustar  jpakkanejpakkane00000000000000# This file is never reached.
x = 3
meson-0.53.2/test cases/failing/44 abs subdir/meson.build0000644000175000017500000000027613366273150024366 0ustar  jpakkanejpakkane00000000000000project('abs subdir', 'c')

# For some reason people insist on doing this, probably
# because Make has taught them to never rely on anything.
subdir(join_paths(meson.source_root(), 'bob'))

meson-0.53.2/test cases/failing/45 abspath to srcdir/0000755000175000017500000000000013625242372023476 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/45 abspath to srcdir/meson.build0000644000175000017500000000010713366273150025636 0ustar  jpakkanejpakkane00000000000000project('meson', 'c')

include_directories(meson.current_source_dir())
meson-0.53.2/test cases/failing/46 pkgconfig variables reserved/0000755000175000017500000000000013625242372025703 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/46 pkgconfig variables reserved/meson.build0000644000175000017500000000057213366273150030051 0ustar  jpakkanejpakkane00000000000000project('variables-reserved-test', 'c', version : '1.0')

pkgg = import('pkgconfig')
lib = shared_library('simple', 'simple.c')
libver = '1.0'
h = install_headers('simple.h')

pkgg.generate(
  libraries : [lib, '-lz'],
  subdirs : '.',
  version : libver,
  name : 'libsimple',
  filebase : 'simple',
  description : 'A simple demo library.',
  variables : [ 'prefix=/tmp/' ]
)
meson-0.53.2/test cases/failing/46 pkgconfig variables reserved/simple.c0000644000175000017500000000007513366273150027342 0ustar  jpakkanejpakkane00000000000000#include"simple.h"

int simple_function() {
    return 42;
}
meson-0.53.2/test cases/failing/46 pkgconfig variables reserved/simple.h0000644000175000017500000000010413366273150027340 0ustar  jpakkanejpakkane00000000000000#ifndef SIMPLE_H_
#define SIMPLE_H_

int simple_function();

#endif
meson-0.53.2/test cases/failing/47 pkgconfig variables zero length/0000755000175000017500000000000013625242372026306 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/47 pkgconfig variables zero length/meson.build0000644000175000017500000000056713366273150030460 0ustar  jpakkanejpakkane00000000000000project('variables-zero-length-test', 'c', version : '1.0')

pkgg = import('pkgconfig')
lib = shared_library('simple', 'simple.c')
libver = '1.0'
h = install_headers('simple.h')

pkgg.generate(
  libraries : [lib, '-lz'],
  subdirs : '.',
  version : libver,
  name : 'libsimple',
  filebase : 'simple',
  description : 'A simple demo library.',
  variables : [ '=value' ]
)
meson-0.53.2/test cases/failing/47 pkgconfig variables zero length/simple.c0000644000175000017500000000007513366273150027745 0ustar  jpakkanejpakkane00000000000000#include"simple.h"

int simple_function() {
    return 42;
}
meson-0.53.2/test cases/failing/47 pkgconfig variables zero length/simple.h0000644000175000017500000000010413366273150027743 0ustar  jpakkanejpakkane00000000000000#ifndef SIMPLE_H_
#define SIMPLE_H_

int simple_function();

#endif
meson-0.53.2/test cases/failing/48 pkgconfig variables zero length value/0000755000175000017500000000000013625242372027404 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/48 pkgconfig variables zero length value/meson.build0000644000175000017500000000057313366273150031553 0ustar  jpakkanejpakkane00000000000000project('variables-zero-length-value-test', 'c', version : '1.0')

pkgg = import('pkgconfig')
lib = shared_library('simple', 'simple.c')
libver = '1.0'
h = install_headers('simple.h')

pkgg.generate(
  libraries : [lib, '-lz'],
  subdirs : '.',
  version : libver,
  name : 'libsimple',
  filebase : 'simple',
  description : 'A simple demo library.',
  variables : [ 'key=' ]
)
meson-0.53.2/test cases/failing/48 pkgconfig variables zero length value/simple.c0000644000175000017500000000007513366273150031043 0ustar  jpakkanejpakkane00000000000000#include"simple.h"

int simple_function() {
    return 42;
}
meson-0.53.2/test cases/failing/48 pkgconfig variables zero length value/simple.h0000644000175000017500000000010413366273150031041 0ustar  jpakkanejpakkane00000000000000#ifndef SIMPLE_H_
#define SIMPLE_H_

int simple_function();

#endif
meson-0.53.2/test cases/failing/49 pkgconfig variables not key value/0000755000175000017500000000000013625242372026535 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/49 pkgconfig variables not key value/meson.build0000644000175000017500000000061313366273150030677 0ustar  jpakkanejpakkane00000000000000project('variables-not-key-value-test', 'c', version : '1.0')

pkgg = import('pkgconfig')
lib = shared_library('simple', 'simple.c')
libver = '1.0'
h = install_headers('simple.h')

pkgg.generate(
  libraries : [lib, '-lz'],
  subdirs : '.',
  version : libver,
  name : 'libsimple',
  filebase : 'simple',
  description : 'A simple demo library.',
  variables : [ 'this_should_be_key_value' ]
)
meson-0.53.2/test cases/failing/49 pkgconfig variables not key value/simple.c0000644000175000017500000000007513366273150030174 0ustar  jpakkanejpakkane00000000000000#include"simple.h"

int simple_function() {
    return 42;
}
meson-0.53.2/test cases/failing/49 pkgconfig variables not key value/simple.h0000644000175000017500000000010413366273150030172 0ustar  jpakkanejpakkane00000000000000#ifndef SIMPLE_H_
#define SIMPLE_H_

int simple_function();

#endif
meson-0.53.2/test cases/failing/5 misplaced option/0000755000175000017500000000000013625242372023350 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/5 misplaced option/meson.build0000644000175000017500000000010312650745767025521 0ustar  jpakkanejpakkane00000000000000project('misplaced option', 'c')

option('dummy', type : 'string')
meson-0.53.2/test cases/failing/50 executable comparison/0000755000175000017500000000000013625242372024452 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/50 executable comparison/meson.build0000644000175000017500000000025113366273150026612 0ustar  jpakkanejpakkane00000000000000project('executable comparison', 'c')

exe1 = executable('prog1', sources : 'prog.c')
exe2 = executable('prog2', sources : 'prog.c')

assert(exe1 < exe2, 'should fail')
meson-0.53.2/test cases/failing/50 executable comparison/prog.c0000644000175000017500000000005613366273150025566 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; }
meson-0.53.2/test cases/failing/51 inconsistent comparison/0000755000175000017500000000000013625242372025052 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/51 inconsistent comparison/meson.build0000644000175000017500000000035313366273150027215 0ustar  jpakkanejpakkane00000000000000project('kwarg before arg', 'c')

# All of these should fail, though only the first one will error out if
# everything's working correctly.
assert([] < 'st', 'should fail')
assert([] < 1, 'should fail')
assert(2 < 'st', 'should fail')
meson-0.53.2/test cases/failing/52 slashname/0000755000175000017500000000000013625242372022153 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/52 slashname/meson.build0000644000175000017500000000050313366273150024313 0ustar  jpakkanejpakkane00000000000000project('slashname', 'c')

# Traverse this subdir so the corresponding dir
# is created inside the build dir.
subdir('sub')

# Try to create an executable that would go in the "sub" dir
# inside the build dir. This is prohibited.
executable('sub/prog', pf)

error('Re-enable me once slash in name is finally prohibited.')

meson-0.53.2/test cases/failing/52 slashname/sub/0000755000175000017500000000000013625242372022744 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/52 slashname/sub/meson.build0000644000175000017500000000002613366273150025104 0ustar  jpakkanejpakkane00000000000000pf = files('prog.c')

meson-0.53.2/test cases/failing/52 slashname/sub/prog.c0000644000175000017500000000016013366273150024054 0ustar  jpakkanejpakkane00000000000000#include

int main(int argc, char **argv) {
    printf("I should not be run ever.\n");
    return 1;
}
meson-0.53.2/test cases/failing/53 reserved meson prefix/0000755000175000017500000000000013625242372024400 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/53 reserved meson prefix/meson-foo/0000755000175000017500000000000013625242372026302 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/53 reserved meson prefix/meson-foo/meson.build0000644000175000017500000000000013366273150030432 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/53 reserved meson prefix/meson.build0000644000175000017500000000004513366273150026541 0ustar  jpakkanejpakkane00000000000000project('test')

subdir('meson-foo')
meson-0.53.2/test cases/failing/54 wrong shared crate type/0000755000175000017500000000000013625242372024606 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/54 wrong shared crate type/foo.rs0000644000175000017500000000000013366273150025725 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/54 wrong shared crate type/meson.build0000644000175000017500000000013113366273150026743 0ustar  jpakkanejpakkane00000000000000project('test', 'rust')

shared_library('test', 'foo.rs', rust_crate_type : 'staticlib')
meson-0.53.2/test cases/failing/55 wrong static crate type/0000755000175000017500000000000013625242372024630 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/55 wrong static crate type/foo.rs0000644000175000017500000000000013366273150025747 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/55 wrong static crate type/meson.build0000644000175000017500000000012613366273150026771 0ustar  jpakkanejpakkane00000000000000project('test', 'rust')

static_library('test', 'foo.rs', rust_crate_type : 'cdylib')
meson-0.53.2/test cases/failing/56 or on new line/0000755000175000017500000000000013625242372022703 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/56 or on new line/meson.build0000644000175000017500000000033413366273150025045 0ustar  jpakkanejpakkane00000000000000project('silent_or', 'c')

if get_option('foo') == 'true'
        or get_option('foo') == 'auto'
else
        message('If this message is printed then something is wrong. The or above should give a syntax error.')
endif
meson-0.53.2/test cases/failing/56 or on new line/meson_options.txt0000644000175000017500000000012013366273150026331 0ustar  jpakkanejpakkane00000000000000option('foo', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto')
meson-0.53.2/test cases/failing/57 kwarg in module/0000755000175000017500000000000013625242372023155 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/57 kwarg in module/meson.build0000644000175000017500000000015413366273150025317 0ustar  jpakkanejpakkane00000000000000project('module test', 'c')

modtest = import('modtest', i_cause: 'a_build_failure')
modtest.print_hello()

meson-0.53.2/test cases/failing/58 link with executable/0000755000175000017500000000000013625242372024201 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/58 link with executable/meson.build0000644000175000017500000000016613366273150026346 0ustar  jpakkanejpakkane00000000000000project('link with exe', 'c')

e = executable('prog', 'prog.c')
m = shared_module('module', 'module.c', link_with: e)
meson-0.53.2/test cases/failing/58 link with executable/module.c0000644000175000017500000000004213366273150025626 0ustar  jpakkanejpakkane00000000000000
int func(void) {
   return 42;
}
meson-0.53.2/test cases/failing/58 link with executable/prog.c0000644000175000017500000000006113366273150025311 0ustar  jpakkanejpakkane00000000000000int
main (int argc, char **argv)
{
  return 0;
}
meson-0.53.2/test cases/failing/59 assign custom target index/0000755000175000017500000000000013625242372025325 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/59 assign custom target index/meson.build0000644000175000017500000000151413366273150027470 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

prog_python = import('python3').find_python()

target = custom_target(
  'target',
  output : ['1', '2'],
  command : [prog_python, '-c',
             'with open("1", "w") as f: f.write("foo"); with open("2", "w") as f: f.write("foo")'],
)

target[0] = 'foo'
meson-0.53.2/test cases/failing/6 missing incdir/0000755000175000017500000000000013625242372023021 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/6 missing incdir/meson.build0000644000175000017500000000010712650745767025176 0ustar  jpakkanejpakkane00000000000000project('missing incdir', 'c')

inc = include_directories('nosuchdir')
meson-0.53.2/test cases/failing/60 getoption prefix/0000755000175000017500000000000013625242372023465 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/60 getoption prefix/meson.build0000644000175000017500000000010313366273150025621 0ustar  jpakkanejpakkane00000000000000project('getopt prefix')

subproject('abc')

get_option('abc:foo')
meson-0.53.2/test cases/failing/60 getoption prefix/subprojects/0000755000175000017500000000000013625242351026025 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/60 getoption prefix/subprojects/abc/0000755000175000017500000000000013625242372026555 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/60 getoption prefix/subprojects/abc/meson.build0000644000175000017500000000002413366273150030713 0ustar  jpakkanejpakkane00000000000000project('abc', 'c')
meson-0.53.2/test cases/failing/60 getoption prefix/subprojects/abc/meson_options.txt0000644000175000017500000000004013366273150032204 0ustar  jpakkanejpakkane00000000000000option('foo', type : 'boolean')
meson-0.53.2/test cases/failing/61 bad option argument/0000755000175000017500000000000013625242372024022 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/61 bad option argument/meson.build0000644000175000017500000000005213366273150026161 0ustar  jpakkanejpakkane00000000000000project('bad option')

get_option('name')
meson-0.53.2/test cases/failing/61 bad option argument/meson_options.txt0000644000175000017500000000005713366273150027461 0ustar  jpakkanejpakkane00000000000000option('name', type : 'string', vaule : 'foo')
meson-0.53.2/test cases/failing/62 subproj filegrab/0000755000175000017500000000000013625242372023421 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/62 subproj filegrab/meson.build0000644000175000017500000000012713366273150025563 0ustar  jpakkanejpakkane00000000000000project('mainproj', 'c')

# Try to grab a file from a parent project.

subproject('a')
meson-0.53.2/test cases/failing/62 subproj filegrab/prog.c0000644000175000017500000000005613366273150024535 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; }
meson-0.53.2/test cases/failing/62 subproj filegrab/subprojects/0000755000175000017500000000000013625242352025762 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/62 subproj filegrab/subprojects/a/0000755000175000017500000000000013625242372026204 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/62 subproj filegrab/subprojects/a/meson.build0000644000175000017500000000006613366273150030350 0ustar  jpakkanejpakkane00000000000000project('a', 'c')

executable('prog', '../../prog.c')
meson-0.53.2/test cases/failing/63 grab subproj/0000755000175000017500000000000013625242372022562 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/63 grab subproj/meson.build0000644000175000017500000000020613366273150024722 0ustar  jpakkanejpakkane00000000000000project('grabber', 'c')

# Try to grab a file from a child subproject.

subproject('foo')

executable('foo', 'subprojects/foo/sub.c')
meson-0.53.2/test cases/failing/63 grab subproj/subprojects/0000755000175000017500000000000013625242352025123 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/63 grab subproj/subprojects/foo/0000755000175000017500000000000013625242372025710 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/63 grab subproj/subprojects/foo/meson.build0000644000175000017500000000005613366273150030053 0ustar  jpakkanejpakkane00000000000000project('foo', 'c')

message('I do nothing.')
meson-0.53.2/test cases/failing/63 grab subproj/subprojects/foo/sub.c0000644000175000017500000000017113366273150026644 0ustar  jpakkanejpakkane00000000000000#include

int main(int argc, char **argv) {
    printf("I am a subproject executable file.\n");
    return 0;
}
meson-0.53.2/test cases/failing/64 grab sibling/0000755000175000017500000000000013625242372022526 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/64 grab sibling/meson.build0000644000175000017500000000005013366273150024663 0ustar  jpakkanejpakkane00000000000000project('master', 'c')

subproject('a')
meson-0.53.2/test cases/failing/64 grab sibling/subprojects/0000755000175000017500000000000013625242352025067 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/64 grab sibling/subprojects/a/0000755000175000017500000000000013625242372025311 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/64 grab sibling/subprojects/a/meson.build0000644000175000017500000000007113366273150027451 0ustar  jpakkanejpakkane00000000000000project('a', 'c')

executable('sneaky', '../b/sneaky.c')
meson-0.53.2/test cases/failing/64 grab sibling/subprojects/b/0000755000175000017500000000000013625242372025312 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/64 grab sibling/subprojects/b/meson.build0000644000175000017500000000005413366273150027453 0ustar  jpakkanejpakkane00000000000000projecT('b', 'c')

message('I do nothing.')
meson-0.53.2/test cases/failing/64 grab sibling/subprojects/b/sneaky.c0000644000175000017500000000020313366273150026743 0ustar  jpakkanejpakkane00000000000000#include

int main(int argc, char **argv) {
    printf("I can only come into existence via trickery.\n");
    return 0;
}
meson-0.53.2/test cases/failing/65 string as link target/0000755000175000017500000000000013625242372024263 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/65 string as link target/meson.build0000644000175000017500000000013213366273150026421 0ustar  jpakkanejpakkane00000000000000project('string as link argument', 'c')
executable('myprog', 'prog.c', link_with: [ '' ])
meson-0.53.2/test cases/failing/65 string as link target/prog.c0000644000175000017500000000005613366273150025377 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; }
meson-0.53.2/test cases/failing/66 dependency not-found and required/0000755000175000017500000000000013625242372026541 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/66 dependency not-found and required/meson.build0000644000175000017500000000007013366273150030700 0ustar  jpakkanejpakkane00000000000000project('dep-test')
dep = dependency('', required:true)
meson-0.53.2/test cases/failing/67 subproj different versions/0000755000175000017500000000000013625242372025452 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/67 subproj different versions/main.c0000644000175000017500000000024013366273150026536 0ustar  jpakkanejpakkane00000000000000#include 
#include "a.h"
#include "b.h"

int main(int argc, char **argv) {
    int life = a_fun() + b_fun();
    printf("%d\n", life);
    return 0;
}
meson-0.53.2/test cases/failing/67 subproj different versions/meson.build0000644000175000017500000000042313366273150027613 0ustar  jpakkanejpakkane00000000000000project('super', 'c')

# A will use version 1 of C
a_dep = dependency('a', fallback: ['a', 'a_dep'])

# B will fail because it requests version 2 of C
b_dep = dependency('b', fallback: ['b', 'b_dep'])

main = executable('main', files('main.c'), dependencies: [a_dep, b_dep])
meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/0000755000175000017500000000000013625242352030013 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/a/0000755000175000017500000000000013625242372030235 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/a/a.c0000644000175000017500000000006413366273150030621 0ustar  jpakkanejpakkane00000000000000#include "c.h"

int a_fun() {
    return c_fun();
}
meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/a/a.h0000644000175000017500000000001513366273150030622 0ustar  jpakkanejpakkane00000000000000int a_fun();
meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/a/meson.build0000644000175000017500000000035013366273150032375 0ustar  jpakkanejpakkane00000000000000project('a', 'c')

c_dep = dependency('c', version:'1', fallback: ['c', 'c_dep'])

alib = library('a', 'a.c',
  dependencies: c_dep)

a_dep = declare_dependency(
  link_with: alib,
  include_directories: include_directories('.'),
)
meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/b/0000755000175000017500000000000013625242372030236 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/b/b.c0000644000175000017500000000005713366273150030625 0ustar  jpakkanejpakkane00000000000000#include "c.h"

int b_fun(){
return c_fun();
}
meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/b/b.h0000644000175000017500000000001513366273150030624 0ustar  jpakkanejpakkane00000000000000int b_fun();
meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/b/meson.build0000644000175000017500000000035013366273150032376 0ustar  jpakkanejpakkane00000000000000project('b', 'c')

c_dep = dependency('c', version:'2', fallback: ['c', 'c_dep'])

blib = library('b', 'b.c',
  dependencies: c_dep)

b_dep = declare_dependency(
  link_with: blib,
  include_directories: include_directories('.'),
)
meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/c/0000755000175000017500000000000013625242372030237 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/c/c.h0000644000175000017500000000004413366273150030630 0ustar  jpakkanejpakkane00000000000000static int c_fun(){
    return 3;
}
meson-0.53.2/test cases/failing/67 subproj different versions/subprojects/c/meson.build0000644000175000017500000000015613366273150032403 0ustar  jpakkanejpakkane00000000000000project('c', 'c', version:'1')

c_dep = declare_dependency(
  include_directories: include_directories('.')
)
meson-0.53.2/test cases/failing/68 wrong boost module/0000755000175000017500000000000013625242372023720 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/68 wrong boost module/meson.build0000644000175000017500000000024513366273150026063 0ustar  jpakkanejpakkane00000000000000project('boosttest', 'cpp',
  default_options : ['cpp_std=c++11'])

# abc doesn't exist
linkdep = dependency('boost', modules : ['thread', 'system', 'test', 'abc'])
meson-0.53.2/test cases/failing/69 install_data rename bad size/0000755000175000017500000000000013625242372025541 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/69 install_data rename bad size/file1.txt0000644000175000017500000000000013366273150027270 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/69 install_data rename bad size/file2.txt0000644000175000017500000000000013366273150027271 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/69 install_data rename bad size/meson.build0000644000175000017500000000014613366273150027704 0ustar  jpakkanejpakkane00000000000000project('data install test', 'c')

install_data(['file1.txt', 'file2.txt'], rename : 'just one name')
meson-0.53.2/test cases/failing/7 go to subproject/0000755000175000017500000000000013625242372023271 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/7 go to subproject/meson.build0000644000175000017500000000005312650745767025446 0ustar  jpakkanejpakkane00000000000000project('fff', 'c')

subdir('subprojects')
meson-0.53.2/test cases/failing/7 go to subproject/subprojects/0000755000175000017500000000000013625242372025634 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/7 go to subproject/subprojects/meson.build0000644000175000017500000000001012650745767030002 0ustar  jpakkanejpakkane00000000000000x = 'x'
meson-0.53.2/test cases/failing/70 skip only subdir/0000755000175000017500000000000013625242372023361 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/70 skip only subdir/meson.build0000644000175000017500000000033413366273150025523 0ustar  jpakkanejpakkane00000000000000# Check that skip_rest only exits subdir, not the whole script.
# Should create an error because main.cpp does not exists.
project('example exit', 'cpp')

subdir('subdir')

message('Good')
executable('main', 'main.cpp')
meson-0.53.2/test cases/failing/70 skip only subdir/subdir/0000755000175000017500000000000013625242372024651 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/70 skip only subdir/subdir/meson.build0000644000175000017500000000004413366273150027011 0ustar  jpakkanejpakkane00000000000000subdir_done()

error('Unreachable')
meson-0.53.2/test cases/failing/71 invalid escape char/0000755000175000017500000000000013625242372023746 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/71 invalid escape char/meson.build0000644000175000017500000000021213366273150026103 0ustar  jpakkanejpakkane00000000000000# Make sure meson exits on invalid string
# The string below contains an invalid unicode code point

'my name is what \uxyzo who are you'
meson-0.53.2/test cases/failing/72 dual override/0000755000175000017500000000000013625242372022727 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/72 dual override/meson.build0000644000175000017500000000022013366273150025063 0ustar  jpakkanejpakkane00000000000000project('yo dawg', 'c')

p = find_program('overrides.py')
meson.override_find_program('override', p)
meson.override_find_program('override', p)
meson-0.53.2/test cases/failing/72 dual override/overrides.py0000644000175000017500000000020213366273150025275 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

print('Yo dawg, we put overrides in your overrides,')
print('so now you can override when you override.')
meson-0.53.2/test cases/failing/73 override used/0000755000175000017500000000000013625242372022743 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/73 override used/meson.build0000644000175000017500000000026313366273150025106 0ustar  jpakkanejpakkane00000000000000project('overridde an already found exe', 'c')

old = find_program('something.py')
replacement = find_program('other.py')
meson.override_find_program('something.py', replacement)
meson-0.53.2/test cases/failing/73 override used/other.py0000755000175000017500000000006713366273150024444 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

print('Doing something else.')
meson-0.53.2/test cases/failing/73 override used/something.py0000755000175000017500000000006213366273150025313 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

print('Doing something.')
meson-0.53.2/test cases/failing/74 run_command unclean exit/0000755000175000017500000000000013625242372025046 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/74 run_command unclean exit/meson.build0000644000175000017500000000017213366273150027210 0ustar  jpakkanejpakkane00000000000000project('run_command unclean exit', 'c')

rcprog = find_program('./returncode.py')
run_command(rcprog, '1', check : true)
meson-0.53.2/test cases/failing/74 run_command unclean exit/returncode.py0000755000175000017500000000007213366273150027574 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys
exit(int(sys.argv[1]))
meson-0.53.2/test cases/failing/75 int literal leading zero/0000755000175000017500000000000013625242372024740 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/75 int literal leading zero/meson.build0000644000175000017500000000013113366273150027075 0ustar  jpakkanejpakkane00000000000000
# This should fail.
# Decimal syntax is 123.
# Octal syntax is 0o123.
fail_0123 = 0123

meson-0.53.2/test cases/failing/76 configuration immutable/0000755000175000017500000000000013625242372025015 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/76 configuration immutable/input0000644000175000017500000000000013366273150026065 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/76 configuration immutable/meson.build0000644000175000017500000000032613366273150027160 0ustar  jpakkanejpakkane00000000000000project('configuration_data is immutable')

a = configuration_data()

configure_file(
    configuration : a,
    input : 'input',
    output : 'output',
)

still_immutable = a
still_immutable.set('hello', 'world')
meson-0.53.2/test cases/failing/77 link with shared module on osx/0000755000175000017500000000000013625242372025764 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/77 link with shared module on osx/meson.build0000644000175000017500000000032113366273150030122 0ustar  jpakkanejpakkane00000000000000project('link with shared module', 'c')

if host_machine.system() != 'darwin'
  error('Test only fails on OSX')
endif

m = shared_module('mymodule', 'module.c')
e = executable('prog', 'prog.c', link_with : m)
meson-0.53.2/test cases/failing/77 link with shared module on osx/module.c0000644000175000017500000000004413366273150027413 0ustar  jpakkanejpakkane00000000000000int func(void) {
    return 1496;
}
meson-0.53.2/test cases/failing/77 link with shared module on osx/prog.c0000644000175000017500000000007013366273150027074 0ustar  jpakkanejpakkane00000000000000
int main(int argc, char **argv) {
    return func();
}
meson-0.53.2/test cases/failing/78 non ascii in ascii encoded configure file/0000755000175000017500000000000013625242372027737 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/78 non ascii in ascii encoded configure file/config9.h.in0000644000175000017500000000003013366273150032044 0ustar  jpakkanejpakkane00000000000000#define MESSAGE "@var@"
meson-0.53.2/test cases/failing/78 non ascii in ascii encoded configure file/meson.build0000644000175000017500000000042513366273150032102 0ustar  jpakkanejpakkane00000000000000project('non acsii to ascii encoding', 'c')
# Writing a non ASCII character with a ASCII encoding should fail
conf9 = configuration_data()
conf9.set('var', 'Š“')
configure_file(
  input : 'config9.h.in',
  output : '@BASENAME@',
  encoding : 'ascii',
  configuration : conf9
)
meson-0.53.2/test cases/failing/79 subproj dependency not-found and required/0000755000175000017500000000000013625242372030212 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/79 subproj dependency not-found and required/meson.build0000644000175000017500000000014313366273150032352 0ustar  jpakkanejpakkane00000000000000project('dep-test')
missing = dependency('', fallback: ['missing', 'missing_dep'], required: true)
meson-0.53.2/test cases/failing/8 recursive/0000755000175000017500000000000013625242372022130 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/8 recursive/meson.build0000644000175000017500000000005712650745767024311 0ustar  jpakkanejpakkane00000000000000project('recursive', 'c')

a = subproject('a')
meson-0.53.2/test cases/failing/8 recursive/subprojects/0000755000175000017500000000000013625242352024471 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/8 recursive/subprojects/a/0000755000175000017500000000000013625242372024713 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/8 recursive/subprojects/a/meson.build0000644000175000017500000000004712650745767027073 0ustar  jpakkanejpakkane00000000000000project('a', 'c')

b = subproject('b')
meson-0.53.2/test cases/failing/8 recursive/subprojects/b/0000755000175000017500000000000013625242372024714 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/8 recursive/subprojects/b/meson.build0000644000175000017500000000004712650745767027074 0ustar  jpakkanejpakkane00000000000000project('b', 'c')

a = subproject('a')
meson-0.53.2/test cases/failing/80 unfound run/0000755000175000017500000000000013625242372022444 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/80 unfound run/meson.build0000644000175000017500000000020213366273150024600 0ustar  jpakkanejpakkane00000000000000project('unfound runtarget')

exe = find_program('nonexisting_prog', required : false)
run_target('invoke_fail', command : [exe])
meson-0.53.2/test cases/failing/81 framework dependency with version/0000755000175000017500000000000013625242372026700 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/81 framework dependency with version/meson.build0000644000175000017500000000043413366273150031043 0ustar  jpakkanejpakkane00000000000000project('framework dependency with version')
# do individual frameworks have a meaningful version to test?  And multiple frameworks might be listed...
# otherwise we're not on OSX and this will definitely fail
dep = dependency('appleframeworks', modules: 'foundation', version: '>0')
meson-0.53.2/test cases/failing/82 override exe config/0000755000175000017500000000000013625242372024012 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/82 override exe config/foo.c0000644000175000017500000000003713366273215024743 0ustar  jpakkanejpakkane00000000000000int main(void) {
  return 0;
}
meson-0.53.2/test cases/failing/82 override exe config/meson.build0000644000175000017500000000021313366273215026152 0ustar  jpakkanejpakkane00000000000000project('myexe', 'c')

foo = executable('foo', 'foo.c')
meson.override_find_program('bar', foo)
bar = find_program('bar')
run_command(bar)
meson-0.53.2/test cases/failing/83 gl dependency with version/0000755000175000017500000000000013625242372025307 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/83 gl dependency with version/meson.build0000644000175000017500000000051013366273215027447 0ustar  jpakkanejpakkane00000000000000project('gl dependency with version', 'c')

host_system = host_machine.system()
if host_system != 'windows' and host_system != 'darwin'
  error('Test only fails on Windows and OSX')
endif

# gl dependency found via system method doesn't have a meaningful version to check
dep = dependency('gl', method: 'system', version: '>0')
meson-0.53.2/test cases/failing/84 threads dependency with version/0000755000175000017500000000000013625242372026340 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/84 threads dependency with version/meson.build0000644000175000017500000000023313366273215030502 0ustar  jpakkanejpakkane00000000000000project('threads dependency with version', 'c')
# threads dependency doesn't have a meaningful version to check
dep = dependency('threads', version: '>0')
meson-0.53.2/test cases/failing/85 gtest dependency with version/0000755000175000017500000000000013625242372026035 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/85 gtest dependency with version/meson.build0000644000175000017500000000024513455557413030206 0ustar  jpakkanejpakkane00000000000000project('gtest dependency with version', ['c', 'cpp'])
# discovering gtest version is not yet implemented
dep = dependency('gtest', method: 'system', version: '>0')
meson-0.53.2/test cases/failing/86 dub libray/0000755000175000017500000000000013625242372022224 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/86 dub libray/meson.build0000644000175000017500000000015713366273215024373 0ustar  jpakkanejpakkane00000000000000project('dub', 'd', meson_version: '0.48.0')

dependency('dubtestproject', method: 'dub') # Not library (none)
meson-0.53.2/test cases/failing/87 dub executable/0000755000175000017500000000000013625242372023064 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/87 dub executable/meson.build0000644000175000017500000000017313366273215025231 0ustar  jpakkanejpakkane00000000000000project('dub', 'd', meson_version: '0.48.0')

dependency('dubtestproject:test1', method: 'dub') # Not library (executable)
meson-0.53.2/test cases/failing/88 dub compiler/0000755000175000017500000000000013625242372022556 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/88 dub compiler/meson.build0000644000175000017500000000051713403223104024705 0ustar  jpakkanejpakkane00000000000000project('dub', 'd', meson_version: '0.48.0')

if meson.get_compiler('d').get_id() == 'dmd'
  if host_machine.system() == 'windows' or host_machine.system() == 'cygwin'
    error('MESON_SKIP_TEST Windows test environment lacks multiple D compilers.')
  endif
endif

dependency('dubtestproject:test2', method: 'dub') # Compiler mismatch
meson-0.53.2/test cases/failing/89 subproj not-found dep/0000755000175000017500000000000013625242372024321 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/89 subproj not-found dep/meson.build0000644000175000017500000000015013531533273026456 0ustar  jpakkanejpakkane00000000000000project('dep-test')
missing = dependency('', fallback: ['somesubproj', 'notfound_dep'], required: true)
meson-0.53.2/test cases/failing/89 subproj not-found dep/subprojects/0000755000175000017500000000000013625242352026662 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/89 subproj not-found dep/subprojects/somesubproj/0000755000175000017500000000000013625242372031234 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/89 subproj not-found dep/subprojects/somesubproj/meson.build0000644000175000017500000000010513531533273033371 0ustar  jpakkanejpakkane00000000000000project('dep', 'c')

notfound_dep = dependency('', required : false)
meson-0.53.2/test cases/failing/9 missing extra file/0000755000175000017500000000000013625242372023577 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/9 missing extra file/meson.build0000644000175000017500000000014012650745767025751 0ustar  jpakkanejpakkane00000000000000project('missing extra file', 'c')

executable('myprog', 'prog.c', extra_files : 'missing.txt')
meson-0.53.2/test cases/failing/9 missing extra file/prog.c0000644000175000017500000000006212650745767024725 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) {
    return 0;
}
meson-0.53.2/test cases/failing/90 invalid configure file/0000755000175000017500000000000013625242372024472 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/90 invalid configure file/input0000644000175000017500000000000013531533273025541 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/90 invalid configure file/meson.build0000644000175000017500000000026513531533273026636 0ustar  jpakkanejpakkane00000000000000project('invalid configura file')

configure_file(
    configuration : configuration_data(),
    input : 'input',
    output : 'output',
    install_dir : '',
    install : true,
)
meson-0.53.2/test cases/failing/91 kwarg dupe/0000755000175000017500000000000013625242373022235 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/91 kwarg dupe/meson.build0000644000175000017500000000017213531533273024375 0ustar  jpakkanejpakkane00000000000000project('dupe kwarg', 'c')

dupedict = {'install': true}

executable('prog', 'prog.c', install: true,
  kwargs: dupedict)
meson-0.53.2/test cases/failing/91 kwarg dupe/prog.c0000644000175000017500000000020213531533273023340 0ustar  jpakkanejpakkane00000000000000#include

int main(int argc, char **argv) {
    printf("I don't get built. It makes me saaaaaad. :(\n");
    return 0;
}
meson-0.53.2/test cases/failing/92 missing pch file/0000755000175000017500000000000013625242373023311 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/92 missing pch file/meson.build0000644000175000017500000000014613531533273025452 0ustar  jpakkanejpakkane00000000000000project('pch test', 'c')
exe = executable('prog', 'prog.c',
c_pch : ['pch/prog_pch.c', 'pch/prog.h'])
meson-0.53.2/test cases/failing/92 missing pch file/prog.c0000644000175000017500000000006213531533273024420 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) {
    return 0;
}
meson-0.53.2/test cases/failing/93 pch source different folder/0000755000175000017500000000000013625242373025424 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/93 pch source different folder/include/0000755000175000017500000000000013625242373027047 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/93 pch source different folder/include/pch.h0000644000175000017500000000000013531533273027756 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/93 pch source different folder/meson.build0000644000175000017500000000027513531533273027570 0ustar  jpakkanejpakkane00000000000000project('pch', 'c')
# It is not allowed to have the PCH implementation in a different
# folder than the header.
exe = executable('prog', 'prog.c',
  c_pch : ['include/pch.h', 'src/pch.c'])
meson-0.53.2/test cases/failing/93 pch source different folder/prog.c0000644000175000017500000000002113571777336026544 0ustar  jpakkanejpakkane00000000000000int main(void) {}meson-0.53.2/test cases/failing/93 pch source different folder/src/0000755000175000017500000000000013625242373026213 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/93 pch source different folder/src/pch.c0000644000175000017500000000000013531533273027115 0ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/94 vala without c/0000755000175000017500000000000013625242373023021 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/94 vala without c/meson.build0000644000175000017500000000006013531533273025155 0ustar  jpakkanejpakkane00000000000000project('vala without c')
add_languages('vala')
meson-0.53.2/test cases/failing/95 unknown config tool/0000755000175000017500000000000013625242373024073 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/95 unknown config tool/meson.build0000644000175000017500000000012713531533273026233 0ustar  jpakkanejpakkane00000000000000project('no-such-config-tool')
dependency('no-such-config-tool', method:'config-tool')
meson-0.53.2/test cases/failing/96 custom target install data/0000755000175000017500000000000013625242373025313 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/96 custom target install data/Info.plist.cpp0000644000175000017500000000006313531533273030041 0ustar  jpakkanejpakkane00000000000000Some data which gets processed before installation
meson-0.53.2/test cases/failing/96 custom target install data/meson.build0000644000175000017500000000034613531533273027456 0ustar  jpakkanejpakkane00000000000000project('custom target install data')

preproc = find_program('preproc.py')

t = custom_target('Info.plist',
    command: [preproc, '@INPUT@', '@OUTPUT@'],
    input: 'Info.plist.cpp',
    output: 'Info.plist',
)

install_data(t)
meson-0.53.2/test cases/failing/96 custom target install data/preproc.py0000644000175000017500000000034513531533273027337 0ustar  jpakkanejpakkane00000000000000#!/usr/bin/env python3

import sys

if len(sys.argv) != 3:
    print(sys.argv[0], '', '')

inf = sys.argv[1]
outf = sys.argv[2]

with open(outf, 'wb') as o:
    with open(inf, 'rb') as i:
        o.write(i.read())
meson-0.53.2/test cases/failing/97 add dict non string key/0000755000175000017500000000000013625242373024461 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/97 add dict non string key/meson.build0000644000175000017500000000030713571777336026637 0ustar  jpakkanejpakkane00000000000000project('add dictionary entry using non-string key')

dict = {}

# An integer variable to be used as a key
key = 1

# Add new entry using integer variable as key should fail
dict += {key : 'myValue'}meson-0.53.2/test cases/failing/98 add dict duplicate keys/0000755000175000017500000000000013625242373024536 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing/98 add dict duplicate keys/meson.build0000644000175000017500000000032013571777336026707 0ustar  jpakkanejpakkane00000000000000project('add dictionary entries with duplicate keys')

dict = {}

# A variable to be used as a key
key = 'myKey'

# Add two entries with duplicate keys should fail
dict += {key : 'myValue1', key : 'myValue2'}meson-0.53.2/test cases/failing build/0000755000175000017500000000000013625242351021046 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/1 vala c werror/0000755000175000017500000000000013625242371023620 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/1 vala c werror/meson.build0000644000175000017500000000060513605171672025766 0ustar  jpakkanejpakkane00000000000000project('valatest', 'c', default_options : 'werror=true')

if find_program('valac', required : false).found()
  add_languages('vala')
  valadeps = [dependency('glib-2.0'), dependency('gobject-2.0')]
  # Must fail due to -Werror and unused variable in C file
  executable('valaprog', 'prog.vala', 'unused-var.c', dependencies : valadeps)
else
  executable('failprog', 'unused-var.c')
endif
meson-0.53.2/test cases/failing build/1 vala c werror/prog.vala0000644000175000017500000000022313003456157025430 0ustar  jpakkanejpakkane00000000000000class MainProg : GLib.Object {

    public static int main(string[] args) {
        stdout.printf("Vala is working.\n");
        return 0;
    }
}
meson-0.53.2/test cases/failing build/1 vala c werror/unused-var.c0000644000175000017500000000011313033265323026043 0ustar  jpakkanejpakkane00000000000000#warning "something"

int
somelib(void)
{
  int unused_var;
  return 33;
}
meson-0.53.2/test cases/failing build/2 hidden symbol/0000755000175000017500000000000013625242371023713 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/2 hidden symbol/bob.c0000644000175000017500000000007113366273150024620 0ustar  jpakkanejpakkane00000000000000#include"bob.h"

int hidden_function() {
    return 7;
}
meson-0.53.2/test cases/failing build/2 hidden symbol/bob.h0000644000175000017500000000004513366273150024626 0ustar  jpakkanejpakkane00000000000000#pragma once

int hidden_function();
meson-0.53.2/test cases/failing build/2 hidden symbol/bobuser.c0000644000175000017500000000012313366273150025515 0ustar  jpakkanejpakkane00000000000000#include"bob.h"

int main(int argc, char **argv) {
    return hidden_function();
}
meson-0.53.2/test cases/failing build/2 hidden symbol/meson.build0000644000175000017500000000046613605171671026065 0ustar  jpakkanejpakkane00000000000000project('hidden symbol', 'c')

if host_machine.system() == 'windows' or host_machine.system() == 'cygwin'
  error('MESON_SKIP_TEST -fvisibility=hidden does not work for PE files.')
endif

l = shared_library('bob', 'bob.c',
  gnu_symbol_visibility: 'hidden')

executable('bobuser', 'bobuser.c',
  link_with: l)
meson-0.53.2/test cases/failing build/3 pch disabled/0000755000175000017500000000000013625242371023475 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/3 pch disabled/c/0000755000175000017500000000000013625242371023717 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/3 pch disabled/c/meson.build0000644000175000017500000000011513426772647026073 0ustar  jpakkanejpakkane00000000000000exe = executable('prog', 'prog.c',
c_pch : ['pch/prog_pch.c', 'pch/prog.h'])
meson-0.53.2/test cases/failing build/3 pch disabled/c/pch/0000755000175000017500000000000013625242371024471 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/3 pch disabled/c/pch/prog.h0000644000175000017500000000002213426772647025620 0ustar  jpakkanejpakkane00000000000000#include
meson-0.53.2/test cases/failing build/3 pch disabled/c/pch/prog_pch.c0000644000175000017500000000013713426772647026454 0ustar  jpakkanejpakkane00000000000000#if !defined(_MSC_VER)
#error "This file is only for use with MSVC."
#endif

#include "prog.h"
meson-0.53.2/test cases/failing build/3 pch disabled/c/prog.c0000644000175000017500000000031413426772647025045 0ustar  jpakkanejpakkane00000000000000// No includes here, they need to come from the PCH

void func() {
    fprintf(stdout, "This is a function that fails if stdio is not #included.\n");
}

int main(int argc, char **argv) {
    return 0;
}

meson-0.53.2/test cases/failing build/3 pch disabled/meson.build0000644000175000017500000000036713605171671025647 0ustar  jpakkanejpakkane00000000000000# Disable PCH usage to make sure backends respect this setting.
# Since the .c file requires PCH usage (it does not include necessary
# headers itself), the build should fail.
project('pch test', 'c', default_options: ['b_pch=false'])
subdir('c')
meson-0.53.2/test cases/failing build/4 cmake subproject isolation/0000755000175000017500000000000013625242371026377 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/4 cmake subproject isolation/incDir/0000755000175000017500000000000013625242371027607 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp0000644000175000017500000000005313625260317031336 0ustar  jpakkanejpakkane00000000000000#pragma once

#define SOME_DEFINE " World"
meson-0.53.2/test cases/failing build/4 cmake subproject isolation/main.cpp0000644000175000017500000000023213625260317030024 0ustar  jpakkanejpakkane00000000000000#include 
#include 

using namespace std;

int main(void) {
  cmModClass obj("Hello");
  cout << obj.getStr() << endl;
  return 0;
}
meson-0.53.2/test cases/failing build/4 cmake subproject isolation/meson.build0000644000175000017500000000111113625260317030533 0ustar  jpakkanejpakkane00000000000000project('subproject isolation', ['c', 'cpp'])

if not find_program('cmake', required: false).found()
  error('MESON_SKIP_TEST CMake is not installed')
endif

incdir = meson.source_root() / 'incDir'

cm = import('cmake')

# This should generate a warning and the include dir should be skipped.
sub_pro = cm.subproject('cmMod', cmake_options : [ '-DMESON_INC_DIR=' + incdir ])
sub_dep = sub_pro.dependency('cmModLib++')

# Since the include dir is skipped, the compilation of this project should fail.
exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep])
test('test1', exe1)
meson-0.53.2/test cases/failing build/4 cmake subproject isolation/subprojects/0000755000175000017500000000000013625242351030740 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/0000755000175000017500000000000013625242371032001 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt0000644000175000017500000000037613625260317034547 0ustar  jpakkanejpakkane00000000000000cmake_minimum_required(VERSION 3.5)

project(cmMod)
set (CMAKE_CXX_STANDARD 14)

include_directories(${CMAKE_CURRENT_BINARY_DIR} ${MESON_INC_DIR})

add_library(cmModLib++ SHARED cmMod.cpp)
include(GenerateExportHeader)
generate_export_header(cmModLib++)
meson-0.53.2/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp0000644000175000017500000000027013625260317033543 0ustar  jpakkanejpakkane00000000000000#include "cmMod.hpp"
#include "fileA.hpp"

using namespace std;

cmModClass::cmModClass(string foo) {
  str = foo + SOME_DEFINE;
}

string cmModClass::getStr() const {
  return str;
}
meson-0.53.2/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp0000644000175000017500000000031313625260317033546 0ustar  jpakkanejpakkane00000000000000#pragma once

#include "cmmodlib++_export.h"
#include 

class CMMODLIB___EXPORT cmModClass {
private:
  std::string str;

public:
  cmModClass(std::string foo);

  std::string getStr() const;
};
meson-0.53.2/test cases/failing test/0000755000175000017500000000000013625242351020726 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing test/1 trivial/0000755000175000017500000000000013625242371022523 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing test/1 trivial/main.c0000644000175000017500000000004113340206727023605 0ustar  jpakkanejpakkane00000000000000int main(void) {
    return 1;
}
meson-0.53.2/test cases/failing test/1 trivial/meson.build0000644000175000017500000000010713605171674024670 0ustar  jpakkanejpakkane00000000000000project('trivial', 'c')

test('My Test', executable('main', 'main.c'))
meson-0.53.2/test cases/failing test/2 signal/0000755000175000017500000000000013625242371022327 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing test/2 signal/main.c0000644000175000017500000000013113340206727023411 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
    kill(getpid(), SIGSEGV);
}
meson-0.53.2/test cases/failing test/2 signal/meson.build0000644000175000017500000000031013605171674024470 0ustar  jpakkanejpakkane00000000000000project('signal', 'c')

if build_machine.system() == 'windows'
    error('MESON_SKIP_TEST test is not compatible with MS Windows.')
else
    test('My Signal Test', executable('main', 'main.c'))
endif
meson-0.53.2/test cases/failing test/3 ambiguous/0000755000175000017500000000000013625242371023046 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing test/3 ambiguous/main.c0000644000175000017500000000013113340206727024130 0ustar  jpakkanejpakkane00000000000000#include 
#include 

int main(void) {
    kill(getpid(), SIGSEGV);
}
meson-0.53.2/test cases/failing test/3 ambiguous/meson.build0000644000175000017500000000046713605171674025224 0ustar  jpakkanejpakkane00000000000000project('ambiguous', 'c')

if build_machine.system() == 'windows'
    error('MESON_SKIP_TEST test is not compatible with MS Windows.')
else
    exe = executable('main', 'main.c')
    test_runner = find_program('test_runner.sh')

    test('My Ambiguous Status Test', test_runner, args : [exe.full_path()])
endif
meson-0.53.2/test cases/failing test/3 ambiguous/test_runner.sh0000755000175000017500000000033513340206727025755 0ustar  jpakkanejpakkane00000000000000#!/bin/sh
#
# This tests that using a shell as an intermediary between Meson and the
# actual unit test which dies due to a signal is still recorded correctly.
#
# The quotes are because the path may contain spaces.
"$1"
meson-0.53.2/test cases/failing test/4 hard error/0000755000175000017500000000000013625242371023104 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing test/4 hard error/main.c0000644000175000017500000000004213440031012024147 0ustar  jpakkanejpakkane00000000000000int main(void) {
    return 99;
}
meson-0.53.2/test cases/failing test/4 hard error/meson.build0000644000175000017500000000020413605171674025247 0ustar  jpakkanejpakkane00000000000000project('trivial', 'c')

# Exit code 99 even overrides should_fail
test('My Test', executable('main', 'main.c'), should_fail: true)
meson-0.53.2/test cases/failing test/5 tap tests/0000755000175000017500000000000013625242371022764 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing test/5 tap tests/meson.build0000644000175000017500000000042613605171675025136 0ustar  jpakkanejpakkane00000000000000project('test features', 'c')

tester = executable('tester', 'tester.c')
test('nonzero return code', tester, args : [], protocol: 'tap')
test('missing test', tester, args : ['1..1'], protocol: 'tap')
test('incorrect skip', tester, args : ['1..1 # skip\nok 1'], protocol: 'tap')
meson-0.53.2/test cases/failing test/5 tap tests/tester.c0000644000175000017500000000032013440031012024410 0ustar  jpakkanejpakkane00000000000000#include 

int main(int argc, char **argv) {
    if (argc != 2) {
        fprintf(stderr, "Incorrect number of arguments, got %i\n", argc);
        return 1;
    }
    puts(argv[1]);
    return 0;
}
meson-0.53.2/test cases/failing test/6 xpass/0000755000175000017500000000000013625242371022214 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/failing test/6 xpass/meson.build0000644000175000017500000000017213605171675024364 0ustar  jpakkanejpakkane00000000000000project('unexpected pass', 'c')

test('should_fail_but_does_not', executable('xpass', 'xpass.c'),
     should_fail: true)
meson-0.53.2/test cases/failing test/6 xpass/xpass.c0000644000175000017500000000005613457141625023522 0ustar  jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; }
meson-0.53.2/test cases/fortran/0000755000175000017500000000000013625242352020031 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/1 basic/0000755000175000017500000000000013625242373021236 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/1 basic/meson.build0000644000175000017500000000056013605172126023375 0ustar  jpakkanejpakkane00000000000000project('simple fortran', 'fortran')

fc = meson.get_compiler('fortran')
if fc.get_id() == 'gcc'
  add_global_arguments('-fbounds-check', language : 'fortran')
endif

args = fc.first_supported_argument(['-ffree-form', '-free', '/free'])
assert(args != [], 'No arguments found?')

e = executable('simple', 'simple.f90',
  fortran_args : args)
test('Simple Fortran', e)
meson-0.53.2/test cases/fortran/1 basic/simple.f900000644000175000017500000000006713571777336023066 0ustar  jpakkanejpakkane00000000000000print *, "Fortran compilation is working."
end program
meson-0.53.2/test cases/fortran/10 find library/0000755000175000017500000000000013625242373022602 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/10 find library/gzip.f900000644000175000017500000000123113426772653024100 0ustar  jpakkanejpakkane00000000000000module gzip

use iso_c_binding, only: c_char, c_ptr, c_int
implicit none

interface
type(c_ptr) function gzopen(path, mode) bind(C)
import c_char, c_ptr

character(kind=c_char), intent(in) :: path(*), mode(*)
end function gzopen
end interface

interface
integer(c_int) function gzwrite(file, buf, len) bind(C)
import c_int, c_ptr, c_char

type(c_ptr), value, intent(in) :: file
character(kind=c_char), intent(in) :: buf
integer(c_int), value, intent(in) :: len
end function gzwrite
end interface

interface
integer(c_int) function gzclose(file) bind(C)
import c_int, c_ptr

type(c_ptr), value, intent(in) :: file
end function gzclose
end interface

end module gzip
meson-0.53.2/test cases/fortran/10 find library/main.f900000644000175000017500000000171013426772653024055 0ustar  jpakkanejpakkane00000000000000
use iso_fortran_env, only: stderr=>error_unit
use iso_c_binding, only: c_int, c_char, c_null_char, c_ptr
use gzip, only: gzopen, gzwrite, gzclose

implicit none

character(kind=c_char,len=*), parameter :: path = c_char_"test.gz"//c_null_char
character(kind=c_char,len=*), parameter :: mode = c_char_"wb9"//c_null_char
integer(c_int), parameter :: buffer_size = 512

type(c_ptr) :: file
character(kind=c_char, len=buffer_size) :: buffer
integer(c_int) :: ret
integer :: i

! open file
file = gzopen(path, mode)

! fill buffer with data
do i=1,buffer_size/4
   write(buffer(4*(i-1)+1:4*i), '(i3.3, a)') i, new_line('')
end do
ret = gzwrite(file, buffer, buffer_size)
if (ret /= buffer_size) then
   write(stderr,'(a, i3, a, i3, a)') 'Error: ', ret, ' / ', buffer_size, &
        ' bytes written.'
   stop 1
end if

! close file
ret = gzclose(file)
if (ret /= 0) then
   write(stderr,*) 'Error: failure to close file with error code ', ret
   stop 1
end if

end program
meson-0.53.2/test cases/fortran/10 find library/meson.build0000644000175000017500000000050213605172136024736 0ustar  jpakkanejpakkane00000000000000project('find fortran library', 'fortran')

fc = meson.get_compiler('fortran')

sources = ['main.f90', 'gzip.f90']
zlib = fc.find_library('z', required: false)

if not zlib.found()
  error('MESON_SKIP_TEST: Z library not available.')
endif

exe = executable('zlibtest', sources, dependencies : zlib)
test('testzlib', exe)
meson-0.53.2/test cases/fortran/11 compiles links runs/0000755000175000017500000000000013625242373024122 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/11 compiles links runs/meson.build0000644000175000017500000000054113605172140026254 0ustar  jpakkanejpakkane00000000000000project('compiles_links_runs', 'fortran')

fc = meson.get_compiler('fortran')

code = '''error stop 123; end'''

if not fc.compiles(code)
  error('Fortran 2008 code failed to compile')
endif

if not fc.links(code)
  error('Fortran 2008 code failed to link')
endif

if fc.run(code).returncode() != 123
  error('Fortran 2008 code failed to run')
endif



meson-0.53.2/test cases/fortran/12 submodule/0000755000175000017500000000000013625242373022236 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/12 submodule/a1.f900000644000175000017500000000047413571777336023100 0ustar  jpakkanejpakkane00000000000000module a1
implicit none

interface
module elemental real function pi2tau(pi)
  real, intent(in) :: pi
end function pi2tau

module real function get_pi()
end function get_pi
end interface

end module a1

program hierN

use a1
real :: tau, pi

pi = get_pi()

tau = pi2tau(pi)

print *,'pi=',pi,'tau=',tau

end program
meson-0.53.2/test cases/fortran/12 submodule/a2.f900000644000175000017500000000022213531533273023052 0ustar  jpakkanejpakkane00000000000000! testing no space between submodule()
submodule(a1) a2

contains

module procedure pi2tau
  pi2tau = 2*pi
end procedure pi2tau

end submodule a2
meson-0.53.2/test cases/fortran/12 submodule/a3.f900000644000175000017500000000032513531533273023057 0ustar  jpakkanejpakkane00000000000000! submodule (bogus) foo
! testing don't detect commented submodule

submodule (a1:a2) a3  ! testing inline comment

contains

module procedure get_pi
  get_pi = 4.*atan(1.)
end procedure get_pi


end submodule a3
meson-0.53.2/test cases/fortran/12 submodule/child.f900000644000175000017500000000026413530557256023647 0ustar  jpakkanejpakkane00000000000000submodule (parent) parent

contains

module procedure pi2tau
  pi2tau = 2*pi
end procedure pi2tau

module procedure good
print *, 'Good!'
end procedure good

end submodule parent

meson-0.53.2/test cases/fortran/12 submodule/meson.build0000644000175000017500000000070413612411367024376 0ustar  jpakkanejpakkane00000000000000project('submodule single level', 'fortran',
  meson_version: '>= 0.50.0')

fortc = meson.get_compiler('fortran')
if fortc.get_id() == 'gcc' and fortc.version().version_compare('<6.0')
  error('MESON_SKIP_TEST need gfortran >= 6.0 for submodule support')
endif

hier2 = executable('single', 'parent.f90', 'child.f90')
test('single-level hierarchy', hier2)

hierN = executable('multi', 'a1.f90', 'a2.f90', 'a3.f90')
test('multi-level hierarchy', hierN)
meson-0.53.2/test cases/fortran/12 submodule/parent.f900000644000175000017500000000050713530557256024055 0ustar  jpakkanejpakkane00000000000000module parent
real, parameter :: pi = 4.*atan(1.)
real :: tau

interface
module elemental real function pi2tau(pi)
  real, intent(in) :: pi
end function pi2tau

module subroutine good()
end subroutine good
end interface

end module parent


use parent

tau = pi2tau(pi)

print *,'pi=',pi, 'tau=', tau

call good()

end program
meson-0.53.2/test cases/fortran/13 coarray/0000755000175000017500000000000013625242373021700 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/13 coarray/main.f900000644000175000017500000000032213436043746023144 0ustar  jpakkanejpakkane00000000000000implicit none

if (this_image() == 1)  print *, 'number of Fortran coarray images:', num_images()

sync all ! semaphore, ensures message above is printed at top.

print *, 'Process ', this_image()

end program
meson-0.53.2/test cases/fortran/13 coarray/meson.build0000644000175000017500000000167213602226377024051 0ustar  jpakkanejpakkane00000000000000project('Fortran coarray', 'fortran',
  meson_version: '>=0.50')

fc = meson.get_compiler('fortran')

if ['pgi', 'flang'].contains(fc.get_id())
  error('MESON_SKIP_TEST: At least through PGI 19.10 and Flang 7.1 do not support Fortran Coarrays.')
endif

# coarray is required because single-image fallback is an intrinsic feature
coarray = dependency('coarray')

# check coarray, because user might not have all the library stack installed correctly
# for example, conflicting library/compiler versions on PATH
# this has to invoke a run of "sync all" to verify the MPI stack is functioning,
# particularly for dynamic linking
if fc.run('sync all; end', dependencies: coarray, name: 'Coarray link & run').returncode() != 0
  error('MESON_SKIP_TEST: coarray stack (including MPI) did not link correctly so that a simple test could run.')
endif

exe = executable('hello', 'main.f90',
  dependencies : coarray)

test('Coarray hello world', exe, timeout: 10)
meson-0.53.2/test cases/fortran/14 fortran links c/0000755000175000017500000000000013625242373023220 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/14 fortran links c/clib.c0000644000175000017500000000010613463632524024273 0ustar  jpakkanejpakkane00000000000000#include 

void hello(void){

  printf("hello from C\n");

}
meson-0.53.2/test cases/fortran/14 fortran links c/clib.def0000644000175000017500000000001713471342322024601 0ustar  jpakkanejpakkane00000000000000EXPORTS
	hello
meson-0.53.2/test cases/fortran/14 fortran links c/f_call_c.f900000644000175000017500000000016413463632524025264 0ustar  jpakkanejpakkane00000000000000implicit none

interface
subroutine hello()  bind (c)
end subroutine hello
end interface

call hello()

end program
meson-0.53.2/test cases/fortran/14 fortran links c/meson.build0000644000175000017500000000074113605172144025360 0ustar  jpakkanejpakkane00000000000000project('Fortran calling C', 'fortran', 'c',
  meson_version: '>= 0.51.0',
  default_options : ['default_library=static'])

ccid = meson.get_compiler('c').get_id()
if ccid == 'msvc' or ccid == 'clang-cl'
  error('MESON_SKIP_TEST: MSVC and GCC do not interoperate like this.')
endif

c_lib = library('clib', 'clib.c', vs_module_defs : 'clib.def')

f_call_c = executable('f_call_c', 'f_call_c.f90',
  link_with: c_lib,
  link_language: 'fortran')
test('Fortran calling C', f_call_c)
meson-0.53.2/test cases/fortran/15 include/0000755000175000017500000000000013625242373021665 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/15 include/inc1.f900000644000175000017500000000012413505171024023023 0ustar  jpakkanejpakkane00000000000000
real :: pi = 4.*atan(1.)
real :: tau

include "inc2.f90"  ! testing inline comment
meson-0.53.2/test cases/fortran/15 include/inc2.f900000644000175000017500000000001413455557413023040 0ustar  jpakkanejpakkane00000000000000
tau = 2*pi
meson-0.53.2/test cases/fortran/15 include/include_hierarchy.f900000644000175000017500000000010713531533273025662 0ustar  jpakkanejpakkane00000000000000
implicit none

include "inc1.f90"

print *, '2*pi:', tau

end program
meson-0.53.2/test cases/fortran/15 include/include_syntax.f900000644000175000017500000000071313531533273025235 0ustar  jpakkanejpakkane00000000000000implicit none

integer :: x, y

x = 1
y = 0

! include "timestwo.f90"

include "timestwo.f90"  ! inline comment check
if (x/=2) error stop 'failed on first include'

! leading space check
  include 'timestwo.f90'
if (x/=4) error stop 'failed on second include'

! Most Fortran compilers can't handle the non-standard #include,
! including (ha!) Flang, Gfortran, Ifort and PGI.
! #include "timestwo.f90"

print *, 'OK: Fortran include tests: x=',x

end programmeson-0.53.2/test cases/fortran/15 include/include_tests.f900000644000175000017500000000100413531533273025043 0ustar  jpakkanejpakkane00000000000000implicit none

integer :: x, y

x = 1
y = 0

! include "timestwo.f90"

! double quote and inline comment check
include "timestwo.f90"  ! inline comment check
if (x/=2) error stop 'failed on first include'

! leading space and single quote check
  include 'timestwo.f90'
if (x/=4) error stop 'failed on second include'

! Most Fortran compilers can't handle the non-standard #include,
! including (ha!) Flang, Gfortran, Ifort and PGI.
! #include "timestwo.f90"

print *, 'OK: Fortran include tests: x=',x

end programmeson-0.53.2/test cases/fortran/15 include/meson.build0000644000175000017500000000044413605172143024024 0ustar  jpakkanejpakkane00000000000000project('Inclusive', 'fortran',
  meson_version: '>= 0.51.1')

hier_exe = executable('include_hierarchy', 'include_hierarchy.f90')
test('Fortran include file hierarchy', hier_exe)

syntax_exe = executable('include_syntax', 'include_syntax.f90')
test('Fortran include file syntax', syntax_exe)meson-0.53.2/test cases/fortran/15 include/timestwo.f900000644000175000017500000000001713531533273024054 0ustar  jpakkanejpakkane00000000000000x = 2*x
y = y+1meson-0.53.2/test cases/fortran/16 openmp/0000755000175000017500000000000013625242373021541 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/16 openmp/main.f900000644000175000017500000000102413531533273023000 0ustar  jpakkanejpakkane00000000000000use, intrinsic :: iso_fortran_env, only: stderr=>error_unit
use omp_lib, only: omp_get_max_threads
implicit none

integer :: N, ierr
character(80) :: buf  ! can't be allocatable in this use case. Just set arbitrarily large.

call get_environment_variable('OMP_NUM_THREADS', buf, status=ierr)
if (ierr/=0) error stop 'environment variable OMP_NUM_THREADS could not be read'
read(buf,*) N

if (omp_get_max_threads() /= N) then
  write(stderr, *) 'Max Fortran threads: ', omp_get_max_threads(), '!=', N
  error stop
endif

end program
meson-0.53.2/test cases/fortran/16 openmp/meson.build0000644000175000017500000000175013605172144023702 0ustar  jpakkanejpakkane00000000000000# This test is complementary to and extends "common/190 openmp" so that
# we can examine more compilers and options than would be warranted in
# the common test where C/C++ must also be handled.
project('openmp', 'fortran',
  meson_version: '>= 0.46')


fc = meson.get_compiler('fortran')
if fc.get_id() == 'gcc' and fc.version().version_compare('<4.2.0')
  error('MESON_SKIP_TEST gcc is too old to support OpenMP.')
endif
if host_machine.system() == 'darwin'
  error('MESON_SKIP_TEST macOS does not support OpenMP.')
endif

openmp = dependency('openmp')

env = environment()
env.set('OMP_NUM_THREADS', '2')

exef = executable('exef',
  'main.f90',
  dependencies : [openmp])
test('OpenMP Fortran', exef, env : env)

openmp_f = dependency('openmp', language : 'fortran')
exe_f = executable('exe_f',
  'main.f90',
  dependencies : [openmp_f])
test('OpenMP Fortran-specific', exe_f, env : env)


# Check we can apply a version constraint
dependency('openmp', version: '>=@0@'.format(openmp.version()))
meson-0.53.2/test cases/fortran/17 add_languages/0000755000175000017500000000000013625242373023022 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/17 add_languages/meson.build0000644000175000017500000000034213605172143025156 0ustar  jpakkanejpakkane00000000000000project('add_lang_fortran')

# catch bug where Fortran compiler is found with project('foo', 'fortran') but
# not by add_languages('fortran')
assert(add_languages('fortran'), 'these tests assume Fortran compiler can be found')meson-0.53.2/test cases/fortran/18 first_arg/0000755000175000017500000000000013625242373022225 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/18 first_arg/meson.build0000644000175000017500000000163113605172147024367 0ustar  jpakkanejpakkane00000000000000project('fortran_args', 'fortran')

fc = meson.get_compiler('fortran')

if fc.get_id() == 'intel-cl'
  is_arg = '/O2'
  useless = '/DFOO'
else
  is_arg = '-O2'
  useless = '-DFOO'
endif

isnt_arg = '-fiambroken'

assert(fc.has_argument(is_arg), 'Arg that should have worked does not work.')
assert(not fc.has_argument(isnt_arg), 'Arg that should be broken is not.')

assert(fc.get_supported_arguments([is_arg, isnt_arg, useless]) == [is_arg, useless], 'Arg filtering returned different result.')

# Have useless at the end to ensure that the search goes from front to back.
l1 = fc.first_supported_argument([isnt_arg, is_arg, isnt_arg, useless])
l2 = fc.first_supported_argument(isnt_arg, isnt_arg, isnt_arg)

assert(l1.length() == 1, 'First supported returned wrong result.')
assert(l1.get(0) == is_arg, 'First supported returned wrong argument.')
assert(l2.length() == 0, 'First supported did not return empty array.')
meson-0.53.2/test cases/fortran/19 fortran_std/0000755000175000017500000000000013625242373022573 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/19 fortran_std/legacy.f0000644000175000017500000000021113571777336024214 0ustar  jpakkanejpakkane00000000000000    ! non-integer loop indices are deleted in Fortran 95 standard
      real a

      do 10 a=0,0.5,0.1
10    continue

      end programmeson-0.53.2/test cases/fortran/19 fortran_std/meson.build0000644000175000017500000000215213605172147024734 0ustar  jpakkanejpakkane00000000000000project('FortranStd', 'fortran',
    default_options: ['warning_level=0'])
# As with C and C++, each Fortran compiler + version has a subset of supported Fortran standards
# Additionally, a necessary option for non-standard Fortran projects is the "legacy"
# option, which allows non-standard syntax and behavior quirks.
# Thus "legacy" is a necessity for some old but important Fortran projects.
# By default, popular Fortran compilers disallow these quirks without "legacy" option.

fc = meson.get_compiler('fortran')

executable('stdnone', 'std95.f90')

executable('std_legacy', 'legacy.f', override_options : ['fortran_std=legacy'])

executable('std_95', 'std95.f90', override_options : ['fortran_std=f95'])

executable('std_f2003', 'std2003.f90', override_options : ['fortran_std=f2003'])

executable('std_f2008', 'std2008.f90', override_options : ['fortran_std=f2008'])

if fc.get_id() == 'gcc'
  if fc.version().version_compare('>=8.0')
    executable('std_f2018', 'std2018.f90', override_options : ['fortran_std=f2018'])
  endif
else
  executable('std_f2018', 'std2018.f90', override_options : ['fortran_std=f2018'])
endifmeson-0.53.2/test cases/fortran/19 fortran_std/std2003.f900000644000175000017500000000121513571777336024225 0ustar  jpakkanejpakkane00000000000000use, intrinsic :: iso_fortran_env, only : error_unit
implicit none

! http://fortranwiki.org/fortran/show/Real+precision
integer, parameter :: sp = selected_real_kind(6, 37)
integer, parameter :: dp = selected_real_kind(15, 307)

real(sp) :: a32
real(dp) :: a64

real(sp), parameter :: pi32 = 4*atan(1._sp)
real(dp), parameter :: pi64 = 4*atan(1._dp)

if (pi32 == pi64) stop 1

call timestwo(a32)
call timestwo(a64)

contains

elemental subroutine timestwo(a)

class(*), intent(inout) :: a

select type (a)
  type is (real(sp))
    a = 2*a
  type is (real(dp))
    a = 2*a
  type is (integer)
    a = 2*a
end select

end subroutine timestwo

end programmeson-0.53.2/test cases/fortran/19 fortran_std/std2008.f900000644000175000017500000000110413571777336024227 0ustar  jpakkanejpakkane00000000000000use, intrinsic :: iso_fortran_env, only : error_unit, sp=>real32, dp=>real64
implicit none

real(sp) :: a32
real(dp) :: a64

real(sp), parameter :: pi32 = 4*atan(1._sp)
real(dp), parameter :: pi64 = 4*atan(1._dp)

if (pi32 == pi64) error stop 'real32 values generally do not exactly equal real64 values'

call timestwo(a32)
call timestwo(a64)

contains

elemental subroutine timestwo(a)

class(*), intent(inout) :: a

select type (a)
  type is (real(sp))
    a = 2*a
  type is (real(dp))
    a = 2*a
  type is (integer)
    a = 2*a
end select

end subroutine timestwo

end programmeson-0.53.2/test cases/fortran/19 fortran_std/std2018.f900000644000175000017500000000121013571777336024226 0ustar  jpakkanejpakkane00000000000000use, intrinsic :: iso_fortran_env, only : error_unit, sp=>real32, dp=>real64
implicit none

real(sp) :: a32
real(dp) :: a64

real(sp), parameter :: pi32 = 4*atan(1._sp)
real(dp), parameter :: pi64 = 4*atan(1._dp)

if (pi32 == pi64) error stop 'real32 values generally do not exactly equal real64 values'

call timestwo(a32)
call timestwo(a64)

contains

elemental subroutine timestwo(a)

class(*), intent(inout) :: a

select type (a)
  type is (real(sp))
    a = 2*a
  type is (real(dp))
    a = 2*a
  type is (integer)
    a = 2*a
  class default
    error stop 'requires real32, real64 or integer'
end select

end subroutine timestwo

end programmeson-0.53.2/test cases/fortran/19 fortran_std/std95.f900000644000175000017500000000021213571777336024072 0ustar  jpakkanejpakkane00000000000000implicit none

integer :: i, j
integer, parameter :: N=3
real :: A(N,N)

A = 0

forall (i=1:N, j=1:N)
  A(i,j) = 1
end forall

end programmeson-0.53.2/test cases/fortran/2 modules/0000755000175000017500000000000013625242373021626 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/2 modules/comment_mod.f900000644000175000017500000000011413505171024024432 0ustar  jpakkanejpakkane00000000000000module line ! inline comment
implicit none

real :: length

end module line
meson-0.53.2/test cases/fortran/2 modules/meson.build0000644000175000017500000000034513605172126023766 0ustar  jpakkanejpakkane00000000000000project('modules', 'fortran',
  default_options : ['default_library=static'])

commented = library('commented', 'comment_mod.f90')

e = executable('modprog', 'mymod.f90', 'prog.f90',
  link_with: commented)
test('moduletest', e)
meson-0.53.2/test cases/fortran/2 modules/mymod.f900000644000175000017500000000025413530557256023300 0ustar  jpakkanejpakkane00000000000000! module circle  to be sure module regex doesn't allow commented modules

module circle
implicit none

real, parameter :: pi = 4.*atan(1.)
real :: radius
end module circle
meson-0.53.2/test cases/fortran/2 modules/prog.f900000644000175000017500000000016713505171024023110 0ustar  jpakkanejpakkane00000000000000use circle, only: pi
use line, only: length
implicit none

print *,'pi=',pi

length = pi
print *, length

end program

meson-0.53.2/test cases/fortran/20 buildtype/0000755000175000017500000000000013625242373022237 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/20 buildtype/main.f900000644000175000017500000000001413602226377023477 0ustar  jpakkanejpakkane00000000000000end program
meson-0.53.2/test cases/fortran/20 buildtype/meson.build0000644000175000017500000000032213605172147024375 0ustar  jpakkanejpakkane00000000000000# checks for unexpected behavior on non-default buildtype and warning_level
project('build type Fortran', 'fortran',
  default_options: ['buildtype=release', 'warning_level=3'])

executable('main', 'main.f90')
meson-0.53.2/test cases/fortran/3 module procedure/0000755000175000017500000000000013625242373023415 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/3 module procedure/meson.build0000644000175000017500000000026013605172126025551 0ustar  jpakkanejpakkane00000000000000project('Fortran 2003 use statement, in same file', 'fortran',
  meson_version: '>= 0.50.0')

e = executable('use_syntax', 'use_syntax.f90')
test('Fortran 2003 use syntax', e)
meson-0.53.2/test cases/fortran/3 module procedure/use_syntax.f900000644000175000017500000000071313531533273026136 0ustar  jpakkanejpakkane00000000000000module circle
implicit none

integer :: x
real :: radius

interface default
  module procedure timestwo
end interface

contains

elemental integer function timestwo(x) result(y)
  integer, intent(in) :: x
   y = 2*x
end function
end module circle

program prog

use, non_intrinsic :: circle, only: timestwo, x

implicit none

x = 3

if (timestwo(x) /= 6) error stop 'fortran module procedure problem'

print *,'OK: Fortran module procedure'

end program prog
meson-0.53.2/test cases/fortran/4 self dependency/0000755000175000017500000000000013625242373023210 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/4 self dependency/meson.build0000644000175000017500000000023213605172126025343 0ustar  jpakkanejpakkane00000000000000project('selfdep', 'fortran')

e = executable('selfdep', 'selfdep.f90')
test('selfdep', e)

library('selfmod', 'src/selfdep_mod.f90')

subproject('sub1')
meson-0.53.2/test cases/fortran/4 self dependency/selfdep.f900000644000175000017500000000032713426772653025164 0ustar  jpakkanejpakkane00000000000000MODULE geom

type :: circle
   REAL :: Pi = 4.*atan(1.)
   REAL :: radius
end type circle
END MODULE geom

PROGRAM prog

use geom, only : circle
IMPLICIT NONE

type(circle) :: ell

ell%radius = 3.

END PROGRAM prog
meson-0.53.2/test cases/fortran/4 self dependency/src/0000755000175000017500000000000013625242373023777 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/4 self dependency/src/selfdep_mod.f900000644000175000017500000000006313436043746026602 0ustar  jpakkanejpakkane00000000000000module a
end module a

module b
use a
end module b
meson-0.53.2/test cases/fortran/4 self dependency/subprojects/0000755000175000017500000000000013625242352025550 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/4 self dependency/subprojects/sub1/0000755000175000017500000000000013625242373026425 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/4 self dependency/subprojects/sub1/main.f900000644000175000017500000000004413436043746027672 0ustar  jpakkanejpakkane00000000000000module a
end

program b
  use a
end
meson-0.53.2/test cases/fortran/4 self dependency/subprojects/sub1/meson.build0000644000175000017500000000011213436043746030564 0ustar  jpakkanejpakkane00000000000000project('subproject self-def', 'fortran')

library('subself', 'main.f90')
meson-0.53.2/test cases/fortran/5 static/0000755000175000017500000000000013625242373021450 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/5 static/main.f900000644000175000017500000000010513426772653022720 0ustar  jpakkanejpakkane00000000000000
use static_hello
implicit none

call static_say_hello()
end program
meson-0.53.2/test cases/fortran/5 static/meson.build0000644000175000017500000000031413605172132023601 0ustar  jpakkanejpakkane00000000000000project('try-static-library', 'fortran')

static_hello = static_library('static_hello', 'static_hello.f90')

exe = executable('test_exe', 'main.f90', link_with : static_hello)
test('static-fortran', exe)
meson-0.53.2/test cases/fortran/5 static/static_hello.f900000644000175000017500000000042413426772653024452 0ustar  jpakkanejpakkane00000000000000module static_hello
implicit none

private
public :: static_say_hello

interface static_say_hello
  module procedure say_hello
end interface static_say_hello

contains

subroutine say_hello
  print *, "Static library called."
end subroutine say_hello

end module static_hello
meson-0.53.2/test cases/fortran/6 dynamic/0000755000175000017500000000000013625242373021606 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/6 dynamic/dynamic.f900000644000175000017500000000033313426772653023561 0ustar  jpakkanejpakkane00000000000000module dynamic
implicit none

private
public :: hello

interface hello
  module procedure say
end interface hello

contains

subroutine say
  print *, "Hello from shared library."
end subroutine say

end module dynamic
meson-0.53.2/test cases/fortran/6 dynamic/main.f900000644000175000017500000000010113426772653023052 0ustar  jpakkanejpakkane00000000000000use dynamic, only: hello
implicit none

call hello()
end program
meson-0.53.2/test cases/fortran/6 dynamic/meson.build0000644000175000017500000000116413605172133023744 0ustar  jpakkanejpakkane00000000000000project('dynamic_fortran', 'fortran')

fcid = meson.get_compiler('fortran').get_id()
if fcid == 'intel-cl' or (host_machine.system() == 'windows' and fcid == 'pgi')
  error('MESON_SKIP_TEST: non-Gfortran Windows Fortran compilers do not do shared libraries in a Fortran standard way')
  # !DEC$ ATTRIBUTES DLLEXPORT must be used!
  # https://software.intel.com/en-us/node/535306
  # https://www.pgroup.com/resources/docs/19.4/x86/pgi-user-guide/index.htm#lib-dynlnk-bld-dll-fort
endif

dynamic = shared_library('dynamic', 'dynamic.f90')
exe = executable('test_exe', 'main.f90', link_with : dynamic)
test('dynamic-fortran', exe)
meson-0.53.2/test cases/fortran/7 generated/0000755000175000017500000000000013625242373022121 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/7 generated/meson.build0000644000175000017500000000127313605172132024257 0ustar  jpakkanejpakkane00000000000000# Tests whether fortran sources files created during configuration are properly
# scanned for dependency information

project('generated', 'fortran')

conf_data = configuration_data()
conf_data.set('ONE', 1)
conf_data.set('TWO', 2)

templates_basenames = ['mod2', 'mod1']
generated_sources = []
foreach template_basename : templates_basenames
  infilename = '@0@.fpp'.format(template_basename)
  outfilename = '@0@.f90'.format(template_basename)
  outfile = configure_file(
      input : infilename, output : outfilename, configuration : conf_data)
  generated_sources += [outfile]
endforeach

sources = ['prog.f90'] + generated_sources
exe = executable('generated', sources)
test('generated', exe)
meson-0.53.2/test cases/fortran/7 generated/mod1.fpp0000644000175000017500000000012613107136000023447 0ustar  jpakkanejpakkane00000000000000module mod1
  implicit none

  integer, parameter :: modval1 = @ONE@

end module mod1
meson-0.53.2/test cases/fortran/7 generated/mod2.fpp0000644000175000017500000000014113107136000023445 0ustar  jpakkanejpakkane00000000000000module mod2
  use mod1
  implicit none

  integer, parameter :: modval2 = @TWO@

end module mod2
meson-0.53.2/test cases/fortran/7 generated/prog.f900000644000175000017500000000013213436043746023407 0ustar  jpakkanejpakkane00000000000000program prog
use mod2
implicit none

if (modval1 + modval2 /= 3) stop 1

end program prog
meson-0.53.2/test cases/fortran/8 module names/0000755000175000017500000000000013625242373022535 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/8 module names/meson.build0000644000175000017500000000023313605172132024666 0ustar  jpakkanejpakkane00000000000000project('mod_name_case', 'fortran')

sources = ['test.f90', 'mod1.f90', 'mod2.f90']

exe = executable('mod_name_case', sources)
test('mod_name_case', exe)
meson-0.53.2/test cases/fortran/8 module names/mod1.f900000644000175000017500000000012413426772653023722 0ustar  jpakkanejpakkane00000000000000module MyMod1
implicit none

integer, parameter :: myModVal1 = 1

end module MyMod1
meson-0.53.2/test cases/fortran/8 module names/mod2.f900000644000175000017500000000012413426772653023723 0ustar  jpakkanejpakkane00000000000000module mymod2
implicit none

integer, parameter :: myModVal2 = 2

end module mymod2
meson-0.53.2/test cases/fortran/8 module names/test.f900000644000175000017500000000020013505171024024013 0ustar  jpakkanejpakkane00000000000000use mymod1
use MyMod2  ! test inline comment

implicit none

integer, parameter :: testVar = myModVal1 + myModVal2

end program
meson-0.53.2/test cases/fortran/9 cpp/0000755000175000017500000000000013625242373020747 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fortran/9 cpp/fortran.f0000644000175000017500000000034013426772653022576 0ustar  jpakkanejpakkane00000000000000      function fortran() bind(C)
      use, intrinsic :: iso_c_binding, only: dp=>c_double
      implicit none

      real(dp) :: r, fortran

      call random_number(r)

      fortran = 2._dp**r

      end function fortran
meson-0.53.2/test cases/fortran/9 cpp/main.cpp0000644000175000017500000000023313571777336022411 0ustar  jpakkanejpakkane00000000000000#include 

extern "C" double fortran();

int main(void) {
    std::cout << "FORTRAN gave us this number: " << fortran() << '\n';
    return 0;
}
meson-0.53.2/test cases/fortran/9 cpp/meson.build0000644000175000017500000000110513605172140023076 0ustar  jpakkanejpakkane00000000000000project('C++ and FORTRAN', 'cpp', 'fortran')

cpp = meson.get_compiler('cpp')
fc = meson.get_compiler('fortran')

if cpp.get_id() == 'clang'
  error('MESON_SKIP_TEST Clang C++ does not find -lgfortran for some reason.')
endif

if build_machine.system() == 'windows' and cpp.get_id() != fc.get_id()
  error('MESON_SKIP_TEST mixing gfortran with non-GNU C++ does not work.')
endif

link_with = []
if fc.get_id() == 'intel'
  link_with += fc.find_library('ifport')
endif

e = executable(
  'cppfort',
  ['main.cpp', 'fortran.f'],
  dependencies : link_with,
)

test('C++ FORTRAN', e)
meson-0.53.2/test cases/fpga/0000755000175000017500000000000013625242352017273 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fpga/1 simple/0000755000175000017500000000000013625242373020710 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/fpga/1 simple/meson.build0000644000175000017500000000017513605172164023053 0ustar  jpakkanejpakkane00000000000000project('lattice', 'c')

is = import('unstable_icestorm')

is.project('spin',
  'spin.v',
  constraint_file : 'spin.pcf',
)

meson-0.53.2/test cases/fpga/1 simple/spin.pcf0000644000175000017500000000013113340206727022343 0ustar  jpakkanejpakkane00000000000000set_io LED1 99
set_io LED2 98
set_io LED3 97
set_io LED4 96
set_io LED5 95
set_io clk 21
meson-0.53.2/test cases/fpga/1 simple/spin.v0000644000175000017500000000130513340206727022044 0ustar  jpakkanejpakkane00000000000000
module top(input clk, output LED1, output LED2, output LED3, output LED4, output LED5);
   
   reg ready = 0;
   reg [23:0] divider;
   reg [3:0] spin;
   
   always @(posedge clk) begin
      if (ready) 
        begin
           if (divider == 6000000) 
             begin
                divider <= 0;
                spin <= {spin[2], spin[3], spin[0], spin[1]};
             end
           else 
             divider <= divider + 1;
        end
      else 
        begin
           ready <= 1;
           spin <= 4'b1010;
           divider <= 0;
        end
   end
   
   assign LED1 = spin[0];
   assign LED2 = spin[1];
   assign LED3 = spin[2];
   assign LED4 = spin[3];
   assign LED5 = 1;
endmodule
meson-0.53.2/test cases/frameworks/0000755000175000017500000000000013625242352020536 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/1 boost/0000755000175000017500000000000013625242373022010 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/1 boost/extralib.cpp0000644000175000017500000000126113340206727024323 0ustar  jpakkanejpakkane00000000000000#define _XOPEN_SOURCE 500

#include 
#include 
#include 
#include 
#include 

using namespace std;
namespace logging = boost::log;

void InitLogger() {
  logging::add_common_attributes();
  logging::register_simple_formatter_factory("Severity");
  string log_format = "%TimeStamp% [%Severity%] - %Message%";

  logging::add_console_log(
    cout,
    logging::keywords::format = log_format
  );
}

int main(int argc, char **argv) {
  InitLogger();
  BOOST_LOG_TRIVIAL(trace) << "SOMETHING";
  return 0;
}
meson-0.53.2/test cases/frameworks/1 boost/linkexe.cc0000644000175000017500000000044513340206727023756 0ustar  jpakkanejpakkane00000000000000#define _XOPEN_SOURCE 500

#include

boost::recursive_mutex m;

struct callable {
    void operator()() {
        boost::recursive_mutex::scoped_lock l(m);
    };
};

int main(int argc, char **argv) {
    callable x;
    boost::thread thr(x);
    thr.join();
    return 0;
}
meson-0.53.2/test cases/frameworks/1 boost/meson.build0000644000175000017500000001060013612411367024144 0ustar  jpakkanejpakkane00000000000000# this test requires the following on Ubuntu: libboost-{system,python,log,thread,test}-dev
project('boosttest', 'cpp',
  default_options : ['cpp_std=c++11'])

add_project_arguments(['-DBOOST_LOG_DYN_LINK'],
  language : 'cpp'
)

dep = dependency('boost', required: false)
if not dep.found()
  error('MESON_SKIP_TEST boost not found.')
endif

compiler = meson.get_compiler('cpp')
if compiler.has_argument('-permissive')
  # boost 1.64, the version we test against, doesn't work with -permissive
  add_project_arguments('-permissive', language: 'cpp')
endif

# We want to have multiple separate configurations of Boost
# within one project. The need to be independent of each other.
# Use one without a library dependency and one with it.

linkdep = dependency('boost', modules : ['thread', 'system', 'test'])
staticdep = dependency('boost', modules : ['thread', 'system'], static : true)
testdep = dependency('boost', modules : ['unit_test_framework'])
nomoddep = dependency('boost')
extralibdep = dependency('boost', modules : ['thread', 'system', 'log_setup', 'log'])

pymod = import('python')
python2 = pymod.find_installation('python2', required: host_machine.system() == 'linux', disabler: true)
python3 = pymod.find_installation('python3', required: host_machine.system() == 'linux', disabler: true)
python2dep = python2.dependency(required: host_machine.system() == 'linux', embed: true, disabler: true)
python3dep = python3.dependency(required: host_machine.system() == 'linux', embed: true, disabler: true)

# compile python 2/3 modules only if we found a corresponding python version
if(python2dep.found() and host_machine.system() == 'linux')
  if(dep.version().version_compare('>=1.67'))
    # if we have a new version of boost, we need to construct the module name based
    # on the installed version of python (and hope that they match the version boost
    # was compiled against)
    py2version_string = ''.join(python2dep.version().split('.'))
    bpython2dep = dependency('boost', modules : ['python' + py2version_string], required: false, disabler: true)
  else
    # if we have an older version of boost, we need to use the old module names
    bpython2dep = dependency('boost', modules : ['python'], required: false, disabler: true)
  endif
else
  python2dep = disabler()
  bpython2dep = disabler()
endif

if(python3dep.found() and host_machine.system() == 'linux')
  if(dep.version().version_compare('>=1.67'))
    py3version_string = ''.join(python3dep.version().split('.'))
    bpython3dep = dependency('boost', modules : ['python' + py3version_string], required: false, disabler: true)
  else
    bpython3dep = dependency('boost', modules : ['python3'], required: false, disabler: true)
  endif
else
  python3dep = disabler()
  bpython3dep = disabler()
endif

linkexe = executable('linkedexe', 'linkexe.cc', dependencies : linkdep)
staticexe = executable('staticlinkedexe', 'linkexe.cc', dependencies : staticdep)
unitexe = executable('utf', 'unit_test.cpp', dependencies: testdep)
nomodexe = executable('nomod', 'nomod.cpp', dependencies : nomoddep)
extralibexe = executable('extralibexe', 'extralib.cpp', dependencies : extralibdep)

# python modules are shared libraries
python2module = shared_library('python2_module', ['python_module.cpp'], dependencies: [python2dep, bpython2dep], name_prefix: '', cpp_args: ['-DMOD_NAME=python2_module'])
python3module = shared_library('python3_module', ['python_module.cpp'], dependencies: [python3dep, bpython3dep], name_prefix: '', cpp_args: ['-DMOD_NAME=python3_module'])

test('Boost linktest', linkexe)
test('Boost statictest', staticexe)
test('Boost UTF test', unitexe)
test('Boost nomod', nomodexe)
test('Boost extralib test', extralibexe)

# explicitly use the correct python interpreter so that we don't have to provide two different python scripts that have different shebang lines
python2interpreter = find_program(python2.path(), required: false, disabler: true)
test('Boost Python2', python2interpreter, args: ['./test_python_module.py', meson.current_build_dir()], workdir: meson.current_source_dir(), depends: python2module)
python3interpreter = find_program(python3.path(), required: false, disabler: true)
test('Boost Python3', python3interpreter, args: ['./test_python_module.py', meson.current_build_dir()], workdir: meson.current_source_dir(), depends: python3module)

subdir('partial_dep')

# check we can apply a version constraint
dependency('boost', version: '>=@0@'.format(dep.version()))
meson-0.53.2/test cases/frameworks/1 boost/nomod.cpp0000644000175000017500000000062012650745767023642 0ustar  jpakkanejpakkane00000000000000#include
#include

boost::any get_any() {
    boost::any foobar = 3;
    return foobar;
}

int main(int argc, char **argv) {
    boost::any result = get_any();
    if(boost::any_cast(result) == 3) {
        std::cout << "Everything is fine in the world.\n";
        return 0;
    } else {
        std::cout << "Mathematics stopped working.\n";
        return 1;
    }
}
meson-0.53.2/test cases/frameworks/1 boost/partial_dep/0000755000175000017500000000000013625242373024274 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/1 boost/partial_dep/foo.cpp0000644000175000017500000000122613340206727025561 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "foo.hpp"

vec Foo::vector() {
    return myvec;
}
meson-0.53.2/test cases/frameworks/1 boost/partial_dep/foo.hpp0000644000175000017500000000144413340206727025570 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include 

typedef boost::fusion::vector vec;


class Foo {
    public:
        Foo() {};
        vec vector();
    private:
        const vec myvec = vec(4);
};
meson-0.53.2/test cases/frameworks/1 boost/partial_dep/main.cpp0000644000175000017500000000147013571777336025742 0ustar  jpakkanejpakkane00000000000000/* Copyright Ā© 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include 
#include 
#include "foo.hpp"


int main(void) {
    auto foo = Foo();
    vec v = foo.vector();
    std::cout << boost::fusion::at_c<0>(v) << std::endl;

    return 0;
}

meson-0.53.2/test cases/frameworks/1 boost/partial_dep/meson.build0000644000175000017500000000164713340206727026443 0ustar  jpakkanejpakkane00000000000000# Copyright Ā© 2018 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

dep_boost = dependency('boost')
dep_boost_headers = dep_boost.partial_dependency(compile_args : true)

libfoo = static_library(
  'foo',
  'foo.cpp',
  dependencies : dep_boost_headers,
)

exe_external_dep = executable(
  'external_dep',
  'main.cpp',
  dependencies : dep_boost,
  link_with : libfoo
)

test('External Dependency', exe_external_dep)
meson-0.53.2/test cases/frameworks/1 boost/python_module.cpp0000644000175000017500000000102313531533273025374 0ustar  jpakkanejpakkane00000000000000#define PY_SSIZE_T_CLEAN
#include 
#include 

struct World
{
    void set(std::string msg) { this->msg = msg; }
    std::string greet() { return msg; }
    std::string version() { return std::to_string(PY_MAJOR_VERSION) + "." + std::to_string(PY_MINOR_VERSION); }
    std::string msg;
};


BOOST_PYTHON_MODULE(MOD_NAME)
{
    using namespace boost::python;
    class_("World")
        .def("greet", &World::greet)
        .def("set", &World::set)
        .def("version", &World::version)
    ;
}
meson-0.53.2/test cases/frameworks/1 boost/test_python_module.py0000644000175000017500000000114013531533273026301 0ustar  jpakkanejpakkane00000000000000import sys
sys.path.append(sys.argv[1])

# import compiled python module depending on version of python we are running with
if sys.version_info[0] == 2:
    import python2_module

if sys.version_info[0] == 3:
    import python3_module


def run():
    msg = 'howdy'
    if sys.version_info[0] == 2:
        w = python2_module.World()

    if sys.version_info[0] == 3:
        w = python3_module.World()

    w.set(msg)

    assert(msg == w.greet())
    version_string = str(sys.version_info[0]) + "." + str(sys.version_info[1])
    assert(version_string == w.version())

if __name__ == '__main__':
    run()
meson-0.53.2/test cases/frameworks/1 boost/unit_test.cpp0000644000175000017500000000034512650745767024550 0ustar  jpakkanejpakkane00000000000000#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "MesonTest"
#define BOOST_TEST_MAIN
#include 

BOOST_AUTO_TEST_CASE(m_test) {
    int x = 2+2;
    BOOST_CHECK(true);
    BOOST_CHECK_EQUAL(x, 4);
}
meson-0.53.2/test cases/frameworks/10 gtk-doc/0000755000175000017500000000000013625242373022272 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/0000755000175000017500000000000013625242373023037 5ustar  jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar-docs.sgml0000644000175000017500000000210513340206727026114 0ustar  jpakkanejpakkane00000000000000

]>

  
    Foolib Reference Manual
    
      for Foobar &version;
    
    
      
        Jonny
        Example
        
          
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar1/0000755000175000017500000000000013625242373024370 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-docs.sgml0000644000175000017500000000211313531533273027445 0ustar jpakkanejpakkane00000000000000 ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar1/meson.build0000644000175000017500000000020613531533273026526 0ustar jpakkanejpakkane00000000000000gnome.gtkdoc('foobar', src_dir : inc, main_sgml : 'foobar-docs.sgml', content_files : [docbook, version_xml], install : true) meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar2/0000755000175000017500000000000013625242373024371 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar2/foobar-docs.sgml0000644000175000017500000000211313531533273027446 0ustar jpakkanejpakkane00000000000000 ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar2/meson.build0000644000175000017500000000024213531533273026527 0ustar jpakkanejpakkane00000000000000gnome.gtkdoc('foobar2', src_dir : inc, main_sgml : 'foobar-docs.sgml', content_files : [docbook, version_xml], install : true, install_dir : 'foobar2') meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar3/0000755000175000017500000000000013625242373024372 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar3/foobar-docs.sgml0000644000175000017500000000211313531533273027447 0ustar jpakkanejpakkane00000000000000 ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar3/meson.build0000644000175000017500000000024013531533273026526 0ustar jpakkanejpakkane00000000000000gnome.gtkdoc('foobar', module_version : '3.0', src_dir : inc, main_sgml : 'foobar-docs.sgml', content_files : [docbook, version_xml], install : true) meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar4/0000755000175000017500000000000013625242373024373 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar4/foobar-docs.sgml0000644000175000017500000000211313531533273027450 0ustar jpakkanejpakkane00000000000000 ]> Foolib Reference Manual for Foobar &version; Jonny Example
unknown@example.com
2015 Foobar corporation holdings ltd
Foobar library This part documents Foobar libs.
meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/foobar4/meson.build0000644000175000017500000000027413531533273026536 0ustar jpakkanejpakkane00000000000000gnome.gtkdoc('foobar2', module_version : '3.0', src_dir : inc, main_sgml : 'foobar-docs.sgml', content_files : [docbook, version_xml], install : true, install_dir : 'foobar3') meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/meson.build0000644000175000017500000000044213531533273025177 0ustar jpakkanejpakkane00000000000000cdata = configuration_data() cdata.set('VERSION', '1.0') version_xml = configure_file(input : 'version.xml.in', output : 'version.xml', configuration : cdata) subdir('foobar1') subdir('foobar2') subdir('foobar3') subdir('foobar4') meson-0.53.2/test cases/frameworks/10 gtk-doc/doc/version.xml.in0000644000175000017500000000001212650745767025660 0ustar jpakkanejpakkane00000000000000@VERSION@ meson-0.53.2/test cases/frameworks/10 gtk-doc/include/0000755000175000017500000000000013625242373023715 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/10 gtk-doc/include/foo-version.h.in0000644000175000017500000000074613123035221026731 0ustar jpakkanejpakkane00000000000000#pragma once /** * SECTION:version * @section_id: foo-version * @short_description: foo-version.h * @title: Foo Versioning */ /** * FOO_MAJOR_VERSION: * * The major version of foo. */ #define FOO_MAJOR_VERSION (@FOO_MAJOR_VERSION@) /** * FOO_MINOR_VERSION: * * The minor version of foo. */ #define FOO_MINOR_VERSION (@FOO_MINOR_VERSION@) /** * FOO_MICRO_VERSION: * * The micro version of foo. */ #define FOO_MICRO_VERSION (@FOO_MICRO_VERSION@) meson-0.53.2/test cases/frameworks/10 gtk-doc/include/foo.h0000644000175000017500000000032012650745767024660 0ustar jpakkanejpakkane00000000000000#pragma once /** * FooIndecision: * @FOO_MAYBE: Something maybe * @FOO_POSSIBLY: Something possible * * The indecision type. **/ typedef enum { FOO_MAYBE, FOO_POSSIBLY, } FooIndecision; meson-0.53.2/test cases/frameworks/10 gtk-doc/include/generate-enums-docbook.py0000644000175000017500000000376413340206727030633 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys DOC_HEADER = ''' {0} {0} {0} enum {1} {1} {1} Values ''' DOC_ENUM = ''' {0} = {1} ''' DOC_FOOTER = ''' ''' if __name__ == '__main__': if len(sys.argv) >= 4: with open(sys.argv[1], 'w') as doc_out: enum_name = sys.argv[2] enum_type = sys.argv[3] doc_out.write(DOC_HEADER.format(enum_name, enum_type)) for i, enum in enumerate(sys.argv[4:]): doc_out.write(DOC_ENUM.format(enum, i)) doc_out.write(DOC_FOOTER) else: print('Use: ' + sys.argv[0] + ' out name type [enums]') sys.exit(0) meson-0.53.2/test cases/frameworks/10 gtk-doc/include/meson.build0000644000175000017500000000111513340206727026052 0ustar jpakkanejpakkane00000000000000cdata = configuration_data() parts = meson.project_version().split('.') cdata.set('FOO_MAJOR_VERSION', parts[0]) cdata.set('FOO_MINOR_VERSION', parts[1]) cdata.set('FOO_MICRO_VERSION', parts[2]) configure_file(input : 'foo-version.h.in', output : 'foo-version.h', configuration : cdata, install : true, install_dir : get_option('includedir')) generate_enums_docbook = find_program('generate-enums-docbook.py') docbook = custom_target('enum-docbook', output : 'bar.xml', command : [generate_enums_docbook, '@OUTPUT@', 'BAR', 'BAR_TYPE', 'BAR_FOO'], build_by_default : true) meson-0.53.2/test cases/frameworks/10 gtk-doc/installed_files.txt0000644000175000017500000000503013403223104026153 0ustar jpakkanejpakkane00000000000000usr/include/foo-version.h usr/share/gtk-doc/html/foobar/BAR.html usr/share/gtk-doc/html/foobar/foobar.devhelp2 usr/share/gtk-doc/html/foobar/foobar.html usr/share/gtk-doc/html/foobar/foobar-foo.html usr/share/gtk-doc/html/foobar/foobar-foo-version.html usr/share/gtk-doc/html/foobar/home.png usr/share/gtk-doc/html/foobar/index.html usr/share/gtk-doc/html/foobar/left.png usr/share/gtk-doc/html/foobar/left-insensitive.png usr/share/gtk-doc/html/foobar/right.png usr/share/gtk-doc/html/foobar/right-insensitive.png usr/share/gtk-doc/html/foobar/style.css usr/share/gtk-doc/html/foobar/up.png usr/share/gtk-doc/html/foobar/up-insensitive.png usr/share/gtk-doc/html/foobar2/BAR.html usr/share/gtk-doc/html/foobar2/foobar2.devhelp2 usr/share/gtk-doc/html/foobar2/foobar.html usr/share/gtk-doc/html/foobar2/foobar2-foo.html usr/share/gtk-doc/html/foobar2/foobar2-foo-version.html usr/share/gtk-doc/html/foobar2/home.png usr/share/gtk-doc/html/foobar2/index.html usr/share/gtk-doc/html/foobar2/left.png usr/share/gtk-doc/html/foobar2/left-insensitive.png usr/share/gtk-doc/html/foobar2/right.png usr/share/gtk-doc/html/foobar2/right-insensitive.png usr/share/gtk-doc/html/foobar2/style.css usr/share/gtk-doc/html/foobar2/up.png usr/share/gtk-doc/html/foobar2/up-insensitive.png usr/share/gtk-doc/html/foobar-3.0/BAR.html usr/share/gtk-doc/html/foobar-3.0/foobar-3.0.devhelp2 usr/share/gtk-doc/html/foobar-3.0/foobar.html usr/share/gtk-doc/html/foobar-3.0/foobar-foo.html usr/share/gtk-doc/html/foobar-3.0/foobar-foo-version.html usr/share/gtk-doc/html/foobar-3.0/home.png usr/share/gtk-doc/html/foobar-3.0/index.html usr/share/gtk-doc/html/foobar-3.0/left.png usr/share/gtk-doc/html/foobar-3.0/left-insensitive.png usr/share/gtk-doc/html/foobar-3.0/right.png usr/share/gtk-doc/html/foobar-3.0/right-insensitive.png usr/share/gtk-doc/html/foobar-3.0/style.css usr/share/gtk-doc/html/foobar-3.0/up.png usr/share/gtk-doc/html/foobar-3.0/up-insensitive.png usr/share/gtk-doc/html/foobar3/BAR.html usr/share/gtk-doc/html/foobar3/foobar2-3.0.devhelp2 usr/share/gtk-doc/html/foobar3/foobar.html usr/share/gtk-doc/html/foobar3/foobar2-foo.html usr/share/gtk-doc/html/foobar3/foobar2-foo-version.html usr/share/gtk-doc/html/foobar3/home.png usr/share/gtk-doc/html/foobar3/index.html usr/share/gtk-doc/html/foobar3/left.png usr/share/gtk-doc/html/foobar3/left-insensitive.png usr/share/gtk-doc/html/foobar3/right.png usr/share/gtk-doc/html/foobar3/right-insensitive.png usr/share/gtk-doc/html/foobar3/style.css usr/share/gtk-doc/html/foobar3/up.png usr/share/gtk-doc/html/foobar3/up-insensitive.png meson-0.53.2/test cases/frameworks/10 gtk-doc/meson.build0000644000175000017500000000137013605172254024433 0ustar jpakkanejpakkane00000000000000project('gtkdoctest', 'c', version : '1.0.0') gtkdoc = find_program('gtkdoc-scan', required: false) if not gtkdoc.found() error('MESON_SKIP_TEST gtkdoc not found.') endif gnome = import('gnome') assert(gnome.gtkdoc_html_dir('foobar') == 'share/gtk-doc/html/foobar', 'Gtkdoc install dir is incorrect.') inc = include_directories('include') subdir('include') # disable this test unless a bug fix for spaces in pathnames is present # https://bugzilla.gnome.org/show_bug.cgi?id=753145 result = run_command(gtkdoc, ['--version']) gtkdoc_ver = result.stdout().strip() if gtkdoc_ver == '' gtkdoc_ver = result.stderr().strip() endif if gtkdoc_ver.version_compare('<1.26') error('MESON_SKIP_TEST gtk-doc test requires gtkdoc >= 1.26.') endif subdir('doc') meson-0.53.2/test cases/frameworks/11 gir subproject/0000755000175000017500000000000013625242373023665 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/11 gir subproject/gir/0000755000175000017500000000000013625242373024446 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/11 gir subproject/gir/meson-subsample.c0000644000175000017500000000540212763077471027734 0ustar jpakkanejpakkane00000000000000#include "meson-subsample.h" struct _MesonSubSample { MesonSample parent_instance; gchar *msg; }; G_DEFINE_TYPE (MesonSubSample, meson_sub_sample, MESON_TYPE_SAMPLE) enum { PROP_0, PROP_MSG, LAST_PROP }; static GParamSpec *gParamSpecs [LAST_PROP]; /** * meson_sub_sample_new: * @msg: The message to set. * * Allocates a new #MesonSubSample. * * Returns: (transfer full): a #MesonSubSample. */ MesonSubSample * meson_sub_sample_new (const gchar *msg) { g_return_val_if_fail (msg != NULL, NULL); return g_object_new (MESON_TYPE_SUB_SAMPLE, "message", msg, NULL); } static void meson_sub_sample_finalize (GObject *object) { MesonSubSample *self = (MesonSubSample *)object; g_clear_pointer (&self->msg, g_free); G_OBJECT_CLASS (meson_sub_sample_parent_class)->finalize (object); } static void meson_sub_sample_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MesonSubSample *self = MESON_SUB_SAMPLE (object); switch (prop_id) { case PROP_MSG: g_value_set_string (value, self->msg); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void meson_sub_sample_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MesonSubSample *self = MESON_SUB_SAMPLE (object); switch (prop_id) { case PROP_MSG: self->msg = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void meson_sub_sample_class_init (MesonSubSampleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = meson_sub_sample_finalize; object_class->get_property = meson_sub_sample_get_property; object_class->set_property = meson_sub_sample_set_property; gParamSpecs [PROP_MSG] = g_param_spec_string ("message", "Message", "The message to print.", NULL, (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs); } static void meson_sub_sample_init (MesonSubSample *self) { } /** * meson_sub_sample_print_message: * @self: a #MesonSubSample. * * Prints the message. * * Returns: Nothing. */ void meson_sub_sample_print_message (MesonSubSample *self) { g_return_if_fail (MESON_IS_SUB_SAMPLE (self)); g_print ("Message: %s\n", self->msg); } meson-0.53.2/test cases/frameworks/11 gir subproject/gir/meson-subsample.h0000644000175000017500000000070412763077471027741 0ustar jpakkanejpakkane00000000000000#ifndef MESON_SUB_SAMPLE_H #define MESON_SUB_SAMPLE_H #if !defined (MESON_TEST) #error "MESON_TEST not defined." #endif #include #include G_BEGIN_DECLS #define MESON_TYPE_SUB_SAMPLE (meson_sub_sample_get_type()) G_DECLARE_FINAL_TYPE (MesonSubSample, meson_sub_sample, MESON, SUB_SAMPLE, MesonSample) MesonSubSample *meson_sub_sample_new (const gchar *msg); G_END_DECLS #endif /* MESON_SUB_SAMPLE_H */ meson-0.53.2/test cases/frameworks/11 gir subproject/gir/meson.build0000644000175000017500000000212613340206727026606 0ustar jpakkanejpakkane00000000000000libsources = ['meson-subsample.c', 'meson-subsample.h'] girsubproject = shared_library( 'girsubproject', sources : libsources, dependencies : [gobj, meson_gir], install : true ) girexe = executable( 'girprog', sources : 'prog.c', dependencies : [gobj, meson_gir], link_with : girsubproject ) gnome.generate_gir( girsubproject, sources : libsources, dependencies : [gobj, meson_gir], nsversion : '1.0', namespace : 'MesonSub', symbol_prefix : 'meson_sub_', identifier_prefix : 'MesonSub', includes : ['GObject-2.0', 'Meson-1.0'], install : true ) message('TEST: ' + girsubproject.outdir()) envdata = environment() envdata.append('GI_TYPELIB_PATH', girsubproject.outdir(), 'subprojects/mesongir', separator : ':') envdata.append('LD_LIBRARY_PATH', girsubproject.outdir(), 'subprojects/mesongir') if ['windows', 'cygwin'].contains(host_machine.system()) envdata.append('PATH', girsubproject.outdir(), 'subprojects/mesongir') endif test('gobject introspection/subproject/c', girexe) test('gobject introspection/subproject/py', find_program('prog.py'), env : envdata) meson-0.53.2/test cases/frameworks/11 gir subproject/gir/prog.c0000644000175000017500000000034512763077471025572 0ustar jpakkanejpakkane00000000000000#include "meson-subsample.h" gint main (gint argc, gchar *argv[]) { MesonSample * i = (MesonSample*) meson_sub_sample_new ("Hello, sub/meson/c!"); meson_sample_print_message (i); g_object_unref (i); return 0; } meson-0.53.2/test cases/frameworks/11 gir subproject/gir/prog.py0000755000175000017500000000024012763077471025775 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 from gi.repository import MesonSub if __name__ == "__main__": s = MesonSub.Sample.new("Hello, sub/meson/py!") s.print_message() meson-0.53.2/test cases/frameworks/11 gir subproject/installed_files.txt0000644000175000017500000000042613366273215027572 0ustar jpakkanejpakkane00000000000000usr/lib/girepository-1.0/Meson-1.0.typelib usr/lib/girepository-1.0/MesonSub-1.0.typelib usr/share/gir-1.0/Meson-1.0.gir usr/share/gir-1.0/MesonSub-1.0.gir usr/lib/?libgirsubproject.so ?cygwin:usr/lib/libgirlib.dll.a usr/lib/?libgirlib.so ?cygwin:usr/lib/libgirsubproject.dll.a meson-0.53.2/test cases/frameworks/11 gir subproject/meson.build0000644000175000017500000000105313605172304026020 0ustar jpakkanejpakkane00000000000000project('gobject-introspection-with-subproject', 'c') gir = find_program('g-ir-scanner', required: false) if not gir.found() error('MESON_SKIP_TEST g-ir-scanner not found.') endif python3 = import('python3') py3 = python3.find_python() if run_command(py3, '-c', 'import gi;').returncode() != 0 error('MESON_SKIP_TEST python3-gi not found') endif gnome = import('gnome') gobj = dependency('gobject-2.0') add_global_arguments('-DMESON_TEST', language : 'c') meson_gir = dependency('meson-gir', fallback : ['mesongir', 'meson_gir']) subdir('gir') meson-0.53.2/test cases/frameworks/11 gir subproject/subprojects/0000755000175000017500000000000013625242352026225 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/11 gir subproject/subprojects/mesongir/0000755000175000017500000000000013625242373030053 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/11 gir subproject/subprojects/mesongir/meson-sample.c0000644000175000017500000000556112763077471032635 0ustar jpakkanejpakkane00000000000000#include "meson-sample.h" typedef struct _MesonSamplePrivate { gchar *msg; } MesonSamplePrivate; G_DEFINE_TYPE_WITH_PRIVATE (MesonSample, meson_sample, G_TYPE_OBJECT) enum { PROP_0, PROP_MSG, LAST_PROP }; static GParamSpec *gParamSpecs [LAST_PROP]; /** * meson_sample_new: * @msg: The message to set. * * Allocates a new #MesonSample. * * Returns: (transfer full): a #MesonSample. */ MesonSample * meson_sample_new (const gchar *msg) { g_return_val_if_fail (msg != NULL, NULL); return g_object_new (MESON_TYPE_SAMPLE, "message", msg, NULL); } static void meson_sample_finalize (GObject *object) { MesonSamplePrivate *priv = meson_sample_get_instance_private ((MesonSample *) object); g_clear_pointer (&priv->msg, g_free); G_OBJECT_CLASS (meson_sample_parent_class)->finalize (object); } static void meson_sample_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MesonSamplePrivate *priv = meson_sample_get_instance_private ((MesonSample *) object); switch (prop_id) { case PROP_MSG: g_value_set_string (value, priv->msg); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void meson_sample_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MesonSamplePrivate *priv = meson_sample_get_instance_private ((MesonSample *) object); switch (prop_id) { case PROP_MSG: priv->msg = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void meson_sample_class_init (MesonSampleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = meson_sample_finalize; object_class->get_property = meson_sample_get_property; object_class->set_property = meson_sample_set_property; gParamSpecs [PROP_MSG] = g_param_spec_string ("message", "Message", "The message to print.", NULL, (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs); } static void meson_sample_init (MesonSample *self) { } /** * meson_sample_print_message: * @self: a #MesonSample. * * Prints the message. * * Returns: Nothing. */ void meson_sample_print_message (MesonSample *self) { MesonSamplePrivate *priv; g_return_if_fail (MESON_IS_SAMPLE (self)); priv = meson_sample_get_instance_private (self); g_print ("Message: %s\n", priv->msg); } meson-0.53.2/test cases/frameworks/11 gir subproject/subprojects/mesongir/meson-sample.h0000644000175000017500000000100012763077471032622 0ustar jpakkanejpakkane00000000000000#ifndef MESON_SAMPLE_H #define MESON_SAMPLE_H #if !defined (MESON_TEST) #error "MESON_TEST not defined." #endif #include G_BEGIN_DECLS #define MESON_TYPE_SAMPLE (meson_sample_get_type()) G_DECLARE_DERIVABLE_TYPE (MesonSample, meson_sample, MESON, SAMPLE, GObject) struct _MesonSampleClass { GObjectClass parent_class; }; MesonSample *meson_sample_new (const gchar *msg); void meson_sample_print_message (MesonSample *self); G_END_DECLS #endif /* MESON_SAMPLE_H */ meson-0.53.2/test cases/frameworks/11 gir subproject/subprojects/mesongir/meson.build0000644000175000017500000000126712763077471032232 0ustar jpakkanejpakkane00000000000000project('gobject-introspection-subproject', 'c') gnome = import('gnome') gobj = dependency('gobject-2.0') libsources = ['meson-sample.c', 'meson-sample.h'] girlib = shared_library( 'girlib', sources : libsources, dependencies : gobj, install : true ) girtarget = gnome.generate_gir( girlib, sources : libsources, nsversion : '1.0', namespace : 'Meson', symbol_prefix : 'meson_', identifier_prefix : 'Meson', includes : ['GObject-2.0'], install : true ) meson_gir = declare_dependency(link_with : girlib, include_directories : [include_directories('.')], dependencies : [gobj], # Everything that uses libgst needs this built to compile sources : girtarget, ) meson-0.53.2/test cases/frameworks/12 multiple gir/0000755000175000017500000000000013625242373023341 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/12 multiple gir/gir/0000755000175000017500000000000013625242373024122 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/12 multiple gir/gir/meson-subsample.c0000644000175000017500000000540212772547213027404 0ustar jpakkanejpakkane00000000000000#include "meson-subsample.h" struct _MesonSubSample { MesonSample parent_instance; gchar *msg; }; G_DEFINE_TYPE (MesonSubSample, meson_sub_sample, MESON_TYPE_SAMPLE) enum { PROP_0, PROP_MSG, LAST_PROP }; static GParamSpec *gParamSpecs [LAST_PROP]; /** * meson_sub_sample_new: * @msg: The message to set. * * Allocates a new #MesonSubSample. * * Returns: (transfer full): a #MesonSubSample. */ MesonSubSample * meson_sub_sample_new (const gchar *msg) { g_return_val_if_fail (msg != NULL, NULL); return g_object_new (MESON_TYPE_SUB_SAMPLE, "message", msg, NULL); } static void meson_sub_sample_finalize (GObject *object) { MesonSubSample *self = (MesonSubSample *)object; g_clear_pointer (&self->msg, g_free); G_OBJECT_CLASS (meson_sub_sample_parent_class)->finalize (object); } static void meson_sub_sample_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MesonSubSample *self = MESON_SUB_SAMPLE (object); switch (prop_id) { case PROP_MSG: g_value_set_string (value, self->msg); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void meson_sub_sample_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MesonSubSample *self = MESON_SUB_SAMPLE (object); switch (prop_id) { case PROP_MSG: self->msg = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void meson_sub_sample_class_init (MesonSubSampleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = meson_sub_sample_finalize; object_class->get_property = meson_sub_sample_get_property; object_class->set_property = meson_sub_sample_set_property; gParamSpecs [PROP_MSG] = g_param_spec_string ("message", "Message", "The message to print.", NULL, (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs); } static void meson_sub_sample_init (MesonSubSample *self) { } /** * meson_sub_sample_print_message: * @self: a #MesonSubSample. * * Prints the message. * * Returns: Nothing. */ void meson_sub_sample_print_message (MesonSubSample *self) { g_return_if_fail (MESON_IS_SUB_SAMPLE (self)); g_print ("Message: %s\n", self->msg); } meson-0.53.2/test cases/frameworks/12 multiple gir/gir/meson-subsample.h0000644000175000017500000000060112772547213027405 0ustar jpakkanejpakkane00000000000000#ifndef MESON_SUB_SAMPLE_H #define MESON_SUB_SAMPLE_H #include #include G_BEGIN_DECLS #define MESON_TYPE_SUB_SAMPLE (meson_sub_sample_get_type()) G_DECLARE_FINAL_TYPE (MesonSubSample, meson_sub_sample, MESON, SUB_SAMPLE, MesonSample) MesonSubSample *meson_sub_sample_new (const gchar *msg); G_END_DECLS #endif /* MESON_SUB_SAMPLE_H */ meson-0.53.2/test cases/frameworks/12 multiple gir/gir/meson.build0000644000175000017500000000120312772547213026263 0ustar jpakkanejpakkane00000000000000libsources = ['meson-subsample.c', 'meson-subsample.h'] girsubproject = shared_library( 'girsubproject', sources : libsources, dependencies : [gobj, girlib_dep], install : true ) girexe = executable( 'girprog', sources : 'prog.c', dependencies : [gobj, girlib_dep], link_with : girsubproject ) gnome.generate_gir( girsubproject, sources : libsources, nsversion : '1.0', namespace : 'MesonSub', symbol_prefix : 'meson_sub_', identifier_prefix : 'MesonSub', includes : ['GObject-2.0', meson_gir], install : true ) message('TEST: ' + girsubproject.outdir()) test('gobject introspection/subproject/c', girexe) meson-0.53.2/test cases/frameworks/12 multiple gir/gir/prog.c0000644000175000017500000000034512772547213025242 0ustar jpakkanejpakkane00000000000000#include "meson-subsample.h" gint main (gint argc, gchar *argv[]) { MesonSample * i = (MesonSample*) meson_sub_sample_new ("Hello, sub/meson/c!"); meson_sample_print_message (i); g_object_unref (i); return 0; } meson-0.53.2/test cases/frameworks/12 multiple gir/installed_files.txt0000644000175000017500000000042613366273215027246 0ustar jpakkanejpakkane00000000000000usr/lib/girepository-1.0/Meson-1.0.typelib usr/lib/girepository-1.0/MesonSub-1.0.typelib usr/lib/?libgirlib.so ?cygwin:usr/lib/libgirlib.dll.a usr/lib/?libgirsubproject.so ?cygwin:usr/lib/libgirsubproject.dll.a usr/share/gir-1.0/Meson-1.0.gir usr/share/gir-1.0/MesonSub-1.0.gir meson-0.53.2/test cases/frameworks/12 multiple gir/meson.build0000644000175000017500000000041413605172304025474 0ustar jpakkanejpakkane00000000000000project('multiple-gobject-introspection', 'c') gir = find_program('g-ir-scanner', required: false) if not gir.found() error('MESON_SKIP_TEST g-ir-scanner not found.') endif gnome = import('gnome') gobj = dependency('gobject-2.0') subdir('mesongir') subdir('gir') meson-0.53.2/test cases/frameworks/12 multiple gir/mesongir/0000755000175000017500000000000013625242373025164 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/12 multiple gir/mesongir/meson-sample.c0000644000175000017500000000553412772547213027742 0ustar jpakkanejpakkane00000000000000#include "meson-sample.h" typedef struct _MesonSamplePrivate { gchar *msg; } MesonSamplePrivate; G_DEFINE_TYPE_WITH_PRIVATE (MesonSample, meson_sample, G_TYPE_OBJECT) enum { PROP_0, PROP_MSG, LAST_PROP }; static GParamSpec *gParamSpecs [LAST_PROP]; /** * meson_sample_new: * @msg: The message to set. * * Allocates a new #MesonSample. * * Returns: (transfer full): a #MesonSample. */ MesonSample * meson_sample_new (const gchar *msg) { g_return_val_if_fail (msg != NULL, NULL); return g_object_new (MESON_TYPE_SAMPLE, "message", msg, NULL); } static void meson_sample_finalize (GObject *object) { MesonSamplePrivate *priv = meson_sample_get_instance_private ((MesonSample *) object); g_clear_pointer (&priv->msg, g_free); G_OBJECT_CLASS (meson_sample_parent_class)->finalize (object); } static void meson_sample_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MesonSamplePrivate *priv = meson_sample_get_instance_private ((MesonSample *) object); switch (prop_id) { case PROP_MSG: g_value_set_string (value, priv->msg); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void meson_sample_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MesonSamplePrivate *priv = meson_sample_get_instance_private ((MesonSample *) object); switch (prop_id) { case PROP_MSG: priv->msg = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void meson_sample_class_init (MesonSampleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = meson_sample_finalize; object_class->get_property = meson_sample_get_property; object_class->set_property = meson_sample_set_property; gParamSpecs [PROP_MSG] = g_param_spec_string ("message", "Message", "The message to print.", NULL, (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs); } static void meson_sample_init (MesonSample *self) { } /** * meson_sample_print_message: * @self: a #MesonSample. * * Prints the message. * */ void meson_sample_print_message (MesonSample *self) { MesonSamplePrivate *priv; g_return_if_fail (MESON_IS_SAMPLE (self)); priv = meson_sample_get_instance_private (self); g_print ("Message: %s\n", priv->msg); } meson-0.53.2/test cases/frameworks/12 multiple gir/mesongir/meson-sample.h.in0000644000175000017500000000067012772547213030350 0ustar jpakkanejpakkane00000000000000#ifndef MESON_SAMPLE_H #define MESON_SAMPLE_H #include <@HEADER@> G_BEGIN_DECLS #define MESON_TYPE_SAMPLE (meson_sample_get_type()) G_DECLARE_DERIVABLE_TYPE (MesonSample, meson_sample, MESON, SAMPLE, GObject) struct _MesonSampleClass { GObjectClass parent_class; }; MesonSample *meson_sample_new (const gchar *msg); void meson_sample_print_message (MesonSample *self); G_END_DECLS #endif /* MESON_SAMPLE_H */ meson-0.53.2/test cases/frameworks/12 multiple gir/mesongir/meson.build0000644000175000017500000000156613340206727027333 0ustar jpakkanejpakkane00000000000000conf = configuration_data() conf.set('HEADER', 'glib-object.h') meson_sample_header = configure_file( input : 'meson-sample.h.in', output : 'meson-sample.h', configuration : conf) libsources = ['meson-sample.c', meson_sample_header] girlib = shared_library( 'girlib', sources : libsources, dependencies : gobj, install : true ) girtarget = gnome.generate_gir( girlib, sources : libsources, nsversion : '1.0', namespace : 'Meson', symbol_prefix : 'meson_', identifier_prefix : 'Meson', includes : ['GObject-2.0'], export_packages : 'meson', install : true ) meson_gir = girtarget[0] meson_typelib = girtarget[1] girlib_inc = include_directories('.') girlib_dep = declare_dependency(link_with : girlib, include_directories : [girlib_inc], dependencies : [gobj], # Everything that uses libgst needs this built to compile sources : girtarget, ) meson-0.53.2/test cases/frameworks/13 yelp/0000755000175000017500000000000013625242373021716 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/13 yelp/help/0000755000175000017500000000000013625242373022646 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/13 yelp/help/C/0000755000175000017500000000000013625242373023030 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/13 yelp/help/C/index.page0000644000175000017500000000025613003456157024775 0ustar jpakkanejpakkane00000000000000 Hello! meson-0.53.2/test cases/frameworks/13 yelp/help/C/media/0000755000175000017500000000000013625242373024107 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/13 yelp/help/C/media/test.txt0000644000175000017500000000000613003456157025620 0ustar jpakkanejpakkane00000000000000hello meson-0.53.2/test cases/frameworks/13 yelp/help/LINGUAS0000644000175000017500000000000613340206727023664 0ustar jpakkanejpakkane00000000000000de es meson-0.53.2/test cases/frameworks/13 yelp/help/de/0000755000175000017500000000000013625242373023236 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/13 yelp/help/de/de.po0000644000175000017500000000045613003456157024170 0ustar jpakkanejpakkane00000000000000msgid "" msgstr "" "Project-Id-Version: meson master\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: page/title #: C/index.page:5 msgid "Hello!" msgstr "Hallo!" meson-0.53.2/test cases/frameworks/13 yelp/help/es/0000755000175000017500000000000013625242373023255 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/13 yelp/help/es/es.po0000644000175000017500000000045713003456157024227 0ustar jpakkanejpakkane00000000000000msgid "" msgstr "" "Project-Id-Version: meson master\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: page/title #: C/index.page:5 msgid "Hello!" msgstr "”Hola!" meson-0.53.2/test cases/frameworks/13 yelp/help/es/media/0000755000175000017500000000000013625242373024334 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/13 yelp/help/es/media/test.txt0000644000175000017500000000000613003456157026045 0ustar jpakkanejpakkane00000000000000Hola. meson-0.53.2/test cases/frameworks/13 yelp/help/meson.build0000644000175000017500000000062113340206727025004 0ustar jpakkanejpakkane00000000000000gnome = import('gnome') gnome.yelp('meson', sources: 'index.page', media: 'media/test.txt', symlink_media: false, languages: ['de', 'es'], ) gnome.yelp('meson-symlink', sources: 'index.page', media: 'media/test.txt', symlink_media: true, languages: ['de', 'es'], ) gnome.yelp('meson-linguas', sources: 'index.page', media: 'media/test.txt', symlink_media: false, ) meson-0.53.2/test cases/frameworks/13 yelp/installed_files.txt0000644000175000017500000000136413340206727025621 0ustar jpakkanejpakkane00000000000000usr/share/help/C/meson/index.page usr/share/help/C/meson/media/test.txt usr/share/help/es/meson/index.page usr/share/help/es/meson/media/test.txt usr/share/help/de/meson/index.page usr/share/help/de/meson/media/test.txt usr/share/help/C/meson-symlink/index.page usr/share/help/C/meson-symlink/media/test.txt usr/share/help/es/meson-symlink/media/test.txt usr/share/help/es/meson-symlink/index.page usr/share/help/de/meson-symlink/index.page usr/share/help/de/meson-symlink/media/test.txt usr/share/help/C/meson-linguas/index.page usr/share/help/C/meson-linguas/media/test.txt usr/share/help/es/meson-linguas/media/test.txt usr/share/help/es/meson-linguas/index.page usr/share/help/de/meson-linguas/index.page usr/share/help/de/meson-linguas/media/test.txt meson-0.53.2/test cases/frameworks/13 yelp/meson.build0000644000175000017500000000024413605172277024063 0ustar jpakkanejpakkane00000000000000project('yelp', 'c') itstool = find_program('itstool', required: false) if not itstool.found() error('MESON_SKIP_TEST itstool not found.') endif subdir('help') meson-0.53.2/test cases/frameworks/14 doxygen/0000755000175000017500000000000013625242373022423 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/14 doxygen/doc/0000755000175000017500000000000013625242373023170 5ustar jpakkanejpakkane00000000000000meson-0.53.2/test cases/frameworks/14 doxygen/doc/Doxyfile.in0000644000175000017500000032212713057037357025315 0ustar jpakkanejpakkane00000000000000# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "The Vast Comedian Project" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = @VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = Comedy generator # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = YES # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 0. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = "@TOP_SRCDIR@/include" "@TOP_SRCDIR@/src" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, # *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.idl \ *.ddl \ *.odl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.cs \ *.d \ *.php \ *.php4 \ *.php5 \ *.phtml \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.pyw \ *.f90 \ *.f95 \ *.f03 \ *.f08 \ *.f \ *.for \ *.tcl \ *.vhd \ *.vhdl \ *.ucf \ *.qsf # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /